diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000000000000000000000000000000000..959cda4af1f990baacf9297b932e2e625a32af6a --- /dev/null +++ b/.gitattributes @@ -0,0 +1,37 @@ +*.7z filter=lfs diff=lfs merge=lfs -text +*.arrow filter=lfs diff=lfs merge=lfs -text +*.bin filter=lfs diff=lfs merge=lfs -text +*.bz2 filter=lfs diff=lfs merge=lfs -text +*.ckpt filter=lfs diff=lfs merge=lfs -text +*.ftz filter=lfs diff=lfs merge=lfs -text +*.gz filter=lfs diff=lfs merge=lfs -text +*.h5 filter=lfs diff=lfs merge=lfs -text +*.joblib filter=lfs diff=lfs merge=lfs -text +*.lfs.* filter=lfs diff=lfs merge=lfs -text +*.mlmodel filter=lfs diff=lfs merge=lfs -text +*.model filter=lfs diff=lfs merge=lfs -text +*.msgpack filter=lfs diff=lfs merge=lfs -text +*.npy filter=lfs diff=lfs merge=lfs -text +*.npz filter=lfs diff=lfs merge=lfs -text +*.onnx filter=lfs diff=lfs merge=lfs -text +*.ot filter=lfs diff=lfs merge=lfs -text +*.parquet filter=lfs diff=lfs merge=lfs -text +*.pb filter=lfs diff=lfs merge=lfs -text +*.pickle filter=lfs diff=lfs merge=lfs -text +*.pkl filter=lfs diff=lfs merge=lfs -text +*.pt filter=lfs diff=lfs merge=lfs -text +*.pth filter=lfs diff=lfs merge=lfs -text +*.rar filter=lfs diff=lfs merge=lfs -text +*.safetensors filter=lfs diff=lfs merge=lfs -text +saved_model/**/* filter=lfs diff=lfs merge=lfs -text +*.tar.* filter=lfs diff=lfs merge=lfs -text +*.tar filter=lfs diff=lfs merge=lfs -text +*.tflite filter=lfs diff=lfs merge=lfs -text +*.tgz filter=lfs diff=lfs merge=lfs -text +*.wasm filter=lfs diff=lfs merge=lfs -text +*.xz filter=lfs diff=lfs merge=lfs -text +*.zip filter=lfs diff=lfs merge=lfs -text +*.zst filter=lfs diff=lfs merge=lfs -text +*tfevents* filter=lfs diff=lfs merge=lfs -text +*.whl filter=lfs diff=lfs merge=lfs -text +*.mp4 filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..fa7ae719d030ae7060cea54aef785c4bbae9b75a --- /dev/null +++ b/.gitignore @@ -0,0 +1,159 @@ +# Local notebooks used for local debug +notebooks_local/ +wandb/ + +# Gradio files + +served_files/ + +# hidden folders +.*/** + +# The rest is taken from https://github.com/Anttwo/SuGaR +*.pt +*.pth +output* +*.slurm +*.pyc +*.ply +*.obj +sugar_tests.ipynb +sugar_sh_tests.ipynb + +# To remove +frosting* +extract_shell.py +train_frosting_refined.py +train_frosting.py +run_frosting_viewer.py +slurm_a100.sh + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ +learnableearthparser/fast_sampler/_sampler.c diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000000000000000000000000000000000000..d3b17cbb35125414350ef6cebe4ca79b2960b28e --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,12 @@ +Copyright 2025, Dmytro Kotovenko, Olga Grebenkova, BjΓΆrn Ommer +Redistribution and use in source and binary forms, with or without modification, are permitted for non-commercial academic research and/or non-commercial personal use only provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +Any use of this software beyond the above specified conditions requires a separate license. Please contact the copyright holders to discuss license terms. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..ea1440f127a4e48bf04f5d01c9963ce54d7c7d0b --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +--- +title: EDGS +emoji: πŸŽ₯ +colorFrom: pink +colorTo: blue +sdk: gradio +sdk_version: 5.25.2 +app_file: app.py +pinned: false +python_version: "3.10" +license: other +--- + +Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference \ No newline at end of file diff --git a/app.py b/app.py new file mode 100644 index 0000000000000000000000000000000000000000..ebb75a0aab5734336904f61d72211586237c0de9 --- /dev/null +++ b/app.py @@ -0,0 +1,434 @@ +import spaces +import torch +import os +import shutil +import tempfile +import argparse +import gradio as gr +import sys +import io +import subprocess +from PIL import Image +import numpy as np +from hydra import initialize, compose +import hydra +from omegaconf import OmegaConf +import time + +def install_submodules(): + subprocess.check_call(['pip', 'install', './submodules/RoMa']) + + + +STATIC_FILE_SERVING_FOLDER = "./served_files" +MODEL_PATH = None +os.makedirs(STATIC_FILE_SERVING_FOLDER, exist_ok=True) + +trainer = None + +class Tee(io.TextIOBase): + + def __init__(self, *streams): + self.streams = streams + + def write(self, data): + for stream in self.streams: + stream.write(data) + return len(data) + + def flush(self): + for stream in self.streams: + stream.flush() + + +def capture_logs(func, *args, **kwargs): + log_capture_string = io.StringIO() + tee = Tee(sys.__stdout__, log_capture_string) + + with contextlib.redirect_stdout(tee): + result = func(*args, **kwargs) + + return result, log_capture_string.getvalue() + + +@spaces.GPU(duration=350) +# Training Pipeline +def run_training_pipeline(scene_dir, + num_ref_views=16, + num_corrs_per_view=20000, + num_steps=1_000, + mode_toggle="Ours (EDGS)"): + with initialize(config_path="./configs", version_base="1.1"): + cfg = compose(config_name="train") + + scene_name = os.path.basename(scene_dir) + model_output_dir = f"./outputs/{scene_name}_trained" + + cfg.wandb.mode = "disabled" + cfg.gs.dataset.model_path = model_output_dir + cfg.gs.dataset.source_path = scene_dir + cfg.gs.dataset.images = "images" + + cfg.gs.opt.TEST_CAM_IDX_TO_LOG = 12 + cfg.train.gs_epochs = 30000 + + if mode_toggle=="Ours (EDGS)": + cfg.gs.opt.opacity_reset_interval = 1_000_000 + cfg.train.reduce_opacity = True + cfg.train.no_densify = True + cfg.train.max_lr = True + + cfg.init_wC.use = True + cfg.init_wC.matches_per_ref = num_corrs_per_view + cfg.init_wC.nns_per_ref = 1 + cfg.init_wC.num_refs = num_ref_views + cfg.init_wC.add_SfM_init = False + cfg.init_wC.scaling_factor = 0.00077 * 2. + + set_seed(cfg.seed) + os.makedirs(cfg.gs.dataset.model_path, exist_ok=True) + + global trainer + global MODEL_PATH + generator3dgs = hydra.utils.instantiate(cfg.gs, do_train_test_split=False) + trainer = EDGSTrainer(GS=generator3dgs, training_config=cfg.gs.opt, device=cfg.device, log_wandb=cfg.wandb.mode != 'disabled') + + # Disable evaluation and saving + trainer.saving_iterations = [] + trainer.evaluate_iterations = [] + + # Initialize + trainer.timer.start() + start_time = time.time() + trainer.init_with_corr(cfg.init_wC, roma_model=roma_model) + time_for_init = time.time()-start_time + + viewpoint_cams = trainer.GS.scene.getTrainCameras() + path_cameras = generate_fully_smooth_cameras_with_tsp(existing_cameras=viewpoint_cams, + n_selected=6, + n_points_per_segment=30, + closed=False) + path_cameras = path_cameras + path_cameras[::-1] + + path_renderings = [] + idx = 0 + # Visualize after init + for _ in range(120): + with torch.no_grad(): + viewpoint_cam = path_cameras[idx] + idx = (idx + 1) % len(path_cameras) + render_pkg = trainer.GS(viewpoint_cam) + image = render_pkg["render"] + image_np = np.clip(image.detach().cpu().numpy().transpose(1, 2, 0), 0, 1) + image_np = (image_np * 255).astype(np.uint8) + path_renderings.append(put_text_on_image(img=image_np, + text=f"Init stage.\nTime:{time_for_init:.3f}s. ")) + path_renderings = path_renderings + [put_text_on_image(img=image_np, text=f"Start fitting.\nTime:{time_for_init:.3f}s. ")]*30 + + # Train and save visualizations during training. + start_time = time.time() + for _ in range(int(num_steps//10)): + with torch.no_grad(): + viewpoint_cam = path_cameras[idx] + idx = (idx + 1) % len(path_cameras) + render_pkg = trainer.GS(viewpoint_cam) + image = render_pkg["render"] + image_np = np.clip(image.detach().cpu().numpy().transpose(1, 2, 0), 0, 1) + image_np = (image_np * 255).astype(np.uint8) + path_renderings.append(put_text_on_image( + img=image_np, + text=f"Fitting stage.\nTime:{time_for_init + time.time()-start_time:.3f}s. ")) + + cfg.train.gs_epochs = 10 + trainer.train(cfg.train) + print(f"Time elapsed: {(time_for_init + time.time()-start_time):.2f}s.") + # if (cfg.init_wC.use == False) and (time_for_init + time.time()-start_time) > 60: + # break + final_time = time.time() + + # Add static frame. To highlight we're done + path_renderings += [put_text_on_image( + img=image_np, text=f"Done.\nTime:{time_for_init + final_time -start_time:.3f}s. ")]*30 + # Final rendering at the end. + for _ in range(len(path_cameras)): + with torch.no_grad(): + viewpoint_cam = path_cameras[idx] + idx = (idx + 1) % len(path_cameras) + render_pkg = trainer.GS(viewpoint_cam) + image = render_pkg["render"] + image_np = np.clip(image.detach().cpu().numpy().transpose(1, 2, 0), 0, 1) + image_np = (image_np * 255).astype(np.uint8) + path_renderings.append(put_text_on_image(img=image_np, + text=f"Final result.\nTime:{time_for_init + final_time -start_time:.3f}s. ")) + + trainer.save_model() + final_video_path = os.path.join(STATIC_FILE_SERVING_FOLDER, f"{scene_name}_final.mp4") + save_numpy_frames_as_mp4(frames=path_renderings, output_path=final_video_path, fps=30, center_crop=0.85) + MODEL_PATH = cfg.gs.dataset.model_path + ply_path = os.path.join(cfg.gs.dataset.model_path, f"point_cloud/iteration_{trainer.gs_step}/point_cloud.ply") + shutil.copy(ply_path, os.path.join(STATIC_FILE_SERVING_FOLDER, "point_cloud_final.ply")) + + return final_video_path, ply_path + +# Gradio Interface +def gradio_interface(input_path, num_ref_views, num_corrs, num_steps): + images, scene_dir = run_full_pipeline(input_path, num_ref_views, num_corrs, max_size=1024) + shutil.copytree(scene_dir, STATIC_FILE_SERVING_FOLDER+'/scene_colmaped', dirs_exist_ok=True) + (final_video_path, ply_path), log_output = capture_logs(run_training_pipeline, + scene_dir, + num_ref_views, + num_corrs, + num_steps + ) + images_rgb = [img[:, :, ::-1] for img in images] + return images_rgb, final_video_path, scene_dir, ply_path, log_output + +# Dummy Render Functions +@spaces.GPU(duration=60) +def render_all_views(scene_dir): + viewpoint_cams = trainer.GS.scene.getTrainCameras() + path_cameras = generate_fully_smooth_cameras_with_tsp(existing_cameras=viewpoint_cams, + n_selected=8, + n_points_per_segment=60, + closed=False) + path_cameras = path_cameras + path_cameras[::-1] + + path_renderings = [] + with torch.no_grad(): + for viewpoint_cam in path_cameras: + render_pkg = trainer.GS(viewpoint_cam) + image = render_pkg["render"] + image_np = np.clip(image.detach().cpu().numpy().transpose(1, 2, 0), 0, 1) + image_np = (image_np * 255).astype(np.uint8) + path_renderings.append(image_np) + save_numpy_frames_as_mp4(frames=path_renderings, + output_path=os.path.join(STATIC_FILE_SERVING_FOLDER, "render_all_views.mp4"), + fps=30, + center_crop=0.85) + + return os.path.join(STATIC_FILE_SERVING_FOLDER, "render_all_views.mp4") + +@spaces.GPU(duration=60) +def render_circular_path(scene_dir): + viewpoint_cams = trainer.GS.scene.getTrainCameras() + path_cameras = generate_circular_camera_path(existing_cameras=viewpoint_cams, + N=240, + radius_scale=0.65, + d=0) + + path_renderings = [] + with torch.no_grad(): + for viewpoint_cam in path_cameras: + render_pkg = trainer.GS(viewpoint_cam) + image = render_pkg["render"] + image_np = np.clip(image.detach().cpu().numpy().transpose(1, 2, 0), 0, 1) + image_np = (image_np * 255).astype(np.uint8) + path_renderings.append(image_np) + save_numpy_frames_as_mp4(frames=path_renderings, + output_path=os.path.join(STATIC_FILE_SERVING_FOLDER, "render_circular_path.mp4"), + fps=30, + center_crop=0.85) + + return os.path.join(STATIC_FILE_SERVING_FOLDER, "render_circular_path.mp4") + +# Download Functions +def download_cameras(): + path = os.path.join(MODEL_PATH, "cameras.json") + return f"[πŸ“₯ Download Cameras.json](file={path})" + +def download_model(): + path = os.path.join(STATIC_FILE_SERVING_FOLDER, "point_cloud_final.ply") + return f"[πŸ“₯ Download Pretrained Model (.ply)](file={path})" + +# Full pipeline helpers +def run_full_pipeline(input_path, num_ref_views, num_corrs, max_size=1024): + tmpdirname = tempfile.mkdtemp() + scene_dir = os.path.join(tmpdirname, "scene") + os.makedirs(scene_dir, exist_ok=True) + + selected_frames = process_input(input_path, num_ref_views, scene_dir, max_size) + run_colmap_on_scene(scene_dir) + + return selected_frames, scene_dir + +# Preprocess Input +def process_input(input_path, num_ref_views, output_dir, max_size=1024): + if isinstance(input_path, (str, os.PathLike)): + if os.path.isdir(input_path): + frames = [] + for img_file in sorted(os.listdir(input_path)): + if img_file.lower().endswith(('jpg', 'jpeg', 'png')): + img = Image.open(os.path.join(output_dir, img_file)).convert('RGB') + img.thumbnail((1024, 1024)) + frames.append(np.array(img)) + else: + frames = read_video_frames(video_input=input_path, max_size=max_size) + else: + frames = read_video_frames(video_input=input_path, max_size=max_size) + + frames_scores = preprocess_frames(frames) + selected_frames_indices = select_optimal_frames(scores=frames_scores, k=min(num_ref_views, len(frames))) + selected_frames = [frames[frame_idx] for frame_idx in selected_frames_indices] + + save_frames_to_scene_dir(frames=selected_frames, scene_dir=output_dir) + return selected_frames + +@spaces.GPU(duration=150) +def preprocess_input(input_path, num_ref_views, max_size=1024): + tmpdirname = tempfile.mkdtemp() + scene_dir = os.path.join(tmpdirname, "scene") + os.makedirs(scene_dir, exist_ok=True) + selected_frames = process_input(input_path, num_ref_views, scene_dir, max_size) + run_colmap_on_scene(scene_dir) + return selected_frames, scene_dir + +def start_training(scene_dir, num_ref_views, num_corrs, num_steps): + return capture_logs(run_training_pipeline, scene_dir, num_ref_views, num_corrs, num_steps) + +# Gradio App +with gr.Blocks() as demo: + with gr.Row(): + with gr.Column(scale=6): + gr.Markdown(""" + ## πŸ“„ EDGS: Eliminating Densification for Efficient Convergence of 3DGS + πŸ”— Project Page + """, elem_id="header") + + gr.Markdown(""" + ### πŸ› οΈ How to Use This Demo + + 1. Upload a **front-facing video** or **a folder of images** of a **static** scene. + 2. Use the sliders to configure the number of reference views, correspondences, and optimization steps. + 3. First press on preprocess Input to extract frames from video(for videos) and COLMAP frames. + 4.Then click **πŸš€ Start Reconstruction** to actually launch the reconstruction pipeline. + 5. Watch the training visualization and explore the 3D model. + ‼️ **If you see nothing in the 3D model viewer**, try rotating or zooming β€” sometimes the initial camera orientation is off. + + + βœ… Best for scenes with small camera motion. + ❗ For full 360Β° or large-scale scenes, we recommend the Colab version (see project page). + """, elem_id="quickstart") + scene_dir_state = gr.State() + ply_model_state = gr.State() + with gr.Row(): + with gr.Column(scale=2): + input_file = gr.File(label="Upload Video or Images", + file_types=[".mp4", ".avi", ".mov", ".png", ".jpg", ".jpeg"], + file_count="multiple") + gr.Examples( + examples = [ + [["assets/examples/video_bakery.mp4"]], + [["assets/examples/video_flowers.mp4"]], + [["assets/examples/video_fruits.mp4"]], + [["assets/examples/video_plant.mp4"]], + [["assets/examples/video_salad.mp4"]], + [["assets/examples/video_tram.mp4"]], + [["assets/examples/video_tulips.mp4"]] + ], + inputs=[input_file], + label="🎞️ ALternatively, try an Example Video", + examples_per_page=4 + ) + ref_slider = gr.Slider(4, 32, value=16, step=1, label="Number of Reference Views") + corr_slider = gr.Slider(5000, 30000, value=20000, step=1000, label="Correspondences per Reference View") + fit_steps_slider = gr.Slider(100, 5000, value=400, step=100, label="Number of optimization steps") + preprocess_button = gr.Button("πŸ“Έ Preprocess Input") + start_button = gr.Button("πŸš€ Start Reconstruction", interactive=False) + gallery = gr.Gallery(label="Selected Reference Views", columns=4, height=300) + + with gr.Column(scale=3): + gr.Markdown("### πŸ‹οΈ Training Visualization") + video_output = gr.Video(label="Training Video", autoplay=True) + render_all_views_button = gr.Button("πŸŽ₯ Render All-Views Path") + render_circular_path_button = gr.Button("πŸŽ₯ Render Circular Path") + rendered_video_output = gr.Video(label="Rendered Video", autoplay=True) + with gr.Column(scale=5): + gr.Markdown("### 🌐 Final 3D Model") + model3d_viewer = gr.Model3D(label="3D Model Viewer") + + gr.Markdown("### πŸ“¦ Output Files") + with gr.Row(height=50): + with gr.Column(): + #gr.Markdown(value=f"[πŸ“₯ Download .ply](file/point_cloud_final.ply)") + download_cameras_button = gr.Button("πŸ“₯ Download Cameras.json") + download_cameras_file = gr.File(label="πŸ“„ Cameras.json") + with gr.Column(): + download_model_button = gr.Button("πŸ“₯ Download Pretrained Model (.ply)") + download_model_file = gr.File(label="πŸ“„ Pretrained Model (.ply)") + + log_output_box = gr.Textbox(label="πŸ–₯️ Log", lines=10, interactive=False) + + def on_preprocess_click(input_file, num_ref_views): + images, scene_dir = preprocess_input(input_file, num_ref_views) + return gr.update(value=[x[...,::-1] for x in images]), scene_dir, gr.update(interactive=True) + + def on_start_click(scene_dir, num_ref_views, num_corrs, num_steps): + (video_path, ply_path), logs = start_training(scene_dir, num_ref_views, num_corrs, num_steps) + return video_path, ply_path, logs + + preprocess_button.click( + fn=on_preprocess_click, + inputs=[input_file, ref_slider], + outputs=[gallery, scene_dir_state, start_button] + ) + + start_button.click( + fn=on_start_click, + inputs=[scene_dir_state, ref_slider, corr_slider, fit_steps_slider], + outputs=[video_output, model3d_viewer, log_output_box] + ) + + render_all_views_button.click(fn=render_all_views, inputs=[scene_dir_state], outputs=[rendered_video_output]) + render_circular_path_button.click(fn=render_circular_path, inputs=[scene_dir_state], outputs=[rendered_video_output]) + + download_cameras_button.click(fn=lambda: os.path.join(MODEL_PATH, "cameras.json"), inputs=[], outputs=[download_cameras_file]) + download_model_button.click(fn=lambda: os.path.join(STATIC_FILE_SERVING_FOLDER, "point_cloud_final.ply"), inputs=[], outputs=[download_model_file]) + + + gr.Markdown(""" + --- + ### πŸ“– Detailed Overview + + If you uploaded a video, it will be automatically cut into a smaller number of frames (default: 16). + + The model pipeline: + 1. 🧠 Runs PyCOLMAP to estimate camera intrinsics & poses (~3–7 seconds for <16 images). + 2. πŸ” Computes 2D-2D correspondences between views. More correspondences generally improve quality. + 3. πŸ”§ Optimizes a 3D Gaussian Splatting model for several steps. + + ### πŸŽ₯ Training Visualization + You will see a visualization of the entire training process in the "Training Video" pane. + + ### πŸŒ€ Rendering & 3D Model + - Render the scene from a circular path of novel views. + - Or from camera views close to the original input. + + The 3D model is shown in the right viewer. You can explore it interactively: + - On PC: WASD keys, arrow keys, and mouse clicks + - On mobile: pan and pinch to zoom + + πŸ•’ Note: the 3D viewer takes a few extra seconds (~5s) to display after training ends. + + --- + Preloaded models coming soon. (TODO) + """, elem_id="details") + + + + +if __name__ == "__main__": + install_submodules() + from source.utils_aux import set_seed + from source.utils_preprocess import read_video_frames, preprocess_frames, select_optimal_frames, save_frames_to_scene_dir, run_colmap_on_scene + from source.trainer import EDGSTrainer + from source.visualization import generate_circular_camera_path, save_numpy_frames_as_mp4, generate_fully_smooth_cameras_with_tsp, put_text_on_image + # Init RoMA model: + sys.path.append('../submodules/RoMa') + from romatch import roma_outdoor, roma_indoor + + roma_model = roma_indoor(device="cpu") + roma_model = roma_model.to("cuda") + roma_model.upsample_preds = False + roma_model.symmetric = False + + demo.launch(share=True) diff --git a/assets/examples/video_bakery.mp4 b/assets/examples/video_bakery.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..95e4788e30b5cf204147a6b190a87f8634237154 --- /dev/null +++ b/assets/examples/video_bakery.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b65c813f2ef9637579350e145fdceed333544d933278be5613c6d49468f4eab0 +size 6362238 diff --git a/assets/examples/video_flowers.mp4 b/assets/examples/video_flowers.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..8d78d5069645162640bff197769351c6315cb290 --- /dev/null +++ b/assets/examples/video_flowers.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c81a7c28e0d59bad38d5a45f6bfa83b80990d1fb78a06f82137e8b57ec38e62b +size 6466943 diff --git a/assets/examples/video_fruits.mp4 b/assets/examples/video_fruits.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..67f28702245db3a1a63fbbc51ffe9ae91974f849 --- /dev/null +++ b/assets/examples/video_fruits.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ac3b937e155d1965a314b478e940f6fd93e90371d3bf7d62d3225d840fe8e126 +size 3356915 diff --git a/assets/examples/video_plant.mp4 b/assets/examples/video_plant.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..2193decaeaedd647bf9518dbe48b94305c0bf7bc --- /dev/null +++ b/assets/examples/video_plant.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e67a40e62de9aacf0941d8cf33a2dd08d256fe60d0fc58f60426c251f9d8abd8 +size 13023885 diff --git a/assets/examples/video_salad.mp4 b/assets/examples/video_salad.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..e8a8ecf4255387f3fc250061dc1db1c33ac14e38 --- /dev/null +++ b/assets/examples/video_salad.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:367d86071a201c124383f0a076ce644b7f86b9c2fbce6aa595c4989ebf259bfb +size 8774427 diff --git a/assets/examples/video_tram.mp4 b/assets/examples/video_tram.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..4c12f5829696b6d6cc4b6e801938ddc5e3041313 --- /dev/null +++ b/assets/examples/video_tram.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:298c297155d3f52edcffcb6b6f9910c992b98ecfb93cfaf8fb64fb340aba1dae +size 4697915 diff --git a/assets/examples/video_tulips.mp4 b/assets/examples/video_tulips.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..1a8747c5bad769c90de4e7dfd7d43b7eb7d5081e --- /dev/null +++ b/assets/examples/video_tulips.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c19942319b8f7e33bb03cb4a39b11797fe38572bf7157af37471b7c8573fb495 +size 7298210 diff --git a/assets/video_fruits_ours_full.mp4 b/assets/video_fruits_ours_full.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..33383013e7df0dcc01ae2a4ff624345959f830cf --- /dev/null +++ b/assets/video_fruits_ours_full.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9c5b113566d3a083b81360b549ed89f70d5e81739f83e182518f6906811311a2 +size 14839197 diff --git a/configs/gs/base.yaml b/configs/gs/base.yaml new file mode 100644 index 0000000000000000000000000000000000000000..5a74ddca24dc480d9332aea2c67ea7069ddb0307 --- /dev/null +++ b/configs/gs/base.yaml @@ -0,0 +1,51 @@ +_target_: source.networks.Warper3DGS + +verbose: True +viewpoint_stack: !!null +sh_degree: 3 + +opt: + iterations: 30000 + position_lr_init: 0.00016 + position_lr_final: 1.6e-06 + position_lr_delay_mult: 0.01 + position_lr_max_steps: 30000 + feature_lr: 0.0025 + opacity_lr: 0.025 + scaling_lr: 0.005 + rotation_lr: 0.001 + percent_dense: 0.01 + lambda_dssim: 0.2 + densification_interval: 100 + opacity_reset_interval: 30000 + densify_from_iter: 500 + densify_until_iter: 15000 + densify_grad_threshold: 0.0002 + random_background: false + save_iterations: [3000, 7000, 15000, 30000] + batch_size: 64 + exposure_lr_init: 0.01 + exposure_lr_final: 0.0001 + exposure_lr_delay_steps: 0 + exposure_lr_delay_mult: 0.0 + + TRAIN_CAM_IDX_TO_LOG: 50 + TEST_CAM_IDX_TO_LOG: 10 + +pipe: + convert_SHs_python: False + compute_cov3D_python: False + debug: False + antialiasing: False + +dataset: + densify_until_iter: 15000 + source_path: '' #path to dataset + model_path: '' #path to logs + images: images + resolution: -1 + white_background: false + data_device: cuda + eval: false + depths: "" + train_test_exp: False \ No newline at end of file diff --git a/configs/train.yaml b/configs/train.yaml new file mode 100644 index 0000000000000000000000000000000000000000..e40ec5be88301016a1c7b4da5d4f3b383b050909 --- /dev/null +++ b/configs/train.yaml @@ -0,0 +1,38 @@ +defaults: + - gs: base + - _self_ + +seed: 228 + +wandb: + mode: "online" # "disabled" for no logging + entity: "3dcorrespondence" + project: "Adv3DGS" + group: null + name: null + tag: "debug" + +train: + gs_epochs: 0 # number of 3dgs iterations + reduce_opacity: True + no_densify: False # if True, the model will not be densified + max_lr: True + +load: + gs: null #path to 3dgs checkpoint + gs_step: null #number of iterations, e.g. 7000 + +device: "cuda:0" +verbose: true + +init_wC: + use: True # use EDGS + matches_per_ref: 15_000 # number of matches per reference + num_refs: 180 # number of reference images + nns_per_ref: 3 # number of nearest neighbors per reference + scaling_factor: 0.001 + proj_err_tolerance: 0.01 + roma_model: "outdoors" # you can change this to "indoors" or "outdoors" + add_SfM_init : False + + diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..c1a2f0e191da208e920757a089451867aef12741 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,32 @@ +--extra-index-url https://download.pytorch.org/whl/cu124 +torch +torchvision +torchaudio + + +# Required libraries from pip +Pillow +huggingface_hub +einops +safetensors +sympy==1.13.1 +wandb +hydra-core +tqdm +torchmetrics +lpips +matplotlib +rich +plyfile +imageio +imageio-ffmpeg +numpy==1.26.4 # Match conda-installed version +opencv-python +pycolmap +moviepy +plotly +scikit-learn +ffmpeg + +https://huggingface.co/spaces/magistrkoljan/test/resolve/main/wheels/diff_gaussian_rasterization-0.0.0-cp310-cp310-linux_x86_64.whl?download=true +https://huggingface.co/spaces/magistrkoljan/test/resolve/main/wheels/simple_knn-0.0.0-cp310-cp310-linux_x86_64.whl?download=true diff --git a/source/EDGS.code-workspace b/source/EDGS.code-workspace new file mode 100644 index 0000000000000000000000000000000000000000..edaa508ccdc6a9c70ca61d91e4ac1f74c34c0c78 --- /dev/null +++ b/source/EDGS.code-workspace @@ -0,0 +1,11 @@ +{ + "folders": [ + { + "path": ".." + }, + { + "path": "../../../../.." + } + ], + "settings": {} +} \ No newline at end of file diff --git a/source/__init__.py b/source/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/source/corr_init.py b/source/corr_init.py new file mode 100644 index 0000000000000000000000000000000000000000..e63c5abc9264fc74924744ca270d207ee71e8fe3 --- /dev/null +++ b/source/corr_init.py @@ -0,0 +1,682 @@ +import sys +sys.path.append('../') +sys.path.append("../submodules") +sys.path.append('../submodules/RoMa') + +from matplotlib import pyplot as plt +from PIL import Image +import torch +import numpy as np + +#from tqdm import tqdm_notebook as tqdm +from tqdm import tqdm +from scipy.cluster.vq import kmeans, vq +from scipy.spatial.distance import cdist + +import torch.nn.functional as F +from romatch import roma_outdoor, roma_indoor +from utils.sh_utils import RGB2SH +from romatch.utils import get_tuple_transform_ops + + +def pairwise_distances(matrix): + """ + Computes the pairwise Euclidean distances between all vectors in the input matrix. + + Args: + matrix (torch.Tensor): Input matrix of shape [N, D], where N is the number of vectors and D is the dimensionality. + + Returns: + torch.Tensor: Pairwise distance matrix of shape [N, N]. + """ + # Compute squared pairwise distances + squared_diff = torch.cdist(matrix, matrix, p=2) + return squared_diff + + +def k_closest_vectors(matrix, k): + """ + Finds the k-closest vectors for each vector in the input matrix based on Euclidean distance. + + Args: + matrix (torch.Tensor): Input matrix of shape [N, D], where N is the number of vectors and D is the dimensionality. + k (int): Number of closest vectors to return for each vector. + + Returns: + torch.Tensor: Indices of the k-closest vectors for each vector, excluding the vector itself. + """ + # Compute pairwise distances + distances = pairwise_distances(matrix) + + # For each vector, sort distances and get the indices of the k-closest vectors (excluding itself) + # Set diagonal distances to infinity to exclude the vector itself from the nearest neighbors + distances.fill_diagonal_(float('inf')) + + # Get the indices of the k smallest distances (k-closest vectors) + _, indices = torch.topk(distances, k, largest=False, dim=1) + + return indices + + +def select_cameras_kmeans(cameras, K): + """ + Selects K cameras from a set using K-means clustering. + + Args: + cameras: NumPy array of shape (N, 16), representing N cameras with their 4x4 homogeneous matrices flattened. + K: Number of clusters (cameras to select). + + Returns: + selected_indices: List of indices of the cameras closest to the cluster centers. + """ + # Ensure input is a NumPy array + if not isinstance(cameras, np.ndarray): + cameras = np.asarray(cameras) + + if cameras.shape[1] != 16: + raise ValueError("Each camera must have 16 values corresponding to a flattened 4x4 matrix.") + + # Perform K-means clustering + cluster_centers, _ = kmeans(cameras, K) + + # Assign each camera to a cluster and find distances to cluster centers + cluster_assignments, _ = vq(cameras, cluster_centers) + + # Find the camera nearest to each cluster center + selected_indices = [] + for k in range(K): + cluster_members = cameras[cluster_assignments == k] + distances = cdist([cluster_centers[k]], cluster_members)[0] + nearest_camera_idx = np.where(cluster_assignments == k)[0][np.argmin(distances)] + selected_indices.append(nearest_camera_idx) + + return selected_indices + + +def compute_warp_and_confidence(viewpoint_cam1, viewpoint_cam2, roma_model, device="cuda", verbose=False, output_dict={}): + """ + Computes the warp and confidence between two viewpoint cameras using the roma_model. + + Args: + viewpoint_cam1: Source viewpoint camera. + viewpoint_cam2: Target viewpoint camera. + roma_model: Pre-trained Roma model for correspondence matching. + device: Device to run the computation on. + verbose: If True, displays the images. + + Returns: + certainty: Confidence tensor. + warp: Warp tensor. + imB: Processed image B as numpy array. + """ + # Prepare images + imA = viewpoint_cam1.original_image.detach().cpu().numpy().transpose(1, 2, 0) + imB = viewpoint_cam2.original_image.detach().cpu().numpy().transpose(1, 2, 0) + imA = Image.fromarray(np.clip(imA * 255, 0, 255).astype(np.uint8)) + imB = Image.fromarray(np.clip(imB * 255, 0, 255).astype(np.uint8)) + + if verbose: + fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(16, 8)) + cax1 = ax[0].imshow(imA) + ax[0].set_title("Image 1") + cax2 = ax[1].imshow(imB) + ax[1].set_title("Image 2") + fig.colorbar(cax1, ax=ax[0]) + fig.colorbar(cax2, ax=ax[1]) + + for axis in ax: + axis.axis('off') + # Save the figure into the dictionary + output_dict[f'image_pair'] = fig + + # Transform images + ws, hs = roma_model.w_resized, roma_model.h_resized + test_transform = get_tuple_transform_ops(resize=(hs, ws), normalize=True) + im_A, im_B = test_transform((imA, imB)) + batch = {"im_A": im_A[None].to(device), "im_B": im_B[None].to(device)} + + # Forward pass through Roma model + corresps = roma_model.forward(batch) if not roma_model.symmetric else roma_model.forward_symmetric(batch) + finest_scale = 1 + hs, ws = roma_model.upsample_res if roma_model.upsample_preds else (hs, ws) + + # Process certainty and warp + certainty = corresps[finest_scale]["certainty"] + im_A_to_im_B = corresps[finest_scale]["flow"] + if roma_model.attenuate_cert: + low_res_certainty = F.interpolate( + corresps[16]["certainty"], size=(hs, ws), align_corners=False, mode="bilinear" + ) + certainty -= 0.5 * low_res_certainty * (low_res_certainty < 0) + + # Upsample predictions if needed + if roma_model.upsample_preds: + im_A_to_im_B = F.interpolate( + im_A_to_im_B, size=(hs, ws), align_corners=False, mode="bilinear" + ) + certainty = F.interpolate( + certainty, size=(hs, ws), align_corners=False, mode="bilinear" + ) + + # Convert predictions to final format + im_A_to_im_B = im_A_to_im_B.permute(0, 2, 3, 1) + im_A_coords = torch.stack(torch.meshgrid( + torch.linspace(-1 + 1 / hs, 1 - 1 / hs, hs, device=device), + torch.linspace(-1 + 1 / ws, 1 - 1 / ws, ws, device=device), + indexing='ij' + ), dim=0).permute(1, 2, 0).unsqueeze(0).expand(im_A_to_im_B.size(0), -1, -1, -1) + + warp = torch.cat((im_A_coords, im_A_to_im_B), dim=-1) + certainty = certainty.sigmoid() + + return certainty[0, 0], warp[0], np.array(imB) + + +def resize_batch(tensors_3d, tensors_4d, target_shape): + """ + Resizes a batch of tensors with shapes [B, H, W] and [B, H, W, 4] to the target spatial dimensions. + + Args: + tensors_3d: Tensor of shape [B, H, W]. + tensors_4d: Tensor of shape [B, H, W, 4]. + target_shape: Tuple (target_H, target_W) specifying the target spatial dimensions. + + Returns: + resized_tensors_3d: Tensor of shape [B, target_H, target_W]. + resized_tensors_4d: Tensor of shape [B, target_H, target_W, 4]. + """ + target_H, target_W = target_shape + + # Resize [B, H, W] tensor + resized_tensors_3d = F.interpolate( + tensors_3d.unsqueeze(1), size=(target_H, target_W), mode="bilinear", align_corners=False + ).squeeze(1) + + # Resize [B, H, W, 4] tensor + B, _, _, C = tensors_4d.shape + resized_tensors_4d = F.interpolate( + tensors_4d.permute(0, 3, 1, 2), size=(target_H, target_W), mode="bilinear", align_corners=False + ).permute(0, 2, 3, 1) + + return resized_tensors_3d, resized_tensors_4d + + +def aggregate_confidences_and_warps(viewpoint_stack, closest_indices, roma_model, source_idx, verbose=False, output_dict={}): + """ + Aggregates confidences and warps by iterating over the nearest neighbors of the source viewpoint. + + Args: + viewpoint_stack: Stack of viewpoint cameras. + closest_indices: Indices of the nearest neighbors for each viewpoint. + roma_model: Pre-trained Roma model. + source_idx: Index of the source viewpoint. + verbose: If True, displays intermediate results. + + Returns: + certainties_max: Aggregated maximum confidences. + warps_max: Aggregated warps corresponding to maximum confidences. + certainties_max_idcs: Pixel-wise index of the image from which we taken the best matching. + imB_compound: List of the neighboring images. + """ + certainties_all, warps_all, imB_compound = [], [], [] + + for nn in tqdm(closest_indices[source_idx]): + + viewpoint_cam1 = viewpoint_stack[source_idx] + viewpoint_cam2 = viewpoint_stack[nn] + + certainty, warp, imB = compute_warp_and_confidence(viewpoint_cam1, viewpoint_cam2, roma_model, verbose=verbose, output_dict=output_dict) + certainties_all.append(certainty) + warps_all.append(warp) + imB_compound.append(imB) + + certainties_all = torch.stack(certainties_all, dim=0) + target_shape = imB_compound[0].shape[:2] + if verbose: + print("certainties_all.shape:", certainties_all.shape) + print("torch.stack(warps_all, dim=0).shape:", torch.stack(warps_all, dim=0).shape) + print("target_shape:", target_shape) + + certainties_all_resized, warps_all_resized = resize_batch(certainties_all, + torch.stack(warps_all, dim=0), + target_shape + ) + + if verbose: + print("warps_all_resized.shape:", warps_all_resized.shape) + for n, cert in enumerate(certainties_all): + fig, ax = plt.subplots() + cax = ax.imshow(cert.cpu().numpy(), cmap='viridis') + fig.colorbar(cax, ax=ax) + ax.set_title("Pixel-wise Confidence") + output_dict[f'certainty_{n}'] = fig + + for n, warp in enumerate(warps_all): + fig, ax = plt.subplots() + cax = ax.imshow(warp.cpu().numpy()[:, :, :3], cmap='viridis') + fig.colorbar(cax, ax=ax) + ax.set_title("Pixel-wise warp") + output_dict[f'warp_resized_{n}'] = fig + + for n, cert in enumerate(certainties_all_resized): + fig, ax = plt.subplots() + cax = ax.imshow(cert.cpu().numpy(), cmap='viridis') + fig.colorbar(cax, ax=ax) + ax.set_title("Pixel-wise Confidence resized") + output_dict[f'certainty_resized_{n}'] = fig + + for n, warp in enumerate(warps_all_resized): + fig, ax = plt.subplots() + cax = ax.imshow(warp.cpu().numpy()[:, :, :3], cmap='viridis') + fig.colorbar(cax, ax=ax) + ax.set_title("Pixel-wise warp resized") + output_dict[f'warp_resized_{n}'] = fig + + certainties_max, certainties_max_idcs = torch.max(certainties_all_resized, dim=0) + H, W = certainties_max.shape + + warps_max = warps_all_resized[certainties_max_idcs, torch.arange(H).unsqueeze(1), torch.arange(W)] + + imA = viewpoint_cam1.original_image.detach().cpu().numpy().transpose(1, 2, 0) + imA = np.clip(imA * 255, 0, 255).astype(np.uint8) + + return certainties_max, warps_max, certainties_max_idcs, imA, imB_compound, certainties_all_resized, warps_all_resized + + + +def extract_keypoints_and_colors(imA, imB_compound, certainties_max, certainties_max_idcs, matches, roma_model, + verbose=False, output_dict={}): + """ + Extracts keypoints and corresponding colors from the source image (imA) and multiple target images (imB_compound). + + Args: + imA: Source image as a NumPy array (H_A, W_A, C). + imB_compound: List of target images as NumPy arrays [(H_B, W_B, C), ...]. + certainties_max: Tensor of pixel-wise maximum confidences. + certainties_max_idcs: Tensor of pixel-wise indices for the best matches. + matches: Matches in normalized coordinates. + roma_model: Roma model instance for keypoint operations. + verbose: if to show intermediate outputs and visualize results + + Returns: + kptsA_np: Keypoints in imA in normalized coordinates. + kptsB_np: Keypoints in imB in normalized coordinates. + kptsA_color: Colors of keypoints in imA. + kptsB_color: Colors of keypoints in imB based on certainties_max_idcs. + """ + H_A, W_A, _ = imA.shape + H, W = certainties_max.shape + + # Convert matches to pixel coordinates + kptsA, kptsB = roma_model.to_pixel_coordinates( + matches, W_A, H_A, H, W # W, H + ) + + kptsA_np = kptsA.detach().cpu().numpy() + kptsB_np = kptsB.detach().cpu().numpy() + kptsA_np = kptsA_np[:, [1, 0]] + + if verbose: + fig, ax = plt.subplots(figsize=(12, 6)) + cax = ax.imshow(imA) + ax.set_title("Reference image, imA") + output_dict[f'reference_image'] = fig + + fig, ax = plt.subplots(figsize=(12, 6)) + cax = ax.imshow(imB_compound[0]) + ax.set_title("Image to compare to image, imB_compound") + output_dict[f'imB_compound'] = fig + + fig, ax = plt.subplots(figsize=(12, 6)) + cax = ax.imshow(np.flipud(imA)) + cax = ax.scatter(kptsA_np[:, 0], H_A - kptsA_np[:, 1], s=.03) + ax.set_title("Keypoints in imA") + ax.set_xlim(0, W_A) + ax.set_ylim(0, H_A) + output_dict[f'kptsA'] = fig + + fig, ax = plt.subplots(figsize=(12, 6)) + cax = ax.imshow(np.flipud(imB_compound[0])) + cax = ax.scatter(kptsB_np[:, 0], H_A - kptsB_np[:, 1], s=.03) + ax.set_title("Keypoints in imB") + ax.set_xlim(0, W_A) + ax.set_ylim(0, H_A) + output_dict[f'kptsB'] = fig + + # Keypoints are in format (row, column) so the first value is alwain in range [0;height] and second is in range[0;width] + + kptsA_np = kptsA.detach().cpu().numpy() + kptsB_np = kptsB.detach().cpu().numpy() + + # Extract colors for keypoints in imA (vectorized) + # New experimental version + kptsA_x = np.round(kptsA_np[:, 0] / 1.).astype(int) + kptsA_y = np.round(kptsA_np[:, 1] / 1.).astype(int) + kptsA_color = imA[np.clip(kptsA_x, 0, H - 1), np.clip(kptsA_y, 0, W - 1)] + + # Create a composite image from imB_compound + imB_compound_np = np.stack(imB_compound, axis=0) + H_B, W_B, _ = imB_compound[0].shape + + # Extract colors for keypoints in imB using certainties_max_idcs + imB_np = imB_compound_np[ + certainties_max_idcs.detach().cpu().numpy(), + np.arange(H).reshape(-1, 1), + np.arange(W) + ] + + if verbose: + print("imB_np.shape:", imB_np.shape) + print("imB_np:", imB_np) + fig, ax = plt.subplots(figsize=(12, 6)) + cax = ax.imshow(np.flipud(imB_np)) + cax = ax.scatter(kptsB_np[:, 0], H_A - kptsB_np[:, 1], s=.03) + ax.set_title("np.flipud(imB_np[0]") + ax.set_xlim(0, W_A) + ax.set_ylim(0, H_A) + output_dict[f'np.flipud(imB_np[0]'] = fig + + + kptsB_x = np.round(kptsB_np[:, 0]).astype(int) + kptsB_y = np.round(kptsB_np[:, 1]).astype(int) + + certainties_max_idcs_np = certainties_max_idcs.detach().cpu().numpy() + kptsB_proj_matrices_idx = certainties_max_idcs_np[np.clip(kptsA_x, 0, H - 1), np.clip(kptsA_y, 0, W - 1)] + kptsB_color = imB_compound_np[kptsB_proj_matrices_idx, np.clip(kptsB_y, 0, H - 1), np.clip(kptsB_x, 0, W - 1)] + + # Normalize keypoints in both images + kptsA_np[:, 0] = kptsA_np[:, 0] / H * 2.0 - 1.0 + kptsA_np[:, 1] = kptsA_np[:, 1] / W * 2.0 - 1.0 + kptsB_np[:, 0] = kptsB_np[:, 0] / W_B * 2.0 - 1.0 + kptsB_np[:, 1] = kptsB_np[:, 1] / H_B * 2.0 - 1.0 + + return kptsA_np[:, [1, 0]], kptsB_np, kptsB_proj_matrices_idx, kptsA_color, kptsB_color + +def prepare_tensor(input_array, device): + """ + Converts an input array to a torch tensor, clones it, and detaches it for safe computation. + Args: + input_array (array-like): The input array to convert. + device (str or torch.device): The device to move the tensor to. + Returns: + torch.Tensor: A detached tensor clone of the input array on the specified device. + """ + if not isinstance(input_array, torch.Tensor): + return torch.tensor(input_array, dtype=torch.float32).to(device).clone().detach() + return input_array.clone().detach().to(device).to(torch.float32) + +def triangulate_points(P1, P2, k1_x, k1_y, k2_x, k2_y, device="cuda"): + """ + Solves for a batch of 3D points given batches of projection matrices and corresponding image points. + + Parameters: + - P1, P2: Tensors of projection matrices of size (batch_size, 4, 4) or (4, 4) + - k1_x, k1_y: Tensors of shape (batch_size,) + - k2_x, k2_y: Tensors of shape (batch_size,) + + Returns: + - X: A tensor containing the 3D homogeneous coordinates, shape (batch_size, 4) + """ + EPS = 1e-4 + # Ensure inputs are tensors + + P1 = prepare_tensor(P1, device) + P2 = prepare_tensor(P2, device) + k1_x = prepare_tensor(k1_x, device) + k1_y = prepare_tensor(k1_y, device) + k2_x = prepare_tensor(k2_x, device) + k2_y = prepare_tensor(k2_y, device) + batch_size = k1_x.shape[0] + + # Expand P1 and P2 if they are not batched + if P1.ndim == 2: + P1 = P1.unsqueeze(0).expand(batch_size, -1, -1) + if P2.ndim == 2: + P2 = P2.unsqueeze(0).expand(batch_size, -1, -1) + + # Extract columns from P1 and P2 + P1_0 = P1[:, :, 0] # Shape: (batch_size, 4) + P1_1 = P1[:, :, 1] + P1_2 = P1[:, :, 2] + + P2_0 = P2[:, :, 0] + P2_1 = P2[:, :, 1] + P2_2 = P2[:, :, 2] + + # Reshape kx and ky to (batch_size, 1) + k1_x = k1_x.view(-1, 1) + k1_y = k1_y.view(-1, 1) + k2_x = k2_x.view(-1, 1) + k2_y = k2_y.view(-1, 1) + + # Construct the equations for each batch + # For camera 1 + A1 = P1_0 - k1_x * P1_2 # Shape: (batch_size, 4) + A2 = P1_1 - k1_y * P1_2 + # For camera 2 + A3 = P2_0 - k2_x * P2_2 + A4 = P2_1 - k2_y * P2_2 + + # Stack the equations + A = torch.stack([A1, A2, A3, A4], dim=1) # Shape: (batch_size, 4, 4) + + # Right-hand side (constants) + b = -A[:, :, 3] # Shape: (batch_size, 4) + A_reduced = A[:, :, :3] # Coefficients of x, y, z + + # Solve using torch.linalg.lstsq (supports batching) + X_xyz = torch.linalg.lstsq(A_reduced, b.unsqueeze(2)).solution.squeeze(2) # Shape: (batch_size, 3) + + # Append 1 to get homogeneous coordinates + ones = torch.ones((batch_size, 1), dtype=torch.float32, device=X_xyz.device) + X = torch.cat([X_xyz, ones], dim=1) # Shape: (batch_size, 4) + + # Now compute the errors of projections. + seeked_splats_proj1 = (X.unsqueeze(1) @ P1).squeeze(1) + seeked_splats_proj1 = seeked_splats_proj1 / (EPS + seeked_splats_proj1[:, [3]]) + seeked_splats_proj2 = (X.unsqueeze(1) @ P2).squeeze(1) + seeked_splats_proj2 = seeked_splats_proj2 / (EPS + seeked_splats_proj2[:, [3]]) + proj1_target = torch.concat([k1_x, k1_y], dim=1) + proj2_target = torch.concat([k2_x, k2_y], dim=1) + errors_proj1 = torch.abs(seeked_splats_proj1[:, :2] - proj1_target).sum(1).detach().cpu().numpy() + errors_proj2 = torch.abs(seeked_splats_proj2[:, :2] - proj2_target).sum(1).detach().cpu().numpy() + + return X, errors_proj1, errors_proj2 + + + +def select_best_keypoints( + NNs_triangulated_points, NNs_errors_proj1, NNs_errors_proj2, device="cuda"): + """ + From all the points fitted to keypoints and corresponding colors from the source image (imA) and multiple target images (imB_compound). + + Args: + NNs_triangulated_points: torch tensor with keypoints coordinates (num_nns, num_points, dim). dim can be arbitrary, + usually 3 or 4(for homogeneous representation). + NNs_errors_proj1: numpy array with projection error of the estimated keypoint on the reference frame (num_nns, num_points). + NNs_errors_proj2: numpy array with projection error of the estimated keypoint on the neighbor frame (num_nns, num_points). + Returns: + selected_keypoints: keypoints with the best score. + """ + + NNs_errors_proj = np.maximum(NNs_errors_proj1, NNs_errors_proj2) + + # Convert indices to PyTorch tensor + indices = torch.from_numpy(np.argmin(NNs_errors_proj, axis=0)).long().to(device) + + # Create index tensor for the second dimension + n_indices = torch.arange(NNs_triangulated_points.shape[1]).long().to(device) + + # Use advanced indexing to select elements + NNs_triangulated_points_selected = NNs_triangulated_points[indices, n_indices, :] # Shape: [N, k] + + return NNs_triangulated_points_selected, np.min(NNs_errors_proj, axis=0) + + + +def init_gaussians_with_corr(gaussians, scene, cfg, device, verbose = False, roma_model=None): + """ + For a given input gaussians and a scene we instantiate a RoMa model(change to indoors if necessary) and process scene + training frames to extract correspondences. Those are used to initialize gaussians + Args: + gaussians: object gaussians of the class GaussianModel that we need to enrich with gaussians. + scene: object of the Scene class. + cfg: configuration. Use init_wC + Returns: + gaussians: inplace transforms object gaussians of the class GaussianModel. + + """ + if roma_model is None: + if cfg.roma_model == "indoors": + roma_model = roma_indoor(device=device) + else: + roma_model = roma_outdoor(device=device) + roma_model.upsample_preds = False + roma_model.symmetric = False + M = cfg.matches_per_ref + upper_thresh = roma_model.sample_thresh + scaling_factor = cfg.scaling_factor + expansion_factor = 1 + keypoint_fit_error_tolerance = cfg.proj_err_tolerance + visualizations = {} + viewpoint_stack = scene.getTrainCameras().copy() + NUM_REFERENCE_FRAMES = min(cfg.num_refs, len(viewpoint_stack)) + NUM_NNS_PER_REFERENCE = min(cfg.nns_per_ref , len(viewpoint_stack)) + # Select cameras using K-means + viewpoint_cam_all = torch.stack([x.world_view_transform.flatten() for x in viewpoint_stack], axis=0) + + selected_indices = select_cameras_kmeans(cameras=viewpoint_cam_all.detach().cpu().numpy(), K=NUM_REFERENCE_FRAMES) + selected_indices = sorted(selected_indices) + + + # Find the k-closest vectors for each vector + viewpoint_cam_all = torch.stack([x.world_view_transform.flatten() for x in viewpoint_stack], axis=0) + closest_indices = k_closest_vectors(viewpoint_cam_all, NUM_NNS_PER_REFERENCE) + if verbose: print("Indices of k-closest vectors for each vector:\n", closest_indices) + + closest_indices_selected = closest_indices[:, :].detach().cpu().numpy() + + all_new_xyz = [] + all_new_features_dc = [] + all_new_features_rest = [] + all_new_opacities = [] + all_new_scaling = [] + all_new_rotation = [] + + # Run roma_model.match once to kinda initialize the model + with torch.no_grad(): + viewpoint_cam1 = viewpoint_stack[0] + viewpoint_cam2 = viewpoint_stack[1] + imA = viewpoint_cam1.original_image.detach().cpu().numpy().transpose(1, 2, 0) + imB = viewpoint_cam2.original_image.detach().cpu().numpy().transpose(1, 2, 0) + imA = Image.fromarray(np.clip(imA * 255, 0, 255).astype(np.uint8)) + imB = Image.fromarray(np.clip(imB * 255, 0, 255).astype(np.uint8)) + warp, certainty_warp = roma_model.match(imA, imB, device=device) + print("Once run full roma_model.match warp.shape:", warp.shape) + print("Once run full roma_model.match certainty_warp.shape:", certainty_warp.shape) + del warp, certainty_warp + torch.cuda.empty_cache() + + for source_idx in tqdm(sorted(selected_indices)): + # 1. Compute keypoints and warping for all the neigboring views + with torch.no_grad(): + # Call the aggregation function to get imA and imB_compound + certainties_max, warps_max, certainties_max_idcs, imA, imB_compound, certainties_all, warps_all = aggregate_confidences_and_warps( + viewpoint_stack=viewpoint_stack, + closest_indices=closest_indices_selected, + roma_model=roma_model, + source_idx=source_idx, + verbose=verbose, output_dict=visualizations + ) + + + # Triangulate keypoints + with torch.no_grad(): + matches = warps_max + certainty = certainties_max + certainty = certainty.clone() + certainty[certainty > upper_thresh] = 1 + matches, certainty = ( + matches.reshape(-1, 4), + certainty.reshape(-1), + ) + + # Select based on certainty elements with high confidence. These are basically all of + # kptsA_np. + good_samples = torch.multinomial(certainty, + num_samples=min(expansion_factor * M, len(certainty)), + replacement=False) + + certainties_max, warps_max, certainties_max_idcs, imA, imB_compound, certainties_all, warps_all + reference_image_dict = { + "ref_image": imA, + "NNs_images": imB_compound, + "certainties_all": certainties_all, + "warps_all": warps_all, + "triangulated_points": [], + "triangulated_points_errors_proj1": [], + "triangulated_points_errors_proj2": [] + + } + with torch.no_grad(): + for NN_idx in tqdm(range(len(warps_all))): + matches_NN = warps_all[NN_idx].reshape(-1, 4)[good_samples] + + # Extract keypoints and colors + kptsA_np, kptsB_np, kptsB_proj_matrices_idcs, kptsA_color, kptsB_color = extract_keypoints_and_colors( + imA, imB_compound, certainties_max, certainties_max_idcs, matches_NN, roma_model + ) + + proj_matrices_A = viewpoint_stack[source_idx].full_proj_transform + proj_matrices_B = viewpoint_stack[closest_indices_selected[source_idx, NN_idx]].full_proj_transform + triangulated_points, triangulated_points_errors_proj1, triangulated_points_errors_proj2 = triangulate_points( + P1=torch.stack([proj_matrices_A] * M, axis=0), + P2=torch.stack([proj_matrices_B] * M, axis=0), + k1_x=kptsA_np[:M, 0], k1_y=kptsA_np[:M, 1], + k2_x=kptsB_np[:M, 0], k2_y=kptsB_np[:M, 1]) + + reference_image_dict["triangulated_points"].append(triangulated_points) + reference_image_dict["triangulated_points_errors_proj1"].append(triangulated_points_errors_proj1) + reference_image_dict["triangulated_points_errors_proj2"].append(triangulated_points_errors_proj2) + + with torch.no_grad(): + NNs_triangulated_points_selected, NNs_triangulated_points_selected_proj_errors = select_best_keypoints( + NNs_triangulated_points=torch.stack(reference_image_dict["triangulated_points"], dim=0), + NNs_errors_proj1=np.stack(reference_image_dict["triangulated_points_errors_proj1"], axis=0), + NNs_errors_proj2=np.stack(reference_image_dict["triangulated_points_errors_proj2"], axis=0)) + + # 4. Save as gaussians + viewpoint_cam1 = viewpoint_stack[source_idx] + N = len(NNs_triangulated_points_selected) + with torch.no_grad(): + new_xyz = NNs_triangulated_points_selected[:, :-1] + all_new_xyz.append(new_xyz) # seeked_splats + all_new_features_dc.append(RGB2SH(torch.tensor(kptsA_color.astype(np.float32) / 255.)).unsqueeze(1)) + all_new_features_rest.append(torch.stack([gaussians._features_rest[-1].clone().detach() * 0.] * N, dim=0)) + # new version that sets points with large error invisible + # TODO: remove those points instead. However it doesn't affect the performance. + mask_bad_points = torch.tensor( + NNs_triangulated_points_selected_proj_errors > keypoint_fit_error_tolerance, + dtype=torch.float32).unsqueeze(1).to(device) + all_new_opacities.append(torch.stack([gaussians._opacity[-1].clone().detach()] * N, dim=0) * 0. - mask_bad_points * (1e1)) + + dist_points_to_cam1 = torch.linalg.norm(viewpoint_cam1.camera_center.clone().detach() - new_xyz, + dim=1, ord=2) + #all_new_scaling.append(torch.log(((dist_points_to_cam1) / 1. * scaling_factor).unsqueeze(1).repeat(1, 3))) + all_new_scaling.append(gaussians.scaling_inverse_activation((dist_points_to_cam1 * scaling_factor).unsqueeze(1).repeat(1, 3))) + all_new_rotation.append(torch.stack([gaussians._rotation[-1].clone().detach()] * N, dim=0)) + + all_new_xyz = torch.cat(all_new_xyz, dim=0) + all_new_features_dc = torch.cat(all_new_features_dc, dim=0) + new_tmp_radii = torch.zeros(all_new_xyz.shape[0]) + prune_mask = torch.ones(all_new_xyz.shape[0], dtype=torch.bool) + + gaussians.densification_postfix(all_new_xyz[prune_mask].to(device), + all_new_features_dc[prune_mask].to(device), + torch.cat(all_new_features_rest, dim=0)[prune_mask].to(device), + torch.cat(all_new_opacities, dim=0)[prune_mask].to(device), + torch.cat(all_new_scaling, dim=0)[prune_mask].to(device), + torch.cat(all_new_rotation, dim=0)[prune_mask].to(device), + new_tmp_radii[prune_mask].to(device)) + + return viewpoint_stack, closest_indices_selected, visualizations \ No newline at end of file diff --git a/source/corr_init_new.py b/source/corr_init_new.py new file mode 100644 index 0000000000000000000000000000000000000000..43f8ab4bc582b46f390c3cc2405378ae67ce6a27 --- /dev/null +++ b/source/corr_init_new.py @@ -0,0 +1,904 @@ +import sys +sys.path.append('../') +sys.path.append("../submodules") +sys.path.append('../submodules/RoMa') + +from matplotlib import pyplot as plt +from PIL import Image +import torch +import numpy as np + +#from tqdm import tqdm_notebook as tqdm +from tqdm import tqdm +from scipy.cluster.vq import kmeans, vq +from scipy.spatial.distance import cdist + +import torch.nn.functional as F +from romatch import roma_outdoor, roma_indoor +from utils.sh_utils import RGB2SH +from romatch.utils import get_tuple_transform_ops + + +def pairwise_distances(matrix): + """ + Computes the pairwise Euclidean distances between all vectors in the input matrix. + + Args: + matrix (torch.Tensor): Input matrix of shape [N, D], where N is the number of vectors and D is the dimensionality. + + Returns: + torch.Tensor: Pairwise distance matrix of shape [N, N]. + """ + # Compute squared pairwise distances + squared_diff = torch.cdist(matrix, matrix, p=2) + return squared_diff + + +def k_closest_vectors(matrix, k): + """ + Finds the k-closest vectors for each vector in the input matrix based on Euclidean distance. + + Args: + matrix (torch.Tensor): Input matrix of shape [N, D], where N is the number of vectors and D is the dimensionality. + k (int): Number of closest vectors to return for each vector. + + Returns: + torch.Tensor: Indices of the k-closest vectors for each vector, excluding the vector itself. + """ + # Compute pairwise distances + distances = pairwise_distances(matrix) + + # For each vector, sort distances and get the indices of the k-closest vectors (excluding itself) + # Set diagonal distances to infinity to exclude the vector itself from the nearest neighbors + distances.fill_diagonal_(float('inf')) + + # Get the indices of the k smallest distances (k-closest vectors) + _, indices = torch.topk(distances, k, largest=False, dim=1) + + return indices + + +def select_cameras_kmeans(cameras, K): + """ + Selects K cameras from a set using K-means clustering. + + Args: + cameras: NumPy array of shape (N, 16), representing N cameras with their 4x4 homogeneous matrices flattened. + K: Number of clusters (cameras to select). + + Returns: + selected_indices: List of indices of the cameras closest to the cluster centers. + """ + # Ensure input is a NumPy array + if not isinstance(cameras, np.ndarray): + cameras = np.asarray(cameras) + + if cameras.shape[1] != 16: + raise ValueError("Each camera must have 16 values corresponding to a flattened 4x4 matrix.") + + # Perform K-means clustering + cluster_centers, _ = kmeans(cameras, K) + + # Assign each camera to a cluster and find distances to cluster centers + cluster_assignments, _ = vq(cameras, cluster_centers) + + # Find the camera nearest to each cluster center + selected_indices = [] + for k in range(K): + cluster_members = cameras[cluster_assignments == k] + distances = cdist([cluster_centers[k]], cluster_members)[0] + nearest_camera_idx = np.where(cluster_assignments == k)[0][np.argmin(distances)] + selected_indices.append(nearest_camera_idx) + + return selected_indices + + +def compute_warp_and_confidence(viewpoint_cam1, viewpoint_cam2, roma_model, device="cuda", verbose=False, output_dict={}): + """ + Computes the warp and confidence between two viewpoint cameras using the roma_model. + + Args: + viewpoint_cam1: Source viewpoint camera. + viewpoint_cam2: Target viewpoint camera. + roma_model: Pre-trained Roma model for correspondence matching. + device: Device to run the computation on. + verbose: If True, displays the images. + + Returns: + certainty: Confidence tensor. + warp: Warp tensor. + imB: Processed image B as numpy array. + """ + # Prepare images + imA = viewpoint_cam1.original_image.detach().cpu().numpy().transpose(1, 2, 0) + imB = viewpoint_cam2.original_image.detach().cpu().numpy().transpose(1, 2, 0) + imA = Image.fromarray(np.clip(imA * 255, 0, 255).astype(np.uint8)) + imB = Image.fromarray(np.clip(imB * 255, 0, 255).astype(np.uint8)) + + if verbose: + fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(16, 8)) + cax1 = ax[0].imshow(imA) + ax[0].set_title("Image 1") + cax2 = ax[1].imshow(imB) + ax[1].set_title("Image 2") + fig.colorbar(cax1, ax=ax[0]) + fig.colorbar(cax2, ax=ax[1]) + + for axis in ax: + axis.axis('off') + # Save the figure into the dictionary + output_dict[f'image_pair'] = fig + + # Transform images + ws, hs = roma_model.w_resized, roma_model.h_resized + test_transform = get_tuple_transform_ops(resize=(hs, ws), normalize=True) + im_A, im_B = test_transform((imA, imB)) + batch = {"im_A": im_A[None].to(device), "im_B": im_B[None].to(device)} + + # Forward pass through Roma model + corresps = roma_model.forward(batch) if not roma_model.symmetric else roma_model.forward_symmetric(batch) + finest_scale = 1 + hs, ws = roma_model.upsample_res if roma_model.upsample_preds else (hs, ws) + + # Process certainty and warp + certainty = corresps[finest_scale]["certainty"] + im_A_to_im_B = corresps[finest_scale]["flow"] + if roma_model.attenuate_cert: + low_res_certainty = F.interpolate( + corresps[16]["certainty"], size=(hs, ws), align_corners=False, mode="bilinear" + ) + certainty -= 0.5 * low_res_certainty * (low_res_certainty < 0) + + # Upsample predictions if needed + if roma_model.upsample_preds: + im_A_to_im_B = F.interpolate( + im_A_to_im_B, size=(hs, ws), align_corners=False, mode="bilinear" + ) + certainty = F.interpolate( + certainty, size=(hs, ws), align_corners=False, mode="bilinear" + ) + + # Convert predictions to final format + im_A_to_im_B = im_A_to_im_B.permute(0, 2, 3, 1) + im_A_coords = torch.stack(torch.meshgrid( + torch.linspace(-1 + 1 / hs, 1 - 1 / hs, hs, device=device), + torch.linspace(-1 + 1 / ws, 1 - 1 / ws, ws, device=device), + indexing='ij' + ), dim=0).permute(1, 2, 0).unsqueeze(0).expand(im_A_to_im_B.size(0), -1, -1, -1) + + warp = torch.cat((im_A_coords, im_A_to_im_B), dim=-1) + certainty = certainty.sigmoid() + + return certainty[0, 0], warp[0], np.array(imB) + + +def resize_batch(tensors_3d, tensors_4d, target_shape): + """ + Resizes a batch of tensors with shapes [B, H, W] and [B, H, W, 4] to the target spatial dimensions. + + Args: + tensors_3d: Tensor of shape [B, H, W]. + tensors_4d: Tensor of shape [B, H, W, 4]. + target_shape: Tuple (target_H, target_W) specifying the target spatial dimensions. + + Returns: + resized_tensors_3d: Tensor of shape [B, target_H, target_W]. + resized_tensors_4d: Tensor of shape [B, target_H, target_W, 4]. + """ + target_H, target_W = target_shape + + # Resize [B, H, W] tensor + resized_tensors_3d = F.interpolate( + tensors_3d.unsqueeze(1), size=(target_H, target_W), mode="bilinear", align_corners=False + ).squeeze(1) + + # Resize [B, H, W, 4] tensor + B, _, _, C = tensors_4d.shape + resized_tensors_4d = F.interpolate( + tensors_4d.permute(0, 3, 1, 2), size=(target_H, target_W), mode="bilinear", align_corners=False + ).permute(0, 2, 3, 1) + + return resized_tensors_3d, resized_tensors_4d + + +def aggregate_confidences_and_warps(viewpoint_stack, closest_indices, roma_model, source_idx, verbose=False, output_dict={}): + """ + Aggregates confidences and warps by iterating over the nearest neighbors of the source viewpoint. + + Args: + viewpoint_stack: Stack of viewpoint cameras. + closest_indices: Indices of the nearest neighbors for each viewpoint. + roma_model: Pre-trained Roma model. + source_idx: Index of the source viewpoint. + verbose: If True, displays intermediate results. + + Returns: + certainties_max: Aggregated maximum confidences. + warps_max: Aggregated warps corresponding to maximum confidences. + certainties_max_idcs: Pixel-wise index of the image from which we taken the best matching. + imB_compound: List of the neighboring images. + """ + certainties_all, warps_all, imB_compound = [], [], [] + + for nn in tqdm(closest_indices[source_idx]): + + viewpoint_cam1 = viewpoint_stack[source_idx] + viewpoint_cam2 = viewpoint_stack[nn] + + certainty, warp, imB = compute_warp_and_confidence(viewpoint_cam1, viewpoint_cam2, roma_model, verbose=verbose, output_dict=output_dict) + certainties_all.append(certainty) + warps_all.append(warp) + imB_compound.append(imB) + + certainties_all = torch.stack(certainties_all, dim=0) + target_shape = imB_compound[0].shape[:2] + if verbose: + print("certainties_all.shape:", certainties_all.shape) + print("torch.stack(warps_all, dim=0).shape:", torch.stack(warps_all, dim=0).shape) + print("target_shape:", target_shape) + + certainties_all_resized, warps_all_resized = resize_batch(certainties_all, + torch.stack(warps_all, dim=0), + target_shape + ) + + if verbose: + print("warps_all_resized.shape:", warps_all_resized.shape) + for n, cert in enumerate(certainties_all): + fig, ax = plt.subplots() + cax = ax.imshow(cert.cpu().numpy(), cmap='viridis') + fig.colorbar(cax, ax=ax) + ax.set_title("Pixel-wise Confidence") + output_dict[f'certainty_{n}'] = fig + + for n, warp in enumerate(warps_all): + fig, ax = plt.subplots() + cax = ax.imshow(warp.cpu().numpy()[:, :, :3], cmap='viridis') + fig.colorbar(cax, ax=ax) + ax.set_title("Pixel-wise warp") + output_dict[f'warp_resized_{n}'] = fig + + for n, cert in enumerate(certainties_all_resized): + fig, ax = plt.subplots() + cax = ax.imshow(cert.cpu().numpy(), cmap='viridis') + fig.colorbar(cax, ax=ax) + ax.set_title("Pixel-wise Confidence resized") + output_dict[f'certainty_resized_{n}'] = fig + + for n, warp in enumerate(warps_all_resized): + fig, ax = plt.subplots() + cax = ax.imshow(warp.cpu().numpy()[:, :, :3], cmap='viridis') + fig.colorbar(cax, ax=ax) + ax.set_title("Pixel-wise warp resized") + output_dict[f'warp_resized_{n}'] = fig + + certainties_max, certainties_max_idcs = torch.max(certainties_all_resized, dim=0) + H, W = certainties_max.shape + + warps_max = warps_all_resized[certainties_max_idcs, torch.arange(H).unsqueeze(1), torch.arange(W)] + + + return certainties_max, warps_max, certainties_max_idcs, imB_compound, certainties_all_resized, warps_all_resized + + + +def extract_keypoints_and_colors(imA, imB_compound, certainties_max, certainties_max_idcs, matches, roma_model, + verbose=False, output_dict={}): + """ + Extracts keypoints and corresponding colors from the source image (imA) and multiple target images (imB_compound). + + Args: + imA: Source image as a NumPy array (H_A, W_A, C). + imB_compound: List of target images as NumPy arrays [(H_B, W_B, C), ...]. + certainties_max: Tensor of pixel-wise maximum confidences. + certainties_max_idcs: Tensor of pixel-wise indices for the best matches. + matches: Matches in normalized coordinates. + roma_model: Roma model instance for keypoint operations. + verbose: if to show intermediate outputs and visualize results + + Returns: + kptsA_np: Keypoints in imA in normalized coordinates. + kptsB_np: Keypoints in imB in normalized coordinates. + kptsA_color: Colors of keypoints in imA. + kptsB_color: Colors of keypoints in imB based on certainties_max_idcs. + """ + H_A, W_A, _ = imA.shape + H, W = certainties_max.shape + + # Convert matches to pixel coordinates + kptsA, kptsB = roma_model.to_pixel_coordinates( + matches, W_A, H_A, H, W # W, H + ) + + kptsA_np = kptsA.detach().cpu().numpy() + kptsB_np = kptsB.detach().cpu().numpy() + kptsA_np = kptsA_np[:, [1, 0]] + + if verbose: + fig, ax = plt.subplots(figsize=(12, 6)) + cax = ax.imshow(imA) + ax.set_title("Reference image, imA") + output_dict[f'reference_image'] = fig + + fig, ax = plt.subplots(figsize=(12, 6)) + cax = ax.imshow(imB_compound[0]) + ax.set_title("Image to compare to image, imB_compound") + output_dict[f'imB_compound'] = fig + + fig, ax = plt.subplots(figsize=(12, 6)) + cax = ax.imshow(np.flipud(imA)) + cax = ax.scatter(kptsA_np[:, 0], H_A - kptsA_np[:, 1], s=.03) + ax.set_title("Keypoints in imA") + ax.set_xlim(0, W_A) + ax.set_ylim(0, H_A) + output_dict[f'kptsA'] = fig + + fig, ax = plt.subplots(figsize=(12, 6)) + cax = ax.imshow(np.flipud(imB_compound[0])) + cax = ax.scatter(kptsB_np[:, 0], H_A - kptsB_np[:, 1], s=.03) + ax.set_title("Keypoints in imB") + ax.set_xlim(0, W_A) + ax.set_ylim(0, H_A) + output_dict[f'kptsB'] = fig + + # Keypoints are in format (row, column) so the first value is alwain in range [0;height] and second is in range[0;width] + + kptsA_np = kptsA.detach().cpu().numpy() + kptsB_np = kptsB.detach().cpu().numpy() + + # Extract colors for keypoints in imA (vectorized) + # New experimental version + kptsA_x = np.round(kptsA_np[:, 0] / 1.).astype(int) + kptsA_y = np.round(kptsA_np[:, 1] / 1.).astype(int) + kptsA_color = imA[np.clip(kptsA_x, 0, H - 1), np.clip(kptsA_y, 0, W - 1)] + + # Create a composite image from imB_compound + imB_compound_np = np.stack(imB_compound, axis=0) + H_B, W_B, _ = imB_compound[0].shape + + # Extract colors for keypoints in imB using certainties_max_idcs + imB_np = imB_compound_np[ + certainties_max_idcs.detach().cpu().numpy(), + np.arange(H).reshape(-1, 1), + np.arange(W) + ] + + if verbose: + print("imB_np.shape:", imB_np.shape) + print("imB_np:", imB_np) + fig, ax = plt.subplots(figsize=(12, 6)) + cax = ax.imshow(np.flipud(imB_np)) + cax = ax.scatter(kptsB_np[:, 0], H_A - kptsB_np[:, 1], s=.03) + ax.set_title("np.flipud(imB_np[0]") + ax.set_xlim(0, W_A) + ax.set_ylim(0, H_A) + output_dict[f'np.flipud(imB_np[0]'] = fig + + + kptsB_x = np.round(kptsB_np[:, 0]).astype(int) + kptsB_y = np.round(kptsB_np[:, 1]).astype(int) + + certainties_max_idcs_np = certainties_max_idcs.detach().cpu().numpy() + kptsB_proj_matrices_idx = certainties_max_idcs_np[np.clip(kptsA_x, 0, H - 1), np.clip(kptsA_y, 0, W - 1)] + kptsB_color = imB_compound_np[kptsB_proj_matrices_idx, np.clip(kptsB_y, 0, H - 1), np.clip(kptsB_x, 0, W - 1)] + + # Normalize keypoints in both images + kptsA_np[:, 0] = kptsA_np[:, 0] / H * 2.0 - 1.0 + kptsA_np[:, 1] = kptsA_np[:, 1] / W * 2.0 - 1.0 + kptsB_np[:, 0] = kptsB_np[:, 0] / W_B * 2.0 - 1.0 + kptsB_np[:, 1] = kptsB_np[:, 1] / H_B * 2.0 - 1.0 + + return kptsA_np[:, [1, 0]], kptsB_np, kptsB_proj_matrices_idx, kptsA_color, kptsB_color + +def prepare_tensor(input_array, device): + """ + Converts an input array to a torch tensor, clones it, and detaches it for safe computation. + Args: + input_array (array-like): The input array to convert. + device (str or torch.device): The device to move the tensor to. + Returns: + torch.Tensor: A detached tensor clone of the input array on the specified device. + """ + if not isinstance(input_array, torch.Tensor): + return torch.tensor(input_array, dtype=torch.float32).to(device).clone().detach() + return input_array.clone().detach().to(device).to(torch.float32) + +def triangulate_points(P1, P2, k1_x, k1_y, k2_x, k2_y, device="cuda"): + """ + Solves for a batch of 3D points given batches of projection matrices and corresponding image points. + + Parameters: + - P1, P2: Tensors of projection matrices of size (batch_size, 4, 4) or (4, 4) + - k1_x, k1_y: Tensors of shape (batch_size,) + - k2_x, k2_y: Tensors of shape (batch_size,) + + Returns: + - X: A tensor containing the 3D homogeneous coordinates, shape (batch_size, 4) + """ + EPS = 1e-4 + # Ensure inputs are tensors + + P1 = prepare_tensor(P1, device) + P2 = prepare_tensor(P2, device) + k1_x = prepare_tensor(k1_x, device) + k1_y = prepare_tensor(k1_y, device) + k2_x = prepare_tensor(k2_x, device) + k2_y = prepare_tensor(k2_y, device) + batch_size = k1_x.shape[0] + + # Expand P1 and P2 if they are not batched + if P1.ndim == 2: + P1 = P1.unsqueeze(0).expand(batch_size, -1, -1) + if P2.ndim == 2: + P2 = P2.unsqueeze(0).expand(batch_size, -1, -1) + + # Extract columns from P1 and P2 + P1_0 = P1[:, :, 0] # Shape: (batch_size, 4) + P1_1 = P1[:, :, 1] + P1_2 = P1[:, :, 2] + + P2_0 = P2[:, :, 0] + P2_1 = P2[:, :, 1] + P2_2 = P2[:, :, 2] + + # Reshape kx and ky to (batch_size, 1) + k1_x = k1_x.view(-1, 1) + k1_y = k1_y.view(-1, 1) + k2_x = k2_x.view(-1, 1) + k2_y = k2_y.view(-1, 1) + + # Construct the equations for each batch + # For camera 1 + A1 = P1_0 - k1_x * P1_2 # Shape: (batch_size, 4) + A2 = P1_1 - k1_y * P1_2 + # For camera 2 + A3 = P2_0 - k2_x * P2_2 + A4 = P2_1 - k2_y * P2_2 + + # Stack the equations + A = torch.stack([A1, A2, A3, A4], dim=1) # Shape: (batch_size, 4, 4) + + # Right-hand side (constants) + b = -A[:, :, 3] # Shape: (batch_size, 4) + A_reduced = A[:, :, :3] # Coefficients of x, y, z + + # Solve using torch.linalg.lstsq (supports batching) + X_xyz = torch.linalg.lstsq(A_reduced, b.unsqueeze(2)).solution.squeeze(2) # Shape: (batch_size, 3) + + # Append 1 to get homogeneous coordinates + ones = torch.ones((batch_size, 1), dtype=torch.float32, device=X_xyz.device) + X = torch.cat([X_xyz, ones], dim=1) # Shape: (batch_size, 4) + + # Now compute the errors of projections. + seeked_splats_proj1 = (X.unsqueeze(1) @ P1).squeeze(1) + seeked_splats_proj1 = seeked_splats_proj1 / (EPS + seeked_splats_proj1[:, [3]]) + seeked_splats_proj2 = (X.unsqueeze(1) @ P2).squeeze(1) + seeked_splats_proj2 = seeked_splats_proj2 / (EPS + seeked_splats_proj2[:, [3]]) + proj1_target = torch.concat([k1_x, k1_y], dim=1) + proj2_target = torch.concat([k2_x, k2_y], dim=1) + errors_proj1 = torch.abs(seeked_splats_proj1[:, :2] - proj1_target).sum(1).detach().cpu().numpy() + errors_proj2 = torch.abs(seeked_splats_proj2[:, :2] - proj2_target).sum(1).detach().cpu().numpy() + + return X, errors_proj1, errors_proj2 + + + +def select_best_keypoints( + NNs_triangulated_points, NNs_errors_proj1, NNs_errors_proj2, device="cuda"): + """ + From all the points fitted to keypoints and corresponding colors from the source image (imA) and multiple target images (imB_compound). + + Args: + NNs_triangulated_points: torch tensor with keypoints coordinates (num_nns, num_points, dim). dim can be arbitrary, + usually 3 or 4(for homogeneous representation). + NNs_errors_proj1: numpy array with projection error of the estimated keypoint on the reference frame (num_nns, num_points). + NNs_errors_proj2: numpy array with projection error of the estimated keypoint on the neighbor frame (num_nns, num_points). + Returns: + selected_keypoints: keypoints with the best score. + """ + + NNs_errors_proj = np.maximum(NNs_errors_proj1, NNs_errors_proj2) + + # Convert indices to PyTorch tensor + indices = torch.from_numpy(np.argmin(NNs_errors_proj, axis=0)).long().to(device) + + # Create index tensor for the second dimension + n_indices = torch.arange(NNs_triangulated_points.shape[1]).long().to(device) + + # Use advanced indexing to select elements + NNs_triangulated_points_selected = NNs_triangulated_points[indices, n_indices, :] # Shape: [N, k] + + return NNs_triangulated_points_selected, np.min(NNs_errors_proj, axis=0) + + + +import time +from collections import defaultdict +from tqdm import tqdm + +# def init_gaussians_with_corr_profiled(gaussians, scene, cfg, device, verbose=False, roma_model=None): +# timings = defaultdict(list) # To accumulate timings + +# if roma_model is None: +# if cfg.roma_model == "indoors": +# roma_model = roma_indoor(device=device) +# else: +# roma_model = roma_outdoor(device=device) +# roma_model.upsample_preds = False +# roma_model.symmetric = False + +# M = cfg.matches_per_ref +# upper_thresh = roma_model.sample_thresh +# scaling_factor = cfg.scaling_factor +# expansion_factor = 1 +# keypoint_fit_error_tolerance = cfg.proj_err_tolerance +# visualizations = {} +# viewpoint_stack = scene.getTrainCameras().copy() +# NUM_REFERENCE_FRAMES = min(cfg.num_refs, len(viewpoint_stack)) +# NUM_NNS_PER_REFERENCE = min(cfg.nns_per_ref, len(viewpoint_stack)) + +# viewpoint_cam_all = torch.stack([x.world_view_transform.flatten() for x in viewpoint_stack], axis=0) + +# selected_indices = select_cameras_kmeans(cameras=viewpoint_cam_all.detach().cpu().numpy(), K=NUM_REFERENCE_FRAMES) +# selected_indices = sorted(selected_indices) + +# viewpoint_cam_all = torch.stack([x.world_view_transform.flatten() for x in viewpoint_stack], axis=0) +# closest_indices = k_closest_vectors(viewpoint_cam_all, NUM_NNS_PER_REFERENCE) +# closest_indices_selected = closest_indices[:, :].detach().cpu().numpy() + +# all_new_xyz = [] +# all_new_features_dc = [] +# all_new_features_rest = [] +# all_new_opacities = [] +# all_new_scaling = [] +# all_new_rotation = [] + +# # Dummy first pass to initialize model +# with torch.no_grad(): +# viewpoint_cam1 = viewpoint_stack[0] +# viewpoint_cam2 = viewpoint_stack[1] +# imA = viewpoint_cam1.original_image.detach().cpu().numpy().transpose(1, 2, 0) +# imB = viewpoint_cam2.original_image.detach().cpu().numpy().transpose(1, 2, 0) +# imA = Image.fromarray(np.clip(imA * 255, 0, 255).astype(np.uint8)) +# imB = Image.fromarray(np.clip(imB * 255, 0, 255).astype(np.uint8)) +# warp, certainty_warp = roma_model.match(imA, imB, device=device) +# del warp, certainty_warp +# torch.cuda.empty_cache() + +# # Main Loop over source_idx +# for source_idx in tqdm(sorted(selected_indices), desc="Profiling source frames"): + +# # =================== Step 1: Aggregate Confidences and Warps =================== +# start = time.time() +# viewpoint_cam1 = viewpoint_stack[source_idx] +# viewpoint_cam2 = viewpoint_stack[closest_indices_selected[source_idx,0]] +# imA = viewpoint_cam1.original_image.detach().cpu().numpy().transpose(1, 2, 0) +# imB = viewpoint_cam2.original_image.detach().cpu().numpy().transpose(1, 2, 0) +# imA = Image.fromarray(np.clip(imA * 255, 0, 255).astype(np.uint8)) +# imB = Image.fromarray(np.clip(imB * 255, 0, 255).astype(np.uint8)) +# warp, certainty_warp = roma_model.match(imA, imB, device=device) + +# certainties_max, warps_max, certainties_max_idcs, imB_compound, certainties_all, warps_all = aggregate_confidences_and_warps( +# viewpoint_stack=viewpoint_stack, +# closest_indices=closest_indices_selected, +# roma_model=roma_model, +# source_idx=source_idx, +# verbose=verbose, +# output_dict=visualizations +# ) + +# certainties_max = certainty_warp +# with torch.no_grad(): +# warps_all = warps.unsqueeze(0) + +# timings['aggregation_warp_certainty'].append(time.time() - start) + +# # =================== Step 2: Good Samples Selection =================== +# start = time.time() +# certainty = certainties_max.reshape(-1).clone() +# certainty[certainty > upper_thresh] = 1 +# good_samples = torch.multinomial(certainty, num_samples=min(expansion_factor * M, len(certainty)), replacement=False) +# timings['good_samples_selection'].append(time.time() - start) + +# # =================== Step 3: Triangulate Keypoints for Each NN =================== +# reference_image_dict = { +# "triangulated_points": [], +# "triangulated_points_errors_proj1": [], +# "triangulated_points_errors_proj2": [] +# } + +# start = time.time() +# for NN_idx in range(len(warps_all)): +# matches_NN = warps_all[NN_idx].reshape(-1, 4)[good_samples] + +# # Extract keypoints and colors +# kptsA_np, kptsB_np, kptsB_proj_matrices_idcs, kptsA_color, kptsB_color = extract_keypoints_and_colors( +# imA, imB_compound, certainties_max, certainties_max_idcs, matches_NN, roma_model +# ) + +# proj_matrices_A = viewpoint_stack[source_idx].full_proj_transform +# proj_matrices_B = viewpoint_stack[closest_indices_selected[source_idx, NN_idx]].full_proj_transform +# triangulated_points, triangulated_points_errors_proj1, triangulated_points_errors_proj2 = triangulate_points( +# P1=torch.stack([proj_matrices_A] * M, axis=0), +# P2=torch.stack([proj_matrices_B] * M, axis=0), +# k1_x=kptsA_np[:M, 0], k1_y=kptsA_np[:M, 1], +# k2_x=kptsB_np[:M, 0], k2_y=kptsB_np[:M, 1]) + +# reference_image_dict["triangulated_points"].append(triangulated_points) +# reference_image_dict["triangulated_points_errors_proj1"].append(triangulated_points_errors_proj1) +# reference_image_dict["triangulated_points_errors_proj2"].append(triangulated_points_errors_proj2) +# timings['triangulation_per_NN'].append(time.time() - start) + +# # =================== Step 4: Select Best Triangulated Points =================== +# start = time.time() +# NNs_triangulated_points_selected, NNs_triangulated_points_selected_proj_errors = select_best_keypoints( +# NNs_triangulated_points=torch.stack(reference_image_dict["triangulated_points"], dim=0), +# NNs_errors_proj1=np.stack(reference_image_dict["triangulated_points_errors_proj1"], axis=0), +# NNs_errors_proj2=np.stack(reference_image_dict["triangulated_points_errors_proj2"], axis=0)) +# timings['select_best_keypoints'].append(time.time() - start) + +# # =================== Step 5: Create New Gaussians =================== +# start = time.time() +# viewpoint_cam1 = viewpoint_stack[source_idx] +# N = len(NNs_triangulated_points_selected) +# new_xyz = NNs_triangulated_points_selected[:, :-1] +# all_new_xyz.append(new_xyz) +# all_new_features_dc.append(RGB2SH(torch.tensor(kptsA_color.astype(np.float32) / 255.)).unsqueeze(1)) +# all_new_features_rest.append(torch.stack([gaussians._features_rest[-1].clone().detach() * 0.] * N, dim=0)) + +# mask_bad_points = torch.tensor( +# NNs_triangulated_points_selected_proj_errors > keypoint_fit_error_tolerance, +# dtype=torch.float32).unsqueeze(1).to(device) + +# all_new_opacities.append(torch.stack([gaussians._opacity[-1].clone().detach()] * N, dim=0) * 0. - mask_bad_points * (1e1)) + +# dist_points_to_cam1 = torch.linalg.norm(viewpoint_cam1.camera_center.clone().detach() - new_xyz, dim=1, ord=2) +# all_new_scaling.append(gaussians.scaling_inverse_activation((dist_points_to_cam1 * scaling_factor).unsqueeze(1).repeat(1, 3))) +# all_new_rotation.append(torch.stack([gaussians._rotation[-1].clone().detach()] * N, dim=0)) +# timings['save_gaussians'].append(time.time() - start) + +# # =================== Final Densification Postfix =================== +# start = time.time() +# all_new_xyz = torch.cat(all_new_xyz, dim=0) +# all_new_features_dc = torch.cat(all_new_features_dc, dim=0) +# new_tmp_radii = torch.zeros(all_new_xyz.shape[0]) +# prune_mask = torch.ones(all_new_xyz.shape[0], dtype=torch.bool) + +# gaussians.densification_postfix( +# all_new_xyz[prune_mask].to(device), +# all_new_features_dc[prune_mask].to(device), +# torch.cat(all_new_features_rest, dim=0)[prune_mask].to(device), +# torch.cat(all_new_opacities, dim=0)[prune_mask].to(device), +# torch.cat(all_new_scaling, dim=0)[prune_mask].to(device), +# torch.cat(all_new_rotation, dim=0)[prune_mask].to(device), +# new_tmp_radii[prune_mask].to(device) +# ) +# timings['final_densification_postfix'].append(time.time() - start) + +# # =================== Print Profiling Results =================== +# print("\n=== Profiling Summary (average per frame) ===") +# for key, times in timings.items(): +# print(f"{key:35s}: {sum(times) / len(times):.4f} sec (total {sum(times):.2f} sec)") + +# return viewpoint_stack, closest_indices_selected, visualizations + + + +def extract_keypoints_and_colors_single(imA, imB, matches, roma_model, verbose=False, output_dict={}): + """ + Extracts keypoints and corresponding colors from a source image (imA) and a single target image (imB). + + Args: + imA: Source image as a NumPy array (H_A, W_A, C). + imB: Target image as a NumPy array (H_B, W_B, C). + matches: Matches in normalized coordinates (torch.Tensor). + roma_model: Roma model instance for keypoint operations. + verbose: If True, outputs intermediate visualizations. + Returns: + kptsA_np: Keypoints in imA (normalized). + kptsB_np: Keypoints in imB (normalized). + kptsA_color: Colors of keypoints in imA. + kptsB_color: Colors of keypoints in imB. + """ + H_A, W_A, _ = imA.shape + H_B, W_B, _ = imB.shape + + # Convert matches to pixel coordinates + # Matches format: (B, 4) = (x1_norm, y1_norm, x2_norm, y2_norm) + kptsA = matches[:, :2] # [N, 2] + kptsB = matches[:, 2:] # [N, 2] + + # Scale normalized coordinates [-1,1] to pixel coordinates + kptsA_pix = torch.zeros_like(kptsA) + kptsB_pix = torch.zeros_like(kptsB) + + # Important! [Normalized to pixel space] + kptsA_pix[:, 0] = (kptsA[:, 0] + 1) * (W_A - 1) / 2 + kptsA_pix[:, 1] = (kptsA[:, 1] + 1) * (H_A - 1) / 2 + + kptsB_pix[:, 0] = (kptsB[:, 0] + 1) * (W_B - 1) / 2 + kptsB_pix[:, 1] = (kptsB[:, 1] + 1) * (H_B - 1) / 2 + + kptsA_np = kptsA_pix.detach().cpu().numpy() + kptsB_np = kptsB_pix.detach().cpu().numpy() + + # Extract colors + kptsA_x = np.round(kptsA_np[:, 0]).astype(int) + kptsA_y = np.round(kptsA_np[:, 1]).astype(int) + kptsB_x = np.round(kptsB_np[:, 0]).astype(int) + kptsB_y = np.round(kptsB_np[:, 1]).astype(int) + + kptsA_color = imA[np.clip(kptsA_y, 0, H_A-1), np.clip(kptsA_x, 0, W_A-1)] + kptsB_color = imB[np.clip(kptsB_y, 0, H_B-1), np.clip(kptsB_x, 0, W_B-1)] + + # Normalize keypoints into [-1, 1] for downstream triangulation + kptsA_np_norm = np.zeros_like(kptsA_np) + kptsB_np_norm = np.zeros_like(kptsB_np) + + kptsA_np_norm[:, 0] = kptsA_np[:, 0] / (W_A - 1) * 2.0 - 1.0 + kptsA_np_norm[:, 1] = kptsA_np[:, 1] / (H_A - 1) * 2.0 - 1.0 + + kptsB_np_norm[:, 0] = kptsB_np[:, 0] / (W_B - 1) * 2.0 - 1.0 + kptsB_np_norm[:, 1] = kptsB_np[:, 1] / (H_B - 1) * 2.0 - 1.0 + + return kptsA_np_norm, kptsB_np_norm, kptsA_color, kptsB_color + + + +def init_gaussians_with_corr_profiled(gaussians, scene, cfg, device, verbose=False, roma_model=None): + timings = defaultdict(list) + + if roma_model is None: + if cfg.roma_model == "indoors": + roma_model = roma_indoor(device=device) + else: + roma_model = roma_outdoor(device=device) + roma_model.upsample_preds = False + roma_model.symmetric = False + + M = cfg.matches_per_ref + upper_thresh = roma_model.sample_thresh + scaling_factor = cfg.scaling_factor + expansion_factor = 1 + keypoint_fit_error_tolerance = cfg.proj_err_tolerance + visualizations = {} + viewpoint_stack = scene.getTrainCameras().copy() + NUM_REFERENCE_FRAMES = min(cfg.num_refs, len(viewpoint_stack)) + NUM_NNS_PER_REFERENCE = 1 # Only ONE neighbor now! + + viewpoint_cam_all = torch.stack([x.world_view_transform.flatten() for x in viewpoint_stack], axis=0) + + selected_indices = select_cameras_kmeans(cameras=viewpoint_cam_all.detach().cpu().numpy(), K=NUM_REFERENCE_FRAMES) + selected_indices = sorted(selected_indices) + + viewpoint_cam_all = torch.stack([x.world_view_transform.flatten() for x in viewpoint_stack], axis=0) + closest_indices = k_closest_vectors(viewpoint_cam_all, NUM_NNS_PER_REFERENCE) + closest_indices_selected = closest_indices[:, :].detach().cpu().numpy() + + all_new_xyz = [] + all_new_features_dc = [] + all_new_features_rest = [] + all_new_opacities = [] + all_new_scaling = [] + all_new_rotation = [] + + # Dummy first pass to initialize model + with torch.no_grad(): + viewpoint_cam1 = viewpoint_stack[0] + viewpoint_cam2 = viewpoint_stack[1] + imA = viewpoint_cam1.original_image.detach().cpu().numpy().transpose(1, 2, 0) + imB = viewpoint_cam2.original_image.detach().cpu().numpy().transpose(1, 2, 0) + imA = Image.fromarray(np.clip(imA * 255, 0, 255).astype(np.uint8)) + imB = Image.fromarray(np.clip(imB * 255, 0, 255).astype(np.uint8)) + warp, certainty_warp = roma_model.match(imA, imB, device=device) + del warp, certainty_warp + torch.cuda.empty_cache() + + # Main Loop over source_idx + for source_idx in tqdm(sorted(selected_indices), desc="Profiling source frames"): + + # =================== Step 1: Compute Warp and Certainty =================== + start = time.time() + viewpoint_cam1 = viewpoint_stack[source_idx] + NNs=closest_indices_selected.shape[1] + viewpoint_cam2 = viewpoint_stack[closest_indices_selected[source_idx, np.random.randint(NNs)]] + imA = viewpoint_cam1.original_image.detach().cpu().numpy().transpose(1, 2, 0) + imB = viewpoint_cam2.original_image.detach().cpu().numpy().transpose(1, 2, 0) + imA = Image.fromarray(np.clip(imA * 255, 0, 255).astype(np.uint8)) + imB = Image.fromarray(np.clip(imB * 255, 0, 255).astype(np.uint8)) + warp, certainty_warp = roma_model.match(imA, imB, device=device) + + certainties_max = certainty_warp # New manual sampling + timings['aggregation_warp_certainty'].append(time.time() - start) + + # =================== Step 2: Good Samples Selection =================== + start = time.time() + certainty = certainties_max.reshape(-1).clone() + certainty[certainty > upper_thresh] = 1 + good_samples = torch.multinomial(certainty, num_samples=min(expansion_factor * M, len(certainty)), replacement=False) + timings['good_samples_selection'].append(time.time() - start) + + # =================== Step 3: Triangulate Keypoints =================== + reference_image_dict = { + "triangulated_points": [], + "triangulated_points_errors_proj1": [], + "triangulated_points_errors_proj2": [] + } + + start = time.time() + matches_NN = warp.reshape(-1, 4)[good_samples] + + # Convert matches to pixel coordinates + kptsA_np, kptsB_np, kptsA_color, kptsB_color = extract_keypoints_and_colors_single( + np.array(imA).astype(np.uint8), + np.array(imB).astype(np.uint8), + matches_NN, + roma_model + ) + + proj_matrices_A = viewpoint_stack[source_idx].full_proj_transform + proj_matrices_B = viewpoint_stack[closest_indices_selected[source_idx, 0]].full_proj_transform + + triangulated_points, triangulated_points_errors_proj1, triangulated_points_errors_proj2 = triangulate_points( + P1=torch.stack([proj_matrices_A] * M, axis=0), + P2=torch.stack([proj_matrices_B] * M, axis=0), + k1_x=kptsA_np[:M, 0], k1_y=kptsA_np[:M, 1], + k2_x=kptsB_np[:M, 0], k2_y=kptsB_np[:M, 1]) + + reference_image_dict["triangulated_points"].append(triangulated_points) + reference_image_dict["triangulated_points_errors_proj1"].append(triangulated_points_errors_proj1) + reference_image_dict["triangulated_points_errors_proj2"].append(triangulated_points_errors_proj2) + timings['triangulation_per_NN'].append(time.time() - start) + + # =================== Step 4: Select Best Triangulated Points =================== + start = time.time() + NNs_triangulated_points_selected, NNs_triangulated_points_selected_proj_errors = select_best_keypoints( + NNs_triangulated_points=torch.stack(reference_image_dict["triangulated_points"], dim=0), + NNs_errors_proj1=np.stack(reference_image_dict["triangulated_points_errors_proj1"], axis=0), + NNs_errors_proj2=np.stack(reference_image_dict["triangulated_points_errors_proj2"], axis=0)) + timings['select_best_keypoints'].append(time.time() - start) + + # =================== Step 5: Create New Gaussians =================== + start = time.time() + viewpoint_cam1 = viewpoint_stack[source_idx] + N = len(NNs_triangulated_points_selected) + new_xyz = NNs_triangulated_points_selected[:, :-1] + all_new_xyz.append(new_xyz) + all_new_features_dc.append(RGB2SH(torch.tensor(kptsA_color.astype(np.float32) / 255.)).unsqueeze(1)) + all_new_features_rest.append(torch.stack([gaussians._features_rest[-1].clone().detach() * 0.] * N, dim=0)) + + mask_bad_points = torch.tensor( + NNs_triangulated_points_selected_proj_errors > keypoint_fit_error_tolerance, + dtype=torch.float32).unsqueeze(1).to(device) + + all_new_opacities.append(torch.stack([gaussians._opacity[-1].clone().detach()] * N, dim=0) * 0. - mask_bad_points * (1e1)) + + dist_points_to_cam1 = torch.linalg.norm(viewpoint_cam1.camera_center.clone().detach() - new_xyz, dim=1, ord=2) + all_new_scaling.append(gaussians.scaling_inverse_activation((dist_points_to_cam1 * scaling_factor).unsqueeze(1).repeat(1, 3))) + all_new_rotation.append(torch.stack([gaussians._rotation[-1].clone().detach()] * N, dim=0)) + timings['save_gaussians'].append(time.time() - start) + + # =================== Final Densification Postfix =================== + start = time.time() + all_new_xyz = torch.cat(all_new_xyz, dim=0) + all_new_features_dc = torch.cat(all_new_features_dc, dim=0) + new_tmp_radii = torch.zeros(all_new_xyz.shape[0]) + prune_mask = torch.ones(all_new_xyz.shape[0], dtype=torch.bool) + + gaussians.densification_postfix( + all_new_xyz[prune_mask].to(device), + all_new_features_dc[prune_mask].to(device), + torch.cat(all_new_features_rest, dim=0)[prune_mask].to(device), + torch.cat(all_new_opacities, dim=0)[prune_mask].to(device), + torch.cat(all_new_scaling, dim=0)[prune_mask].to(device), + torch.cat(all_new_rotation, dim=0)[prune_mask].to(device), + new_tmp_radii[prune_mask].to(device) + ) + timings['final_densification_postfix'].append(time.time() - start) + + # =================== Print Profiling Results =================== + print("\n=== Profiling Summary (average per frame) ===") + for key, times in timings.items(): + print(f"{key:35s}: {sum(times) / len(times):.4f} sec (total {sum(times):.2f} sec)") + + return viewpoint_stack, closest_indices_selected, visualizations \ No newline at end of file diff --git a/source/data_utils.py b/source/data_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..df5a566a9b482e5c5f05ef02b24e325d56f8bcef --- /dev/null +++ b/source/data_utils.py @@ -0,0 +1,28 @@ +def scene_cameras_train_test_split(scene, verbose=False): + """ + Iterate over resolutions in the scene. For each resolution check if this resolution has test_cameras + if it doesn't then extract every 8th camera from the train and put it to the test set. This follows the + evaluation protocol suggested by Kerbl et al. in the seminal work on 3DGS. All changes to the input + object scene are inplace changes. + :param scene: Scene Class object from the gaussian-splatting.scene module + :param verbose: Print initial and final stage of the function + :return: None + + """ + if verbose: print("Preparing train and test sets split...") + for resolution in scene.train_cameras.keys(): + if len(scene.test_cameras[resolution]) == 0: + if verbose: + print(f"Found no test_cameras for resolution {resolution}. Move every 8th camera out ouf total "+\ + f"{len(scene.train_cameras[resolution])} train cameras to the test set now") + N = len(scene.train_cameras[resolution]) + scene.test_cameras[resolution] = [scene.train_cameras[resolution][idx] for idx in range(0, N) + if idx % 8 == 0] + scene.train_cameras[resolution] = [scene.train_cameras[resolution][idx] for idx in range(0, N) + if idx % 8 != 0] + if verbose: + print(f"Done. Now train and test sets contain each {len(scene.train_cameras[resolution])} and " + \ + f"{len(scene.test_cameras[resolution])} cameras respectively.") + + + return diff --git a/source/losses.py b/source/losses.py new file mode 100644 index 0000000000000000000000000000000000000000..dcaf4d0dddc779cb734fc1cbc84c4a3950a1d98c --- /dev/null +++ b/source/losses.py @@ -0,0 +1,100 @@ +# Code is copied from the gaussian-splatting/utils/loss_utils.py + +import torch +import torch.nn.functional as F +from torch.autograd import Variable +from math import exp + +def l1_loss(network_output, gt, mean=True): + return torch.abs((network_output - gt)).mean() if mean else torch.abs((network_output - gt)) + +def l2_loss(network_output, gt): + return ((network_output - gt) ** 2).mean() + +def gaussian(window_size, sigma): + gauss = torch.Tensor([exp(-(x - window_size // 2) ** 2 / float(2 * sigma ** 2)) for x in range(window_size)]) + return gauss / gauss.sum() + +def create_window(window_size, channel): + _1D_window = gaussian(window_size, 1.5).unsqueeze(1) + _2D_window = _1D_window.mm(_1D_window.t()).float().unsqueeze(0).unsqueeze(0) + window = Variable(_2D_window.expand(channel, 1, window_size, window_size).contiguous()) + return window + +def ssim(img1, img2, window_size=11, size_average=True, mask = None): + channel = img1.size(-3) + window = create_window(window_size, channel) + + if img1.is_cuda: + window = window.cuda(img1.get_device()) + window = window.type_as(img1) + + return _ssim(img1, img2, window, window_size, channel, size_average, mask) + +def _ssim(img1, img2, window, window_size, channel, size_average=True, mask = None): + mu1 = F.conv2d(img1, window, padding=window_size // 2, groups=channel) + mu2 = F.conv2d(img2, window, padding=window_size // 2, groups=channel) + + mu1_sq = mu1.pow(2) + mu2_sq = mu2.pow(2) + mu1_mu2 = mu1 * mu2 + + sigma1_sq = F.conv2d(img1 * img1, window, padding=window_size // 2, groups=channel) - mu1_sq + sigma2_sq = F.conv2d(img2 * img2, window, padding=window_size // 2, groups=channel) - mu2_sq + sigma12 = F.conv2d(img1 * img2, window, padding=window_size // 2, groups=channel) - mu1_mu2 + + C1 = 0.01 ** 2 + C2 = 0.03 ** 2 + + ssim_map = ((2 * mu1_mu2 + C1) * (2 * sigma12 + C2)) / ((mu1_sq + mu2_sq + C1) * (sigma1_sq + sigma2_sq + C2)) + + if mask is not None: + ssim_map = ssim_map * mask + + if size_average: + return ssim_map.mean() + else: + return ssim_map.mean(1).mean(1).mean(1) + + +def mse(img1, img2): + return (((img1 - img2)) ** 2).view(img1.shape[0], -1).mean(1, keepdim=True) + +def psnr(img1, img2): + """ + Computes the Peak Signal-to-Noise Ratio (PSNR) between two single images. NOT BATCHED! + Args: + img1 (torch.Tensor): The first image tensor, with pixel values scaled between 0 and 1. + Shape should be (channels, height, width). + img2 (torch.Tensor): The second image tensor with the same shape as img1, used for comparison. + + Returns: + torch.Tensor: A scalar tensor containing the PSNR value in decibels (dB). + """ + mse = (((img1 - img2)) ** 2).view(img1.shape[0], -1).mean(1, keepdim=True) + return 20 * torch.log10(1.0 / torch.sqrt(mse)) + + +def tv_loss(image): + """ + Computes the total variation (TV) loss for an image of shape [3, H, W]. + + Args: + image (torch.Tensor): Input image of shape [3, H, W] + + Returns: + torch.Tensor: Scalar value representing the total variation loss. + """ + # Ensure the image has the correct dimensions + assert image.ndim == 3 and image.shape[0] == 3, "Input must be of shape [3, H, W]" + + # Compute the difference between adjacent pixels in the x-direction (width) + diff_x = torch.abs(image[:, :, 1:] - image[:, :, :-1]) + + # Compute the difference between adjacent pixels in the y-direction (height) + diff_y = torch.abs(image[:, 1:, :] - image[:, :-1, :]) + + # Sum the total variation in both directions + tv_loss_value = torch.mean(diff_x) + torch.mean(diff_y) + + return tv_loss_value \ No newline at end of file diff --git a/source/networks.py b/source/networks.py new file mode 100644 index 0000000000000000000000000000000000000000..4d289c12bf50e900a04065c37b4fc8911cae07ea --- /dev/null +++ b/source/networks.py @@ -0,0 +1,52 @@ +import torch + +import sys +sys.path.append('./submodules/gaussian-splatting/') + +from random import randint +from scene import Scene, GaussianModel +from gaussian_renderer import render +from source.data_utils import scene_cameras_train_test_split + +class Warper3DGS(torch.nn.Module): + def __init__(self, sh_degree, opt, pipe, dataset, viewpoint_stack, verbose, + do_train_test_split=True): + super(Warper3DGS, self).__init__() + """ + Init Warper using all the objects necessary for rendering gaussian splats. + Here we merely link class objects to the objects instantiated outsided the class. + """ + print("ready!!!7") + self.gaussians = GaussianModel(sh_degree) + print("ready!!!8") + self.gaussians.tmp_radii = torch.zeros((self.gaussians.get_xyz.shape[0]), device="cuda") + self.render = render + self.gs_config_opt = opt + bg_color = [1, 1, 1] if dataset.white_background else [0, 0, 0] + self.bg = torch.tensor(bg_color, dtype=torch.float32, device="cuda") + self.pipe = pipe + print("ready!!!") + self.scene = Scene(dataset, self.gaussians, shuffle=False) + print("ready2") + if do_train_test_split: + scene_cameras_train_test_split(self.scene, verbose=verbose) + + self.gaussians.training_setup(opt) + self.viewpoint_stack = viewpoint_stack + if not self.viewpoint_stack: + self.viewpoint_stack = self.scene.getTrainCameras().copy() + + def forward(self, viewpoint_cam=None): + """ + For a provided camera viewpoint_cam we render gaussians from this viewpoint. + If no camera provided then we use the self.viewpoint_stack (list of cameras). + If the latter is empty we reinitialize it using the self.scene object. + """ + if not viewpoint_cam: + if not self.viewpoint_stack: + self.viewpoint_stack = self.scene.getTrainCameras().copy() + viewpoint_cam = self.viewpoint_stack[randint(0, len(self.viewpoint_stack) - 1)] + + render_pkg = self.render(viewpoint_cam, self.gaussians, self.pipe, self.bg) + return render_pkg + diff --git a/source/timer.py b/source/timer.py new file mode 100755 index 0000000000000000000000000000000000000000..c01ff93c1bdc94a07f1c20a07fb0a983dc496e62 --- /dev/null +++ b/source/timer.py @@ -0,0 +1,24 @@ +import time +class Timer: + def __init__(self): + self.start_time = None + self.elapsed = 0 + self.paused = False + + def start(self): + if self.start_time is None: + self.start_time = time.time() + elif self.paused: + self.start_time = time.time() - self.elapsed + self.paused = False + + def pause(self): + if not self.paused: + self.elapsed = time.time() - self.start_time + self.paused = True + + def get_elapsed_time(self): + if self.paused: + return self.elapsed + else: + return time.time() - self.start_time \ No newline at end of file diff --git a/source/trainer.py b/source/trainer.py new file mode 100644 index 0000000000000000000000000000000000000000..eb6debb0e2429ea6d9cbfaec3adf1246ece6986d --- /dev/null +++ b/source/trainer.py @@ -0,0 +1,262 @@ +import torch +from random import randint +from tqdm.rich import trange +from tqdm import tqdm as tqdm +from source.networks import Warper3DGS +import wandb +import sys + +sys.path.append('./submodules/gaussian-splatting/') +import lpips +from source.losses import ssim, l1_loss, psnr +from rich.console import Console +from rich.theme import Theme + +custom_theme = Theme({ + "info": "dim cyan", + "warning": "magenta", + "danger": "bold red" +}) + +#from source.corr_init import init_gaussians_with_corr +from source.corr_init_new import init_gaussians_with_corr_profiled as init_gaussians_with_corr +from source.utils_aux import log_samples + +from source.timer import Timer + +class EDGSTrainer: + def __init__(self, + GS: Warper3DGS, + training_config, + dataset_white_background=False, + device=torch.device('cuda'), + log_wandb=True, + ): + self.GS = GS + self.scene = GS.scene + self.viewpoint_stack = GS.viewpoint_stack + self.gaussians = GS.gaussians + + self.training_config = training_config + self.GS_optimizer = GS.gaussians.optimizer + self.dataset_white_background = dataset_white_background + + self.training_step = 1 + self.gs_step = 0 + self.CONSOLE = Console(width=120, theme=custom_theme) + self.saving_iterations = training_config.save_iterations + self.evaluate_iterations = None + self.batch_size = training_config.batch_size + self.ema_loss_for_log = 0.0 + + # Logs in the format {step:{"loss1":loss1_value, "loss2":loss2_value}} + self.logs_losses = {} + self.lpips = lpips.LPIPS(net='vgg').to(device) + self.device = device + self.timer = Timer() + self.log_wandb = log_wandb + + def load_checkpoints(self, load_cfg): + # Load 3DGS checkpoint + if load_cfg.gs: + self.gs.gaussians.restore( + torch.load(f"{load_cfg.gs}/chkpnt{load_cfg.gs_step}.pth")[0], + self.training_config) + self.GS_optimizer = self.GS.gaussians.optimizer + self.CONSOLE.print(f"3DGS loaded from checkpoint for iteration {load_cfg.gs_step}", + style="info") + self.training_step += load_cfg.gs_step + self.gs_step += load_cfg.gs_step + + def train(self, train_cfg): + # 3DGS training + self.CONSOLE.print("Train 3DGS for {} iterations".format(train_cfg.gs_epochs), style="info") + with trange(self.training_step, self.training_step + train_cfg.gs_epochs, desc="[green]Train gaussians") as progress_bar: + for self.training_step in progress_bar: + radii = self.train_step_gs(max_lr=train_cfg.max_lr, no_densify=train_cfg.no_densify) + with torch.no_grad(): + if train_cfg.no_densify: + self.prune(radii) + else: + self.densify_and_prune(radii) + if train_cfg.reduce_opacity: + # Slightly reduce opacity every few steps: + if self.gs_step < self.training_config.densify_until_iter and self.gs_step % 10 == 0: + opacities_new = torch.log(torch.exp(self.GS.gaussians._opacity.data) * 0.99) + self.GS.gaussians._opacity.data = opacities_new + self.timer.pause() + # Progress bar + if self.training_step % 10 == 0: + progress_bar.set_postfix({"[red]Loss": f"{self.ema_loss_for_log:.{7}f}"}, refresh=True) + # Log and save + if self.training_step in self.saving_iterations: + self.save_model() + if self.evaluate_iterations is not None: + if self.training_step in self.evaluate_iterations: + self.evaluate() + else: + if (self.training_step <= 3000 and self.training_step % 500 == 0) or \ + (self.training_step > 3000 and self.training_step % 1000 == 228) : + self.evaluate() + + self.timer.start() + + + def evaluate(self): + torch.cuda.empty_cache() + log_gen_images, log_real_images = [], [] + validation_configs = ({'name': 'test', 'cameras': self.scene.getTestCameras(), 'cam_idx': self.training_config.TEST_CAM_IDX_TO_LOG}, + {'name': 'train', + 'cameras': [self.scene.getTrainCameras()[idx % len(self.scene.getTrainCameras())] for idx in + range(0, 150, 5)], 'cam_idx': 10}) + if self.log_wandb: + wandb.log({f"Number of Gaussians": len(self.GS.gaussians._xyz)}, step=self.training_step) + for config in validation_configs: + if config['cameras'] and len(config['cameras']) > 0: + l1_test = 0.0 + psnr_test = 0.0 + ssim_test = 0.0 + lpips_splat_test = 0.0 + for idx, viewpoint in enumerate(config['cameras']): + image = torch.clamp(self.GS(viewpoint)["render"], 0.0, 1.0) + gt_image = torch.clamp(viewpoint.original_image.to(self.device), 0.0, 1.0) + l1_test += l1_loss(image, gt_image).double() + psnr_test += psnr(image.unsqueeze(0), gt_image.unsqueeze(0)).double() + ssim_test += ssim(image, gt_image).double() + lpips_splat_test += self.lpips(image, gt_image).detach().double() + if idx in [config['cam_idx']]: + log_gen_images.append(image) + log_real_images.append(gt_image) + psnr_test /= len(config['cameras']) + l1_test /= len(config['cameras']) + ssim_test /= len(config['cameras']) + lpips_splat_test /= len(config['cameras']) + if self.log_wandb: + wandb.log({f"{config['name']}/L1": l1_test.item(), f"{config['name']}/PSNR": psnr_test.item(), \ + f"{config['name']}/SSIM": ssim_test.item(), f"{config['name']}/LPIPS_splat": lpips_splat_test.item()}, step = self.training_step) + self.CONSOLE.print("\n[ITER {}], #{} gaussians, Evaluating {}: L1={:.6f}, PSNR={:.6f}, SSIM={:.6f}, LPIPS_splat={:.6f} ".format( + self.training_step, len(self.GS.gaussians._xyz), config['name'], l1_test.item(), psnr_test.item(), ssim_test.item(), lpips_splat_test.item()), style="info") + if self.log_wandb: + with torch.no_grad(): + log_samples(torch.stack((log_real_images[0],log_gen_images[0])) , [], self.training_step, caption="Real and Generated Samples") + wandb.log({"time": self.timer.get_elapsed_time()}, step=self.training_step) + torch.cuda.empty_cache() + + def train_step_gs(self, max_lr = False, no_densify = False): + self.gs_step += 1 + if max_lr: + self.GS.gaussians.update_learning_rate(max(self.gs_step, 8_000)) + else: + self.GS.gaussians.update_learning_rate(self.gs_step) + # Every 1000 its we increase the levels of SH up to a maximum degree + if self.gs_step % 1000 == 0: + self.GS.gaussians.oneupSHdegree() + + # Pick a random Camera + if not self.viewpoint_stack: + self.viewpoint_stack = self.scene.getTrainCameras().copy() + viewpoint_cam = self.viewpoint_stack.pop(randint(0, len(self.viewpoint_stack) - 1)) + + render_pkg = self.GS(viewpoint_cam=viewpoint_cam) + image = render_pkg["render"] + # Loss + gt_image = viewpoint_cam.original_image.to(self.device) + L1_loss = l1_loss(image, gt_image) + + ssim_loss = (1.0 - ssim(image, gt_image)) + loss = (1.0 - self.training_config.lambda_dssim) * L1_loss + \ + self.training_config.lambda_dssim * ssim_loss + self.timer.pause() + self.logs_losses[self.training_step] = {"loss": loss.item(), + "L1_loss": L1_loss.item(), + "ssim_loss": ssim_loss.item()} + + if self.log_wandb: + for k, v in self.logs_losses[self.training_step].items(): + wandb.log({f"train/{k}": v}, step=self.training_step) + self.ema_loss_for_log = 0.4 * self.logs_losses[self.training_step]["loss"] + 0.6 * self.ema_loss_for_log + self.timer.start() + self.GS_optimizer.zero_grad(set_to_none=True) + loss.backward() + with torch.no_grad(): + if self.gs_step < self.training_config.densify_until_iter and not no_densify: + self.GS.gaussians.max_radii2D[render_pkg["visibility_filter"]] = torch.max( + self.GS.gaussians.max_radii2D[render_pkg["visibility_filter"]], + render_pkg["radii"][render_pkg["visibility_filter"]]) + self.GS.gaussians.add_densification_stats(render_pkg["viewspace_points"], + render_pkg["visibility_filter"]) + + # Optimizer step + self.GS_optimizer.step() + self.GS_optimizer.zero_grad(set_to_none=True) + return render_pkg["radii"] + + def densify_and_prune(self, radii = None): + # Densification or pruning + if self.gs_step < self.training_config.densify_until_iter: + if (self.gs_step > self.training_config.densify_from_iter) and \ + (self.gs_step % self.training_config.densification_interval == 0): + size_threshold = 20 if self.gs_step > self.training_config.opacity_reset_interval else None + self.GS.gaussians.densify_and_prune(self.training_config.densify_grad_threshold, + 0.005, + self.GS.scene.cameras_extent, + size_threshold, radii) + if self.gs_step % self.training_config.opacity_reset_interval == 0 or ( + self.dataset_white_background and self.gs_step == self.training_config.densify_from_iter): + self.GS.gaussians.reset_opacity() + + + + def save_model(self): + print("\n[ITER {}] Saving Gaussians".format(self.gs_step)) + self.scene.save(self.gs_step) + print("\n[ITER {}] Saving Checkpoint".format(self.gs_step)) + torch.save((self.GS.gaussians.capture(), self.gs_step), + self.scene.model_path + "/chkpnt" + str(self.gs_step) + ".pth") + + + def init_with_corr(self, cfg, verbose=False, roma_model=None): + """ + Initializes image with matchings. Also removes SfM init points. + Args: + cfg: configuration part named init_wC. Check train.yaml + verbose: whether you want to print intermediate results. Useful for debug. + roma_model: optionally you can pass here preinit RoMA model to avoid reinit + it every time. + """ + if not cfg.use: + return None + N_splats_at_init = len(self.GS.gaussians._xyz) + print("N_splats_at_init:", N_splats_at_init) + camera_set, selected_indices, visualization_dict = init_gaussians_with_corr( + self.GS.gaussians, + self.scene, + cfg, + self.device, + verbose=verbose, + roma_model=roma_model) + + # Remove SfM points and leave only matchings inits + if not cfg.add_SfM_init: + with torch.no_grad(): + N_splats_after_init = len(self.GS.gaussians._xyz) + print("N_splats_after_init:", N_splats_after_init) + self.gaussians.tmp_radii = torch.zeros(self.gaussians._xyz.shape[0]).to(self.device) + mask = torch.concat([torch.ones(N_splats_at_init, dtype=torch.bool), + torch.zeros(N_splats_after_init-N_splats_at_init, dtype=torch.bool)], + axis=0) + self.GS.gaussians.prune_points(mask) + with torch.no_grad(): + gaussians = self.gaussians + gaussians._scaling = gaussians.scaling_inverse_activation(gaussians.scaling_activation(gaussians._scaling)*0.5) + return visualization_dict + + + def prune(self, radii, min_opacity=0.005): + self.GS.gaussians.tmp_radii = radii + if self.gs_step < self.training_config.densify_until_iter: + prune_mask = (self.GS.gaussians.get_opacity < min_opacity).squeeze() + self.GS.gaussians.prune_points(prune_mask) + torch.cuda.empty_cache() + self.GS.gaussians.tmp_radii = None + diff --git a/source/utils_aux.py b/source/utils_aux.py new file mode 100644 index 0000000000000000000000000000000000000000..48fcc752cd2c2ef142086d70b4a079f63e940809 --- /dev/null +++ b/source/utils_aux.py @@ -0,0 +1,92 @@ +# Perlin noise code taken from https://gist.github.com/adefossez/0646dbe9ed4005480a2407c62aac8869 +from types import SimpleNamespace +import random +import numpy as np +import torch +import torchvision +import wandb +import random +import torchvision.transforms as T +import torchvision.transforms.functional as F +import torch +from PIL import Image + +def parse_dict_to_namespace(dict_nested): + """Turns nested dictionary into nested namespaces""" + if type(dict_nested) != dict and type(dict_nested) != list: return dict_nested + x = SimpleNamespace() + for key, val in dict_nested.items(): + if type(val) == dict: + setattr(x, key, parse_dict_to_namespace(val)) + elif type(val) == list: + setattr(x, key, [parse_dict_to_namespace(v) for v in val]) + else: + setattr(x, key, val) + return x + +def set_seed(seed=42, cuda=True): + random.seed(seed) + np.random.seed(seed) + torch.manual_seed(seed) + if cuda: + torch.cuda.manual_seed_all(seed) + + + +def log_samples(samples, scores, iteration, caption="Real Samples"): + # Create a grid of images + grid = torchvision.utils.make_grid(samples) + + # Log the images and scores to wandb + wandb.log({ + f"{caption}_images": [wandb.Image(grid, caption=f"{caption}: {scores}")], + }, step = iteration) + + + +def pairwise_distances(matrix): + """ + Computes the pairwise Euclidean distances between all vectors in the input matrix. + + Args: + matrix (torch.Tensor): Input matrix of shape [N, D], where N is the number of vectors and D is the dimensionality. + + Returns: + torch.Tensor: Pairwise distance matrix of shape [N, N]. + """ + # Compute squared pairwise distances + squared_diff = torch.cdist(matrix, matrix, p=2) + return squared_diff + +def k_closest_vectors(matrix, k): + """ + Finds the k-closest vectors for each vector in the input matrix based on Euclidean distance. + + Args: + matrix (torch.Tensor): Input matrix of shape [N, D], where N is the number of vectors and D is the dimensionality. + k (int): Number of closest vectors to return for each vector. + + Returns: + torch.Tensor: Indices of the k-closest vectors for each vector, excluding the vector itself. + """ + # Compute pairwise distances + distances = pairwise_distances(matrix) + + # For each vector, sort distances and get the indices of the k-closest vectors (excluding itself) + # Set diagonal distances to infinity to exclude the vector itself from the nearest neighbors + distances.fill_diagonal_(float('inf')) + + # Get the indices of the k smallest distances (k-closest vectors) + _, indices = torch.topk(distances, k, largest=False, dim=1) + + return indices + +def process_image(image_tensor): + image_np = image_tensor.detach().cpu().numpy().transpose(1, 2, 0) + return Image.fromarray(np.clip(image_np * 255, 0, 255).astype(np.uint8)) + + +def normalize_keypoints(kpts_np, width, height): + kpts_np[:, 0] = kpts_np[:, 0] / width * 2. - 1. + kpts_np[:, 1] = kpts_np[:, 1] / height * 2. - 1. + return kpts_np \ No newline at end of file diff --git a/source/utils_preprocess.py b/source/utils_preprocess.py new file mode 100644 index 0000000000000000000000000000000000000000..7c6dab31946b10d57c6e9b6a3d948297e7b27227 --- /dev/null +++ b/source/utils_preprocess.py @@ -0,0 +1,334 @@ +# This file contains function for video or image collection preprocessing. +# For video we do the preprocessing and select k sharpest frames. +# Afterwards scene is constructed +import cv2 +import numpy as np +from tqdm import tqdm +import pycolmap +import os +import time +import tempfile +from moviepy import VideoFileClip +from matplotlib import pyplot as plt +from PIL import Image +import cv2 +from tqdm import tqdm + +WORKDIR = "../outputs/" + + +def get_rotation_moviepy(video_path): + clip = VideoFileClip(video_path) + rotation = 0 + + try: + displaymatrix = clip.reader.infos['inputs'][0]['streams'][2]['metadata'].get('displaymatrix', '') + if 'rotation of' in displaymatrix: + angle = float(displaymatrix.strip().split('rotation of')[-1].split('degrees')[0]) + rotation = int(angle) % 360 + + except Exception as e: + print(f"No displaymatrix rotation found: {e}") + + clip.reader.close() + #if clip.audio: + # clip.audio.reader.close_proc() + + return rotation + +def resize_max_side(frame, max_size): + h, w = frame.shape[:2] + scale = max_size / max(h, w) + if scale < 1: + frame = cv2.resize(frame, (int(w * scale), int(h * scale))) + return frame + +def read_video_frames(video_input, k=1, max_size=1024): + """ + Extracts every k-th frame from a video or list of images, resizes to max size, and returns frames as list. + + Parameters: + video_input (str, file-like, or list): Path to video file, file-like object, or list of image files. + k (int): Interval for frame extraction (every k-th frame). + max_size (int): Maximum size for width or height after resizing. + + Returns: + frames (list): List of resized frames (numpy arrays). + """ + # Handle list of image files (not single video in a list) + if isinstance(video_input, list): + # If it's a single video in a list, treat it as video + if len(video_input) == 1 and video_input[0].name.endswith(('.mp4', '.avi', '.mov')): + video_input = video_input[0] # unwrap single video file + else: + # Treat as list of images + frames = [] + for img_file in video_input: + img = Image.open(img_file.name).convert("RGB") + img.thumbnail((max_size, max_size)) + frames.append(np.array(img)[...,::-1]) + return frames + + # Handle file-like or path + if hasattr(video_input, 'name'): + video_path = video_input.name + elif isinstance(video_input, (str, os.PathLike)): + video_path = str(video_input) + else: + raise ValueError("Unsupported video input type. Must be a filepath, file-like object, or list of images.") + + + cap = cv2.VideoCapture(video_path) + if not cap.isOpened(): + raise ValueError(f"Error: Could not open video {video_path}.") + + total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) + frame_count = 0 + frames = [] + + with tqdm(total=total_frames // k, desc="Processing Video", unit="frame") as pbar: + while True: + ret, frame = cap.read() + if not ret: + break + if frame_count % k == 0: + frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) + h, w = frame.shape[:2] + scale = max(h, w) / max_size + if scale > 1: + frame = cv2.resize(frame, (int(w / scale), int(h / scale))) + frames.append(frame[...,[2,1,0]]) + pbar.update(1) + frame_count += 1 + + cap.release() + return frames + +def resize_max_side(frame, max_size): + """ + Resizes the frame so that its largest side equals max_size, maintaining aspect ratio. + """ + height, width = frame.shape[:2] + max_dim = max(height, width) + + if max_dim <= max_size: + return frame # No need to resize + + scale = max_size / max_dim + new_width = int(width * scale) + new_height = int(height * scale) + + resized_frame = cv2.resize(frame, (new_width, new_height), interpolation=cv2.INTER_AREA) + return resized_frame + + + +def variance_of_laplacian(image): + # compute the Laplacian of the image and then return the focus + # measure, which is simply the variance of the Laplacian + return cv2.Laplacian(image, cv2.CV_64F).var() + +def process_all_frames(IMG_FOLDER = '/scratch/datasets/hq_data/night2_all_frames', + to_visualize=False, + save_images=True): + dict_scores = {} + for idx, img_name in tqdm(enumerate(sorted([x for x in os.listdir(IMG_FOLDER) if '.png' in x]))): + + img = cv2.imread(os.path.join(IMG_FOLDER, img_name))#[250:, 100:] + gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) + fm = variance_of_laplacian(gray) + \ + variance_of_laplacian(cv2.resize(gray, (0,0), fx=0.75, fy=0.75)) + \ + variance_of_laplacian(cv2.resize(gray, (0,0), fx=0.5, fy=0.5)) + \ + variance_of_laplacian(cv2.resize(gray, (0,0), fx=0.25, fy=0.25)) + if to_visualize: + plt.figure() + plt.title(f"Laplacian score: {fm:.2f}") + plt.imshow(img[..., [2,1,0]]) + plt.show() + dict_scores[idx] = {"idx" : idx, + "img_name" : img_name, + "score" : fm} + if save_images: + dict_scores[idx]["img"] = img + + return dict_scores + +def select_optimal_frames(scores, k): + """ + Selects a minimal subset of frames while ensuring no gaps exceed k. + + Args: + scores (list of float): List of scores where index represents frame number. + k (int): Maximum allowed gap between selected frames. + + Returns: + list of int: Indices of selected frames. + """ + n = len(scores) + selected = [0, n-1] + i = 0 # Start at the first frame + + while i < n: + # Find the best frame to select within the next k frames + best_idx = max(range(i, min(i + k + 1, n)), key=lambda x: scores[x], default=None) + + if best_idx is None: + break # No more frames left + + selected.append(best_idx) + i = best_idx + k + 1 # Move forward, ensuring gaps stay within k + + return sorted(selected) + + +def variance_of_laplacian(image): + """ + Compute the variance of Laplacian as a focus measure. + """ + return cv2.Laplacian(image, cv2.CV_64F).var() + +def preprocess_frames(frames, verbose=False): + """ + Compute sharpness scores for a list of frames using multi-scale Laplacian variance. + + Args: + frames (list of np.ndarray): List of frames (BGR images). + verbose (bool): If True, print scores. + + Returns: + list of float: Sharpness scores for each frame. + """ + scores = [] + + for idx, frame in enumerate(tqdm(frames, desc="Scoring frames")): + gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) + + fm = ( + variance_of_laplacian(gray) + + variance_of_laplacian(cv2.resize(gray, (0, 0), fx=0.75, fy=0.75)) + + variance_of_laplacian(cv2.resize(gray, (0, 0), fx=0.5, fy=0.5)) + + variance_of_laplacian(cv2.resize(gray, (0, 0), fx=0.25, fy=0.25)) + ) + + if verbose: + print(f"Frame {idx}: Sharpness Score = {fm:.2f}") + + scores.append(fm) + + return scores + +def select_optimal_frames(scores, k): + """ + Selects k frames by splitting into k segments and picking the sharpest frame from each. + + Args: + scores (list of float): List of sharpness scores. + k (int): Number of frames to select. + + Returns: + list of int: Indices of selected frames. + """ + n = len(scores) + selected_indices = [] + segment_size = n // k + + for i in range(k): + start = i * segment_size + end = (i + 1) * segment_size if i < k - 1 else n # Last chunk may be larger + segment_scores = scores[start:end] + + if len(segment_scores) == 0: + continue # Safety check if some segment is empty + + best_in_segment = start + np.argmax(segment_scores) + selected_indices.append(best_in_segment) + + return sorted(selected_indices) + +def save_frames_to_scene_dir(frames, scene_dir): + """ + Saves a list of frames into the target scene directory under 'images/' subfolder. + + Args: + frames (list of np.ndarray): List of frames (BGR images) to save. + scene_dir (str): Target path where 'images/' subfolder will be created. + """ + images_dir = os.path.join(scene_dir, "images") + os.makedirs(images_dir, exist_ok=True) + + for idx, frame in enumerate(frames): + filename = os.path.join(images_dir, f"{idx:08d}.png") # 00000000.png, 00000001.png, etc. + cv2.imwrite(filename, frame) + + print(f"Saved {len(frames)} frames to {images_dir}") + + +def run_colmap_on_scene(scene_dir): + """ + Runs feature extraction, matching, and mapping on all images inside scene_dir/images using pycolmap. + + Args: + scene_dir (str): Path to scene directory containing 'images' folder. + + TODO: if the function hasn't managed to match all the frames either increase image size, + increase number of features or just remove those frames from the folder scene_dir/images + """ + start_time = time.time() + print(f"Running COLMAP pipeline on all images inside {scene_dir}") + + # Setup paths + database_path = os.path.join(scene_dir, "database.db") + sparse_path = os.path.join(scene_dir, "sparse") + image_dir = os.path.join(scene_dir, "images") + + # Make sure output directories exist + os.makedirs(sparse_path, exist_ok=True) + + # Step 1: Feature Extraction + pycolmap.extract_features( + database_path, + image_dir, + sift_options={ + "max_num_features": 512 * 2, + "max_image_size": 512 * 1, + } + ) + print(f"Finished feature extraction in {(time.time() - start_time):.2f}s.") + + # Step 2: Feature Matching + pycolmap.match_exhaustive(database_path) + print(f"Finished feature matching in {(time.time() - start_time):.2f}s.") + + # Step 3: Mapping + pipeline_options = pycolmap.IncrementalPipelineOptions() + pipeline_options.min_num_matches = 15 + pipeline_options.multiple_models = True + pipeline_options.max_num_models = 50 + pipeline_options.max_model_overlap = 20 + pipeline_options.min_model_size = 10 + pipeline_options.extract_colors = True + pipeline_options.num_threads = 8 + pipeline_options.mapper.init_min_num_inliers = 30 + pipeline_options.mapper.init_max_error = 8.0 + pipeline_options.mapper.init_min_tri_angle = 5.0 + + reconstruction = pycolmap.incremental_mapping( + database_path=database_path, + image_path=image_dir, + output_path=sparse_path, + options=pipeline_options, + ) + print(f"Finished incremental mapping in {(time.time() - start_time):.2f}s.") + + # Step 4: Post-process Cameras to SIMPLE_PINHOLE + recon_path = os.path.join(sparse_path, "0") + reconstruction = pycolmap.Reconstruction(recon_path) + + for cam in reconstruction.cameras.values(): + cam.model = 'SIMPLE_PINHOLE' + cam.params = cam.params[:3] # Keep only [f, cx, cy] + + reconstruction.write(recon_path) + + print(f"Total pipeline time: {(time.time() - start_time):.2f}s.") + diff --git a/source/vggt_to_colmap.py b/source/vggt_to_colmap.py new file mode 100644 index 0000000000000000000000000000000000000000..c2bda741f2e5c91d84851c8e68650a6a975948ff --- /dev/null +++ b/source/vggt_to_colmap.py @@ -0,0 +1,598 @@ +# Reuse code taken from the implementation of atakan-topaloglu: +# https://github.com/atakan-topaloglu/vggt/blob/main/vggt_to_colmap.py + +import os +import argparse +import numpy as np +import torch +import glob +import struct +from scipy.spatial.transform import Rotation +import sys +from PIL import Image +import cv2 +import requests +import tempfile + +sys.path.append("submodules/vggt/") + +from vggt.models.vggt import VGGT +from vggt.utils.load_fn import load_and_preprocess_images +from vggt.utils.pose_enc import pose_encoding_to_extri_intri +from vggt.utils.geometry import unproject_depth_map_to_point_map + +def load_model(device=None): + """Load and initialize the VGGT model.""" + if device is None: + device = "cuda" if torch.cuda.is_available() else "cpu" + print(f"Using device: {device}") + + model = VGGT.from_pretrained("facebook/VGGT-1B") + + # model = VGGT() + # _URL = "https://huggingface.co/facebook/VGGT-1B/resolve/main/model.pt" + # model.load_state_dict(torch.hub.load_state_dict_from_url(_URL)) + + model.eval() + model = model.to(device) + return model, device + +def process_images(image_dir, model, device): + """Process images with VGGT and return predictions.""" + image_names = glob.glob(os.path.join(image_dir, "*")) + image_names = sorted([f for f in image_names if f.lower().endswith(('.png', '.jpg', '.jpeg'))]) + print(f"Found {len(image_names)} images") + + if len(image_names) == 0: + raise ValueError(f"No images found in {image_dir}") + + original_images = [] + for img_path in image_names: + img = Image.open(img_path).convert('RGB') + original_images.append(np.array(img)) + + images = load_and_preprocess_images(image_names).to(device) + print(f"Preprocessed images shape: {images.shape}") + + print("Running inference...") + dtype = torch.bfloat16 if torch.cuda.get_device_capability()[0] >= 8 else torch.float16 + + with torch.no_grad(): + with torch.cuda.amp.autocast(dtype=dtype): + predictions = model(images) + + print("Converting pose encoding to camera parameters...") + extrinsic, intrinsic = pose_encoding_to_extri_intri(predictions["pose_enc"], images.shape[-2:]) + predictions["extrinsic"] = extrinsic + predictions["intrinsic"] = intrinsic + + for key in predictions.keys(): + if isinstance(predictions[key], torch.Tensor): + predictions[key] = predictions[key].cpu().numpy().squeeze(0) # remove batch dimension + + print("Computing 3D points from depth maps...") + depth_map = predictions["depth"] # (S, H, W, 1) + world_points = unproject_depth_map_to_point_map(depth_map, predictions["extrinsic"], predictions["intrinsic"]) + predictions["world_points_from_depth"] = world_points + + predictions["original_images"] = original_images + + S, H, W = world_points.shape[:3] + normalized_images = np.zeros((S, H, W, 3), dtype=np.float32) + + for i, img in enumerate(original_images): + resized_img = cv2.resize(img, (W, H)) + normalized_images[i] = resized_img / 255.0 + + predictions["images"] = normalized_images + + return predictions, image_names + +def extrinsic_to_colmap_format(extrinsics): + """Convert extrinsic matrices to COLMAP format (quaternion + translation).""" + num_cameras = extrinsics.shape[0] + quaternions = [] + translations = [] + + for i in range(num_cameras): + # VGGT's extrinsic is camera-to-world (R|t) format + R = extrinsics[i, :3, :3] + t = extrinsics[i, :3, 3] + + # Convert rotation matrix to quaternion + # COLMAP quaternion format is [qw, qx, qy, qz] + rot = Rotation.from_matrix(R) + quat = rot.as_quat() # scipy returns [x, y, z, w] + quat = np.array([quat[3], quat[0], quat[1], quat[2]]) # Convert to [w, x, y, z] + + quaternions.append(quat) + translations.append(t) + + return np.array(quaternions), np.array(translations) + +def download_file_from_url(url, filename): + """Downloads a file from a URL, handling redirects.""" + try: + response = requests.get(url, allow_redirects=False) + response.raise_for_status() + + if response.status_code == 302: + redirect_url = response.headers["Location"] + response = requests.get(redirect_url, stream=True) + response.raise_for_status() + else: + response = requests.get(url, stream=True) + response.raise_for_status() + + with open(filename, "wb") as f: + for chunk in response.iter_content(chunk_size=8192): + f.write(chunk) + print(f"Downloaded {filename} successfully.") + return True + + except requests.exceptions.RequestException as e: + print(f"Error downloading file: {e}") + return False + +def segment_sky(image_path, onnx_session, mask_filename=None): + """ + Segments sky from an image using an ONNX model. + """ + image = cv2.imread(image_path) + + result_map = run_skyseg(onnx_session, [320, 320], image) + result_map_original = cv2.resize(result_map, (image.shape[1], image.shape[0])) + + # Fix: Invert the mask so that 255 = non-sky, 0 = sky + # The model outputs low values for sky, high values for non-sky + output_mask = np.zeros_like(result_map_original) + output_mask[result_map_original < 32] = 255 # Use threshold of 32 + + if mask_filename is not None: + os.makedirs(os.path.dirname(mask_filename), exist_ok=True) + cv2.imwrite(mask_filename, output_mask) + + return output_mask + +def run_skyseg(onnx_session, input_size, image): + """ + Runs sky segmentation inference using ONNX model. + """ + import copy + + temp_image = copy.deepcopy(image) + resize_image = cv2.resize(temp_image, dsize=(input_size[0], input_size[1])) + x = cv2.cvtColor(resize_image, cv2.COLOR_BGR2RGB) + x = np.array(x, dtype=np.float32) + mean = [0.485, 0.456, 0.406] + std = [0.229, 0.224, 0.225] + x = (x / 255 - mean) / std + x = x.transpose(2, 0, 1) + x = x.reshape(-1, 3, input_size[0], input_size[1]).astype("float32") + + input_name = onnx_session.get_inputs()[0].name + output_name = onnx_session.get_outputs()[0].name + onnx_result = onnx_session.run([output_name], {input_name: x}) + + onnx_result = np.array(onnx_result).squeeze() + min_value = np.min(onnx_result) + max_value = np.max(onnx_result) + onnx_result = (onnx_result - min_value) / (max_value - min_value) + onnx_result *= 255 + onnx_result = onnx_result.astype("uint8") + + return onnx_result + +def filter_and_prepare_points(predictions, conf_threshold, mask_sky=False, mask_black_bg=False, + mask_white_bg=False, stride=1, prediction_mode="Depthmap and Camera Branch"): + """ + Filter points based on confidence and prepare for COLMAP format. + Implementation matches the conventions in the original VGGT code. + """ + + if "Pointmap" in prediction_mode: + print("Using Pointmap Branch") + if "world_points" in predictions: + pred_world_points = predictions["world_points"] + pred_world_points_conf = predictions.get("world_points_conf", np.ones_like(pred_world_points[..., 0])) + else: + print("Warning: world_points not found in predictions, falling back to depth-based points") + pred_world_points = predictions["world_points_from_depth"] + pred_world_points_conf = predictions.get("depth_conf", np.ones_like(pred_world_points[..., 0])) + else: + print("Using Depthmap and Camera Branch") + pred_world_points = predictions["world_points_from_depth"] + pred_world_points_conf = predictions.get("depth_conf", np.ones_like(pred_world_points[..., 0])) + + colors_rgb = predictions["images"] + + S, H, W = pred_world_points.shape[:3] + if colors_rgb.shape[:3] != (S, H, W): + print(f"Reshaping colors_rgb from {colors_rgb.shape} to match {(S, H, W, 3)}") + reshaped_colors = np.zeros((S, H, W, 3), dtype=np.float32) + for i in range(S): + if i < len(colors_rgb): + reshaped_colors[i] = cv2.resize(colors_rgb[i], (W, H)) + colors_rgb = reshaped_colors + + colors_rgb = (colors_rgb * 255).astype(np.uint8) + + if mask_sky: + print("Applying sky segmentation mask") + try: + import onnxruntime + + with tempfile.TemporaryDirectory() as temp_dir: + print(f"Created temporary directory for sky segmentation: {temp_dir}") + temp_images_dir = os.path.join(temp_dir, "images") + sky_masks_dir = os.path.join(temp_dir, "sky_masks") + os.makedirs(temp_images_dir, exist_ok=True) + os.makedirs(sky_masks_dir, exist_ok=True) + + image_list = [] + for i, img in enumerate(colors_rgb): + img_path = os.path.join(temp_images_dir, f"image_{i:04d}.png") + image_list.append(img_path) + cv2.imwrite(img_path, cv2.cvtColor(img, cv2.COLOR_RGB2BGR)) + + + skyseg_path = os.path.join(temp_dir, "skyseg.onnx") + if not os.path.exists("skyseg.onnx"): + print("Downloading skyseg.onnx...") + download_success = download_file_from_url( + "https://huggingface.co/JianyuanWang/skyseg/resolve/main/skyseg.onnx", + skyseg_path + ) + if not download_success: + print("Failed to download skyseg model, skipping sky filtering") + mask_sky = False + else: + + import shutil + shutil.copy("skyseg.onnx", skyseg_path) + + if mask_sky: + skyseg_session = onnxruntime.InferenceSession(skyseg_path) + sky_mask_list = [] + + for img_path in image_list: + mask_path = os.path.join(sky_masks_dir, os.path.basename(img_path)) + sky_mask = segment_sky(img_path, skyseg_session, mask_path) + + if sky_mask.shape[0] != H or sky_mask.shape[1] != W: + sky_mask = cv2.resize(sky_mask, (W, H)) + + sky_mask_list.append(sky_mask) + + sky_mask_array = np.array(sky_mask_list) + + sky_mask_binary = (sky_mask_array > 0.1).astype(np.float32) + pred_world_points_conf = pred_world_points_conf * sky_mask_binary + print(f"Applied sky mask, shape: {sky_mask_binary.shape}") + + except (ImportError, Exception) as e: + print(f"Error in sky segmentation: {e}") + mask_sky = False + + vertices_3d = pred_world_points.reshape(-1, 3) + conf = pred_world_points_conf.reshape(-1) + colors_rgb_flat = colors_rgb.reshape(-1, 3) + + + + if len(conf) != len(colors_rgb_flat): + print(f"WARNING: Shape mismatch between confidence ({len(conf)}) and colors ({len(colors_rgb_flat)})") + min_size = min(len(conf), len(colors_rgb_flat)) + conf = conf[:min_size] + vertices_3d = vertices_3d[:min_size] + colors_rgb_flat = colors_rgb_flat[:min_size] + + if conf_threshold == 0.0: + conf_thres_value = 0.0 + else: + conf_thres_value = np.percentile(conf, conf_threshold) + + print(f"Using confidence threshold: {conf_threshold}% (value: {conf_thres_value:.4f})") + conf_mask = (conf >= conf_thres_value) & (conf > 1e-5) + + if mask_black_bg: + print("Filtering black background") + black_bg_mask = colors_rgb_flat.sum(axis=1) >= 16 + conf_mask = conf_mask & black_bg_mask + + if mask_white_bg: + print("Filtering white background") + white_bg_mask = ~((colors_rgb_flat[:, 0] > 240) & (colors_rgb_flat[:, 1] > 240) & (colors_rgb_flat[:, 2] > 240)) + conf_mask = conf_mask & white_bg_mask + + filtered_vertices = vertices_3d[conf_mask] + filtered_colors = colors_rgb_flat[conf_mask] + + if len(filtered_vertices) == 0: + print("Warning: No points remaining after filtering. Using default point.") + filtered_vertices = np.array([[0, 0, 0]]) + filtered_colors = np.array([[200, 200, 200]]) + + print(f"Filtered to {len(filtered_vertices)} points") + + points3D = [] + point_indices = {} + image_points2D = [[] for _ in range(len(pred_world_points))] + + print(f"Preparing points for COLMAP format with stride {stride}...") + + total_points = 0 + for img_idx in range(S): + for y in range(0, H, stride): + for x in range(0, W, stride): + flat_idx = img_idx * H * W + y * W + x + + if flat_idx >= len(conf): + continue + + if conf[flat_idx] < conf_thres_value or conf[flat_idx] <= 1e-5: + continue + + if mask_black_bg and colors_rgb_flat[flat_idx].sum() < 16: + continue + + if mask_white_bg and all(colors_rgb_flat[flat_idx] > 240): + continue + + point3D = vertices_3d[flat_idx] + rgb = colors_rgb_flat[flat_idx] + + if not np.all(np.isfinite(point3D)): + continue + + point_hash = hash_point(point3D, scale=100) + + if point_hash not in point_indices: + point_idx = len(points3D) + point_indices[point_hash] = point_idx + + point_entry = { + "id": point_idx, + "xyz": point3D, + "rgb": rgb, + "error": 1.0, + "track": [(img_idx, len(image_points2D[img_idx]))] + } + points3D.append(point_entry) + total_points += 1 + else: + point_idx = point_indices[point_hash] + points3D[point_idx]["track"].append((img_idx, len(image_points2D[img_idx]))) + + image_points2D[img_idx].append((x, y, point_indices[point_hash])) + + print(f"Prepared {len(points3D)} 3D points with {sum(len(pts) for pts in image_points2D)} observations for COLMAP") + return points3D, image_points2D + +def hash_point(point, scale=100): + """Create a hash for a 3D point by quantizing coordinates.""" + quantized = tuple(np.round(point * scale).astype(int)) + return hash(quantized) + +def write_colmap_cameras_txt(file_path, intrinsics, image_width, image_height): + """Write camera intrinsics to COLMAP cameras.txt format.""" + with open(file_path, 'w') as f: + f.write("# Camera list with one line of data per camera:\n") + f.write("# CAMERA_ID, MODEL, WIDTH, HEIGHT, PARAMS[]\n") + f.write(f"# Number of cameras: {len(intrinsics)}\n") + + for i, intrinsic in enumerate(intrinsics): + camera_id = i + 1 # COLMAP uses 1-indexed camera IDs + model = "PINHOLE" + + fx = intrinsic[0, 0] + fy = intrinsic[1, 1] + cx = intrinsic[0, 2] + cy = intrinsic[1, 2] + + f.write(f"{camera_id} {model} {image_width} {image_height} {fx} {fy} {cx} {cy}\n") + +def write_colmap_images_txt(file_path, quaternions, translations, image_points2D, image_names): + """Write camera poses and keypoints to COLMAP images.txt format.""" + with open(file_path, 'w') as f: + f.write("# Image list with two lines of data per image:\n") + f.write("# IMAGE_ID, QW, QX, QY, QZ, TX, TY, TZ, CAMERA_ID, NAME\n") + f.write("# POINTS2D[] as (X, Y, POINT3D_ID)\n") + + num_points = sum(len(points) for points in image_points2D) + avg_points = num_points / len(image_points2D) if image_points2D else 0 + f.write(f"# Number of images: {len(quaternions)}, mean observations per image: {avg_points:.1f}\n") + + for i in range(len(quaternions)): + image_id = i + 1 + camera_id = i + 1 + + qw, qx, qy, qz = quaternions[i] + tx, ty, tz = translations[i] + + f.write(f"{image_id} {qw} {qx} {qy} {qz} {tx} {ty} {tz} {camera_id} {os.path.basename(image_names[i])}\n") + + points_line = " ".join([f"{x} {y} {point3d_id+1}" for x, y, point3d_id in image_points2D[i]]) + f.write(f"{points_line}\n") + +def write_colmap_points3D_txt(file_path, points3D): + """Write 3D points and tracks to COLMAP points3D.txt format.""" + with open(file_path, 'w') as f: + f.write("# 3D point list with one line of data per point:\n") + f.write("# POINT3D_ID, X, Y, Z, R, G, B, ERROR, TRACK[] as (IMAGE_ID, POINT2D_IDX)\n") + + avg_track_length = sum(len(point["track"]) for point in points3D) / len(points3D) if points3D else 0 + f.write(f"# Number of points: {len(points3D)}, mean track length: {avg_track_length:.4f}\n") + + for point in points3D: + point_id = point["id"] + 1 + x, y, z = point["xyz"] + r, g, b = point["rgb"] + error = point["error"] + + track = " ".join([f"{img_id+1} {point2d_idx}" for img_id, point2d_idx in point["track"]]) + + f.write(f"{point_id} {x} {y} {z} {int(r)} {int(g)} {int(b)} {error} {track}\n") + +def write_colmap_cameras_bin(file_path, intrinsics, image_width, image_height): + """Write camera intrinsics to COLMAP cameras.bin format.""" + with open(file_path, 'wb') as fid: + # Write number of cameras (uint64) + fid.write(struct.pack(' List[Camera]: + """ + Generate a circular path of cameras around an existing camera group, + with each new camera oriented to look at the average viewing direction. + + Parameters: + existing_cameras (List[Camera]): List of existing camera objects to estimate average orientation and layout. + N (int): Number of new cameras to generate along the circular path. + radius_scale (float): Scale factor to adjust the radius of the circle. + d (float): Distance ahead of each camera used to estimate its look-at point. + + Returns: + List[Camera]: A list of newly generated Camera objects forming a circular path and oriented toward a shared view center. + """ + # Step 1: Compute average camera position + center = np.mean([cam.T for cam in existing_cameras], axis=0) + + # Estimate where each camera is looking + # d denotes how far ahead each camera sees β€” you can scale this + look_targets = [cam.T + cam.R[:, 2] * d for cam in existing_cameras] + center_of_view = np.mean(look_targets, axis=0) + + # Step 2: Define circular plane basis using fixed up vector + avg_forward = normalize(np.mean([cam.R[:, 2] for cam in existing_cameras], axis=0)) + up_guess = np.array([0, 1, 0]) + right = normalize(np.cross(avg_forward, up_guess)) + up = normalize(np.cross(right, avg_forward)) + + # Step 3: Estimate radius + avg_radius = np.mean([np.linalg.norm(cam.T - center) for cam in existing_cameras]) * radius_scale + + # Step 4: Create cameras on a circular path + angles = np.linspace(0, 2 * np.pi, N, endpoint=False) + reference_cam = existing_cameras[0] + new_cameras = [] + + + for i, a in enumerate(angles): + position = center + avg_radius * (np.cos(a) * right + np.sin(a) * up) + + if d < 1e-5 or radius_scale < 1e-5: + # Use same orientation as the first camera + R = reference_cam.R.copy() + else: + # Change orientation + R = look_at_rotation(position, center_of_view) + new_cameras.append(Camera( + R=R, + T=position, # New position + FoVx=reference_cam.FoVx, + FoVy=reference_cam.FoVy, + resolution=(reference_cam.image_width, reference_cam.image_height), + colmap_id=-1, + depth_params=None, + image=Image.fromarray(np.zeros((reference_cam.image_height, reference_cam.image_width, 3), dtype=np.uint8)), + invdepthmap=None, + image_name=f"circular_a={a:.3f}", + uid=i + )) + + return new_cameras + + +def save_numpy_frames_as_gif(frames, output_path="animation.gif", duration=100): + """ + Save a list of RGB NumPy frames as a looping GIF animation. + + Parameters: + frames (List[np.ndarray]): List of RGB images as uint8 NumPy arrays (shape HxWx3). + output_path (str): Path to save the output GIF. + duration (int): Duration per frame in milliseconds. + + Returns: + None + """ + pil_frames = [Image.fromarray(f) for f in frames] + pil_frames[0].save( + output_path, + save_all=True, + append_images=pil_frames[1:], + duration=duration, # duration per frame in ms + loop=0 + ) + print(f"GIF saved to: {output_path}") + +def center_crop_frame(frame: np.ndarray, crop_fraction: float) -> np.ndarray: + """ + Crop the central region of the frame by the given fraction. + + Parameters: + frame (np.ndarray): Input RGB image (H, W, 3). + crop_fraction (float): Fraction of the original size to retain (e.g., 0.8 keeps 80%). + + Returns: + np.ndarray: Cropped RGB image. + """ + if crop_fraction >= 1.0: + return frame + + h, w, _ = frame.shape + new_h, new_w = int(h * crop_fraction), int(w * crop_fraction) + start_y = (h - new_h) // 2 + start_x = (w - new_w) // 2 + return frame[start_y:start_y + new_h, start_x:start_x + new_w, :] + + + +def generate_smooth_closed_camera_path(existing_cameras: List[Camera], N: int = 120, d: float = 2.0, s=.25) -> List[Camera]: + """ + Generate a smooth, closed path interpolating the positions of existing cameras. + + Parameters: + existing_cameras (List[Camera]): List of existing cameras. + N (int): Number of points (cameras) to sample along the smooth path. + d (float): Distance ahead for estimating the center of view. + + Returns: + List[Camera]: A list of smoothly moving Camera objects along a closed loop. + """ + # Step 1: Extract camera positions + positions = np.array([cam.T for cam in existing_cameras]) + + # Step 2: Estimate center of view + look_targets = [cam.T + cam.R[:, 2] * d for cam in existing_cameras] + center_of_view = np.mean(look_targets, axis=0) + + # Step 3: Fit a smooth closed spline through the positions + positions = np.vstack([positions, positions[0]]) # close the loop + tck, u = splprep(positions.T, s=s, per=True) # periodic=True for closed loop + + # Step 4: Sample points along the spline + u_fine = np.linspace(0, 1, N) + smooth_path = np.stack(splev(u_fine, tck), axis=-1) + + # Step 5: Generate cameras along the smooth path + reference_cam = existing_cameras[0] + new_cameras = [] + + for i, pos in enumerate(smooth_path): + R = look_at_rotation(pos, center_of_view) + new_cameras.append(Camera( + R=R, + T=pos, + FoVx=reference_cam.FoVx, + FoVy=reference_cam.FoVy, + resolution=(reference_cam.image_width, reference_cam.image_height), + colmap_id=-1, + depth_params=None, + image=Image.fromarray(np.zeros((reference_cam.image_height, reference_cam.image_width, 3), dtype=np.uint8)), + invdepthmap=None, + image_name=f"smooth_path_i={i}", + uid=i + )) + + return new_cameras + + +def save_numpy_frames_as_mp4(frames, output_path="animation.mp4", fps=10, center_crop: float = 1.0): + """ + Save a list of RGB NumPy frames as an MP4 video with optional center cropping. + + Parameters: + frames (List[np.ndarray]): List of RGB images as uint8 NumPy arrays (shape HxWx3). + output_path (str): Path to save the output MP4. + fps (int): Frames per second for playback speed. + center_crop (float): Fraction (0 < center_crop <= 1.0) of central region to retain. + Use 1.0 for no cropping; 0.8 to crop to 80% center region. + + Returns: + None + """ + with imageio.get_writer(output_path, fps=fps, codec='libx264', quality=8) as writer: + for frame in frames: + cropped = center_crop_frame(frame, center_crop) + writer.append_data(cropped) + print(f"MP4 saved to: {output_path}") + + + +def put_text_on_image(img: np.ndarray, text: str) -> np.ndarray: + """ + Draws multiline white text on a copy of the input image, positioned near the bottom + and around 80% of the image width. Handles '\n' characters to split text into multiple lines. + + Args: + img (np.ndarray): Input image as a (H, W, 3) uint8 numpy array. + text (str): Text string to draw on the image. Newlines '\n' are treated as line breaks. + + Returns: + np.ndarray: The output image with the text drawn on it. + + Notes: + - The function automatically adjusts line spacing and prevents text from going outside the image. + - Text is drawn in white with small font size (0.5) for minimal visual impact. + """ + img = img.copy() + height, width, _ = img.shape + + font = cv2.FONT_HERSHEY_SIMPLEX + font_scale = 1. + color = (255, 255, 255) + thickness = 2 + line_spacing = 5 # extra pixels between lines + + lines = text.split('\n') + + # Precompute the maximum text width to adjust starting x + max_text_width = max(cv2.getTextSize(line, font, font_scale, thickness)[0][0] for line in lines) + + x = int(0.8 * width) + x = min(x, width - max_text_width - 30) # margin on right + #x = int(0.03 * width) + + # Start near the bottom, but move up depending on number of lines + total_text_height = len(lines) * (cv2.getTextSize('A', font, font_scale, thickness)[0][1] + line_spacing) + y_start = int(height*0.9) - total_text_height # 30 pixels from bottom + + for i, line in enumerate(lines): + y = y_start + i * (cv2.getTextSize(line, font, font_scale, thickness)[0][1] + line_spacing) + cv2.putText(img, line, (x, y), font, font_scale, color, thickness, cv2.LINE_AA) + + return img + + + + +def catmull_rom_spline(P0, P1, P2, P3, n_points=20): + """ + Compute Catmull-Rom spline segment between P1 and P2. + """ + t = np.linspace(0, 1, n_points)[:, None] + + M = 0.5 * np.array([ + [-1, 3, -3, 1], + [ 2, -5, 4, -1], + [-1, 0, 1, 0], + [ 0, 2, 0, 0] + ]) + + G = np.stack([P0, P1, P2, P3], axis=0) + T = np.concatenate([t**3, t**2, t, np.ones_like(t)], axis=1) + + return T @ M @ G + +def sort_cameras_pca(existing_cameras: List[Camera]): + """ + Sort cameras along the main PCA axis. + """ + positions = np.array([cam.T for cam in existing_cameras]) + pca = PCA(n_components=1) + scores = pca.fit_transform(positions) + sorted_indices = np.argsort(scores[:, 0]) + return sorted_indices + +def generate_fully_smooth_cameras(existing_cameras: List[Camera], + n_selected: int = 30, + n_points_per_segment: int = 20, + d: float = 2.0, + closed: bool = False) -> List[Camera]: + """ + Generate a fully smooth camera path using PCA ordering, global Catmull-Rom spline for positions, and global SLERP for orientations. + + Args: + existing_cameras (List[Camera]): List of input cameras. + n_selected (int): Number of cameras to select after sorting. + n_points_per_segment (int): Number of interpolated points per spline segment. + d (float): Distance ahead for estimating center of view. + closed (bool): Whether to close the path. + + Returns: + List[Camera]: List of smoothly moving Camera objects. + """ + # 1. Sort cameras along PCA axis + sorted_indices = sort_cameras_pca(existing_cameras) + sorted_cameras = [existing_cameras[i] for i in sorted_indices] + positions = np.array([cam.T for cam in sorted_cameras]) + + # 2. Subsample uniformly + idx = np.linspace(0, len(positions) - 1, n_selected).astype(int) + sampled_positions = positions[idx] + sampled_cameras = [sorted_cameras[i] for i in idx] + + # 3. Prepare for Catmull-Rom + if closed: + sampled_positions = np.vstack([sampled_positions[-1], sampled_positions, sampled_positions[0], sampled_positions[1]]) + else: + sampled_positions = np.vstack([sampled_positions[0], sampled_positions, sampled_positions[-1], sampled_positions[-1]]) + + # 4. Generate smooth path positions + path_positions = [] + for i in range(1, len(sampled_positions) - 2): + segment = catmull_rom_spline(sampled_positions[i-1], sampled_positions[i], sampled_positions[i+1], sampled_positions[i+2], n_points_per_segment) + path_positions.append(segment) + path_positions = np.concatenate(path_positions, axis=0) + + # 5. Global SLERP for rotations + rotations = R.from_matrix([cam.R for cam in sampled_cameras]) + key_times = np.linspace(0, 1, len(rotations)) + slerp = Slerp(key_times, rotations) + + query_times = np.linspace(0, 1, len(path_positions)) + interpolated_rotations = slerp(query_times) + + # 6. Generate Camera objects + reference_cam = existing_cameras[0] + smooth_cameras = [] + + for i, pos in enumerate(path_positions): + R_interp = interpolated_rotations[i].as_matrix() + + smooth_cameras.append(Camera( + R=R_interp, + T=pos, + FoVx=reference_cam.FoVx, + FoVy=reference_cam.FoVy, + resolution=(reference_cam.image_width, reference_cam.image_height), + colmap_id=-1, + depth_params=None, + image=Image.fromarray(np.zeros((reference_cam.image_height, reference_cam.image_width, 3), dtype=np.uint8)), + invdepthmap=None, + image_name=f"fully_smooth_path_i={i}", + uid=i + )) + + return smooth_cameras + + +def plot_cameras_and_smooth_path_with_orientation(existing_cameras: List[Camera], smooth_cameras: List[Camera], scale: float = 0.1): + """ + Plot input cameras and smooth path cameras with their orientations in 3D. + + Args: + existing_cameras (List[Camera]): List of original input cameras. + smooth_cameras (List[Camera]): List of smooth path cameras. + scale (float): Length of orientation arrows. + + Returns: + None + """ + # Input cameras + input_positions = np.array([cam.T for cam in existing_cameras]) + + # Smooth cameras + smooth_positions = np.array([cam.T for cam in smooth_cameras]) + + fig = go.Figure() + + # Plot input camera positions + fig.add_trace(go.Scatter3d( + x=input_positions[:, 0], y=input_positions[:, 1], z=input_positions[:, 2], + mode='markers', + marker=dict(size=4, color='blue'), + name='Input Cameras' + )) + + # Plot smooth path positions + fig.add_trace(go.Scatter3d( + x=smooth_positions[:, 0], y=smooth_positions[:, 1], z=smooth_positions[:, 2], + mode='lines+markers', + line=dict(color='red', width=3), + marker=dict(size=2, color='red'), + name='Smooth Path Cameras' + )) + + # Plot input camera orientations + for cam in existing_cameras: + origin = cam.T + forward = cam.R[:, 2] # Forward direction + + fig.add_trace(go.Cone( + x=[origin[0]], y=[origin[1]], z=[origin[2]], + u=[forward[0]], v=[forward[1]], w=[forward[2]], + colorscale=[[0, 'blue'], [1, 'blue']], + sizemode="absolute", + sizeref=scale, + anchor="tail", + showscale=False, + name='Input Camera Direction' + )) + + # Plot smooth camera orientations + for cam in smooth_cameras: + origin = cam.T + forward = cam.R[:, 2] # Forward direction + + fig.add_trace(go.Cone( + x=[origin[0]], y=[origin[1]], z=[origin[2]], + u=[forward[0]], v=[forward[1]], w=[forward[2]], + colorscale=[[0, 'red'], [1, 'red']], + sizemode="absolute", + sizeref=scale, + anchor="tail", + showscale=False, + name='Smooth Camera Direction' + )) + + fig.update_layout( + scene=dict( + xaxis_title='X', + yaxis_title='Y', + zaxis_title='Z', + aspectmode='data' + ), + title="Input Cameras and Smooth Path with Orientations", + margin=dict(l=0, r=0, b=0, t=30) + ) + + fig.show() + + +def solve_tsp_nearest_neighbor(points: np.ndarray): + """ + Solve TSP approximately using nearest neighbor heuristic. + + Args: + points (np.ndarray): (N, 3) array of points. + + Returns: + List[int]: Optimal visiting order of points. + """ + N = points.shape[0] + dist = distance_matrix(points, points) + visited = [0] + unvisited = set(range(1, N)) + + while unvisited: + last = visited[-1] + next_city = min(unvisited, key=lambda city: dist[last, city]) + visited.append(next_city) + unvisited.remove(next_city) + + return visited + +def solve_tsp_2opt(points: np.ndarray, n_iter: int = 1000) -> np.ndarray: + """ + Solve TSP approximately using Nearest Neighbor + 2-Opt. + + Args: + points (np.ndarray): Array of shape (N, D) with points. + n_iter (int): Number of 2-opt iterations. + + Returns: + np.ndarray: Ordered list of indices. + """ + n_points = points.shape[0] + + # === 1. Start with Nearest Neighbor + unvisited = list(range(n_points)) + current = unvisited.pop(0) + path = [current] + + while unvisited: + dists = np.linalg.norm(points[unvisited] - points[current], axis=1) + next_idx = unvisited[np.argmin(dists)] + unvisited.remove(next_idx) + path.append(next_idx) + current = next_idx + + # === 2. Apply 2-Opt improvements + def path_length(path): + return np.sum(np.linalg.norm(points[path[i]] - points[path[i+1]], axis=0) for i in range(len(path)-1)) + + best_length = path_length(path) + improved = True + + for _ in range(n_iter): + if not improved: + break + improved = False + for i in range(1, n_points - 2): + for j in range(i + 1, n_points): + if j - i == 1: continue + new_path = path[:i] + path[i:j][::-1] + path[j:] + new_length = path_length(new_path) + if new_length < best_length: + path = new_path + best_length = new_length + improved = True + break + if improved: + break + + return np.array(path) + +def generate_fully_smooth_cameras_with_tsp(existing_cameras: List[Camera], + n_selected: int = 30, + n_points_per_segment: int = 20, + d: float = 2.0, + closed: bool = False) -> List[Camera]: + """ + Generate a fully smooth camera path using TSP ordering, global Catmull-Rom spline for positions, and global SLERP for orientations. + + Args: + existing_cameras (List[Camera]): List of input cameras. + n_selected (int): Number of cameras to select after ordering. + n_points_per_segment (int): Number of interpolated points per spline segment. + d (float): Distance ahead for estimating center of view. + closed (bool): Whether to close the path. + + Returns: + List[Camera]: List of smoothly moving Camera objects. + """ + positions = np.array([cam.T for cam in existing_cameras]) + + # 1. Solve approximate TSP + order = solve_tsp_nearest_neighbor(positions) + ordered_cameras = [existing_cameras[i] for i in order] + ordered_positions = positions[order] + + # 2. Subsample uniformly + idx = np.linspace(0, len(ordered_positions) - 1, n_selected).astype(int) + sampled_positions = ordered_positions[idx] + sampled_cameras = [ordered_cameras[i] for i in idx] + + # 3. Prepare for Catmull-Rom + if closed: + sampled_positions = np.vstack([sampled_positions[-1], sampled_positions, sampled_positions[0], sampled_positions[1]]) + else: + sampled_positions = np.vstack([sampled_positions[0], sampled_positions, sampled_positions[-1], sampled_positions[-1]]) + + # 4. Generate smooth path positions + path_positions = [] + for i in range(1, len(sampled_positions) - 2): + segment = catmull_rom_spline(sampled_positions[i-1], sampled_positions[i], sampled_positions[i+1], sampled_positions[i+2], n_points_per_segment) + path_positions.append(segment) + path_positions = np.concatenate(path_positions, axis=0) + + # 5. Global SLERP for rotations + rotations = R.from_matrix([cam.R for cam in sampled_cameras]) + key_times = np.linspace(0, 1, len(rotations)) + slerp = Slerp(key_times, rotations) + + query_times = np.linspace(0, 1, len(path_positions)) + interpolated_rotations = slerp(query_times) + + # 6. Generate Camera objects + reference_cam = existing_cameras[0] + smooth_cameras = [] + + for i, pos in enumerate(path_positions): + R_interp = interpolated_rotations[i].as_matrix() + + smooth_cameras.append(Camera( + R=R_interp, + T=pos, + FoVx=reference_cam.FoVx, + FoVy=reference_cam.FoVy, + resolution=(reference_cam.image_width, reference_cam.image_height), + colmap_id=-1, + depth_params=None, + image=Image.fromarray(np.zeros((reference_cam.image_height, reference_cam.image_width, 3), dtype=np.uint8)), + invdepthmap=None, + image_name=f"fully_smooth_path_i={i}", + uid=i + )) + + return smooth_cameras + +from typing import List +import numpy as np +from sklearn.mixture import GaussianMixture +from scipy.spatial.transform import Rotation as R, Slerp +from PIL import Image + +def generate_clustered_smooth_cameras_with_tsp(existing_cameras: List[Camera], + n_selected: int = 30, + n_points_per_segment: int = 20, + d: float = 2.0, + n_clusters: int = 5, + closed: bool = False) -> List[Camera]: + """ + Generate a fully smooth camera path using clustering + TSP between nearest cluster centers + TSP inside clusters. + Positions are normalized before clustering and denormalized before generating final cameras. + + Args: + existing_cameras (List[Camera]): List of input cameras. + n_selected (int): Number of cameras to select after ordering. + n_points_per_segment (int): Number of interpolated points per spline segment. + d (float): Distance ahead for estimating center of view. + n_clusters (int): Number of GMM clusters. + closed (bool): Whether to close the path. + + Returns: + List[Camera]: Smooth path of Camera objects. + """ + # Extract positions and rotations + positions = np.array([cam.T for cam in existing_cameras]) + rotations = np.array([R.from_matrix(cam.R).as_quat() for cam in existing_cameras]) + + # === Normalize positions + mean_pos = np.mean(positions, axis=0) + scale_pos = np.std(positions, axis=0) + scale_pos[scale_pos == 0] = 1.0 # avoid division by zero + + positions_normalized = (positions - mean_pos) / scale_pos + + # === Features for clustering (only positions, not rotations) + features = positions_normalized + + # === 1. GMM clustering + gmm = GaussianMixture(n_components=n_clusters, covariance_type='full', random_state=42) + cluster_labels = gmm.fit_predict(features) + + clusters = {} + cluster_centers = [] + + for cluster_id in range(n_clusters): + cluster_indices = np.where(cluster_labels == cluster_id)[0] + if len(cluster_indices) == 0: + continue + clusters[cluster_id] = cluster_indices + cluster_center = np.mean(features[cluster_indices], axis=0) + cluster_centers.append(cluster_center) + + cluster_centers = np.stack(cluster_centers) + + # === 2. Remap cluster centers to nearest existing cameras + if False: + mapped_centers = [] + for center in cluster_centers: + dists = np.linalg.norm(features - center, axis=1) + nearest_idx = np.argmin(dists) + mapped_centers.append(features[nearest_idx]) + mapped_centers = np.stack(mapped_centers) + cluster_centers = mapped_centers + # === 3. Solve TSP between mapped cluster centers + cluster_order = solve_tsp_2opt(cluster_centers) + + # === 4. For each cluster, solve TSP inside cluster + final_indices = [] + for cluster_id in cluster_order: + cluster_indices = clusters[cluster_id] + cluster_positions = features[cluster_indices] + + if len(cluster_positions) == 1: + final_indices.append(cluster_indices[0]) + continue + + local_order = solve_tsp_nearest_neighbor(cluster_positions) + ordered_cluster_indices = cluster_indices[local_order] + final_indices.extend(ordered_cluster_indices) + + ordered_cameras = [existing_cameras[i] for i in final_indices] + ordered_positions = positions_normalized[final_indices] + + # === 5. Subsample uniformly + idx = np.linspace(0, len(ordered_positions) - 1, n_selected).astype(int) + sampled_positions = ordered_positions[idx] + sampled_cameras = [ordered_cameras[i] for i in idx] + + # === 6. Prepare for Catmull-Rom spline + if closed: + sampled_positions = np.vstack([sampled_positions[-1], sampled_positions, sampled_positions[0], sampled_positions[1]]) + else: + sampled_positions = np.vstack([sampled_positions[0], sampled_positions, sampled_positions[-1], sampled_positions[-1]]) + + # === 7. Smooth path positions + path_positions = [] + for i in range(1, len(sampled_positions) - 2): + segment = catmull_rom_spline(sampled_positions[i-1], sampled_positions[i], sampled_positions[i+1], sampled_positions[i+2], n_points_per_segment) + path_positions.append(segment) + path_positions = np.concatenate(path_positions, axis=0) + + # === 8. Denormalize + path_positions = path_positions * scale_pos + mean_pos + + # === 9. SLERP for rotations + rotations = R.from_matrix([cam.R for cam in sampled_cameras]) + key_times = np.linspace(0, 1, len(rotations)) + slerp = Slerp(key_times, rotations) + + query_times = np.linspace(0, 1, len(path_positions)) + interpolated_rotations = slerp(query_times) + + # === 10. Generate Camera objects + reference_cam = existing_cameras[0] + smooth_cameras = [] + + for i, pos in enumerate(path_positions): + R_interp = interpolated_rotations[i].as_matrix() + + smooth_cameras.append(Camera( + R=R_interp, + T=pos, + FoVx=reference_cam.FoVx, + FoVy=reference_cam.FoVy, + resolution=(reference_cam.image_width, reference_cam.image_height), + colmap_id=-1, + depth_params=None, + image=Image.fromarray(np.zeros((reference_cam.image_height, reference_cam.image_width, 3), dtype=np.uint8)), + invdepthmap=None, + image_name=f"clustered_smooth_path_i={i}", + uid=i + )) + + return smooth_cameras + + +# def generate_clustered_path(existing_cameras: List[Camera], +# n_points_per_segment: int = 20, +# d: float = 2.0, +# n_clusters: int = 5, +# closed: bool = False) -> List[Camera]: +# """ +# Generate a smooth camera path using GMM clustering and TSP on cluster centers. + +# Args: +# existing_cameras (List[Camera]): List of input cameras. +# n_points_per_segment (int): Number of interpolated points per spline segment. +# d (float): Distance ahead for estimating center of view. +# n_clusters (int): Number of GMM clusters (zones). +# closed (bool): Whether to close the path. + +# Returns: +# List[Camera]: Smooth path of Camera objects. +# """ +# # Extract positions and rotations +# positions = np.array([cam.T for cam in existing_cameras]) + +# # === Normalize positions +# mean_pos = np.mean(positions, axis=0) +# scale_pos = np.std(positions, axis=0) +# scale_pos[scale_pos == 0] = 1.0 + +# positions_normalized = (positions - mean_pos) / scale_pos + +# # === 1. GMM clustering (only positions) +# gmm = GaussianMixture(n_components=n_clusters, covariance_type='full', random_state=42) +# cluster_labels = gmm.fit_predict(positions_normalized) + +# cluster_centers = [] +# for cluster_id in range(n_clusters): +# cluster_indices = np.where(cluster_labels == cluster_id)[0] +# if len(cluster_indices) == 0: +# continue +# cluster_center = np.mean(positions_normalized[cluster_indices], axis=0) +# cluster_centers.append(cluster_center) + +# cluster_centers = np.stack(cluster_centers) + +# # === 2. Solve TSP between cluster centers +# cluster_order = solve_tsp_2opt(cluster_centers) + +# # === 3. Reorder cluster centers +# ordered_centers = cluster_centers[cluster_order] + +# # === 4. Prepare Catmull-Rom spline +# if closed: +# ordered_centers = np.vstack([ordered_centers[-1], ordered_centers, ordered_centers[0], ordered_centers[1]]) +# else: +# ordered_centers = np.vstack([ordered_centers[0], ordered_centers, ordered_centers[-1], ordered_centers[-1]]) + +# # === 5. Generate smooth path positions +# path_positions = [] +# for i in range(1, len(ordered_centers) - 2): +# segment = catmull_rom_spline(ordered_centers[i-1], ordered_centers[i], ordered_centers[i+1], ordered_centers[i+2], n_points_per_segment) +# path_positions.append(segment) +# path_positions = np.concatenate(path_positions, axis=0) + +# # === 6. Denormalize back +# path_positions = path_positions * scale_pos + mean_pos + +# # === 7. Generate dummy rotations (constant forward facing) +# reference_cam = existing_cameras[0] +# default_rotation = R.from_matrix(reference_cam.R) + +# # For simplicity, fixed rotation for all +# smooth_cameras = [] + +# for i, pos in enumerate(path_positions): +# R_interp = default_rotation.as_matrix() + +# smooth_cameras.append(Camera( +# R=R_interp, +# T=pos, +# FoVx=reference_cam.FoVx, +# FoVy=reference_cam.FoVy, +# resolution=(reference_cam.image_width, reference_cam.image_height), +# colmap_id=-1, +# depth_params=None, +# image=Image.fromarray(np.zeros((reference_cam.image_height, reference_cam.image_width, 3), dtype=np.uint8)), +# invdepthmap=None, +# image_name=f"cluster_path_i={i}", +# uid=i +# )) + +# return smooth_cameras + +from typing import List +import numpy as np +from sklearn.cluster import KMeans +from scipy.spatial.transform import Rotation as R, Slerp +from PIL import Image + +def generate_clustered_path(existing_cameras: List[Camera], + n_points_per_segment: int = 20, + d: float = 2.0, + n_clusters: int = 5, + closed: bool = False) -> List[Camera]: + """ + Generate a smooth camera path using K-Means clustering and TSP on cluster centers. + + Args: + existing_cameras (List[Camera]): List of input cameras. + n_points_per_segment (int): Number of interpolated points per spline segment. + d (float): Distance ahead for estimating center of view. + n_clusters (int): Number of KMeans clusters (zones). + closed (bool): Whether to close the path. + + Returns: + List[Camera]: Smooth path of Camera objects. + """ + # Extract positions + positions = np.array([cam.T for cam in existing_cameras]) + + # === Normalize positions + mean_pos = np.mean(positions, axis=0) + scale_pos = np.std(positions, axis=0) + scale_pos[scale_pos == 0] = 1.0 + + positions_normalized = (positions - mean_pos) / scale_pos + + # === 1. K-Means clustering (only positions) + kmeans = KMeans(n_clusters=n_clusters, random_state=42, n_init='auto') + cluster_labels = kmeans.fit_predict(positions_normalized) + + cluster_centers = [] + for cluster_id in range(n_clusters): + cluster_indices = np.where(cluster_labels == cluster_id)[0] + if len(cluster_indices) == 0: + continue + cluster_center = np.mean(positions_normalized[cluster_indices], axis=0) + cluster_centers.append(cluster_center) + + cluster_centers = np.stack(cluster_centers) + + # === 2. Solve TSP between cluster centers + cluster_order = solve_tsp_2opt(cluster_centers) + + # === 3. Reorder cluster centers + ordered_centers = cluster_centers[cluster_order] + + # === 4. Prepare Catmull-Rom spline + if closed: + ordered_centers = np.vstack([ordered_centers[-1], ordered_centers, ordered_centers[0], ordered_centers[1]]) + else: + ordered_centers = np.vstack([ordered_centers[0], ordered_centers, ordered_centers[-1], ordered_centers[-1]]) + + # === 5. Generate smooth path positions + path_positions = [] + for i in range(1, len(ordered_centers) - 2): + segment = catmull_rom_spline(ordered_centers[i-1], ordered_centers[i], ordered_centers[i+1], ordered_centers[i+2], n_points_per_segment) + path_positions.append(segment) + path_positions = np.concatenate(path_positions, axis=0) + + # === 6. Denormalize back + path_positions = path_positions * scale_pos + mean_pos + + # === 7. Generate dummy rotations (constant forward facing) + reference_cam = existing_cameras[0] + default_rotation = R.from_matrix(reference_cam.R) + + # For simplicity, fixed rotation for all + smooth_cameras = [] + + for i, pos in enumerate(path_positions): + R_interp = default_rotation.as_matrix() + + smooth_cameras.append(Camera( + R=R_interp, + T=pos, + FoVx=reference_cam.FoVx, + FoVy=reference_cam.FoVy, + resolution=(reference_cam.image_width, reference_cam.image_height), + colmap_id=-1, + depth_params=None, + image=Image.fromarray(np.zeros((reference_cam.image_height, reference_cam.image_width, 3), dtype=np.uint8)), + invdepthmap=None, + image_name=f"cluster_path_i={i}", + uid=i + )) + + return smooth_cameras + + + + +def visualize_image_with_points(image, points): + """ + Visualize an image with points overlaid on top. This is useful for correspondences visualizations + + Parameters: + - image: PIL Image object + - points: Numpy array of shape [N, 2] containing (x, y) coordinates of points + + Returns: + - None (displays the visualization) + """ + + # Convert PIL image to numpy array + img_array = np.array(image) + + # Create a figure and axis + fig, ax = plt.subplots(figsize=(7,7)) + + # Display the image + ax.imshow(img_array) + + # Scatter plot the points on top of the image + ax.scatter(points[:, 0], points[:, 1], color='red', marker='o', s=1) + + # Show the plot + plt.show() + + +def visualize_correspondences(image1, points1, image2, points2): + """ + Visualize two images concatenated horizontally with key points and correspondences. + + Parameters: + - image1: PIL Image object (left image) + - points1: Numpy array of shape [N, 2] containing (x, y) coordinates of key points for image1 + - image2: PIL Image object (right image) + - points2: Numpy array of shape [N, 2] containing (x, y) coordinates of key points for image2 + + Returns: + - None (displays the visualization) + """ + + # Concatenate images horizontally + concatenated_image = np.concatenate((np.array(image1), np.array(image2)), axis=1) + + # Create a figure and axis + fig, ax = plt.subplots(figsize=(10,10)) + + # Display the concatenated image + ax.imshow(concatenated_image) + + # Plot key points on the left image + ax.scatter(points1[:, 0], points1[:, 1], color='red', marker='o', s=10) + + # Plot key points on the right image + ax.scatter(points2[:, 0] + image1.width, points2[:, 1], color='blue', marker='o', s=10) + + # Draw lines connecting corresponding key points + for i in range(len(points1)): + ax.plot([points1[i, 0], points2[i, 0] + image1.width], [points1[i, 1], points2[i, 1]])#, color='green') + + # Show the plot + plt.show() + diff --git a/submodules/RoMa/.gitignore b/submodules/RoMa/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..7f8801c4b89dd12eeca1e5709e8161f017370a44 --- /dev/null +++ b/submodules/RoMa/.gitignore @@ -0,0 +1,11 @@ +*.egg-info* +*.vscode* +*__pycache__* +vis* +workspace* +.venv +.DS_Store +jobs/* +*ignore_me* +*.pth +wandb* \ No newline at end of file diff --git a/submodules/RoMa/LICENSE b/submodules/RoMa/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..ca95157052a76debc473afb395bffae0c1329e63 --- /dev/null +++ b/submodules/RoMa/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Johan Edstedt + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/submodules/RoMa/README.md b/submodules/RoMa/README.md new file mode 100644 index 0000000000000000000000000000000000000000..8458762622603dc8d0b4a89ba5cb3354bee7deb5 --- /dev/null +++ b/submodules/RoMa/README.md @@ -0,0 +1,123 @@ +# +

+

RoMa πŸ›οΈ:
Robust Dense Feature Matching
⭐CVPR 2024⭐

+

+ Johan Edstedt + Β· + Qiyu Sun + Β· + Georg BΓΆkman + Β· + MΓ₯rten WadenbΓ€ck + Β· + Michael Felsberg +

+

+ Paper | + Project Page +

+
+

+
+

+ example +
+ RoMa is the robust dense feature matcher capable of estimating pixel-dense warps and reliable certainties for almost any image pair. +

+ +## Setup/Install +In your python environment (tested on Linux python 3.10), run: +```bash +pip install -e . +``` +## Demo / How to Use +We provide two demos in the [demos folder](demo). +Here's the gist of it: +```python +from romatch import roma_outdoor +roma_model = roma_outdoor(device=device) +# Match +warp, certainty = roma_model.match(imA_path, imB_path, device=device) +# Sample matches for estimation +matches, certainty = roma_model.sample(warp, certainty) +# Convert to pixel coordinates (RoMa produces matches in [-1,1]x[-1,1]) +kptsA, kptsB = roma_model.to_pixel_coordinates(matches, H_A, W_A, H_B, W_B) +# Find a fundamental matrix (or anything else of interest) +F, mask = cv2.findFundamentalMat( + kptsA.cpu().numpy(), kptsB.cpu().numpy(), ransacReprojThreshold=0.2, method=cv2.USAC_MAGSAC, confidence=0.999999, maxIters=10000 +) +``` + +**New**: You can also match arbitrary keypoints with RoMa. See [match_keypoints](romatch/models/matcher.py) in RegressionMatcher. + +## Settings + +### Resolution +By default RoMa uses an initial resolution of (560,560) which is then upsampled to (864,864). +You can change this at construction (see roma_outdoor kwargs). +You can also change this later, by changing the roma_model.w_resized, roma_model.h_resized, and roma_model.upsample_res. + +### Sampling +roma_model.sample_thresh controls the thresholding used when sampling matches for estimation. In certain cases a lower or higher threshold may improve results. + + +## Reproducing Results +The experiments in the paper are provided in the [experiments folder](experiments). + +### Training +1. First follow the instructions provided here: https://github.com/Parskatt/DKM for downloading and preprocessing datasets. +2. Run the relevant experiment, e.g., +```bash +torchrun --nproc_per_node=4 --nnodes=1 --rdzv_backend=c10d experiments/roma_outdoor.py +``` +### Testing +```bash +python experiments/roma_outdoor.py --only_test --benchmark mega-1500 +``` +## License +All our code except DINOv2 is MIT license. +DINOv2 has an Apache 2 license [DINOv2](https://github.com/facebookresearch/dinov2/blob/main/LICENSE). + +## Acknowledgement +Our codebase builds on the code in [DKM](https://github.com/Parskatt/DKM). + +## Tiny RoMa +If you find that RoMa is too heavy, you might want to try Tiny RoMa which is built on top of XFeat. +```python +from romatch import tiny_roma_v1_outdoor +tiny_roma_model = tiny_roma_v1_outdoor(device=device) +``` +Mega1500: +| | AUC@5 | AUC@10 | AUC@20 | +|----------|----------|----------|----------| +| XFeat | 46.4 | 58.9 | 69.2 | +| XFeat* | 51.9 | 67.2 | 78.9 | +| Tiny RoMa v1 | 56.4 | 69.5 | 79.5 | +| RoMa | - | - | - | + +Mega-8-Scenes (See DKM): +| | AUC@5 | AUC@10 | AUC@20 | +|----------|----------|----------|----------| +| XFeat | - | - | - | +| XFeat* | 50.1 | 64.4 | 75.2 | +| Tiny RoMa v1 | 57.7 | 70.5 | 79.6 | +| RoMa | - | - | - | + +IMC22 :'): +| | mAA@10 | +|----------|----------| +| XFeat | 42.1 | +| XFeat* | - | +| Tiny RoMa v1 | 42.2 | +| RoMa | - | + +## BibTeX +If you find our models useful, please consider citing our paper! +``` +@article{edstedt2024roma, +title={{RoMa: Robust Dense Feature Matching}}, +author={Edstedt, Johan and Sun, Qiyu and BΓΆkman, Georg and WadenbΓ€ck, MΓ₯rten and Felsberg, Michael}, +journal={IEEE Conference on Computer Vision and Pattern Recognition}, +year={2024} +} +``` diff --git a/submodules/RoMa/data/.gitignore b/submodules/RoMa/data/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..c96a04f008ee21e260b28f7701595ed59e2839e3 --- /dev/null +++ b/submodules/RoMa/data/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/submodules/RoMa/demo/demo_3D_effect.py b/submodules/RoMa/demo/demo_3D_effect.py new file mode 100644 index 0000000000000000000000000000000000000000..ae26caaf92deb884dfabb6eca96aec3406325c3f --- /dev/null +++ b/submodules/RoMa/demo/demo_3D_effect.py @@ -0,0 +1,47 @@ +from PIL import Image +import torch +import torch.nn.functional as F +import numpy as np +from romatch.utils.utils import tensor_to_pil + +from romatch import roma_outdoor + +device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') +if torch.backends.mps.is_available(): + device = torch.device('mps') + +if __name__ == "__main__": + from argparse import ArgumentParser + parser = ArgumentParser() + parser.add_argument("--im_A_path", default="assets/toronto_A.jpg", type=str) + parser.add_argument("--im_B_path", default="assets/toronto_B.jpg", type=str) + parser.add_argument("--save_path", default="demo/gif/roma_warp_toronto", type=str) + + args, _ = parser.parse_known_args() + im1_path = args.im_A_path + im2_path = args.im_B_path + save_path = args.save_path + + # Create model + roma_model = roma_outdoor(device=device, coarse_res=560, upsample_res=(864, 1152)) + roma_model.symmetric = False + + H, W = roma_model.get_output_resolution() + + im1 = Image.open(im1_path).resize((W, H)) + im2 = Image.open(im2_path).resize((W, H)) + + # Match + warp, certainty = roma_model.match(im1_path, im2_path, device=device) + # Sampling not needed, but can be done with model.sample(warp, certainty) + x1 = (torch.tensor(np.array(im1)) / 255).to(device).permute(2, 0, 1) + x2 = (torch.tensor(np.array(im2)) / 255).to(device).permute(2, 0, 1) + + coords_A, coords_B = warp[...,:2], warp[...,2:] + for i, x in enumerate(np.linspace(0,2*np.pi,200)): + t = (1 + np.cos(x))/2 + interp_warp = (1-t)*coords_A + t*coords_B + im2_transfer_rgb = F.grid_sample( + x2[None], interp_warp[None], mode="bilinear", align_corners=False + )[0] + tensor_to_pil(im2_transfer_rgb, unnormalize=False).save(f"{save_path}_{i:03d}.jpg") \ No newline at end of file diff --git a/submodules/RoMa/demo/demo_fundamental.py b/submodules/RoMa/demo/demo_fundamental.py new file mode 100644 index 0000000000000000000000000000000000000000..65ea9ccb76525da3e88e4f426bdebdc4fe742161 --- /dev/null +++ b/submodules/RoMa/demo/demo_fundamental.py @@ -0,0 +1,34 @@ +from PIL import Image +import torch +import cv2 +from romatch import roma_outdoor + +device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') +if torch.backends.mps.is_available(): + device = torch.device('mps') + +if __name__ == "__main__": + from argparse import ArgumentParser + parser = ArgumentParser() + parser.add_argument("--im_A_path", default="assets/sacre_coeur_A.jpg", type=str) + parser.add_argument("--im_B_path", default="assets/sacre_coeur_B.jpg", type=str) + + args, _ = parser.parse_known_args() + im1_path = args.im_A_path + im2_path = args.im_B_path + + # Create model + roma_model = roma_outdoor(device=device) + + + W_A, H_A = Image.open(im1_path).size + W_B, H_B = Image.open(im2_path).size + + # Match + warp, certainty = roma_model.match(im1_path, im2_path, device=device) + # Sample matches for estimation + matches, certainty = roma_model.sample(warp, certainty) + kpts1, kpts2 = roma_model.to_pixel_coordinates(matches, H_A, W_A, H_B, W_B) + F, mask = cv2.findFundamentalMat( + kpts1.cpu().numpy(), kpts2.cpu().numpy(), ransacReprojThreshold=0.2, method=cv2.USAC_MAGSAC, confidence=0.999999, maxIters=10000 + ) \ No newline at end of file diff --git a/submodules/RoMa/demo/demo_match.py b/submodules/RoMa/demo/demo_match.py new file mode 100644 index 0000000000000000000000000000000000000000..582767e19d8b50c6c241ea32f81cabb38f52fce2 --- /dev/null +++ b/submodules/RoMa/demo/demo_match.py @@ -0,0 +1,50 @@ +import os +os.environ['PYTORCH_ENABLE_MPS_FALLBACK'] = '1' +import torch +from PIL import Image +import torch.nn.functional as F +import numpy as np +from romatch.utils.utils import tensor_to_pil + +from romatch import roma_outdoor + +device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') +if torch.backends.mps.is_available(): + device = torch.device('mps') + +if __name__ == "__main__": + from argparse import ArgumentParser + parser = ArgumentParser() + parser.add_argument("--im_A_path", default="assets/toronto_A.jpg", type=str) + parser.add_argument("--im_B_path", default="assets/toronto_B.jpg", type=str) + parser.add_argument("--save_path", default="demo/roma_warp_toronto.jpg", type=str) + + args, _ = parser.parse_known_args() + im1_path = args.im_A_path + im2_path = args.im_B_path + save_path = args.save_path + + # Create model + roma_model = roma_outdoor(device=device, coarse_res=560, upsample_res=(864, 1152)) + + H, W = roma_model.get_output_resolution() + + im1 = Image.open(im1_path).resize((W, H)) + im2 = Image.open(im2_path).resize((W, H)) + + # Match + warp, certainty = roma_model.match(im1_path, im2_path, device=device) + # Sampling not needed, but can be done with model.sample(warp, certainty) + x1 = (torch.tensor(np.array(im1)) / 255).to(device).permute(2, 0, 1) + x2 = (torch.tensor(np.array(im2)) / 255).to(device).permute(2, 0, 1) + + im2_transfer_rgb = F.grid_sample( + x2[None], warp[:,:W, 2:][None], mode="bilinear", align_corners=False + )[0] + im1_transfer_rgb = F.grid_sample( + x1[None], warp[:, W:, :2][None], mode="bilinear", align_corners=False + )[0] + warp_im = torch.cat((im2_transfer_rgb,im1_transfer_rgb),dim=2) + white_im = torch.ones((H,2*W),device=device) + vis_im = certainty * warp_im + (1 - certainty) * white_im + tensor_to_pil(vis_im, unnormalize=False).save(save_path) \ No newline at end of file diff --git a/submodules/RoMa/demo/demo_match_opencv_sift.py b/submodules/RoMa/demo/demo_match_opencv_sift.py new file mode 100644 index 0000000000000000000000000000000000000000..3196fcfaab248f6c4c6247a0afb4db745206aee8 --- /dev/null +++ b/submodules/RoMa/demo/demo_match_opencv_sift.py @@ -0,0 +1,43 @@ +from PIL import Image +import numpy as np + +import numpy as np +import cv2 as cv +import matplotlib.pyplot as plt + + + +if __name__ == "__main__": + from argparse import ArgumentParser + parser = ArgumentParser() + parser.add_argument("--im_A_path", default="assets/toronto_A.jpg", type=str) + parser.add_argument("--im_B_path", default="assets/toronto_B.jpg", type=str) + parser.add_argument("--save_path", default="demo/roma_warp_toronto.jpg", type=str) + + args, _ = parser.parse_known_args() + im1_path = args.im_A_path + im2_path = args.im_B_path + save_path = args.save_path + + img1 = cv.imread(im1_path,cv.IMREAD_GRAYSCALE) # queryImage + img2 = cv.imread(im2_path,cv.IMREAD_GRAYSCALE) # trainImage + # Initiate SIFT detector + sift = cv.SIFT_create() + # find the keypoints and descriptors with SIFT + kp1, des1 = sift.detectAndCompute(img1,None) + kp2, des2 = sift.detectAndCompute(img2,None) + # BFMatcher with default params + bf = cv.BFMatcher() + matches = bf.knnMatch(des1,des2,k=2) + # Apply ratio test + good = [] + for m,n in matches: + if m.distance < 0.75*n.distance: + good.append([m]) + # cv.drawMatchesKnn expects list of lists as matches. + draw_params = dict(matchColor = (255,0,0), # draw matches in red color + singlePointColor = None, + flags = 2) + + img3 = cv.drawMatchesKnn(img1,kp1,img2,kp2,good,None,**draw_params) + Image.fromarray(img3).save("demo/sift_matches.png") diff --git a/submodules/RoMa/demo/demo_match_tiny.py b/submodules/RoMa/demo/demo_match_tiny.py new file mode 100644 index 0000000000000000000000000000000000000000..b8e66a4b80a2361e22673ddc59632f48ad653b69 --- /dev/null +++ b/submodules/RoMa/demo/demo_match_tiny.py @@ -0,0 +1,77 @@ +import os +os.environ['PYTORCH_ENABLE_MPS_FALLBACK'] = '1' +import torch +from PIL import Image +import torch.nn.functional as F +import numpy as np +from romatch.utils.utils import tensor_to_pil + +from romatch import tiny_roma_v1_outdoor + +device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') +if torch.backends.mps.is_available(): + device = torch.device('mps') + +if __name__ == "__main__": + from argparse import ArgumentParser + parser = ArgumentParser() + parser.add_argument("--im_A_path", default="assets/sacre_coeur_A.jpg", type=str) + parser.add_argument("--im_B_path", default="assets/sacre_coeur_B.jpg", type=str) + parser.add_argument("--save_A_path", default="demo/tiny_roma_warp_A.jpg", type=str) + parser.add_argument("--save_B_path", default="demo/tiny_roma_warp_B.jpg", type=str) + + args, _ = parser.parse_known_args() + im1_path = args.im_A_path + im2_path = args.im_B_path + + # Create model + roma_model = tiny_roma_v1_outdoor(device=device) + + # Match + warp, certainty1 = roma_model.match(im1_path, im2_path) + + h1, w1 = warp.shape[:2] + + # maybe im1.size != im2.size + im1 = Image.open(im1_path).resize((w1, h1)) + im2 = Image.open(im2_path) + x1 = (torch.tensor(np.array(im1)) / 255).to(device).permute(2, 0, 1) + x2 = (torch.tensor(np.array(im2)) / 255).to(device).permute(2, 0, 1) + + h2, w2 = x2.shape[1:] + g1_p2x = w2 / 2 * (warp[..., 2] + 1) + g1_p2y = h2 / 2 * (warp[..., 3] + 1) + g2_p1x = torch.zeros((h2, w2), dtype=torch.float32).to(device) - 2 + g2_p1y = torch.zeros((h2, w2), dtype=torch.float32).to(device) - 2 + + x, y = torch.meshgrid( + torch.arange(w1, device=device), + torch.arange(h1, device=device), + indexing="xy", + ) + g2x = torch.round(g1_p2x[y, x]).long() + g2y = torch.round(g1_p2y[y, x]).long() + idx_x = torch.bitwise_and(0 <= g2x, g2x < w2) + idx_y = torch.bitwise_and(0 <= g2y, g2y < h2) + idx = torch.bitwise_and(idx_x, idx_y) + g2_p1x[g2y[idx], g2x[idx]] = x[idx].float() * 2 / w1 - 1 + g2_p1y[g2y[idx], g2x[idx]] = y[idx].float() * 2 / h1 - 1 + + certainty2 = F.grid_sample( + certainty1[None][None], + torch.stack([g2_p1x, g2_p1y], dim=2)[None], + mode="bilinear", + align_corners=False, + )[0] + + white_im1 = torch.ones((h1, w1), device = device) + white_im2 = torch.ones((h2, w2), device = device) + + certainty1 = F.avg_pool2d(certainty1[None], kernel_size=5, stride=1, padding=2)[0] + certainty2 = F.avg_pool2d(certainty2[None], kernel_size=5, stride=1, padding=2)[0] + + vis_im1 = certainty1 * x1 + (1 - certainty1) * white_im1 + vis_im2 = certainty2 * x2 + (1 - certainty2) * white_im2 + + tensor_to_pil(vis_im1, unnormalize=False).save(args.save_A_path) + tensor_to_pil(vis_im2, unnormalize=False).save(args.save_B_path) \ No newline at end of file diff --git a/submodules/RoMa/demo/gif/.gitignore b/submodules/RoMa/demo/gif/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..c96a04f008ee21e260b28f7701595ed59e2839e3 --- /dev/null +++ b/submodules/RoMa/demo/gif/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/submodules/RoMa/experiments/eval_roma_outdoor.py b/submodules/RoMa/experiments/eval_roma_outdoor.py new file mode 100644 index 0000000000000000000000000000000000000000..de549ae2952f0efd5c209dc92da5afe811f4ba7a --- /dev/null +++ b/submodules/RoMa/experiments/eval_roma_outdoor.py @@ -0,0 +1,57 @@ +import json + +from romatch.benchmarks import MegadepthDenseBenchmark +from romatch.benchmarks import MegaDepthPoseEstimationBenchmark, HpatchesHomogBenchmark +from romatch.benchmarks import Mega1500PoseLibBenchmark + +def test_mega_8_scenes(model, name): + mega_8_scenes_benchmark = MegaDepthPoseEstimationBenchmark("data/megadepth", + scene_names=['mega_8_scenes_0019_0.1_0.3.npz', + 'mega_8_scenes_0025_0.1_0.3.npz', + 'mega_8_scenes_0021_0.1_0.3.npz', + 'mega_8_scenes_0008_0.1_0.3.npz', + 'mega_8_scenes_0032_0.1_0.3.npz', + 'mega_8_scenes_1589_0.1_0.3.npz', + 'mega_8_scenes_0063_0.1_0.3.npz', + 'mega_8_scenes_0024_0.1_0.3.npz', + 'mega_8_scenes_0019_0.3_0.5.npz', + 'mega_8_scenes_0025_0.3_0.5.npz', + 'mega_8_scenes_0021_0.3_0.5.npz', + 'mega_8_scenes_0008_0.3_0.5.npz', + 'mega_8_scenes_0032_0.3_0.5.npz', + 'mega_8_scenes_1589_0.3_0.5.npz', + 'mega_8_scenes_0063_0.3_0.5.npz', + 'mega_8_scenes_0024_0.3_0.5.npz']) + mega_8_scenes_results = mega_8_scenes_benchmark.benchmark(model, model_name=name) + print(mega_8_scenes_results) + json.dump(mega_8_scenes_results, open(f"results/mega_8_scenes_{name}.json", "w")) + +def test_mega1500(model, name): + mega1500_benchmark = MegaDepthPoseEstimationBenchmark("data/megadepth") + mega1500_results = mega1500_benchmark.benchmark(model, model_name=name) + json.dump(mega1500_results, open(f"results/mega1500_{name}.json", "w")) + +def test_mega1500_poselib(model, name): + mega1500_benchmark = Mega1500PoseLibBenchmark("data/megadepth") + mega1500_results = mega1500_benchmark.benchmark(model, model_name=name) + json.dump(mega1500_results, open(f"results/mega1500_{name}.json", "w")) + +def test_mega_dense(model, name): + megadense_benchmark = MegadepthDenseBenchmark("data/megadepth", num_samples = 1000) + megadense_results = megadense_benchmark.benchmark(model) + json.dump(megadense_results, open(f"results/mega_dense_{name}.json", "w")) + +def test_hpatches(model, name): + hpatches_benchmark = HpatchesHomogBenchmark("data/hpatches") + hpatches_results = hpatches_benchmark.benchmark(model) + json.dump(hpatches_results, open(f"results/hpatches_{name}.json", "w")) + + +if __name__ == "__main__": + from romatch import roma_outdoor + device = "cuda" + model = roma_outdoor(device = device, coarse_res = 672, upsample_res = 1344) + experiment_name = "roma_latest" + test_mega1500(model, experiment_name) + #test_mega1500_poselib(model, experiment_name) + diff --git a/submodules/RoMa/experiments/eval_tiny_roma_v1_outdoor.py b/submodules/RoMa/experiments/eval_tiny_roma_v1_outdoor.py new file mode 100644 index 0000000000000000000000000000000000000000..0541ffce7bcfe92c3016572dd3b450fc3535c90c --- /dev/null +++ b/submodules/RoMa/experiments/eval_tiny_roma_v1_outdoor.py @@ -0,0 +1,84 @@ +import torch +import os +from pathlib import Path +import json +from romatch.benchmarks import ScanNetBenchmark +from romatch.benchmarks import Mega1500PoseLibBenchmark, ScanNetPoselibBenchmark +from romatch.benchmarks import MegaDepthPoseEstimationBenchmark + +def test_mega_8_scenes(model, name): + mega_8_scenes_benchmark = MegaDepthPoseEstimationBenchmark("data/megadepth", + scene_names=['mega_8_scenes_0019_0.1_0.3.npz', + 'mega_8_scenes_0025_0.1_0.3.npz', + 'mega_8_scenes_0021_0.1_0.3.npz', + 'mega_8_scenes_0008_0.1_0.3.npz', + 'mega_8_scenes_0032_0.1_0.3.npz', + 'mega_8_scenes_1589_0.1_0.3.npz', + 'mega_8_scenes_0063_0.1_0.3.npz', + 'mega_8_scenes_0024_0.1_0.3.npz', + 'mega_8_scenes_0019_0.3_0.5.npz', + 'mega_8_scenes_0025_0.3_0.5.npz', + 'mega_8_scenes_0021_0.3_0.5.npz', + 'mega_8_scenes_0008_0.3_0.5.npz', + 'mega_8_scenes_0032_0.3_0.5.npz', + 'mega_8_scenes_1589_0.3_0.5.npz', + 'mega_8_scenes_0063_0.3_0.5.npz', + 'mega_8_scenes_0024_0.3_0.5.npz']) + mega_8_scenes_results = mega_8_scenes_benchmark.benchmark(model, model_name=name) + print(mega_8_scenes_results) + json.dump(mega_8_scenes_results, open(f"results/mega_8_scenes_{name}.json", "w")) + +def test_mega1500(model, name): + mega1500_benchmark = MegaDepthPoseEstimationBenchmark("data/megadepth") + mega1500_results = mega1500_benchmark.benchmark(model, model_name=name) + json.dump(mega1500_results, open(f"results/mega1500_{name}.json", "w")) + +def test_mega1500_poselib(model, name): + #model.exact_softmax = True + mega1500_benchmark = Mega1500PoseLibBenchmark("data/megadepth", num_ransac_iter = 1, test_every = 1) + mega1500_results = mega1500_benchmark.benchmark(model, model_name=name) + json.dump(mega1500_results, open(f"results/mega1500_poselib_{name}.json", "w")) + +def test_mega_8_scenes_poselib(model, name): + mega1500_benchmark = Mega1500PoseLibBenchmark("data/megadepth", num_ransac_iter = 1, test_every = 1, + scene_names=['mega_8_scenes_0019_0.1_0.3.npz', + 'mega_8_scenes_0025_0.1_0.3.npz', + 'mega_8_scenes_0021_0.1_0.3.npz', + 'mega_8_scenes_0008_0.1_0.3.npz', + 'mega_8_scenes_0032_0.1_0.3.npz', + 'mega_8_scenes_1589_0.1_0.3.npz', + 'mega_8_scenes_0063_0.1_0.3.npz', + 'mega_8_scenes_0024_0.1_0.3.npz', + 'mega_8_scenes_0019_0.3_0.5.npz', + 'mega_8_scenes_0025_0.3_0.5.npz', + 'mega_8_scenes_0021_0.3_0.5.npz', + 'mega_8_scenes_0008_0.3_0.5.npz', + 'mega_8_scenes_0032_0.3_0.5.npz', + 'mega_8_scenes_1589_0.3_0.5.npz', + 'mega_8_scenes_0063_0.3_0.5.npz', + 'mega_8_scenes_0024_0.3_0.5.npz']) + mega1500_results = mega1500_benchmark.benchmark(model, model_name=name) + json.dump(mega1500_results, open(f"results/mega_8_scenes_poselib_{name}.json", "w")) + +def test_scannet_poselib(model, name): + scannet_benchmark = ScanNetPoselibBenchmark("data/scannet") + scannet_results = scannet_benchmark.benchmark(model) + json.dump(scannet_results, open(f"results/scannet_{name}.json", "w")) + +def test_scannet(model, name): + scannet_benchmark = ScanNetBenchmark("data/scannet") + scannet_results = scannet_benchmark.benchmark(model) + json.dump(scannet_results, open(f"results/scannet_{name}.json", "w")) + +if __name__ == "__main__": + os.environ["TORCH_CUDNN_V8_API_ENABLED"] = "1" # For BF16 computations + os.environ["OMP_NUM_THREADS"] = "16" + torch.backends.cudnn.allow_tf32 = True # allow tf32 on cudnn + from romatch import tiny_roma_v1_outdoor + + experiment_name = Path(__file__).stem + device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') + model = tiny_roma_v1_outdoor(device) + #test_mega1500_poselib(model, experiment_name) + test_mega_8_scenes_poselib(model, experiment_name) + \ No newline at end of file diff --git a/submodules/RoMa/experiments/roma_indoor.py b/submodules/RoMa/experiments/roma_indoor.py new file mode 100644 index 0000000000000000000000000000000000000000..c7df478d1a352ad840cb7f2d84f0de22fbe5835e --- /dev/null +++ b/submodules/RoMa/experiments/roma_indoor.py @@ -0,0 +1,320 @@ +import os +import torch +from argparse import ArgumentParser + +from torch import nn +from torch.utils.data import ConcatDataset +import torch.distributed as dist +from torch.nn.parallel import DistributedDataParallel as DDP + +import json +import wandb +from tqdm import tqdm + +from romatch.benchmarks import MegadepthDenseBenchmark +from romatch.datasets.megadepth import MegadepthBuilder +from romatch.datasets.scannet import ScanNetBuilder +from romatch.losses.robust_loss import RobustLosses +from romatch.benchmarks import MegadepthDenseBenchmark, ScanNetBenchmark +from romatch.train.train import train_k_steps +from romatch.models.matcher import * +from romatch.models.transformer import Block, TransformerDecoder, MemEffAttention +from romatch.models.encoders import * +from romatch.checkpointing import CheckPoint + +resolutions = {"low":(448, 448), "medium":(14*8*5, 14*8*5), "high":(14*8*6, 14*8*6)} + +def get_model(pretrained_backbone=True, resolution = "medium", **kwargs): + gp_dim = 512 + feat_dim = 512 + decoder_dim = gp_dim + feat_dim + cls_to_coord_res = 64 + coordinate_decoder = TransformerDecoder( + nn.Sequential(*[Block(decoder_dim, 8, attn_class=MemEffAttention) for _ in range(5)]), + decoder_dim, + cls_to_coord_res**2 + 1, + is_classifier=True, + amp = True, + pos_enc = False,) + dw = True + hidden_blocks = 8 + kernel_size = 5 + displacement_emb = "linear" + disable_local_corr_grad = True + + conv_refiner = nn.ModuleDict( + { + "16": ConvRefiner( + 2 * 512+128+(2*7+1)**2, + 2 * 512+128+(2*7+1)**2, + 2 + 1, + kernel_size=kernel_size, + dw=dw, + hidden_blocks=hidden_blocks, + displacement_emb=displacement_emb, + displacement_emb_dim=128, + local_corr_radius = 7, + corr_in_other = True, + amp = True, + disable_local_corr_grad = disable_local_corr_grad, + bn_momentum = 0.01, + ), + "8": ConvRefiner( + 2 * 512+64+(2*3+1)**2, + 2 * 512+64+(2*3+1)**2, + 2 + 1, + kernel_size=kernel_size, + dw=dw, + hidden_blocks=hidden_blocks, + displacement_emb=displacement_emb, + displacement_emb_dim=64, + local_corr_radius = 3, + corr_in_other = True, + amp = True, + disable_local_corr_grad = disable_local_corr_grad, + bn_momentum = 0.01, + ), + "4": ConvRefiner( + 2 * 256+32+(2*2+1)**2, + 2 * 256+32+(2*2+1)**2, + 2 + 1, + kernel_size=kernel_size, + dw=dw, + hidden_blocks=hidden_blocks, + displacement_emb=displacement_emb, + displacement_emb_dim=32, + local_corr_radius = 2, + corr_in_other = True, + amp = True, + disable_local_corr_grad = disable_local_corr_grad, + bn_momentum = 0.01, + ), + "2": ConvRefiner( + 2 * 64+16, + 128+16, + 2 + 1, + kernel_size=kernel_size, + dw=dw, + hidden_blocks=hidden_blocks, + displacement_emb=displacement_emb, + displacement_emb_dim=16, + amp = True, + disable_local_corr_grad = disable_local_corr_grad, + bn_momentum = 0.01, + ), + "1": ConvRefiner( + 2 * 9 + 6, + 24, + 2 + 1, + kernel_size=kernel_size, + dw=dw, + hidden_blocks = hidden_blocks, + displacement_emb = displacement_emb, + displacement_emb_dim = 6, + amp = True, + disable_local_corr_grad = disable_local_corr_grad, + bn_momentum = 0.01, + ), + } + ) + kernel_temperature = 0.2 + learn_temperature = False + no_cov = True + kernel = CosKernel + only_attention = False + basis = "fourier" + gp16 = GP( + kernel, + T=kernel_temperature, + learn_temperature=learn_temperature, + only_attention=only_attention, + gp_dim=gp_dim, + basis=basis, + no_cov=no_cov, + ) + gps = nn.ModuleDict({"16": gp16}) + proj16 = nn.Sequential(nn.Conv2d(1024, 512, 1, 1), nn.BatchNorm2d(512)) + proj8 = nn.Sequential(nn.Conv2d(512, 512, 1, 1), nn.BatchNorm2d(512)) + proj4 = nn.Sequential(nn.Conv2d(256, 256, 1, 1), nn.BatchNorm2d(256)) + proj2 = nn.Sequential(nn.Conv2d(128, 64, 1, 1), nn.BatchNorm2d(64)) + proj1 = nn.Sequential(nn.Conv2d(64, 9, 1, 1), nn.BatchNorm2d(9)) + proj = nn.ModuleDict({ + "16": proj16, + "8": proj8, + "4": proj4, + "2": proj2, + "1": proj1, + }) + displacement_dropout_p = 0.0 + gm_warp_dropout_p = 0.0 + decoder = Decoder(coordinate_decoder, + gps, + proj, + conv_refiner, + detach=True, + scales=["16", "8", "4", "2", "1"], + displacement_dropout_p = displacement_dropout_p, + gm_warp_dropout_p = gm_warp_dropout_p) + h,w = resolutions[resolution] + encoder = CNNandDinov2( + cnn_kwargs = dict( + pretrained=pretrained_backbone, + amp = True), + amp = True, + use_vgg = True, + ) + matcher = RegressionMatcher(encoder, decoder, h=h, w=w, alpha=1, beta=0,**kwargs) + return matcher + +def train(args): + dist.init_process_group('nccl') + #torch._dynamo.config.verbose=True + gpus = int(os.environ['WORLD_SIZE']) + # create model and move it to GPU with id rank + rank = dist.get_rank() + print(f"Start running DDP on rank {rank}") + device_id = rank % torch.cuda.device_count() + romatch.LOCAL_RANK = device_id + torch.cuda.set_device(device_id) + + resolution = args.train_resolution + wandb_log = not args.dont_log_wandb + experiment_name = os.path.splitext(os.path.basename(__file__))[0] + wandb_mode = "online" if wandb_log and rank == 0 and False else "disabled" + wandb.init(project="romatch", entity=args.wandb_entity, name=experiment_name, reinit=False, mode = wandb_mode) + checkpoint_dir = "workspace/checkpoints/" + h,w = resolutions[resolution] + model = get_model(pretrained_backbone=True, resolution=resolution, attenuate_cert = False).to(device_id) + # Num steps + global_step = 0 + batch_size = args.gpu_batch_size + step_size = gpus*batch_size + romatch.STEP_SIZE = step_size + + N = (32 * 250000) # 250k steps of batch size 32 + # checkpoint every + k = 25000 // romatch.STEP_SIZE + + # Data + mega = MegadepthBuilder(data_root="data/megadepth", loftr_ignore=True, imc21_ignore = True) + use_horizontal_flip_aug = True + rot_prob = 0 + depth_interpolation_mode = "bilinear" + megadepth_train1 = mega.build_scenes( + split="train_loftr", min_overlap=0.01, shake_t=32, use_horizontal_flip_aug = use_horizontal_flip_aug, rot_prob = rot_prob, + ht=h,wt=w, + ) + megadepth_train2 = mega.build_scenes( + split="train_loftr", min_overlap=0.35, shake_t=32, use_horizontal_flip_aug = use_horizontal_flip_aug, rot_prob = rot_prob, + ht=h,wt=w, + ) + megadepth_train = ConcatDataset(megadepth_train1 + megadepth_train2) + mega_ws = mega.weight_scenes(megadepth_train, alpha=0.75) + + scannet = ScanNetBuilder(data_root="data/scannet") + scannet_train = scannet.build_scenes(split="train", ht=h, wt=w, use_horizontal_flip_aug = use_horizontal_flip_aug) + scannet_train = ConcatDataset(scannet_train) + scannet_ws = scannet.weight_scenes(scannet_train, alpha=0.75) + + # Loss and optimizer + depth_loss_scannet = RobustLosses( + ce_weight=0.0, + local_dist={1:4, 2:4, 4:8, 8:8}, + local_largest_scale=8, + depth_interpolation_mode=depth_interpolation_mode, + alpha = 0.5, + c = 1e-4,) + # Loss and optimizer + depth_loss_mega = RobustLosses( + ce_weight=0.01, + local_dist={1:4, 2:4, 4:8, 8:8}, + local_largest_scale=8, + depth_interpolation_mode=depth_interpolation_mode, + alpha = 0.5, + c = 1e-4,) + parameters = [ + {"params": model.encoder.parameters(), "lr": romatch.STEP_SIZE * 5e-6 / 8}, + {"params": model.decoder.parameters(), "lr": romatch.STEP_SIZE * 1e-4 / 8}, + ] + optimizer = torch.optim.AdamW(parameters, weight_decay=0.01) + lr_scheduler = torch.optim.lr_scheduler.MultiStepLR( + optimizer, milestones=[(9*N/romatch.STEP_SIZE)//10]) + megadense_benchmark = MegadepthDenseBenchmark("data/megadepth", num_samples = 1000, h=h,w=w) + checkpointer = CheckPoint(checkpoint_dir, experiment_name) + model, optimizer, lr_scheduler, global_step = checkpointer.load(model, optimizer, lr_scheduler, global_step) + romatch.GLOBAL_STEP = global_step + ddp_model = DDP(model, device_ids=[device_id], find_unused_parameters = False, gradient_as_bucket_view=True) + grad_scaler = torch.cuda.amp.GradScaler(growth_interval=1_000_000) + grad_clip_norm = 0.01 + for n in range(romatch.GLOBAL_STEP, N, k * romatch.STEP_SIZE): + mega_sampler = torch.utils.data.WeightedRandomSampler( + mega_ws, num_samples = batch_size * k, replacement=False + ) + mega_dataloader = iter( + torch.utils.data.DataLoader( + megadepth_train, + batch_size = batch_size, + sampler = mega_sampler, + num_workers = 8, + ) + ) + scannet_ws_sampler = torch.utils.data.WeightedRandomSampler( + scannet_ws, num_samples=batch_size * k, replacement=False + ) + scannet_dataloader = iter( + torch.utils.data.DataLoader( + scannet_train, + batch_size=batch_size, + sampler=scannet_ws_sampler, + num_workers=gpus * 8, + ) + ) + for n_k in tqdm(range(n, n + 2 * k, 2),disable = romatch.RANK > 0): + train_k_steps( + n_k, 1, mega_dataloader, ddp_model, depth_loss_mega, optimizer, lr_scheduler, grad_scaler, grad_clip_norm = grad_clip_norm, progress_bar=False + ) + train_k_steps( + n_k + 1, 1, scannet_dataloader, ddp_model, depth_loss_scannet, optimizer, lr_scheduler, grad_scaler, grad_clip_norm = grad_clip_norm, progress_bar=False + ) + checkpointer.save(model, optimizer, lr_scheduler, romatch.GLOBAL_STEP) + wandb.log(megadense_benchmark.benchmark(model), step = romatch.GLOBAL_STEP) + +def test_scannet(model, name, resolution, sample_mode): + scannet_benchmark = ScanNetBenchmark("data/scannet") + scannet_results = scannet_benchmark.benchmark(model) + json.dump(scannet_results, open(f"results/scannet_{name}.json", "w")) + +if __name__ == "__main__": + import warnings + warnings.filterwarnings('ignore', category=UserWarning, message='TypedStorage is deprecated') + warnings.filterwarnings('ignore')#, category=UserWarning)#, message='WARNING batched routines are designed for small sizes.') + os.environ["TORCH_CUDNN_V8_API_ENABLED"] = "1" # For BF16 computations + os.environ["OMP_NUM_THREADS"] = "16" + + import romatch + parser = ArgumentParser() + parser.add_argument("--test", action='store_true') + parser.add_argument("--debug_mode", action='store_true') + parser.add_argument("--dont_log_wandb", action='store_true') + parser.add_argument("--train_resolution", default='medium') + parser.add_argument("--gpu_batch_size", default=4, type=int) + parser.add_argument("--wandb_entity", required = False) + + args, _ = parser.parse_known_args() + romatch.DEBUG_MODE = args.debug_mode + if not args.test: + train(args) + experiment_name = os.path.splitext(os.path.basename(__file__))[0] + checkpoint_dir = "workspace/" + checkpoint_name = checkpoint_dir + experiment_name + ".pth" + test_resolution = "medium" + sample_mode = "threshold_balanced" + symmetric = True + upsample_preds = False + attenuate_cert = True + + model = get_model(pretrained_backbone=False, resolution = test_resolution, sample_mode = sample_mode, upsample_preds = upsample_preds, symmetric=symmetric, name=experiment_name, attenuate_cert = attenuate_cert) + model = model.cuda() + states = torch.load(checkpoint_name) + model.load_state_dict(states["model"]) + test_scannet(model, experiment_name, resolution = test_resolution, sample_mode = sample_mode) diff --git a/submodules/RoMa/experiments/train_roma_outdoor.py b/submodules/RoMa/experiments/train_roma_outdoor.py new file mode 100644 index 0000000000000000000000000000000000000000..a47bfca577a1633fd0f3950319b99e88ac2476f1 --- /dev/null +++ b/submodules/RoMa/experiments/train_roma_outdoor.py @@ -0,0 +1,307 @@ +import os +import torch +from argparse import ArgumentParser + +from torch import nn +from torch.utils.data import ConcatDataset +import torch.distributed as dist +from torch.nn.parallel import DistributedDataParallel as DDP +import json +import wandb + +from romatch.benchmarks import MegadepthDenseBenchmark +from romatch.datasets.megadepth import MegadepthBuilder +from romatch.losses.robust_loss import RobustLosses +from romatch.benchmarks import MegaDepthPoseEstimationBenchmark, MegadepthDenseBenchmark, HpatchesHomogBenchmark + +from romatch.train.train import train_k_steps +from romatch.models.matcher import * +from romatch.models.transformer import Block, TransformerDecoder, MemEffAttention +from romatch.models.encoders import * +from romatch.checkpointing import CheckPoint + +resolutions = {"low":(448, 448), "medium":(14*8*5, 14*8*5), "high":(14*8*6, 14*8*6)} + +def get_model(pretrained_backbone=True, resolution = "medium", **kwargs): + import warnings + warnings.filterwarnings('ignore', category=UserWarning, message='TypedStorage is deprecated') + gp_dim = 512 + feat_dim = 512 + decoder_dim = gp_dim + feat_dim + cls_to_coord_res = 64 + coordinate_decoder = TransformerDecoder( + nn.Sequential(*[Block(decoder_dim, 8, attn_class=MemEffAttention) for _ in range(5)]), + decoder_dim, + cls_to_coord_res**2 + 1, + is_classifier=True, + amp = True, + pos_enc = False,) + dw = True + hidden_blocks = 8 + kernel_size = 5 + displacement_emb = "linear" + disable_local_corr_grad = True + + conv_refiner = nn.ModuleDict( + { + "16": ConvRefiner( + 2 * 512+128+(2*7+1)**2, + 2 * 512+128+(2*7+1)**2, + 2 + 1, + kernel_size=kernel_size, + dw=dw, + hidden_blocks=hidden_blocks, + displacement_emb=displacement_emb, + displacement_emb_dim=128, + local_corr_radius = 7, + corr_in_other = True, + amp = True, + disable_local_corr_grad = disable_local_corr_grad, + bn_momentum = 0.01, + ), + "8": ConvRefiner( + 2 * 512+64+(2*3+1)**2, + 2 * 512+64+(2*3+1)**2, + 2 + 1, + kernel_size=kernel_size, + dw=dw, + hidden_blocks=hidden_blocks, + displacement_emb=displacement_emb, + displacement_emb_dim=64, + local_corr_radius = 3, + corr_in_other = True, + amp = True, + disable_local_corr_grad = disable_local_corr_grad, + bn_momentum = 0.01, + ), + "4": ConvRefiner( + 2 * 256+32+(2*2+1)**2, + 2 * 256+32+(2*2+1)**2, + 2 + 1, + kernel_size=kernel_size, + dw=dw, + hidden_blocks=hidden_blocks, + displacement_emb=displacement_emb, + displacement_emb_dim=32, + local_corr_radius = 2, + corr_in_other = True, + amp = True, + disable_local_corr_grad = disable_local_corr_grad, + bn_momentum = 0.01, + ), + "2": ConvRefiner( + 2 * 64+16, + 128+16, + 2 + 1, + kernel_size=kernel_size, + dw=dw, + hidden_blocks=hidden_blocks, + displacement_emb=displacement_emb, + displacement_emb_dim=16, + amp = True, + disable_local_corr_grad = disable_local_corr_grad, + bn_momentum = 0.01, + ), + "1": ConvRefiner( + 2 * 9 + 6, + 24, + 2 + 1, + kernel_size=kernel_size, + dw=dw, + hidden_blocks = hidden_blocks, + displacement_emb = displacement_emb, + displacement_emb_dim = 6, + amp = True, + disable_local_corr_grad = disable_local_corr_grad, + bn_momentum = 0.01, + ), + } + ) + kernel_temperature = 0.2 + learn_temperature = False + no_cov = True + kernel = CosKernel + only_attention = False + basis = "fourier" + gp16 = GP( + kernel, + T=kernel_temperature, + learn_temperature=learn_temperature, + only_attention=only_attention, + gp_dim=gp_dim, + basis=basis, + no_cov=no_cov, + ) + gps = nn.ModuleDict({"16": gp16}) + proj16 = nn.Sequential(nn.Conv2d(1024, 512, 1, 1), nn.BatchNorm2d(512)) + proj8 = nn.Sequential(nn.Conv2d(512, 512, 1, 1), nn.BatchNorm2d(512)) + proj4 = nn.Sequential(nn.Conv2d(256, 256, 1, 1), nn.BatchNorm2d(256)) + proj2 = nn.Sequential(nn.Conv2d(128, 64, 1, 1), nn.BatchNorm2d(64)) + proj1 = nn.Sequential(nn.Conv2d(64, 9, 1, 1), nn.BatchNorm2d(9)) + proj = nn.ModuleDict({ + "16": proj16, + "8": proj8, + "4": proj4, + "2": proj2, + "1": proj1, + }) + displacement_dropout_p = 0.0 + gm_warp_dropout_p = 0.0 + decoder = Decoder(coordinate_decoder, + gps, + proj, + conv_refiner, + detach=True, + scales=["16", "8", "4", "2", "1"], + displacement_dropout_p = displacement_dropout_p, + gm_warp_dropout_p = gm_warp_dropout_p) + h,w = resolutions[resolution] + encoder = CNNandDinov2( + cnn_kwargs = dict( + pretrained=pretrained_backbone, + amp = True), + amp = True, + use_vgg = True, + ) + matcher = RegressionMatcher(encoder, decoder, h=h, w=w,**kwargs) + return matcher + +def train(args): + dist.init_process_group('nccl') + #torch._dynamo.config.verbose=True + gpus = int(os.environ['WORLD_SIZE']) + # create model and move it to GPU with id rank + rank = dist.get_rank() + print(f"Start running DDP on rank {rank}") + device_id = rank % torch.cuda.device_count() + romatch.LOCAL_RANK = device_id + torch.cuda.set_device(device_id) + + resolution = args.train_resolution + wandb_log = not args.dont_log_wandb + experiment_name = os.path.splitext(os.path.basename(__file__))[0] + wandb_mode = "online" if wandb_log and rank == 0 else "disabled" + wandb.init(project="romatch", entity=args.wandb_entity, name=experiment_name, reinit=False, mode = wandb_mode) + checkpoint_dir = "workspace/checkpoints/" + h,w = resolutions[resolution] + model = get_model(pretrained_backbone=True, resolution=resolution, attenuate_cert = False).to(device_id) + # Num steps + global_step = 0 + batch_size = args.gpu_batch_size + step_size = gpus*batch_size + romatch.STEP_SIZE = step_size + + N = (32 * 250000) # 250k steps of batch size 32 + # checkpoint every + k = 25000 // romatch.STEP_SIZE + + # Data + mega = MegadepthBuilder(data_root="data/megadepth", loftr_ignore=True, imc21_ignore = True) + use_horizontal_flip_aug = True + rot_prob = 0 + depth_interpolation_mode = "bilinear" + megadepth_train1 = mega.build_scenes( + split="train_loftr", min_overlap=0.01, shake_t=32, use_horizontal_flip_aug = use_horizontal_flip_aug, rot_prob = rot_prob, + ht=h,wt=w, + ) + megadepth_train2 = mega.build_scenes( + split="train_loftr", min_overlap=0.35, shake_t=32, use_horizontal_flip_aug = use_horizontal_flip_aug, rot_prob = rot_prob, + ht=h,wt=w, + ) + megadepth_train = ConcatDataset(megadepth_train1 + megadepth_train2) + mega_ws = mega.weight_scenes(megadepth_train, alpha=0.75) + # Loss and optimizer + depth_loss = RobustLosses( + ce_weight=0.01, + local_dist={1:4, 2:4, 4:8, 8:8}, + local_largest_scale=8, + depth_interpolation_mode=depth_interpolation_mode, + alpha = 0.5, + c = 1e-4,) + parameters = [ + {"params": model.encoder.parameters(), "lr": romatch.STEP_SIZE * 5e-6 / 8}, + {"params": model.decoder.parameters(), "lr": romatch.STEP_SIZE * 1e-4 / 8}, + ] + optimizer = torch.optim.AdamW(parameters, weight_decay=0.01) + lr_scheduler = torch.optim.lr_scheduler.MultiStepLR( + optimizer, milestones=[(9*N/romatch.STEP_SIZE)//10]) + megadense_benchmark = MegadepthDenseBenchmark("data/megadepth", num_samples = 1000, h=h,w=w) + checkpointer = CheckPoint(checkpoint_dir, experiment_name) + model, optimizer, lr_scheduler, global_step = checkpointer.load(model, optimizer, lr_scheduler, global_step) + romatch.GLOBAL_STEP = global_step + ddp_model = DDP(model, device_ids=[device_id], find_unused_parameters = False, gradient_as_bucket_view=True) + grad_scaler = torch.cuda.amp.GradScaler(growth_interval=1_000_000) + grad_clip_norm = 0.01 + for n in range(romatch.GLOBAL_STEP, N, k * romatch.STEP_SIZE): + mega_sampler = torch.utils.data.WeightedRandomSampler( + mega_ws, num_samples = batch_size * k, replacement=False + ) + mega_dataloader = iter( + torch.utils.data.DataLoader( + megadepth_train, + batch_size = batch_size, + sampler = mega_sampler, + num_workers = 8, + ) + ) + train_k_steps( + n, k, mega_dataloader, ddp_model, depth_loss, optimizer, lr_scheduler, grad_scaler, grad_clip_norm = grad_clip_norm, + ) + checkpointer.save(model, optimizer, lr_scheduler, romatch.GLOBAL_STEP) + wandb.log(megadense_benchmark.benchmark(model), step = romatch.GLOBAL_STEP) + +def test_mega_8_scenes(model, name): + mega_8_scenes_benchmark = MegaDepthPoseEstimationBenchmark("data/megadepth", + scene_names=['mega_8_scenes_0019_0.1_0.3.npz', + 'mega_8_scenes_0025_0.1_0.3.npz', + 'mega_8_scenes_0021_0.1_0.3.npz', + 'mega_8_scenes_0008_0.1_0.3.npz', + 'mega_8_scenes_0032_0.1_0.3.npz', + 'mega_8_scenes_1589_0.1_0.3.npz', + 'mega_8_scenes_0063_0.1_0.3.npz', + 'mega_8_scenes_0024_0.1_0.3.npz', + 'mega_8_scenes_0019_0.3_0.5.npz', + 'mega_8_scenes_0025_0.3_0.5.npz', + 'mega_8_scenes_0021_0.3_0.5.npz', + 'mega_8_scenes_0008_0.3_0.5.npz', + 'mega_8_scenes_0032_0.3_0.5.npz', + 'mega_8_scenes_1589_0.3_0.5.npz', + 'mega_8_scenes_0063_0.3_0.5.npz', + 'mega_8_scenes_0024_0.3_0.5.npz']) + mega_8_scenes_results = mega_8_scenes_benchmark.benchmark(model, model_name=name) + print(mega_8_scenes_results) + json.dump(mega_8_scenes_results, open(f"results/mega_8_scenes_{name}.json", "w")) + +def test_mega1500(model, name): + mega1500_benchmark = MegaDepthPoseEstimationBenchmark("data/megadepth") + mega1500_results = mega1500_benchmark.benchmark(model, model_name=name) + json.dump(mega1500_results, open(f"results/mega1500_{name}.json", "w")) + +def test_mega_dense(model, name): + megadense_benchmark = MegadepthDenseBenchmark("data/megadepth", num_samples = 1000) + megadense_results = megadense_benchmark.benchmark(model) + json.dump(megadense_results, open(f"results/mega_dense_{name}.json", "w")) + +def test_hpatches(model, name): + hpatches_benchmark = HpatchesHomogBenchmark("data/hpatches") + hpatches_results = hpatches_benchmark.benchmark(model) + json.dump(hpatches_results, open(f"results/hpatches_{name}.json", "w")) + + +if __name__ == "__main__": + os.environ["TORCH_CUDNN_V8_API_ENABLED"] = "1" # For BF16 computations + os.environ["OMP_NUM_THREADS"] = "16" + torch.backends.cudnn.allow_tf32 = True # allow tf32 on cudnn + import romatch + parser = ArgumentParser() + parser.add_argument("--only_test", action='store_true') + parser.add_argument("--debug_mode", action='store_true') + parser.add_argument("--dont_log_wandb", action='store_true') + parser.add_argument("--train_resolution", default='medium') + parser.add_argument("--gpu_batch_size", default=8, type=int) + parser.add_argument("--wandb_entity", required = False) + + args, _ = parser.parse_known_args() + romatch.DEBUG_MODE = args.debug_mode + if not args.only_test: + train(args) diff --git a/submodules/RoMa/experiments/train_tiny_roma_v1_outdoor.py b/submodules/RoMa/experiments/train_tiny_roma_v1_outdoor.py new file mode 100644 index 0000000000000000000000000000000000000000..8fbb97452b7744792b1fa08fb9e2fd23b9566684 --- /dev/null +++ b/submodules/RoMa/experiments/train_tiny_roma_v1_outdoor.py @@ -0,0 +1,498 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +import os +import torch +from argparse import ArgumentParser +from pathlib import Path +import math +import numpy as np + +from torch import nn +from torch.utils.data import ConcatDataset +import torch.distributed as dist +from torch.nn.parallel import DistributedDataParallel as DDP +import json +import wandb +from PIL import Image +from torchvision.transforms import ToTensor + +from romatch.benchmarks import MegadepthDenseBenchmark, ScanNetBenchmark +from romatch.benchmarks import Mega1500PoseLibBenchmark, ScanNetPoselibBenchmark +from romatch.datasets.megadepth import MegadepthBuilder +from romatch.losses.robust_loss_tiny_roma import RobustLosses +from romatch.benchmarks import MegaDepthPoseEstimationBenchmark, MegadepthDenseBenchmark, HpatchesHomogBenchmark +from romatch.train.train import train_k_steps +from romatch.checkpointing import CheckPoint + +resolutions = {"low":(448, 448), "medium":(14*8*5, 14*8*5), "high":(14*8*6, 14*8*6), "xfeat": (600,800), "big": (768, 1024)} + +def kde(x, std = 0.1): + # use a gaussian kernel to estimate density + x = x.half() # Do it in half precision TODO: remove hardcoding + scores = (-torch.cdist(x,x)**2/(2*std**2)).exp() + density = scores.sum(dim=-1) + return density + +class BasicLayer(nn.Module): + """ + Basic Convolutional Layer: Conv2d -> BatchNorm -> ReLU + """ + def __init__(self, in_channels, out_channels, kernel_size=3, stride=1, padding=1, dilation=1, bias=False, relu = True): + super().__init__() + self.layer = nn.Sequential( + nn.Conv2d( in_channels, out_channels, kernel_size, padding = padding, stride=stride, dilation=dilation, bias = bias), + nn.BatchNorm2d(out_channels, affine=False), + nn.ReLU(inplace = True) if relu else nn.Identity() + ) + + def forward(self, x): + return self.layer(x) + +class XFeatModel(nn.Module): + """ + Implementation of architecture described in + "XFeat: Accelerated Features for Lightweight Image Matching, CVPR 2024." + """ + + def __init__(self, xfeat = None, + freeze_xfeat = True, + sample_mode = "threshold_balanced", + symmetric = False, + exact_softmax = False): + super().__init__() + if xfeat is None: + xfeat = torch.hub.load('verlab/accelerated_features', 'XFeat', pretrained = True, top_k = 4096).net + del xfeat.heatmap_head, xfeat.keypoint_head, xfeat.fine_matcher + if freeze_xfeat: + xfeat.train(False) + self.xfeat = [xfeat]# hide params from ddp + else: + self.xfeat = nn.ModuleList([xfeat]) + self.freeze_xfeat = freeze_xfeat + match_dim = 256 + self.coarse_matcher = nn.Sequential( + BasicLayer(64+64+2, match_dim,), + BasicLayer(match_dim, match_dim,), + BasicLayer(match_dim, match_dim,), + BasicLayer(match_dim, match_dim,), + nn.Conv2d(match_dim, 3, kernel_size=1, bias=True, padding=0)) + fine_match_dim = 64 + self.fine_matcher = nn.Sequential( + BasicLayer(24+24+2, fine_match_dim,), + BasicLayer(fine_match_dim, fine_match_dim,), + BasicLayer(fine_match_dim, fine_match_dim,), + BasicLayer(fine_match_dim, fine_match_dim,), + nn.Conv2d(fine_match_dim, 3, kernel_size=1, bias=True, padding=0),) + self.sample_mode = sample_mode + self.sample_thresh = 0.2 + self.symmetric = symmetric + self.exact_softmax = exact_softmax + + @property + def device(self): + return self.fine_matcher[-1].weight.device + + def preprocess_tensor(self, x): + """ Guarantee that image is divisible by 32 to avoid aliasing artifacts. """ + H, W = x.shape[-2:] + _H, _W = (H//32) * 32, (W//32) * 32 + rh, rw = H/_H, W/_W + + x = F.interpolate(x, (_H, _W), mode='bilinear', align_corners=False) + return x, rh, rw + + def forward_single(self, x): + with torch.inference_mode(self.freeze_xfeat or not self.training): + xfeat = self.xfeat[0] + with torch.no_grad(): + x = x.mean(dim=1, keepdim = True) + x = xfeat.norm(x) + + #main backbone + x1 = xfeat.block1(x) + x2 = xfeat.block2(x1 + xfeat.skip1(x)) + x3 = xfeat.block3(x2) + x4 = xfeat.block4(x3) + x5 = xfeat.block5(x4) + x4 = F.interpolate(x4, (x3.shape[-2], x3.shape[-1]), mode='bilinear') + x5 = F.interpolate(x5, (x3.shape[-2], x3.shape[-1]), mode='bilinear') + feats = xfeat.block_fusion( x3 + x4 + x5 ) + if self.freeze_xfeat: + return x2.clone(), feats.clone() + return x2, feats + + def to_pixel_coordinates(self, coords, H_A, W_A, H_B = None, W_B = None): + if coords.shape[-1] == 2: + return self._to_pixel_coordinates(coords, H_A, W_A) + + if isinstance(coords, (list, tuple)): + kpts_A, kpts_B = coords[0], coords[1] + else: + kpts_A, kpts_B = coords[...,:2], coords[...,2:] + return self._to_pixel_coordinates(kpts_A, H_A, W_A), self._to_pixel_coordinates(kpts_B, H_B, W_B) + + def _to_pixel_coordinates(self, coords, H, W): + kpts = torch.stack((W/2 * (coords[...,0]+1), H/2 * (coords[...,1]+1)),axis=-1) + return kpts + + def pos_embed(self, corr_volume: torch.Tensor): + B, H1, W1, H0, W0 = corr_volume.shape + grid = torch.stack( + torch.meshgrid( + torch.linspace(-1+1/W1,1-1/W1, W1), + torch.linspace(-1+1/H1,1-1/H1, H1), + indexing = "xy"), + dim = -1).float().to(corr_volume).reshape(H1*W1, 2) + down = 4 + if not self.training and not self.exact_softmax: + grid_lr = torch.stack( + torch.meshgrid( + torch.linspace(-1+down/W1,1-down/W1, W1//down), + torch.linspace(-1+down/H1,1-down/H1, H1//down), + indexing = "xy"), + dim = -1).float().to(corr_volume).reshape(H1*W1 //down**2, 2) + cv = corr_volume + best_match = cv.reshape(B,H1*W1,H0,W0).amax(dim=1) # B, HW, H, W + P_lowres = torch.cat((cv[:,::down,::down].reshape(B,H1*W1 // down**2,H0,W0), best_match[:,None]),dim=1).softmax(dim=1) + pos_embeddings = torch.einsum('bchw,cd->bdhw', P_lowres[:,:-1], grid_lr) + pos_embeddings += P_lowres[:,-1] * grid[best_match].permute(0,3,1,2) + else: + P = corr_volume.reshape(B,H1*W1,H0,W0).softmax(dim=1) # B, HW, H, W + pos_embeddings = torch.einsum('bchw,cd->bdhw', P, grid) + return pos_embeddings + + def visualize_warp(self, warp, certainty, im_A = None, im_B = None, + im_A_path = None, im_B_path = None, symmetric = True, save_path = None, unnormalize = False): + device = warp.device + H,W2,_ = warp.shape + W = W2//2 if symmetric else W2 + if im_A is None: + from PIL import Image + im_A, im_B = Image.open(im_A_path).convert("RGB"), Image.open(im_B_path).convert("RGB") + if not isinstance(im_A, torch.Tensor): + im_A = im_A.resize((W,H)) + im_B = im_B.resize((W,H)) + x_B = (torch.tensor(np.array(im_B)) / 255).to(device).permute(2, 0, 1) + if symmetric: + x_A = (torch.tensor(np.array(im_A)) / 255).to(device).permute(2, 0, 1) + else: + if symmetric: + x_A = im_A + x_B = im_B + im_A_transfer_rgb = F.grid_sample( + x_B[None], warp[:,:W, 2:][None], mode="bilinear", align_corners=False + )[0] + if symmetric: + im_B_transfer_rgb = F.grid_sample( + x_A[None], warp[:, W:, :2][None], mode="bilinear", align_corners=False + )[0] + warp_im = torch.cat((im_A_transfer_rgb,im_B_transfer_rgb),dim=2) + white_im = torch.ones((H,2*W),device=device) + else: + warp_im = im_A_transfer_rgb + white_im = torch.ones((H, W), device = device) + vis_im = certainty * warp_im + (1 - certainty) * white_im + if save_path is not None: + from romatch.utils import tensor_to_pil + tensor_to_pil(vis_im, unnormalize=unnormalize).save(save_path) + return vis_im + + def corr_volume(self, feat0, feat1): + """ + input: + feat0 -> torch.Tensor(B, C, H, W) + feat1 -> torch.Tensor(B, C, H, W) + return: + corr_volume -> torch.Tensor(B, H, W, H, W) + """ + B, C, H0, W0 = feat0.shape + B, C, H1, W1 = feat1.shape + feat0 = feat0.view(B, C, H0*W0) + feat1 = feat1.view(B, C, H1*W1) + corr_volume = torch.einsum('bci,bcj->bji', feat0, feat1).reshape(B, H1, W1, H0 , W0)/math.sqrt(C) #16*16*16 + return corr_volume + + @torch.inference_mode() + def match_from_path(self, im0_path, im1_path): + device = self.device + im0 = ToTensor()(Image.open(im0_path))[None].to(device) + im1 = ToTensor()(Image.open(im1_path))[None].to(device) + return self.match(im0, im1, batched = False) + + @torch.inference_mode() + def match(self, im0, im1, *args, batched = True): + # stupid + if isinstance(im0, (str, Path)): + return self.match_from_path(im0, im1) + elif isinstance(im0, Image.Image): + batched = False + device = self.device + im0 = ToTensor()(im0)[None].to(device) + im1 = ToTensor()(im1)[None].to(device) + + B,C,H0,W0 = im0.shape + B,C,H1,W1 = im1.shape + self.train(False) + corresps = self.forward({"im_A":im0, "im_B":im1}) + #return 1,1 + flow = F.interpolate( + corresps[4]["flow"], + size = (H0, W0), + mode = "bilinear", align_corners = False).permute(0,2,3,1).reshape(B,H0,W0,2) + grid = torch.stack( + torch.meshgrid( + torch.linspace(-1+1/W0,1-1/W0, W0), + torch.linspace(-1+1/H0,1-1/H0, H0), + indexing = "xy"), + dim = -1).float().to(flow.device).expand(B, H0, W0, 2) + + certainty = F.interpolate(corresps[4]["certainty"], size = (H0,W0), mode = "bilinear", align_corners = False) + warp, cert = torch.cat((grid, flow), dim = -1), certainty[:,0].sigmoid() + if batched: + return warp, cert + else: + return warp[0], cert[0] + + def sample( + self, + matches, + certainty, + num=10000, + ): + if "threshold" in self.sample_mode: + upper_thresh = self.sample_thresh + certainty = certainty.clone() + certainty[certainty > upper_thresh] = 1 + matches, certainty = ( + matches.reshape(-1, 4), + certainty.reshape(-1), + ) + expansion_factor = 4 if "balanced" in self.sample_mode else 1 + good_samples = torch.multinomial(certainty, + num_samples = min(expansion_factor*num, len(certainty)), + replacement=False) + good_matches, good_certainty = matches[good_samples], certainty[good_samples] + if "balanced" not in self.sample_mode: + return good_matches, good_certainty + density = kde(good_matches, std=0.1) + p = 1 / (density+1) + p[density < 10] = 1e-7 # Basically should have at least 10 perfect neighbours, or around 100 ok ones + balanced_samples = torch.multinomial(p, + num_samples = min(num,len(good_certainty)), + replacement=False) + return good_matches[balanced_samples], good_certainty[balanced_samples] + + def forward(self, batch): + """ + input: + x -> torch.Tensor(B, C, H, W) grayscale or rgb images + return: + + """ + im0 = batch["im_A"] + im1 = batch["im_B"] + corresps = {} + im0, rh0, rw0 = self.preprocess_tensor(im0) + im1, rh1, rw1 = self.preprocess_tensor(im1) + B, C, H0, W0 = im0.shape + B, C, H1, W1 = im1.shape + to_normalized = torch.tensor((2/W1, 2/H1, 1)).to(im0.device)[None,:,None,None] + + if im0.shape[-2:] == im1.shape[-2:]: + x = torch.cat([im0, im1], dim=0) + x = self.forward_single(x) + feats_x0_c, feats_x1_c = x[1].chunk(2) + feats_x0_f, feats_x1_f = x[0].chunk(2) + else: + feats_x0_f, feats_x0_c = self.forward_single(im0) + feats_x1_f, feats_x1_c = self.forward_single(im1) + corr_volume = self.corr_volume(feats_x0_c, feats_x1_c) + coarse_warp = self.pos_embed(corr_volume) + coarse_matches = torch.cat((coarse_warp, torch.zeros_like(coarse_warp[:,-1:])), dim=1) + feats_x1_c_warped = F.grid_sample(feats_x1_c, coarse_matches.permute(0, 2, 3, 1)[...,:2], mode = 'bilinear', align_corners = False) + coarse_matches_delta = self.coarse_matcher(torch.cat((feats_x0_c, feats_x1_c_warped, coarse_warp), dim=1)) + coarse_matches = coarse_matches + coarse_matches_delta * to_normalized + corresps[8] = {"flow": coarse_matches[:,:2], "certainty": coarse_matches[:,2:]} + coarse_matches_up = F.interpolate(coarse_matches, size = feats_x0_f.shape[-2:], mode = "bilinear", align_corners = False) + coarse_matches_up_detach = coarse_matches_up.detach()#note the detach + feats_x1_f_warped = F.grid_sample(feats_x1_f, coarse_matches_up_detach.permute(0, 2, 3, 1)[...,:2], mode = 'bilinear', align_corners = False) + fine_matches_delta = self.fine_matcher(torch.cat((feats_x0_f, feats_x1_f_warped, coarse_matches_up_detach[:,:2]), dim=1)) + fine_matches = coarse_matches_up_detach+fine_matches_delta * to_normalized + corresps[4] = {"flow": fine_matches[:,:2], "certainty": fine_matches[:,2:]} + return corresps + + + + + +def train(args): + rank = 0 + gpus = 1 + device_id = rank % torch.cuda.device_count() + romatch.LOCAL_RANK = 0 + torch.cuda.set_device(device_id) + + resolution = "big" + wandb_log = not args.dont_log_wandb + experiment_name = Path(__file__).stem + wandb_mode = "online" if wandb_log and rank == 0 else "disabled" + wandb.init(project="romatch", entity=args.wandb_entity, name=experiment_name, reinit=False, mode = wandb_mode) + checkpoint_dir = "workspace/checkpoints/" + h,w = resolutions[resolution] + model = XFeatModel(freeze_xfeat = False).to(device_id) + # Num steps + global_step = 0 + batch_size = args.gpu_batch_size + step_size = gpus*batch_size + romatch.STEP_SIZE = step_size + + N = 2_000_000 # 2M pairs + # checkpoint every + k = 25000 // romatch.STEP_SIZE + + # Data + mega = MegadepthBuilder(data_root="data/megadepth", loftr_ignore=True, imc21_ignore = True) + use_horizontal_flip_aug = True + normalize = False # don't imgnet normalize + rot_prob = 0 + depth_interpolation_mode = "bilinear" + megadepth_train1 = mega.build_scenes( + split="train_loftr", min_overlap=0.01, shake_t=32, use_horizontal_flip_aug = use_horizontal_flip_aug, rot_prob = rot_prob, + ht=h,wt=w, normalize = normalize + ) + megadepth_train2 = mega.build_scenes( + split="train_loftr", min_overlap=0.35, shake_t=32, use_horizontal_flip_aug = use_horizontal_flip_aug, rot_prob = rot_prob, + ht=h,wt=w, normalize = normalize + ) + megadepth_train = ConcatDataset(megadepth_train1 + megadepth_train2) + mega_ws = mega.weight_scenes(megadepth_train, alpha=0.75) + # Loss and optimizer + depth_loss = RobustLosses( + ce_weight=0.01, + local_dist={4:4}, + depth_interpolation_mode=depth_interpolation_mode, + alpha = {4:0.15, 8:0.15}, + c = 1e-4, + epe_mask_prob_th = 0.001, + ) + parameters = [ + {"params": model.parameters(), "lr": romatch.STEP_SIZE * 1e-4 / 8}, + ] + optimizer = torch.optim.AdamW(parameters, weight_decay=0.01) + lr_scheduler = torch.optim.lr_scheduler.MultiStepLR( + optimizer, milestones=[(9*N/romatch.STEP_SIZE)//10]) + #megadense_benchmark = MegadepthDenseBenchmark("data/megadepth", num_samples = 1000, h=h,w=w) + mega1500_benchmark = Mega1500PoseLibBenchmark("data/megadepth", num_ransac_iter = 1, test_every = 30) + + checkpointer = CheckPoint(checkpoint_dir, experiment_name) + model, optimizer, lr_scheduler, global_step = checkpointer.load(model, optimizer, lr_scheduler, global_step) + romatch.GLOBAL_STEP = global_step + grad_scaler = torch.cuda.amp.GradScaler(growth_interval=1_000_000) + grad_clip_norm = 0.01 + #megadense_benchmark.benchmark(model) + for n in range(romatch.GLOBAL_STEP, N, k * romatch.STEP_SIZE): + mega_sampler = torch.utils.data.WeightedRandomSampler( + mega_ws, num_samples = batch_size * k, replacement=False + ) + mega_dataloader = iter( + torch.utils.data.DataLoader( + megadepth_train, + batch_size = batch_size, + sampler = mega_sampler, + num_workers = 8, + ) + ) + train_k_steps( + n, k, mega_dataloader, model, depth_loss, optimizer, lr_scheduler, grad_scaler, grad_clip_norm = grad_clip_norm, + ) + checkpointer.save(model, optimizer, lr_scheduler, romatch.GLOBAL_STEP) + wandb.log(mega1500_benchmark.benchmark(model, model_name=experiment_name), step = romatch.GLOBAL_STEP) + +def test_mega_8_scenes(model, name): + mega_8_scenes_benchmark = MegaDepthPoseEstimationBenchmark("data/megadepth", + scene_names=['mega_8_scenes_0019_0.1_0.3.npz', + 'mega_8_scenes_0025_0.1_0.3.npz', + 'mega_8_scenes_0021_0.1_0.3.npz', + 'mega_8_scenes_0008_0.1_0.3.npz', + 'mega_8_scenes_0032_0.1_0.3.npz', + 'mega_8_scenes_1589_0.1_0.3.npz', + 'mega_8_scenes_0063_0.1_0.3.npz', + 'mega_8_scenes_0024_0.1_0.3.npz', + 'mega_8_scenes_0019_0.3_0.5.npz', + 'mega_8_scenes_0025_0.3_0.5.npz', + 'mega_8_scenes_0021_0.3_0.5.npz', + 'mega_8_scenes_0008_0.3_0.5.npz', + 'mega_8_scenes_0032_0.3_0.5.npz', + 'mega_8_scenes_1589_0.3_0.5.npz', + 'mega_8_scenes_0063_0.3_0.5.npz', + 'mega_8_scenes_0024_0.3_0.5.npz']) + mega_8_scenes_results = mega_8_scenes_benchmark.benchmark(model, model_name=name) + print(mega_8_scenes_results) + json.dump(mega_8_scenes_results, open(f"results/mega_8_scenes_{name}.json", "w")) + +def test_mega1500(model, name): + mega1500_benchmark = MegaDepthPoseEstimationBenchmark("data/megadepth") + mega1500_results = mega1500_benchmark.benchmark(model, model_name=name) + json.dump(mega1500_results, open(f"results/mega1500_{name}.json", "w")) + +def test_mega1500_poselib(model, name): + mega1500_benchmark = Mega1500PoseLibBenchmark("data/megadepth", num_ransac_iter = 1, test_every = 1) + mega1500_results = mega1500_benchmark.benchmark(model, model_name=name) + json.dump(mega1500_results, open(f"results/mega1500_poselib_{name}.json", "w")) + +def test_mega_8_scenes_poselib(model, name): + mega1500_benchmark = Mega1500PoseLibBenchmark("data/megadepth", num_ransac_iter = 1, test_every = 1, + scene_names=['mega_8_scenes_0019_0.1_0.3.npz', + 'mega_8_scenes_0025_0.1_0.3.npz', + 'mega_8_scenes_0021_0.1_0.3.npz', + 'mega_8_scenes_0008_0.1_0.3.npz', + 'mega_8_scenes_0032_0.1_0.3.npz', + 'mega_8_scenes_1589_0.1_0.3.npz', + 'mega_8_scenes_0063_0.1_0.3.npz', + 'mega_8_scenes_0024_0.1_0.3.npz', + 'mega_8_scenes_0019_0.3_0.5.npz', + 'mega_8_scenes_0025_0.3_0.5.npz', + 'mega_8_scenes_0021_0.3_0.5.npz', + 'mega_8_scenes_0008_0.3_0.5.npz', + 'mega_8_scenes_0032_0.3_0.5.npz', + 'mega_8_scenes_1589_0.3_0.5.npz', + 'mega_8_scenes_0063_0.3_0.5.npz', + 'mega_8_scenes_0024_0.3_0.5.npz']) + mega1500_results = mega1500_benchmark.benchmark(model, model_name=name) + json.dump(mega1500_results, open(f"results/mega_8_scenes_poselib_{name}.json", "w")) + +def test_scannet_poselib(model, name): + scannet_benchmark = ScanNetPoselibBenchmark("data/scannet") + scannet_results = scannet_benchmark.benchmark(model) + json.dump(scannet_results, open(f"results/scannet_{name}.json", "w")) + +def test_scannet(model, name): + scannet_benchmark = ScanNetBenchmark("data/scannet") + scannet_results = scannet_benchmark.benchmark(model) + json.dump(scannet_results, open(f"results/scannet_{name}.json", "w")) + +if __name__ == "__main__": + os.environ["TORCH_CUDNN_V8_API_ENABLED"] = "1" # For BF16 computations + os.environ["OMP_NUM_THREADS"] = "16" + torch.backends.cudnn.allow_tf32 = True # allow tf32 on cudnn + import romatch + parser = ArgumentParser() + parser.add_argument("--only_test", action='store_true') + parser.add_argument("--debug_mode", action='store_true') + parser.add_argument("--dont_log_wandb", action='store_true') + parser.add_argument("--train_resolution", default='medium') + parser.add_argument("--gpu_batch_size", default=8, type=int) + parser.add_argument("--wandb_entity", required = False) + + args, _ = parser.parse_known_args() + romatch.DEBUG_MODE = args.debug_mode + if not args.only_test: + train(args) + + experiment_name = "tiny_roma_v1_outdoor"#Path(__file__).stem + device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') + model = XFeatModel(freeze_xfeat=False, exact_softmax=False).to(device) + model.load_state_dict(torch.load(f"{experiment_name}.pth")) + test_mega1500_poselib(model, experiment_name) + \ No newline at end of file diff --git a/submodules/RoMa/requirements.txt b/submodules/RoMa/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..81360b228245bc573dba770458e4dbeb76d0dd9f --- /dev/null +++ b/submodules/RoMa/requirements.txt @@ -0,0 +1,14 @@ +torch +einops +torchvision +opencv-python +kornia +albumentations +loguru +tqdm +matplotlib +h5py +wandb +timm +poselib +#xformers # Optional, used for memefficient attention \ No newline at end of file diff --git a/submodules/RoMa/romatch/__init__.py b/submodules/RoMa/romatch/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..45c2aff7bb510b1d8dfcdc9c4d91ffc3aa5021f6 --- /dev/null +++ b/submodules/RoMa/romatch/__init__.py @@ -0,0 +1,8 @@ +import os +from .models import roma_outdoor, tiny_roma_v1_outdoor, roma_indoor + +DEBUG_MODE = False +RANK = int(os.environ.get('RANK', default = 0)) +GLOBAL_STEP = 0 +STEP_SIZE = 1 +LOCAL_RANK = -1 \ No newline at end of file diff --git a/submodules/RoMa/romatch/benchmarks/__init__.py b/submodules/RoMa/romatch/benchmarks/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..af32a46ba4a48d719e3ad38f9b2355a13fe6cc44 --- /dev/null +++ b/submodules/RoMa/romatch/benchmarks/__init__.py @@ -0,0 +1,6 @@ +from .hpatches_sequences_homog_benchmark import HpatchesHomogBenchmark +from .scannet_benchmark import ScanNetBenchmark +from .megadepth_pose_estimation_benchmark import MegaDepthPoseEstimationBenchmark +from .megadepth_dense_benchmark import MegadepthDenseBenchmark +from .megadepth_pose_estimation_benchmark_poselib import Mega1500PoseLibBenchmark +#from .scannet_benchmark_poselib import ScanNetPoselibBenchmark \ No newline at end of file diff --git a/submodules/RoMa/romatch/benchmarks/hpatches_sequences_homog_benchmark.py b/submodules/RoMa/romatch/benchmarks/hpatches_sequences_homog_benchmark.py new file mode 100644 index 0000000000000000000000000000000000000000..5972361f80d4f4e5cafd8fd359c87c0433a0a5a5 --- /dev/null +++ b/submodules/RoMa/romatch/benchmarks/hpatches_sequences_homog_benchmark.py @@ -0,0 +1,113 @@ +from PIL import Image +import numpy as np + +import os + +from tqdm import tqdm +from romatch.utils import pose_auc +import cv2 + + +class HpatchesHomogBenchmark: + """Hpatches grid goes from [0,n-1] instead of [0.5,n-0.5]""" + + def __init__(self, dataset_path) -> None: + seqs_dir = "hpatches-sequences-release" + self.seqs_path = os.path.join(dataset_path, seqs_dir) + self.seq_names = sorted(os.listdir(self.seqs_path)) + # Ignore seqs is same as LoFTR. + self.ignore_seqs = set( + [ + "i_contruction", + "i_crownnight", + "i_dc", + "i_pencils", + "i_whitebuilding", + "v_artisans", + "v_astronautis", + "v_talent", + ] + ) + + def convert_coordinates(self, im_A_coords, im_A_to_im_B, wq, hq, wsup, hsup): + offset = 0.5 # Hpatches assumes that the center of the top-left pixel is at [0,0] (I think) + im_A_coords = ( + np.stack( + ( + wq * (im_A_coords[..., 0] + 1) / 2, + hq * (im_A_coords[..., 1] + 1) / 2, + ), + axis=-1, + ) + - offset + ) + im_A_to_im_B = ( + np.stack( + ( + wsup * (im_A_to_im_B[..., 0] + 1) / 2, + hsup * (im_A_to_im_B[..., 1] + 1) / 2, + ), + axis=-1, + ) + - offset + ) + return im_A_coords, im_A_to_im_B + + def benchmark(self, model, model_name = None): + n_matches = [] + homog_dists = [] + for seq_idx, seq_name in tqdm( + enumerate(self.seq_names), total=len(self.seq_names) + ): + im_A_path = os.path.join(self.seqs_path, seq_name, "1.ppm") + im_A = Image.open(im_A_path) + w1, h1 = im_A.size + for im_idx in range(2, 7): + im_B_path = os.path.join(self.seqs_path, seq_name, f"{im_idx}.ppm") + im_B = Image.open(im_B_path) + w2, h2 = im_B.size + H = np.loadtxt( + os.path.join(self.seqs_path, seq_name, "H_1_" + str(im_idx)) + ) + dense_matches, dense_certainty = model.match( + im_A_path, im_B_path + ) + good_matches, _ = model.sample(dense_matches, dense_certainty, 5000) + pos_a, pos_b = self.convert_coordinates( + good_matches[:, :2], good_matches[:, 2:], w1, h1, w2, h2 + ) + try: + H_pred, inliers = cv2.findHomography( + pos_a, + pos_b, + method = cv2.RANSAC, + confidence = 0.99999, + ransacReprojThreshold = 3 * min(w2, h2) / 480, + ) + except: + H_pred = None + if H_pred is None: + H_pred = np.zeros((3, 3)) + H_pred[2, 2] = 1.0 + corners = np.array( + [[0, 0, 1], [0, h1 - 1, 1], [w1 - 1, 0, 1], [w1 - 1, h1 - 1, 1]] + ) + real_warped_corners = np.dot(corners, np.transpose(H)) + real_warped_corners = ( + real_warped_corners[:, :2] / real_warped_corners[:, 2:] + ) + warped_corners = np.dot(corners, np.transpose(H_pred)) + warped_corners = warped_corners[:, :2] / warped_corners[:, 2:] + mean_dist = np.mean( + np.linalg.norm(real_warped_corners - warped_corners, axis=1) + ) / (min(w2, h2) / 480.0) + homog_dists.append(mean_dist) + + n_matches = np.array(n_matches) + thresholds = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + auc = pose_auc(np.array(homog_dists), thresholds) + return { + "hpatches_homog_auc_3": auc[2], + "hpatches_homog_auc_5": auc[4], + "hpatches_homog_auc_10": auc[9], + } diff --git a/submodules/RoMa/romatch/benchmarks/megadepth_dense_benchmark.py b/submodules/RoMa/romatch/benchmarks/megadepth_dense_benchmark.py new file mode 100644 index 0000000000000000000000000000000000000000..09d0a297f2937afc609eed3a74aa0c3c4c7ccebc --- /dev/null +++ b/submodules/RoMa/romatch/benchmarks/megadepth_dense_benchmark.py @@ -0,0 +1,106 @@ +import torch +import numpy as np +import tqdm +from romatch.datasets import MegadepthBuilder +from romatch.utils import warp_kpts +from torch.utils.data import ConcatDataset +import romatch + +class MegadepthDenseBenchmark: + def __init__(self, data_root="data/megadepth", h = 384, w = 512, num_samples = 2000) -> None: + mega = MegadepthBuilder(data_root=data_root) + self.dataset = ConcatDataset( + mega.build_scenes(split="test_loftr", ht=h, wt=w) + ) # fixed resolution of 384,512 + self.num_samples = num_samples + + def geometric_dist(self, depth1, depth2, T_1to2, K1, K2, dense_matches): + b, h1, w1, d = dense_matches.shape + with torch.no_grad(): + x1 = dense_matches[..., :2].reshape(b, h1 * w1, 2) + mask, x2 = warp_kpts( + x1.double(), + depth1.double(), + depth2.double(), + T_1to2.double(), + K1.double(), + K2.double(), + ) + x2 = torch.stack( + (w1 * (x2[..., 0] + 1) / 2, h1 * (x2[..., 1] + 1) / 2), dim=-1 + ) + prob = mask.float().reshape(b, h1, w1) + x2_hat = dense_matches[..., 2:] + x2_hat = torch.stack( + (w1 * (x2_hat[..., 0] + 1) / 2, h1 * (x2_hat[..., 1] + 1) / 2), dim=-1 + ) + gd = (x2_hat - x2.reshape(b, h1, w1, 2)).norm(dim=-1) + gd = gd[prob == 1] + pck_1 = (gd < 1.0).float().mean() + pck_3 = (gd < 3.0).float().mean() + pck_5 = (gd < 5.0).float().mean() + return gd, pck_1, pck_3, pck_5, prob + + def benchmark(self, model, batch_size=8): + model.train(False) + with torch.no_grad(): + gd_tot = 0.0 + pck_1_tot = 0.0 + pck_3_tot = 0.0 + pck_5_tot = 0.0 + sampler = torch.utils.data.WeightedRandomSampler( + torch.ones(len(self.dataset)), replacement=False, num_samples=self.num_samples + ) + B = batch_size + dataloader = torch.utils.data.DataLoader( + self.dataset, batch_size=B, num_workers=batch_size, sampler=sampler + ) + for idx, data in tqdm.tqdm(enumerate(dataloader), disable = romatch.RANK > 0): + im_A, im_B, depth1, depth2, T_1to2, K1, K2 = ( + data["im_A"].cuda(), + data["im_B"].cuda(), + data["im_A_depth"].cuda(), + data["im_B_depth"].cuda(), + data["T_1to2"].cuda(), + data["K1"].cuda(), + data["K2"].cuda(), + ) + matches, certainty = model.match(im_A, im_B, batched=True) + gd, pck_1, pck_3, pck_5, prob = self.geometric_dist( + depth1, depth2, T_1to2, K1, K2, matches + ) + if romatch.DEBUG_MODE: + from romatch.utils.utils import tensor_to_pil + import torch.nn.functional as F + path = "vis" + H, W = model.get_output_resolution() + white_im = torch.ones((B,1,H,W),device="cuda") + im_B_transfer_rgb = F.grid_sample( + im_B.cuda(), matches[:,:,:W, 2:], mode="bilinear", align_corners=False + ) + warp_im = im_B_transfer_rgb + c_b = certainty[:,None]#(certainty*0.9 + 0.1*torch.ones_like(certainty))[:,None] + vis_im = c_b * warp_im + (1 - c_b) * white_im + for b in range(B): + import os + os.makedirs(f"{path}/{model.name}/{idx}_{b}_{H}_{W}",exist_ok=True) + tensor_to_pil(vis_im[b], unnormalize=True).save( + f"{path}/{model.name}/{idx}_{b}_{H}_{W}/warp.jpg") + tensor_to_pil(im_A[b].cuda(), unnormalize=True).save( + f"{path}/{model.name}/{idx}_{b}_{H}_{W}/im_A.jpg") + tensor_to_pil(im_B[b].cuda(), unnormalize=True).save( + f"{path}/{model.name}/{idx}_{b}_{H}_{W}/im_B.jpg") + + + gd_tot, pck_1_tot, pck_3_tot, pck_5_tot = ( + gd_tot + gd.mean(), + pck_1_tot + pck_1, + pck_3_tot + pck_3, + pck_5_tot + pck_5, + ) + return { + "epe": gd_tot.item() / len(dataloader), + "mega_pck_1": pck_1_tot.item() / len(dataloader), + "mega_pck_3": pck_3_tot.item() / len(dataloader), + "mega_pck_5": pck_5_tot.item() / len(dataloader), + } diff --git a/submodules/RoMa/romatch/benchmarks/megadepth_pose_estimation_benchmark.py b/submodules/RoMa/romatch/benchmarks/megadepth_pose_estimation_benchmark.py new file mode 100644 index 0000000000000000000000000000000000000000..36f293f9556d919643f6f39156314a5b402d9082 --- /dev/null +++ b/submodules/RoMa/romatch/benchmarks/megadepth_pose_estimation_benchmark.py @@ -0,0 +1,118 @@ +import numpy as np +import torch +from romatch.utils import * +from PIL import Image +from tqdm import tqdm +import torch.nn.functional as F +import romatch +import kornia.geometry.epipolar as kepi + +class MegaDepthPoseEstimationBenchmark: + def __init__(self, data_root="data/megadepth", scene_names = None) -> None: + if scene_names is None: + self.scene_names = [ + "0015_0.1_0.3.npz", + "0015_0.3_0.5.npz", + "0022_0.1_0.3.npz", + "0022_0.3_0.5.npz", + "0022_0.5_0.7.npz", + ] + else: + self.scene_names = scene_names + self.scenes = [ + np.load(f"{data_root}/{scene}", allow_pickle=True) + for scene in self.scene_names + ] + self.data_root = data_root + + def benchmark(self, model, model_name = None): + with torch.no_grad(): + data_root = self.data_root + tot_e_t, tot_e_R, tot_e_pose = [], [], [] + thresholds = [5, 10, 20] + for scene_ind in range(len(self.scenes)): + import os + scene_name = os.path.splitext(self.scene_names[scene_ind])[0] + scene = self.scenes[scene_ind] + pairs = scene["pair_infos"] + intrinsics = scene["intrinsics"] + poses = scene["poses"] + im_paths = scene["image_paths"] + pair_inds = range(len(pairs)) + for pairind in tqdm(pair_inds): + idx1, idx2 = pairs[pairind][0] + K1 = intrinsics[idx1].copy() + T1 = poses[idx1].copy() + R1, t1 = T1[:3, :3], T1[:3, 3] + K2 = intrinsics[idx2].copy() + T2 = poses[idx2].copy() + R2, t2 = T2[:3, :3], T2[:3, 3] + R, t = compute_relative_pose(R1, t1, R2, t2) + T1_to_2 = np.concatenate((R,t[:,None]), axis=-1) + im_A_path = f"{data_root}/{im_paths[idx1]}" + im_B_path = f"{data_root}/{im_paths[idx2]}" + dense_matches, dense_certainty = model.match( + im_A_path, im_B_path, K1.copy(), K2.copy(), T1_to_2.copy() + ) + sparse_matches,_ = model.sample( + dense_matches, dense_certainty, 5_000 + ) + + im_A = Image.open(im_A_path) + w1, h1 = im_A.size + im_B = Image.open(im_B_path) + w2, h2 = im_B.size + if True: # Note: we keep this true as it was used in DKM/RoMa papers. There is very little difference compared to setting to False. + scale1 = 1200 / max(w1, h1) + scale2 = 1200 / max(w2, h2) + w1, h1 = scale1 * w1, scale1 * h1 + w2, h2 = scale2 * w2, scale2 * h2 + K1, K2 = K1.copy(), K2.copy() + K1[:2] = K1[:2] * scale1 + K2[:2] = K2[:2] * scale2 + + kpts1, kpts2 = model.to_pixel_coordinates(sparse_matches, h1, w1, h2, w2) + kpts1, kpts2 = kpts1.cpu().numpy(), kpts2.cpu().numpy() + for _ in range(5): + shuffling = np.random.permutation(np.arange(len(kpts1))) + kpts1 = kpts1[shuffling] + kpts2 = kpts2[shuffling] + try: + threshold = 0.5 + norm_threshold = threshold / (np.mean(np.abs(K1[:2, :2])) + np.mean(np.abs(K2[:2, :2]))) + R_est, t_est, mask = estimate_pose( + kpts1, + kpts2, + K1, + K2, + norm_threshold, + conf=0.99999, + ) + T1_to_2_est = np.concatenate((R_est, t_est), axis=-1) # + e_t, e_R = compute_pose_error(T1_to_2_est, R, t) + e_pose = max(e_t, e_R) + except Exception as e: + print(repr(e)) + e_t, e_R = 90, 90 + e_pose = max(e_t, e_R) + tot_e_t.append(e_t) + tot_e_R.append(e_R) + tot_e_pose.append(e_pose) + tot_e_pose = np.array(tot_e_pose) + auc = pose_auc(tot_e_pose, thresholds) + acc_5 = (tot_e_pose < 5).mean() + acc_10 = (tot_e_pose < 10).mean() + acc_15 = (tot_e_pose < 15).mean() + acc_20 = (tot_e_pose < 20).mean() + map_5 = acc_5 + map_10 = np.mean([acc_5, acc_10]) + map_20 = np.mean([acc_5, acc_10, acc_15, acc_20]) + print(f"{model_name} auc: {auc}") + return { + "auc_5": auc[0], + "auc_10": auc[1], + "auc_20": auc[2], + "map_5": map_5, + "map_10": map_10, + "map_20": map_20, + } diff --git a/submodules/RoMa/romatch/benchmarks/megadepth_pose_estimation_benchmark_poselib.py b/submodules/RoMa/romatch/benchmarks/megadepth_pose_estimation_benchmark_poselib.py new file mode 100644 index 0000000000000000000000000000000000000000..4732ccf2af5b50e6db60831d7c63c5bf70ec727c --- /dev/null +++ b/submodules/RoMa/romatch/benchmarks/megadepth_pose_estimation_benchmark_poselib.py @@ -0,0 +1,119 @@ +import numpy as np +import torch +from romatch.utils import * +from PIL import Image +from tqdm import tqdm +import torch.nn.functional as F +import romatch +import kornia.geometry.epipolar as kepi + +# wrap cause pyposelib is still in dev +# will add in deps later +import poselib + +class Mega1500PoseLibBenchmark: + def __init__(self, data_root="data/megadepth", scene_names = None, num_ransac_iter = 5, test_every = 1) -> None: + if scene_names is None: + self.scene_names = [ + "0015_0.1_0.3.npz", + "0015_0.3_0.5.npz", + "0022_0.1_0.3.npz", + "0022_0.3_0.5.npz", + "0022_0.5_0.7.npz", + ] + else: + self.scene_names = scene_names + self.scenes = [ + np.load(f"{data_root}/{scene}", allow_pickle=True) + for scene in self.scene_names + ] + self.data_root = data_root + self.num_ransac_iter = num_ransac_iter + self.test_every = test_every + + def benchmark(self, model, model_name = None): + with torch.no_grad(): + data_root = self.data_root + tot_e_t, tot_e_R, tot_e_pose = [], [], [] + thresholds = [5, 10, 20] + for scene_ind in range(len(self.scenes)): + import os + scene_name = os.path.splitext(self.scene_names[scene_ind])[0] + scene = self.scenes[scene_ind] + pairs = scene["pair_infos"] + intrinsics = scene["intrinsics"] + poses = scene["poses"] + im_paths = scene["image_paths"] + pair_inds = range(len(pairs))[::self.test_every] + for pairind in (pbar := tqdm(pair_inds, desc = "Current AUC: ?")): + idx1, idx2 = pairs[pairind][0] + K1 = intrinsics[idx1].copy() + T1 = poses[idx1].copy() + R1, t1 = T1[:3, :3], T1[:3, 3] + K2 = intrinsics[idx2].copy() + T2 = poses[idx2].copy() + R2, t2 = T2[:3, :3], T2[:3, 3] + R, t = compute_relative_pose(R1, t1, R2, t2) + T1_to_2 = np.concatenate((R,t[:,None]), axis=-1) + im_A_path = f"{data_root}/{im_paths[idx1]}" + im_B_path = f"{data_root}/{im_paths[idx2]}" + dense_matches, dense_certainty = model.match( + im_A_path, im_B_path, K1.copy(), K2.copy(), T1_to_2.copy() + ) + sparse_matches,_ = model.sample( + dense_matches, dense_certainty, 5_000 + ) + + im_A = Image.open(im_A_path) + w1, h1 = im_A.size + im_B = Image.open(im_B_path) + w2, h2 = im_B.size + kpts1, kpts2 = model.to_pixel_coordinates(sparse_matches, h1, w1, h2, w2) + kpts1, kpts2 = kpts1.cpu().numpy(), kpts2.cpu().numpy() + for _ in range(self.num_ransac_iter): + shuffling = np.random.permutation(np.arange(len(kpts1))) + kpts1 = kpts1[shuffling] + kpts2 = kpts2[shuffling] + try: + threshold = 1 + camera1 = {'model': 'PINHOLE', 'width': w1, 'height': h1, 'params': K1[[0,1,0,1], [0,1,2,2]]} + camera2 = {'model': 'PINHOLE', 'width': w2, 'height': h2, 'params': K2[[0,1,0,1], [0,1,2,2]]} + relpose, res = poselib.estimate_relative_pose( + kpts1, + kpts2, + camera1, + camera2, + ransac_opt = {"max_reproj_error": 2*threshold, "max_epipolar_error": threshold, "min_inliers": 8, "max_iterations": 10_000}, + ) + Rt_est = relpose.Rt + R_est, t_est = Rt_est[:3,:3], Rt_est[:3,3:] + mask = np.array(res['inliers']).astype(np.float32) + T1_to_2_est = np.concatenate((R_est, t_est), axis=-1) # + e_t, e_R = compute_pose_error(T1_to_2_est, R, t) + e_pose = max(e_t, e_R) + except Exception as e: + print(repr(e)) + e_t, e_R = 90, 90 + e_pose = max(e_t, e_R) + tot_e_t.append(e_t) + tot_e_R.append(e_R) + tot_e_pose.append(e_pose) + pbar.set_description(f"Current AUC: {pose_auc(tot_e_pose, thresholds)}") + tot_e_pose = np.array(tot_e_pose) + auc = pose_auc(tot_e_pose, thresholds) + acc_5 = (tot_e_pose < 5).mean() + acc_10 = (tot_e_pose < 10).mean() + acc_15 = (tot_e_pose < 15).mean() + acc_20 = (tot_e_pose < 20).mean() + map_5 = acc_5 + map_10 = np.mean([acc_5, acc_10]) + map_20 = np.mean([acc_5, acc_10, acc_15, acc_20]) + print(f"{model_name} auc: {auc}") + return { + "auc_5": auc[0], + "auc_10": auc[1], + "auc_20": auc[2], + "map_5": map_5, + "map_10": map_10, + "map_20": map_20, + } diff --git a/submodules/RoMa/romatch/benchmarks/scannet_benchmark.py b/submodules/RoMa/romatch/benchmarks/scannet_benchmark.py new file mode 100644 index 0000000000000000000000000000000000000000..8c6b3c0eeb1c211d224edde84974529c66b52460 --- /dev/null +++ b/submodules/RoMa/romatch/benchmarks/scannet_benchmark.py @@ -0,0 +1,143 @@ +import os.path as osp +import numpy as np +import torch +from romatch.utils import * +from PIL import Image +from tqdm import tqdm + + +class ScanNetBenchmark: + def __init__(self, data_root="data/scannet") -> None: + self.data_root = data_root + + def benchmark(self, model, model_name = None): + model.train(False) + with torch.no_grad(): + data_root = self.data_root + tmp = np.load(osp.join(data_root, "test.npz")) + pairs, rel_pose = tmp["name"], tmp["rel_pose"] + tot_e_t, tot_e_R, tot_e_pose = [], [], [] + pair_inds = np.random.choice( + range(len(pairs)), size=len(pairs), replace=False + ) + for pairind in tqdm(pair_inds, smoothing=0.9): + scene = pairs[pairind] + scene_name = f"scene0{scene[0]}_00" + im_A_path = osp.join( + self.data_root, + "scans_test", + scene_name, + "color", + f"{scene[2]}.jpg", + ) + im_A = Image.open(im_A_path) + im_B_path = osp.join( + self.data_root, + "scans_test", + scene_name, + "color", + f"{scene[3]}.jpg", + ) + im_B = Image.open(im_B_path) + T_gt = rel_pose[pairind].reshape(3, 4) + R, t = T_gt[:3, :3], T_gt[:3, 3] + K = np.stack( + [ + np.array([float(i) for i in r.split()]) + for r in open( + osp.join( + self.data_root, + "scans_test", + scene_name, + "intrinsic", + "intrinsic_color.txt", + ), + "r", + ) + .read() + .split("\n") + if r + ] + ) + w1, h1 = im_A.size + w2, h2 = im_B.size + K1 = K.copy() + K2 = K.copy() + dense_matches, dense_certainty = model.match(im_A_path, im_B_path) + sparse_matches, sparse_certainty = model.sample( + dense_matches, dense_certainty, 5000 + ) + scale1 = 480 / min(w1, h1) + scale2 = 480 / min(w2, h2) + w1, h1 = scale1 * w1, scale1 * h1 + w2, h2 = scale2 * w2, scale2 * h2 + K1 = K1 * scale1 + K2 = K2 * scale2 + + offset = 0.5 + kpts1 = sparse_matches[:, :2] + kpts1 = ( + np.stack( + ( + w1 * (kpts1[:, 0] + 1) / 2 - offset, + h1 * (kpts1[:, 1] + 1) / 2 - offset, + ), + axis=-1, + ) + ) + kpts2 = sparse_matches[:, 2:] + kpts2 = ( + np.stack( + ( + w2 * (kpts2[:, 0] + 1) / 2 - offset, + h2 * (kpts2[:, 1] + 1) / 2 - offset, + ), + axis=-1, + ) + ) + for _ in range(5): + shuffling = np.random.permutation(np.arange(len(kpts1))) + kpts1 = kpts1[shuffling] + kpts2 = kpts2[shuffling] + try: + norm_threshold = 0.5 / ( + np.mean(np.abs(K1[:2, :2])) + np.mean(np.abs(K2[:2, :2]))) + R_est, t_est, mask = estimate_pose( + kpts1, + kpts2, + K1, + K2, + norm_threshold, + conf=0.99999, + ) + T1_to_2_est = np.concatenate((R_est, t_est), axis=-1) # + e_t, e_R = compute_pose_error(T1_to_2_est, R, t) + e_pose = max(e_t, e_R) + except Exception as e: + print(repr(e)) + e_t, e_R = 90, 90 + e_pose = max(e_t, e_R) + tot_e_t.append(e_t) + tot_e_R.append(e_R) + tot_e_pose.append(e_pose) + tot_e_t.append(e_t) + tot_e_R.append(e_R) + tot_e_pose.append(e_pose) + tot_e_pose = np.array(tot_e_pose) + thresholds = [5, 10, 20] + auc = pose_auc(tot_e_pose, thresholds) + acc_5 = (tot_e_pose < 5).mean() + acc_10 = (tot_e_pose < 10).mean() + acc_15 = (tot_e_pose < 15).mean() + acc_20 = (tot_e_pose < 20).mean() + map_5 = acc_5 + map_10 = np.mean([acc_5, acc_10]) + map_20 = np.mean([acc_5, acc_10, acc_15, acc_20]) + return { + "auc_5": auc[0], + "auc_10": auc[1], + "auc_20": auc[2], + "map_5": map_5, + "map_10": map_10, + "map_20": map_20, + } diff --git a/submodules/RoMa/romatch/checkpointing/__init__.py b/submodules/RoMa/romatch/checkpointing/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..22f5afe727aa6f6e8fffa9ecf5be69cbff686577 --- /dev/null +++ b/submodules/RoMa/romatch/checkpointing/__init__.py @@ -0,0 +1 @@ +from .checkpoint import CheckPoint diff --git a/submodules/RoMa/romatch/checkpointing/checkpoint.py b/submodules/RoMa/romatch/checkpointing/checkpoint.py new file mode 100644 index 0000000000000000000000000000000000000000..ab5a5131322241475323f1b992d9d3f7b21dbdac --- /dev/null +++ b/submodules/RoMa/romatch/checkpointing/checkpoint.py @@ -0,0 +1,60 @@ +import os +import torch +from torch.nn.parallel.data_parallel import DataParallel +from torch.nn.parallel.distributed import DistributedDataParallel +from loguru import logger +import gc + +import romatch + +class CheckPoint: + def __init__(self, dir=None, name="tmp"): + self.name = name + self.dir = dir + os.makedirs(self.dir, exist_ok=True) + + def save( + self, + model, + optimizer, + lr_scheduler, + n, + ): + if romatch.RANK == 0: + assert model is not None + if isinstance(model, (DataParallel, DistributedDataParallel)): + model = model.module + states = { + "model": model.state_dict(), + "n": n, + "optimizer": optimizer.state_dict(), + "lr_scheduler": lr_scheduler.state_dict(), + } + torch.save(states, self.dir + self.name + f"_latest.pth") + logger.info(f"Saved states {list(states.keys())}, at step {n}") + + def load( + self, + model, + optimizer, + lr_scheduler, + n, + ): + if os.path.exists(self.dir + self.name + f"_latest.pth") and romatch.RANK == 0: + states = torch.load(self.dir + self.name + f"_latest.pth") + if "model" in states: + model.load_state_dict(states["model"]) + if "n" in states: + n = states["n"] if states["n"] else n + if "optimizer" in states: + try: + optimizer.load_state_dict(states["optimizer"]) + except Exception as e: + print(f"Failed to load states for optimizer, with error {e}") + if "lr_scheduler" in states: + lr_scheduler.load_state_dict(states["lr_scheduler"]) + print(f"Loaded states {list(states.keys())}, at step {n}") + del states + gc.collect() + torch.cuda.empty_cache() + return model, optimizer, lr_scheduler, n \ No newline at end of file diff --git a/submodules/RoMa/romatch/datasets/__init__.py b/submodules/RoMa/romatch/datasets/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..b60c709926a4a7bd019b73eac10879063a996c90 --- /dev/null +++ b/submodules/RoMa/romatch/datasets/__init__.py @@ -0,0 +1,2 @@ +from .megadepth import MegadepthBuilder +from .scannet import ScanNetBuilder \ No newline at end of file diff --git a/submodules/RoMa/romatch/datasets/megadepth.py b/submodules/RoMa/romatch/datasets/megadepth.py new file mode 100644 index 0000000000000000000000000000000000000000..88f775ef412f7bd062cc9a1d67d95a030e7a15dd --- /dev/null +++ b/submodules/RoMa/romatch/datasets/megadepth.py @@ -0,0 +1,232 @@ +import os +from PIL import Image +import h5py +import numpy as np +import torch +import torchvision.transforms.functional as tvf +import kornia.augmentation as K +from romatch.utils import get_depth_tuple_transform_ops, get_tuple_transform_ops +import romatch +from romatch.utils import * +import math + +class MegadepthScene: + def __init__( + self, + data_root, + scene_info, + ht=384, + wt=512, + min_overlap=0.0, + max_overlap=1.0, + shake_t=0, + rot_prob=0.0, + normalize=True, + max_num_pairs = 100_000, + scene_name = None, + use_horizontal_flip_aug = False, + use_single_horizontal_flip_aug = False, + colorjiggle_params = None, + random_eraser = None, + use_randaug = False, + randaug_params = None, + randomize_size = False, + ) -> None: + self.data_root = data_root + self.scene_name = os.path.splitext(scene_name)[0]+f"_{min_overlap}_{max_overlap}" + self.image_paths = scene_info["image_paths"] + self.depth_paths = scene_info["depth_paths"] + self.intrinsics = scene_info["intrinsics"] + self.poses = scene_info["poses"] + self.pairs = scene_info["pairs"] + self.overlaps = scene_info["overlaps"] + threshold = (self.overlaps > min_overlap) & (self.overlaps < max_overlap) + self.pairs = self.pairs[threshold] + self.overlaps = self.overlaps[threshold] + if len(self.pairs) > max_num_pairs: + pairinds = np.random.choice( + np.arange(0, len(self.pairs)), max_num_pairs, replace=False + ) + self.pairs = self.pairs[pairinds] + self.overlaps = self.overlaps[pairinds] + if randomize_size: + area = ht * wt + s = int(16 * (math.sqrt(area)//16)) + sizes = ((ht,wt), (s,s), (wt,ht)) + choice = romatch.RANK % 3 + ht, wt = sizes[choice] + # counts, bins = np.histogram(self.overlaps,20) + # print(counts) + self.im_transform_ops = get_tuple_transform_ops( + resize=(ht, wt), normalize=normalize, colorjiggle_params = colorjiggle_params, + ) + self.depth_transform_ops = get_depth_tuple_transform_ops( + resize=(ht, wt) + ) + self.wt, self.ht = wt, ht + self.shake_t = shake_t + self.random_eraser = random_eraser + if use_horizontal_flip_aug and use_single_horizontal_flip_aug: + raise ValueError("Can't both flip both images and only flip one") + self.use_horizontal_flip_aug = use_horizontal_flip_aug + self.use_single_horizontal_flip_aug = use_single_horizontal_flip_aug + self.use_randaug = use_randaug + + def load_im(self, im_path): + im = Image.open(im_path) + return im + + def horizontal_flip(self, im_A, im_B, depth_A, depth_B, K_A, K_B): + im_A = im_A.flip(-1) + im_B = im_B.flip(-1) + depth_A, depth_B = depth_A.flip(-1), depth_B.flip(-1) + flip_mat = torch.tensor([[-1, 0, self.wt],[0,1,0],[0,0,1.]]).to(K_A.device) + K_A = flip_mat@K_A + K_B = flip_mat@K_B + + return im_A, im_B, depth_A, depth_B, K_A, K_B + + def load_depth(self, depth_ref, crop=None): + depth = np.array(h5py.File(depth_ref, "r")["depth"]) + return torch.from_numpy(depth) + + def __len__(self): + return len(self.pairs) + + def scale_intrinsic(self, K, wi, hi): + sx, sy = self.wt / wi, self.ht / hi + sK = torch.tensor([[sx, 0, 0], [0, sy, 0], [0, 0, 1]]) + return sK @ K + + def rand_shake(self, *things): + t = np.random.choice(range(-self.shake_t, self.shake_t + 1), size=2) + return [ + tvf.affine(thing, angle=0.0, translate=list(t), scale=1.0, shear=[0.0, 0.0]) + for thing in things + ], t + + def __getitem__(self, pair_idx): + # read intrinsics of original size + idx1, idx2 = self.pairs[pair_idx] + K1 = torch.tensor(self.intrinsics[idx1].copy(), dtype=torch.float).reshape(3, 3) + K2 = torch.tensor(self.intrinsics[idx2].copy(), dtype=torch.float).reshape(3, 3) + + # read and compute relative poses + T1 = self.poses[idx1] + T2 = self.poses[idx2] + T_1to2 = torch.tensor(np.matmul(T2, np.linalg.inv(T1)), dtype=torch.float)[ + :4, :4 + ] # (4, 4) + + # Load positive pair data + im_A, im_B = self.image_paths[idx1], self.image_paths[idx2] + depth1, depth2 = self.depth_paths[idx1], self.depth_paths[idx2] + im_A_ref = os.path.join(self.data_root, im_A) + im_B_ref = os.path.join(self.data_root, im_B) + depth_A_ref = os.path.join(self.data_root, depth1) + depth_B_ref = os.path.join(self.data_root, depth2) + im_A = self.load_im(im_A_ref) + im_B = self.load_im(im_B_ref) + K1 = self.scale_intrinsic(K1, im_A.width, im_A.height) + K2 = self.scale_intrinsic(K2, im_B.width, im_B.height) + + if self.use_randaug: + im_A, im_B = self.rand_augment(im_A, im_B) + + depth_A = self.load_depth(depth_A_ref) + depth_B = self.load_depth(depth_B_ref) + # Process images + im_A, im_B = self.im_transform_ops((im_A, im_B)) + depth_A, depth_B = self.depth_transform_ops( + (depth_A[None, None], depth_B[None, None]) + ) + + [im_A, im_B, depth_A, depth_B], t = self.rand_shake(im_A, im_B, depth_A, depth_B) + K1[:2, 2] += t + K2[:2, 2] += t + + im_A, im_B = im_A[None], im_B[None] + if self.random_eraser is not None: + im_A, depth_A = self.random_eraser(im_A, depth_A) + im_B, depth_B = self.random_eraser(im_B, depth_B) + + if self.use_horizontal_flip_aug: + if np.random.rand() > 0.5: + im_A, im_B, depth_A, depth_B, K1, K2 = self.horizontal_flip(im_A, im_B, depth_A, depth_B, K1, K2) + if self.use_single_horizontal_flip_aug: + if np.random.rand() > 0.5: + im_B, depth_B, K2 = self.single_horizontal_flip(im_B, depth_B, K2) + + if romatch.DEBUG_MODE: + tensor_to_pil(im_A[0], unnormalize=True).save( + f"vis/im_A.jpg") + tensor_to_pil(im_B[0], unnormalize=True).save( + f"vis/im_B.jpg") + + data_dict = { + "im_A": im_A[0], + "im_A_identifier": self.image_paths[idx1].split("/")[-1].split(".jpg")[0], + "im_B": im_B[0], + "im_B_identifier": self.image_paths[idx2].split("/")[-1].split(".jpg")[0], + "im_A_depth": depth_A[0, 0], + "im_B_depth": depth_B[0, 0], + "K1": K1, + "K2": K2, + "T_1to2": T_1to2, + "im_A_path": im_A_ref, + "im_B_path": im_B_ref, + + } + return data_dict + + +class MegadepthBuilder: + def __init__(self, data_root="data/megadepth", loftr_ignore=True, imc21_ignore = True) -> None: + self.data_root = data_root + self.scene_info_root = os.path.join(data_root, "prep_scene_info") + self.all_scenes = os.listdir(self.scene_info_root) + self.test_scenes = ["0017.npy", "0004.npy", "0048.npy", "0013.npy"] + # LoFTR did the D2-net preprocessing differently than we did and got more ignore scenes, can optionially ignore those + self.loftr_ignore_scenes = set(['0121.npy', '0133.npy', '0168.npy', '0178.npy', '0229.npy', '0349.npy', '0412.npy', '0430.npy', '0443.npy', '1001.npy', '5014.npy', '5015.npy', '5016.npy']) + self.imc21_scenes = set(['0008.npy', '0019.npy', '0021.npy', '0024.npy', '0025.npy', '0032.npy', '0063.npy', '1589.npy']) + self.test_scenes_loftr = ["0015.npy", "0022.npy"] + self.loftr_ignore = loftr_ignore + self.imc21_ignore = imc21_ignore + + def build_scenes(self, split="train", min_overlap=0.0, scene_names = None, **kwargs): + if split == "train": + scene_names = set(self.all_scenes) - set(self.test_scenes) + elif split == "train_loftr": + scene_names = set(self.all_scenes) - set(self.test_scenes_loftr) + elif split == "test": + scene_names = self.test_scenes + elif split == "test_loftr": + scene_names = self.test_scenes_loftr + elif split == "custom": + scene_names = scene_names + else: + raise ValueError(f"Split {split} not available") + scenes = [] + for scene_name in scene_names: + if self.loftr_ignore and scene_name in self.loftr_ignore_scenes: + continue + if self.imc21_ignore and scene_name in self.imc21_scenes: + continue + if ".npy" not in scene_name: + continue + scene_info = np.load( + os.path.join(self.scene_info_root, scene_name), allow_pickle=True + ).item() + scenes.append( + MegadepthScene( + self.data_root, scene_info, min_overlap=min_overlap,scene_name = scene_name, **kwargs + ) + ) + return scenes + + def weight_scenes(self, concat_dataset, alpha=0.5): + ns = [] + for d in concat_dataset.datasets: + ns.append(len(d)) + ws = torch.cat([torch.ones(n) / n**alpha for n in ns]) + return ws diff --git a/submodules/RoMa/romatch/datasets/scannet.py b/submodules/RoMa/romatch/datasets/scannet.py new file mode 100644 index 0000000000000000000000000000000000000000..e03261557147cd3449c76576a5e5e22c0ae288e9 --- /dev/null +++ b/submodules/RoMa/romatch/datasets/scannet.py @@ -0,0 +1,160 @@ +import os +import random +from PIL import Image +import cv2 +import h5py +import numpy as np +import torch +from torch.utils.data import ( + Dataset, + DataLoader, + ConcatDataset) + +import torchvision.transforms.functional as tvf +import kornia.augmentation as K +import os.path as osp +import matplotlib.pyplot as plt +import romatch +from romatch.utils import get_depth_tuple_transform_ops, get_tuple_transform_ops +from romatch.utils.transforms import GeometricSequential +from tqdm import tqdm + +class ScanNetScene: + def __init__(self, data_root, scene_info, ht = 384, wt = 512, min_overlap=0., shake_t = 0, rot_prob=0.,use_horizontal_flip_aug = False, +) -> None: + self.scene_root = osp.join(data_root,"scans","scans_train") + self.data_names = scene_info['name'] + self.overlaps = scene_info['score'] + # Only sample 10s + valid = (self.data_names[:,-2:] % 10).sum(axis=-1) == 0 + self.overlaps = self.overlaps[valid] + self.data_names = self.data_names[valid] + if len(self.data_names) > 10000: + pairinds = np.random.choice(np.arange(0,len(self.data_names)),10000,replace=False) + self.data_names = self.data_names[pairinds] + self.overlaps = self.overlaps[pairinds] + self.im_transform_ops = get_tuple_transform_ops(resize=(ht, wt), normalize=True) + self.depth_transform_ops = get_depth_tuple_transform_ops(resize=(ht, wt), normalize=False) + self.wt, self.ht = wt, ht + self.shake_t = shake_t + self.H_generator = GeometricSequential(K.RandomAffine(degrees=90, p=rot_prob)) + self.use_horizontal_flip_aug = use_horizontal_flip_aug + + def load_im(self, im_B, crop=None): + im = Image.open(im_B) + return im + + def load_depth(self, depth_ref, crop=None): + depth = cv2.imread(str(depth_ref), cv2.IMREAD_UNCHANGED) + depth = depth / 1000 + depth = torch.from_numpy(depth).float() # (h, w) + return depth + + def __len__(self): + return len(self.data_names) + + def scale_intrinsic(self, K, wi, hi): + sx, sy = self.wt / wi, self.ht / hi + sK = torch.tensor([[sx, 0, 0], + [0, sy, 0], + [0, 0, 1]]) + return sK@K + + def horizontal_flip(self, im_A, im_B, depth_A, depth_B, K_A, K_B): + im_A = im_A.flip(-1) + im_B = im_B.flip(-1) + depth_A, depth_B = depth_A.flip(-1), depth_B.flip(-1) + flip_mat = torch.tensor([[-1, 0, self.wt],[0,1,0],[0,0,1.]]).to(K_A.device) + K_A = flip_mat@K_A + K_B = flip_mat@K_B + + return im_A, im_B, depth_A, depth_B, K_A, K_B + def read_scannet_pose(self,path): + """ Read ScanNet's Camera2World pose and transform it to World2Camera. + + Returns: + pose_w2c (np.ndarray): (4, 4) + """ + cam2world = np.loadtxt(path, delimiter=' ') + world2cam = np.linalg.inv(cam2world) + return world2cam + + + def read_scannet_intrinsic(self,path): + """ Read ScanNet's intrinsic matrix and return the 3x3 matrix. + """ + intrinsic = np.loadtxt(path, delimiter=' ') + return torch.tensor(intrinsic[:-1, :-1], dtype = torch.float) + + def __getitem__(self, pair_idx): + # read intrinsics of original size + data_name = self.data_names[pair_idx] + scene_name, scene_sub_name, stem_name_1, stem_name_2 = data_name + scene_name = f'scene{scene_name:04d}_{scene_sub_name:02d}' + + # read the intrinsic of depthmap + K1 = K2 = self.read_scannet_intrinsic(osp.join(self.scene_root, + scene_name, + 'intrinsic', 'intrinsic_color.txt'))#the depth K is not the same, but doesnt really matter + # read and compute relative poses + T1 = self.read_scannet_pose(osp.join(self.scene_root, + scene_name, + 'pose', f'{stem_name_1}.txt')) + T2 = self.read_scannet_pose(osp.join(self.scene_root, + scene_name, + 'pose', f'{stem_name_2}.txt')) + T_1to2 = torch.tensor(np.matmul(T2, np.linalg.inv(T1)), dtype=torch.float)[:4, :4] # (4, 4) + + # Load positive pair data + im_A_ref = os.path.join(self.scene_root, scene_name, 'color', f'{stem_name_1}.jpg') + im_B_ref = os.path.join(self.scene_root, scene_name, 'color', f'{stem_name_2}.jpg') + depth_A_ref = os.path.join(self.scene_root, scene_name, 'depth', f'{stem_name_1}.png') + depth_B_ref = os.path.join(self.scene_root, scene_name, 'depth', f'{stem_name_2}.png') + + im_A = self.load_im(im_A_ref) + im_B = self.load_im(im_B_ref) + depth_A = self.load_depth(depth_A_ref) + depth_B = self.load_depth(depth_B_ref) + + # Recompute camera intrinsic matrix due to the resize + K1 = self.scale_intrinsic(K1, im_A.width, im_A.height) + K2 = self.scale_intrinsic(K2, im_B.width, im_B.height) + # Process images + im_A, im_B = self.im_transform_ops((im_A, im_B)) + depth_A, depth_B = self.depth_transform_ops((depth_A[None,None], depth_B[None,None])) + if self.use_horizontal_flip_aug: + if np.random.rand() > 0.5: + im_A, im_B, depth_A, depth_B, K1, K2 = self.horizontal_flip(im_A, im_B, depth_A, depth_B, K1, K2) + + data_dict = {'im_A': im_A, + 'im_B': im_B, + 'im_A_depth': depth_A[0,0], + 'im_B_depth': depth_B[0,0], + 'K1': K1, + 'K2': K2, + 'T_1to2':T_1to2, + } + return data_dict + + +class ScanNetBuilder: + def __init__(self, data_root = 'data/scannet') -> None: + self.data_root = data_root + self.scene_info_root = os.path.join(data_root,'scannet_indices') + self.all_scenes = os.listdir(self.scene_info_root) + + def build_scenes(self, split = 'train', min_overlap=0., **kwargs): + # Note: split doesn't matter here as we always use same scannet_train scenes + scene_names = self.all_scenes + scenes = [] + for scene_name in tqdm(scene_names, disable = romatch.RANK > 0): + scene_info = np.load(os.path.join(self.scene_info_root,scene_name), allow_pickle=True) + scenes.append(ScanNetScene(self.data_root, scene_info, min_overlap=min_overlap, **kwargs)) + return scenes + + def weight_scenes(self, concat_dataset, alpha=.5): + ns = [] + for d in concat_dataset.datasets: + ns.append(len(d)) + ws = torch.cat([torch.ones(n)/n**alpha for n in ns]) + return ws diff --git a/submodules/RoMa/romatch/losses/__init__.py b/submodules/RoMa/romatch/losses/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..2e08abacfc0f83d7de0f2ddc0583766a80bf53cf --- /dev/null +++ b/submodules/RoMa/romatch/losses/__init__.py @@ -0,0 +1 @@ +from .robust_loss import RobustLosses \ No newline at end of file diff --git a/submodules/RoMa/romatch/losses/robust_loss.py b/submodules/RoMa/romatch/losses/robust_loss.py new file mode 100644 index 0000000000000000000000000000000000000000..80d430069666fabe2471ec7eda2fa6e9c996f041 --- /dev/null +++ b/submodules/RoMa/romatch/losses/robust_loss.py @@ -0,0 +1,161 @@ +from einops.einops import rearrange +import torch +import torch.nn as nn +import torch.nn.functional as F +from romatch.utils.utils import get_gt_warp +import wandb +import romatch +import math + +class RobustLosses(nn.Module): + def __init__( + self, + robust=False, + center_coords=False, + scale_normalize=False, + ce_weight=0.01, + local_loss=True, + local_dist=4.0, + local_largest_scale=8, + smooth_mask = False, + depth_interpolation_mode = "bilinear", + mask_depth_loss = False, + relative_depth_error_threshold = 0.05, + alpha = 1., + c = 1e-3, + ): + super().__init__() + self.robust = robust # measured in pixels + self.center_coords = center_coords + self.scale_normalize = scale_normalize + self.ce_weight = ce_weight + self.local_loss = local_loss + self.local_dist = local_dist + self.local_largest_scale = local_largest_scale + self.smooth_mask = smooth_mask + self.depth_interpolation_mode = depth_interpolation_mode + self.mask_depth_loss = mask_depth_loss + self.relative_depth_error_threshold = relative_depth_error_threshold + self.avg_overlap = dict() + self.alpha = alpha + self.c = c + + def gm_cls_loss(self, x2, prob, scale_gm_cls, gm_certainty, scale): + with torch.no_grad(): + B, C, H, W = scale_gm_cls.shape + device = x2.device + cls_res = round(math.sqrt(C)) + G = torch.meshgrid(*[torch.linspace(-1+1/cls_res, 1 - 1/cls_res, steps = cls_res,device = device) for _ in range(2)], indexing='ij') + G = torch.stack((G[1], G[0]), dim = -1).reshape(C,2) + GT = (G[None,:,None,None,:]-x2[:,None]).norm(dim=-1).min(dim=1).indices + cls_loss = F.cross_entropy(scale_gm_cls, GT, reduction = 'none')[prob > 0.99] + certainty_loss = F.binary_cross_entropy_with_logits(gm_certainty[:,0], prob) + if not torch.any(cls_loss): + cls_loss = (certainty_loss * 0.0) # Prevent issues where prob is 0 everywhere + + losses = { + f"gm_certainty_loss_{scale}": certainty_loss.mean(), + f"gm_cls_loss_{scale}": cls_loss.mean(), + } + wandb.log(losses, step = romatch.GLOBAL_STEP) + return losses + + def delta_cls_loss(self, x2, prob, flow_pre_delta, delta_cls, certainty, scale, offset_scale): + with torch.no_grad(): + B, C, H, W = delta_cls.shape + device = x2.device + cls_res = round(math.sqrt(C)) + G = torch.meshgrid(*[torch.linspace(-1+1/cls_res, 1 - 1/cls_res, steps = cls_res,device = device) for _ in range(2)]) + G = torch.stack((G[1], G[0]), dim = -1).reshape(C,2) * offset_scale + GT = (G[None,:,None,None,:] + flow_pre_delta[:,None] - x2[:,None]).norm(dim=-1).min(dim=1).indices + cls_loss = F.cross_entropy(delta_cls, GT, reduction = 'none')[prob > 0.99] + certainty_loss = F.binary_cross_entropy_with_logits(certainty[:,0], prob) + if not torch.any(cls_loss): + cls_loss = (certainty_loss * 0.0) # Prevent issues where prob is 0 everywhere + losses = { + f"delta_certainty_loss_{scale}": certainty_loss.mean(), + f"delta_cls_loss_{scale}": cls_loss.mean(), + } + wandb.log(losses, step = romatch.GLOBAL_STEP) + return losses + + def regression_loss(self, x2, prob, flow, certainty, scale, eps=1e-8, mode = "delta"): + epe = (flow.permute(0,2,3,1) - x2).norm(dim=-1) + if scale == 1: + pck_05 = (epe[prob > 0.99] < 0.5 * (2/512)).float().mean() + wandb.log({"train_pck_05": pck_05}, step = romatch.GLOBAL_STEP) + + ce_loss = F.binary_cross_entropy_with_logits(certainty[:, 0], prob) + a = self.alpha[scale] if isinstance(self.alpha, dict) else self.alpha + cs = self.c * scale + x = epe[prob > 0.99] + reg_loss = cs**a * ((x/(cs))**2 + 1**2)**(a/2) + if not torch.any(reg_loss): + reg_loss = (ce_loss * 0.0) # Prevent issues where prob is 0 everywhere + losses = { + f"{mode}_certainty_loss_{scale}": ce_loss.mean(), + f"{mode}_regression_loss_{scale}": reg_loss.mean(), + } + wandb.log(losses, step = romatch.GLOBAL_STEP) + return losses + + def forward(self, corresps, batch): + scales = list(corresps.keys()) + tot_loss = 0.0 + # scale_weights due to differences in scale for regression gradients and classification gradients + scale_weights = {1:1, 2:1, 4:1, 8:1, 16:1} + for scale in scales: + scale_corresps = corresps[scale] + scale_certainty, flow_pre_delta, delta_cls, offset_scale, scale_gm_cls, scale_gm_certainty, flow, scale_gm_flow = ( + scale_corresps["certainty"], + scale_corresps.get("flow_pre_delta"), + scale_corresps.get("delta_cls"), + scale_corresps.get("offset_scale"), + scale_corresps.get("gm_cls"), + scale_corresps.get("gm_certainty"), + scale_corresps["flow"], + scale_corresps.get("gm_flow"), + + ) + if flow_pre_delta is not None: + flow_pre_delta = rearrange(flow_pre_delta, "b d h w -> b h w d") + b, h, w, d = flow_pre_delta.shape + else: + # _ = 1 + b, _, h, w = scale_certainty.shape + gt_warp, gt_prob = get_gt_warp( + batch["im_A_depth"], + batch["im_B_depth"], + batch["T_1to2"], + batch["K1"], + batch["K2"], + H=h, + W=w, + ) + x2 = gt_warp.float() + prob = gt_prob + + if self.local_largest_scale >= scale: + prob = prob * ( + F.interpolate(prev_epe[:, None], size=(h, w), mode="nearest-exact")[:, 0] + < (2 / 512) * (self.local_dist[scale] * scale)) + + if scale_gm_cls is not None: + gm_cls_losses = self.gm_cls_loss(x2, prob, scale_gm_cls, scale_gm_certainty, scale) + gm_loss = self.ce_weight * gm_cls_losses[f"gm_certainty_loss_{scale}"] + gm_cls_losses[f"gm_cls_loss_{scale}"] + tot_loss = tot_loss + scale_weights[scale] * gm_loss + elif scale_gm_flow is not None: + gm_flow_losses = self.regression_loss(x2, prob, scale_gm_flow, scale_gm_certainty, scale, mode = "gm") + gm_loss = self.ce_weight * gm_flow_losses[f"gm_certainty_loss_{scale}"] + gm_flow_losses[f"gm_regression_loss_{scale}"] + tot_loss = tot_loss + scale_weights[scale] * gm_loss + + if delta_cls is not None: + delta_cls_losses = self.delta_cls_loss(x2, prob, flow_pre_delta, delta_cls, scale_certainty, scale, offset_scale) + delta_cls_loss = self.ce_weight * delta_cls_losses[f"delta_certainty_loss_{scale}"] + delta_cls_losses[f"delta_cls_loss_{scale}"] + tot_loss = tot_loss + scale_weights[scale] * delta_cls_loss + else: + delta_regression_losses = self.regression_loss(x2, prob, flow, scale_certainty, scale) + reg_loss = self.ce_weight * delta_regression_losses[f"delta_certainty_loss_{scale}"] + delta_regression_losses[f"delta_regression_loss_{scale}"] + tot_loss = tot_loss + scale_weights[scale] * reg_loss + prev_epe = (flow.permute(0,2,3,1) - x2).norm(dim=-1).detach() + return tot_loss diff --git a/submodules/RoMa/romatch/losses/robust_loss_tiny_roma.py b/submodules/RoMa/romatch/losses/robust_loss_tiny_roma.py new file mode 100644 index 0000000000000000000000000000000000000000..a17c24678b093ca843d16c1a17ea16f19fa594d5 --- /dev/null +++ b/submodules/RoMa/romatch/losses/robust_loss_tiny_roma.py @@ -0,0 +1,160 @@ +from einops.einops import rearrange +import torch +import torch.nn as nn +import torch.nn.functional as F +from romatch.utils.utils import get_gt_warp +import wandb +import romatch +import math + +# This is slightly different than regular romatch due to significantly worse corresps +# The confidence loss is quite tricky here //Johan + +class RobustLosses(nn.Module): + def __init__( + self, + robust=False, + center_coords=False, + scale_normalize=False, + ce_weight=0.01, + local_loss=True, + local_dist=None, + smooth_mask = False, + depth_interpolation_mode = "bilinear", + mask_depth_loss = False, + relative_depth_error_threshold = 0.05, + alpha = 1., + c = 1e-3, + epe_mask_prob_th = None, + cert_only_on_consistent_depth = False, + ): + super().__init__() + if local_dist is None: + local_dist = {} + self.robust = robust # measured in pixels + self.center_coords = center_coords + self.scale_normalize = scale_normalize + self.ce_weight = ce_weight + self.local_loss = local_loss + self.local_dist = local_dist + self.smooth_mask = smooth_mask + self.depth_interpolation_mode = depth_interpolation_mode + self.mask_depth_loss = mask_depth_loss + self.relative_depth_error_threshold = relative_depth_error_threshold + self.avg_overlap = dict() + self.alpha = alpha + self.c = c + self.epe_mask_prob_th = epe_mask_prob_th + self.cert_only_on_consistent_depth = cert_only_on_consistent_depth + + def corr_volume_loss(self, mnn:torch.Tensor, corr_volume:torch.Tensor, scale): + b, h,w, h,w = corr_volume.shape + inv_temp = 10 + corr_volume = corr_volume.reshape(-1, h*w, h*w) + nll = -(inv_temp*corr_volume).log_softmax(dim = 1) - (inv_temp*corr_volume).log_softmax(dim = 2) + corr_volume_loss = nll[mnn[:,0], mnn[:,1], mnn[:,2]].mean() + + losses = { + f"gm_corr_volume_loss_{scale}": corr_volume_loss.mean(), + } + wandb.log(losses, step = romatch.GLOBAL_STEP) + return losses + + + + def regression_loss(self, x2, prob, flow, certainty, scale, eps=1e-8, mode = "delta"): + epe = (flow.permute(0,2,3,1) - x2).norm(dim=-1) + if scale in self.local_dist: + prob = prob * (epe < (2 / 512) * (self.local_dist[scale] * scale)).float() + if scale == 1: + pck_05 = (epe[prob > 0.99] < 0.5 * (2/512)).float().mean() + wandb.log({"train_pck_05": pck_05}, step = romatch.GLOBAL_STEP) + if self.epe_mask_prob_th is not None: + # if too far away from gt, certainty should be 0 + gt_cert = prob * (epe < scale * self.epe_mask_prob_th) + else: + gt_cert = prob + if self.cert_only_on_consistent_depth: + ce_loss = F.binary_cross_entropy_with_logits(certainty[:, 0][prob > 0], gt_cert[prob > 0]) + else: + ce_loss = F.binary_cross_entropy_with_logits(certainty[:, 0], gt_cert) + a = self.alpha[scale] if isinstance(self.alpha, dict) else self.alpha + cs = self.c * scale + x = epe[prob > 0.99] + reg_loss = cs**a * ((x/(cs))**2 + 1**2)**(a/2) + if not torch.any(reg_loss): + reg_loss = (ce_loss * 0.0) # Prevent issues where prob is 0 everywhere + losses = { + f"{mode}_certainty_loss_{scale}": ce_loss.mean(), + f"{mode}_regression_loss_{scale}": reg_loss.mean(), + } + wandb.log(losses, step = romatch.GLOBAL_STEP) + return losses + + def forward(self, corresps, batch): + scales = list(corresps.keys()) + tot_loss = 0.0 + # scale_weights due to differences in scale for regression gradients and classification gradients + for scale in scales: + scale_corresps = corresps[scale] + scale_certainty, flow_pre_delta, delta_cls, offset_scale, scale_gm_corr_volume, scale_gm_certainty, flow, scale_gm_flow = ( + scale_corresps["certainty"], + scale_corresps.get("flow_pre_delta"), + scale_corresps.get("delta_cls"), + scale_corresps.get("offset_scale"), + scale_corresps.get("corr_volume"), + scale_corresps.get("gm_certainty"), + scale_corresps["flow"], + scale_corresps.get("gm_flow"), + + ) + if flow_pre_delta is not None: + flow_pre_delta = rearrange(flow_pre_delta, "b d h w -> b h w d") + b, h, w, d = flow_pre_delta.shape + else: + # _ = 1 + b, _, h, w = scale_certainty.shape + gt_warp, gt_prob = get_gt_warp( + batch["im_A_depth"], + batch["im_B_depth"], + batch["T_1to2"], + batch["K1"], + batch["K2"], + H=h, + W=w, + ) + x2 = gt_warp.float() + prob = gt_prob + + if scale_gm_corr_volume is not None: + gt_warp_back, _ = get_gt_warp( + batch["im_B_depth"], + batch["im_A_depth"], + batch["T_1to2"].inverse(), + batch["K2"], + batch["K1"], + H=h, + W=w, + ) + grid = torch.stack(torch.meshgrid(torch.linspace(-1+1/w, 1-1/w, w), torch.linspace(-1+1/h, 1-1/h, h), indexing='xy'), dim =-1).to(gt_warp.device) + #fwd_bck = F.grid_sample(gt_warp_back.permute(0,3,1,2), gt_warp, align_corners=False, mode = 'bilinear').permute(0,2,3,1) + #diff = (fwd_bck - grid).norm(dim = -1) + with torch.no_grad(): + D_B = torch.cdist(gt_warp.float().reshape(-1,h*w,2), grid.reshape(-1,h*w,2)) + D_A = torch.cdist(grid.reshape(-1,h*w,2), gt_warp_back.float().reshape(-1,h*w,2)) + inds = torch.nonzero((D_B == D_B.min(dim=-1, keepdim = True).values) + * (D_A == D_A.min(dim=-2, keepdim = True).values) + * (D_B < 0.01) + * (D_A < 0.01)) + + gm_cls_losses = self.corr_volume_loss(inds, scale_gm_corr_volume, scale) + gm_loss = gm_cls_losses[f"gm_corr_volume_loss_{scale}"] + tot_loss = tot_loss + gm_loss + elif scale_gm_flow is not None: + gm_flow_losses = self.regression_loss(x2, prob, scale_gm_flow, scale_gm_certainty, scale, mode = "gm") + gm_loss = self.ce_weight * gm_flow_losses[f"gm_certainty_loss_{scale}"] + gm_flow_losses[f"gm_regression_loss_{scale}"] + tot_loss = tot_loss + gm_loss + delta_regression_losses = self.regression_loss(x2, prob, flow, scale_certainty, scale) + reg_loss = self.ce_weight * delta_regression_losses[f"delta_certainty_loss_{scale}"] + delta_regression_losses[f"delta_regression_loss_{scale}"] + tot_loss = tot_loss + reg_loss + return tot_loss diff --git a/submodules/RoMa/romatch/models/__init__.py b/submodules/RoMa/romatch/models/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..7650c9c7480920905e27578f175fcb5f995cc8ba --- /dev/null +++ b/submodules/RoMa/romatch/models/__init__.py @@ -0,0 +1 @@ +from .model_zoo import roma_outdoor, tiny_roma_v1_outdoor, roma_indoor \ No newline at end of file diff --git a/submodules/RoMa/romatch/models/encoders.py b/submodules/RoMa/romatch/models/encoders.py new file mode 100644 index 0000000000000000000000000000000000000000..84fb54395139a2ca21860ce2c18d033ad0afb19f --- /dev/null +++ b/submodules/RoMa/romatch/models/encoders.py @@ -0,0 +1,122 @@ +from typing import Optional, Union +import torch +from torch import device +import torch.nn as nn +import torch.nn.functional as F +import torchvision.models as tvm +import gc +from romatch.utils.utils import get_autocast_params + + +class ResNet50(nn.Module): + def __init__(self, pretrained=False, high_res = False, weights = None, + dilation = None, freeze_bn = True, anti_aliased = False, early_exit = False, amp = False, amp_dtype = torch.float16) -> None: + super().__init__() + if dilation is None: + dilation = [False,False,False] + if anti_aliased: + pass + else: + if weights is not None: + self.net = tvm.resnet50(weights = weights,replace_stride_with_dilation=dilation) + else: + self.net = tvm.resnet50(pretrained=pretrained,replace_stride_with_dilation=dilation) + + self.high_res = high_res + self.freeze_bn = freeze_bn + self.early_exit = early_exit + self.amp = amp + self.amp_dtype = amp_dtype + + def forward(self, x, **kwargs): + autocast_device, autocast_enabled, autocast_dtype = get_autocast_params(x.device, self.amp, self.amp_dtype) + with torch.autocast(autocast_device, enabled=autocast_enabled, dtype = autocast_dtype): + net = self.net + feats = {1:x} + x = net.conv1(x) + x = net.bn1(x) + x = net.relu(x) + feats[2] = x + x = net.maxpool(x) + x = net.layer1(x) + feats[4] = x + x = net.layer2(x) + feats[8] = x + if self.early_exit: + return feats + x = net.layer3(x) + feats[16] = x + x = net.layer4(x) + feats[32] = x + return feats + + def train(self, mode=True): + super().train(mode) + if self.freeze_bn: + for m in self.modules(): + if isinstance(m, nn.BatchNorm2d): + m.eval() + pass + +class VGG19(nn.Module): + def __init__(self, pretrained=False, amp = False, amp_dtype = torch.float16) -> None: + super().__init__() + self.layers = nn.ModuleList(tvm.vgg19_bn(pretrained=pretrained).features[:40]) + self.amp = amp + self.amp_dtype = amp_dtype + + def forward(self, x, **kwargs): + autocast_device, autocast_enabled, autocast_dtype = get_autocast_params(x.device, self.amp, self.amp_dtype) + with torch.autocast(device_type=autocast_device, enabled=autocast_enabled, dtype = autocast_dtype): + feats = {} + scale = 1 + for layer in self.layers: + if isinstance(layer, nn.MaxPool2d): + feats[scale] = x + scale = scale*2 + x = layer(x) + return feats + +class CNNandDinov2(nn.Module): + def __init__(self, cnn_kwargs = None, amp = False, use_vgg = False, dinov2_weights = None, amp_dtype = torch.float16): + super().__init__() + if dinov2_weights is None: + dinov2_weights = torch.hub.load_state_dict_from_url("https://dl.fbaipublicfiles.com/dinov2/dinov2_vitl14/dinov2_vitl14_pretrain.pth", map_location="cpu") + from .transformer import vit_large + vit_kwargs = dict(img_size= 518, + patch_size= 14, + init_values = 1.0, + ffn_layer = "mlp", + block_chunks = 0, + ) + + dinov2_vitl14 = vit_large(**vit_kwargs).eval() + dinov2_vitl14.load_state_dict(dinov2_weights) + cnn_kwargs = cnn_kwargs if cnn_kwargs is not None else {} + if not use_vgg: + self.cnn = ResNet50(**cnn_kwargs) + else: + self.cnn = VGG19(**cnn_kwargs) + self.amp = amp + self.amp_dtype = amp_dtype + if self.amp: + dinov2_vitl14 = dinov2_vitl14.to(self.amp_dtype) + self.dinov2_vitl14 = [dinov2_vitl14] # ugly hack to not show parameters to DDP + + + def train(self, mode: bool = True): + return self.cnn.train(mode) + + def forward(self, x, upsample = False): + B,C,H,W = x.shape + feature_pyramid = self.cnn(x) + + if not upsample: + with torch.no_grad(): + if self.dinov2_vitl14[0].device != x.device: + self.dinov2_vitl14[0] = self.dinov2_vitl14[0].to(x.device).to(self.amp_dtype) + dinov2_features_16 = self.dinov2_vitl14[0].forward_features(x.to(self.amp_dtype)) + features_16 = dinov2_features_16['x_norm_patchtokens'].permute(0,2,1).reshape(B,1024,H//14, W//14) + del dinov2_features_16 + feature_pyramid[16] = features_16 + return feature_pyramid \ No newline at end of file diff --git a/submodules/RoMa/romatch/models/matcher.py b/submodules/RoMa/romatch/models/matcher.py new file mode 100644 index 0000000000000000000000000000000000000000..36c7427cc6a22f6b54b7ce8f9f55e1736cfb7494 --- /dev/null +++ b/submodules/RoMa/romatch/models/matcher.py @@ -0,0 +1,760 @@ +import os +import math +import numpy as np +import torch +import torch.nn as nn +import torch.nn.functional as F +from einops import rearrange +import warnings +from warnings import warn +from PIL import Image + +from romatch.utils import get_tuple_transform_ops +from romatch.utils.local_correlation import local_correlation +from romatch.utils.utils import cls_to_flow_refine, get_autocast_params +from romatch.utils.kde import kde + +class ConvRefiner(nn.Module): + def __init__( + self, + in_dim=6, + hidden_dim=16, + out_dim=2, + dw=False, + kernel_size=5, + hidden_blocks=3, + displacement_emb = None, + displacement_emb_dim = None, + local_corr_radius = None, + corr_in_other = None, + no_im_B_fm = False, + amp = False, + concat_logits = False, + use_bias_block_1 = True, + use_cosine_corr = False, + disable_local_corr_grad = False, + is_classifier = False, + sample_mode = "bilinear", + norm_type = nn.BatchNorm2d, + bn_momentum = 0.1, + amp_dtype = torch.float16, + ): + super().__init__() + self.bn_momentum = bn_momentum + self.block1 = self.create_block( + in_dim, hidden_dim, dw=dw, kernel_size=kernel_size, bias = use_bias_block_1, + ) + self.hidden_blocks = nn.Sequential( + *[ + self.create_block( + hidden_dim, + hidden_dim, + dw=dw, + kernel_size=kernel_size, + norm_type=norm_type, + ) + for hb in range(hidden_blocks) + ] + ) + self.hidden_blocks = self.hidden_blocks + self.out_conv = nn.Conv2d(hidden_dim, out_dim, 1, 1, 0) + if displacement_emb: + self.has_displacement_emb = True + self.disp_emb = nn.Conv2d(2,displacement_emb_dim,1,1,0) + else: + self.has_displacement_emb = False + self.local_corr_radius = local_corr_radius + self.corr_in_other = corr_in_other + self.no_im_B_fm = no_im_B_fm + self.amp = amp + self.concat_logits = concat_logits + self.use_cosine_corr = use_cosine_corr + self.disable_local_corr_grad = disable_local_corr_grad + self.is_classifier = is_classifier + self.sample_mode = sample_mode + self.amp_dtype = amp_dtype + + def create_block( + self, + in_dim, + out_dim, + dw=False, + kernel_size=5, + bias = True, + norm_type = nn.BatchNorm2d, + ): + num_groups = 1 if not dw else in_dim + if dw: + assert ( + out_dim % in_dim == 0 + ), "outdim must be divisible by indim for depthwise" + conv1 = nn.Conv2d( + in_dim, + out_dim, + kernel_size=kernel_size, + stride=1, + padding=kernel_size // 2, + groups=num_groups, + bias=bias, + ) + norm = norm_type(out_dim, momentum = self.bn_momentum) if norm_type is nn.BatchNorm2d else norm_type(num_channels = out_dim) + relu = nn.ReLU(inplace=True) + conv2 = nn.Conv2d(out_dim, out_dim, 1, 1, 0) + return nn.Sequential(conv1, norm, relu, conv2) + + def forward(self, x, y, flow, scale_factor = 1, logits = None): + b,c,hs,ws = x.shape + autocast_device, autocast_enabled, autocast_dtype = get_autocast_params(x.device, enabled=self.amp, dtype=self.amp_dtype) + with torch.autocast(autocast_device, enabled=autocast_enabled, dtype = autocast_dtype): + x_hat = F.grid_sample(y, flow.permute(0, 2, 3, 1), align_corners=False, mode = self.sample_mode) + if self.has_displacement_emb: + im_A_coords = torch.meshgrid( + ( + torch.linspace(-1 + 1 / hs, 1 - 1 / hs, hs, device=x.device), + torch.linspace(-1 + 1 / ws, 1 - 1 / ws, ws, device=x.device), + ), indexing='ij' + ) + im_A_coords = torch.stack((im_A_coords[1], im_A_coords[0])) + im_A_coords = im_A_coords[None].expand(b, 2, hs, ws) + in_displacement = flow-im_A_coords + emb_in_displacement = self.disp_emb(40/32 * scale_factor * in_displacement) + if self.local_corr_radius: + if self.corr_in_other: + # Corr in other means take a kxk grid around the predicted coordinate in other image + local_corr = local_correlation(x,y,local_radius=self.local_corr_radius,flow = flow, + sample_mode = self.sample_mode) + else: + raise NotImplementedError("Local corr in own frame should not be used.") + if self.no_im_B_fm: + x_hat = torch.zeros_like(x) + d = torch.cat((x, x_hat, emb_in_displacement, local_corr), dim=1) + else: + d = torch.cat((x, x_hat, emb_in_displacement), dim=1) + else: + if self.no_im_B_fm: + x_hat = torch.zeros_like(x) + d = torch.cat((x, x_hat), dim=1) + if self.concat_logits: + d = torch.cat((d, logits), dim=1) + d = self.block1(d) + d = self.hidden_blocks(d) + d = self.out_conv(d.float()) + displacement, certainty = d[:, :-1], d[:, -1:] + return displacement, certainty + +class CosKernel(nn.Module): # similar to softmax kernel + def __init__(self, T, learn_temperature=False): + super().__init__() + self.learn_temperature = learn_temperature + if self.learn_temperature: + self.T = nn.Parameter(torch.tensor(T)) + else: + self.T = T + + def __call__(self, x, y, eps=1e-6): + c = torch.einsum("bnd,bmd->bnm", x, y) / ( + x.norm(dim=-1)[..., None] * y.norm(dim=-1)[:, None] + eps + ) + if self.learn_temperature: + T = self.T.abs() + 0.01 + else: + T = torch.tensor(self.T, device=c.device) + K = ((c - 1.0) / T).exp() + return K + +class GP(nn.Module): + def __init__( + self, + kernel, + T=1, + learn_temperature=False, + only_attention=False, + gp_dim=64, + basis="fourier", + covar_size=5, + only_nearest_neighbour=False, + sigma_noise=0.1, + no_cov=False, + predict_features = False, + ): + super().__init__() + self.K = kernel(T=T, learn_temperature=learn_temperature) + self.sigma_noise = sigma_noise + self.covar_size = covar_size + self.pos_conv = torch.nn.Conv2d(2, gp_dim, 1, 1) + self.only_attention = only_attention + self.only_nearest_neighbour = only_nearest_neighbour + self.basis = basis + self.no_cov = no_cov + self.dim = gp_dim + self.predict_features = predict_features + + def get_local_cov(self, cov): + K = self.covar_size + b, h, w, h, w = cov.shape + hw = h * w + cov = F.pad(cov, 4 * (K // 2,)) # pad v_q + delta = torch.stack( + torch.meshgrid( + torch.arange(-(K // 2), K // 2 + 1), torch.arange(-(K // 2), K // 2 + 1), + indexing = 'ij'), + dim=-1, + ) + positions = torch.stack( + torch.meshgrid( + torch.arange(K // 2, h + K // 2), torch.arange(K // 2, w + K // 2), + indexing = 'ij'), + dim=-1, + ) + neighbours = positions[:, :, None, None, :] + delta[None, :, :] + points = torch.arange(hw)[:, None].expand(hw, K**2) + local_cov = cov.reshape(b, hw, h + K - 1, w + K - 1)[ + :, + points.flatten(), + neighbours[..., 0].flatten(), + neighbours[..., 1].flatten(), + ].reshape(b, h, w, K**2) + return local_cov + + def reshape(self, x): + return rearrange(x, "b d h w -> b (h w) d") + + def project_to_basis(self, x): + if self.basis == "fourier": + return torch.cos(8 * math.pi * self.pos_conv(x)) + elif self.basis == "linear": + return self.pos_conv(x) + else: + raise ValueError( + "No other bases other than fourier and linear currently im_Bed in public release" + ) + + def get_pos_enc(self, y): + b, c, h, w = y.shape + coarse_coords = torch.meshgrid( + ( + torch.linspace(-1 + 1 / h, 1 - 1 / h, h, device=y.device), + torch.linspace(-1 + 1 / w, 1 - 1 / w, w, device=y.device), + ), + indexing = 'ij' + ) + + coarse_coords = torch.stack((coarse_coords[1], coarse_coords[0]), dim=-1)[ + None + ].expand(b, h, w, 2) + coarse_coords = rearrange(coarse_coords, "b h w d -> b d h w") + coarse_embedded_coords = self.project_to_basis(coarse_coords) + return coarse_embedded_coords + + def forward(self, x, y, **kwargs): + b, c, h1, w1 = x.shape + b, c, h2, w2 = y.shape + f = self.get_pos_enc(y) + b, d, h2, w2 = f.shape + x, y, f = self.reshape(x.float()), self.reshape(y.float()), self.reshape(f) + K_xx = self.K(x, x) + K_yy = self.K(y, y) + K_xy = self.K(x, y) + K_yx = K_xy.permute(0, 2, 1) + sigma_noise = self.sigma_noise * torch.eye(h2 * w2, device=x.device)[None, :, :] + with warnings.catch_warnings(): + K_yy_inv = torch.linalg.inv(K_yy + sigma_noise) + + mu_x = K_xy.matmul(K_yy_inv.matmul(f)) + mu_x = rearrange(mu_x, "b (h w) d -> b d h w", h=h1, w=w1) + if not self.no_cov: + cov_x = K_xx - K_xy.matmul(K_yy_inv.matmul(K_yx)) + cov_x = rearrange(cov_x, "b (h w) (r c) -> b h w r c", h=h1, w=w1, r=h1, c=w1) + local_cov_x = self.get_local_cov(cov_x) + local_cov_x = rearrange(local_cov_x, "b h w K -> b K h w") + gp_feats = torch.cat((mu_x, local_cov_x), dim=1) + else: + gp_feats = mu_x + return gp_feats + +class Decoder(nn.Module): + def __init__( + self, embedding_decoder, gps, proj, conv_refiner, detach=False, scales="all", pos_embeddings = None, + num_refinement_steps_per_scale = 1, warp_noise_std = 0.0, displacement_dropout_p = 0.0, gm_warp_dropout_p = 0.0, + flow_upsample_mode = "bilinear", amp_dtype = torch.float16, + ): + super().__init__() + self.embedding_decoder = embedding_decoder + self.num_refinement_steps_per_scale = num_refinement_steps_per_scale + self.gps = gps + self.proj = proj + self.conv_refiner = conv_refiner + self.detach = detach + if pos_embeddings is None: + self.pos_embeddings = {} + else: + self.pos_embeddings = pos_embeddings + if scales == "all": + self.scales = ["32", "16", "8", "4", "2", "1"] + else: + self.scales = scales + self.warp_noise_std = warp_noise_std + self.refine_init = 4 + self.displacement_dropout_p = displacement_dropout_p + self.gm_warp_dropout_p = gm_warp_dropout_p + self.flow_upsample_mode = flow_upsample_mode + self.amp_dtype = amp_dtype + + def get_placeholder_flow(self, b, h, w, device): + coarse_coords = torch.meshgrid( + ( + torch.linspace(-1 + 1 / h, 1 - 1 / h, h, device=device), + torch.linspace(-1 + 1 / w, 1 - 1 / w, w, device=device), + ), + indexing = 'ij' + ) + coarse_coords = torch.stack((coarse_coords[1], coarse_coords[0]), dim=-1)[ + None + ].expand(b, h, w, 2) + coarse_coords = rearrange(coarse_coords, "b h w d -> b d h w") + return coarse_coords + + def get_positional_embedding(self, b, h ,w, device): + coarse_coords = torch.meshgrid( + ( + torch.linspace(-1 + 1 / h, 1 - 1 / h, h, device=device), + torch.linspace(-1 + 1 / w, 1 - 1 / w, w, device=device), + ), + indexing = 'ij' + ) + + coarse_coords = torch.stack((coarse_coords[1], coarse_coords[0]), dim=-1)[ + None + ].expand(b, h, w, 2) + coarse_coords = rearrange(coarse_coords, "b h w d -> b d h w") + coarse_embedded_coords = self.pos_embedding(coarse_coords) + return coarse_embedded_coords + + def forward(self, f1, f2, gt_warp = None, gt_prob = None, upsample = False, flow = None, certainty = None, scale_factor = 1): + coarse_scales = self.embedding_decoder.scales() + all_scales = self.scales if not upsample else ["8", "4", "2", "1"] + sizes = {scale: f1[scale].shape[-2:] for scale in f1} + h, w = sizes[1] + b = f1[1].shape[0] + device = f1[1].device + coarsest_scale = int(all_scales[0]) + old_stuff = torch.zeros( + b, self.embedding_decoder.hidden_dim, *sizes[coarsest_scale], device=f1[coarsest_scale].device + ) + corresps = {} + if not upsample: + flow = self.get_placeholder_flow(b, *sizes[coarsest_scale], device) + certainty = 0.0 + else: + flow = F.interpolate( + flow, + size=sizes[coarsest_scale], + align_corners=False, + mode="bilinear", + ) + certainty = F.interpolate( + certainty, + size=sizes[coarsest_scale], + align_corners=False, + mode="bilinear", + ) + displacement = 0.0 + for new_scale in all_scales: + ins = int(new_scale) + corresps[ins] = {} + f1_s, f2_s = f1[ins], f2[ins] + if new_scale in self.proj: + autocast_device, autocast_enabled, autocast_dtype = get_autocast_params(f1_s.device, str(f1_s)=='cuda', self.amp_dtype) + with torch.autocast(autocast_device, enabled=autocast_enabled, dtype = autocast_dtype): + if not autocast_enabled: + f1_s, f2_s = f1_s.to(torch.float32), f2_s.to(torch.float32) + f1_s, f2_s = self.proj[new_scale](f1_s), self.proj[new_scale](f2_s) + + if ins in coarse_scales: + old_stuff = F.interpolate( + old_stuff, size=sizes[ins], mode="bilinear", align_corners=False + ) + gp_posterior = self.gps[new_scale](f1_s, f2_s) + gm_warp_or_cls, certainty, old_stuff = self.embedding_decoder( + gp_posterior, f1_s, old_stuff, new_scale + ) + + if self.embedding_decoder.is_classifier: + flow = cls_to_flow_refine( + gm_warp_or_cls, + ).permute(0,3,1,2) + corresps[ins].update({"gm_cls": gm_warp_or_cls,"gm_certainty": certainty,}) if self.training else None + else: + corresps[ins].update({"gm_flow": gm_warp_or_cls,"gm_certainty": certainty,}) if self.training else None + flow = gm_warp_or_cls.detach() + + if new_scale in self.conv_refiner: + corresps[ins].update({"flow_pre_delta": flow}) if self.training else None + delta_flow, delta_certainty = self.conv_refiner[new_scale]( + f1_s, f2_s, flow, scale_factor = scale_factor, logits = certainty, + ) + corresps[ins].update({"delta_flow": delta_flow,}) if self.training else None + displacement = ins*torch.stack((delta_flow[:, 0].float() / (self.refine_init * w), + delta_flow[:, 1].float() / (self.refine_init * h),),dim=1,) + flow = flow + displacement + certainty = ( + certainty + delta_certainty + ) # predict both certainty and displacement + corresps[ins].update({ + "certainty": certainty, + "flow": flow, + }) + if new_scale != "1": + flow = F.interpolate( + flow, + size=sizes[ins // 2], + mode=self.flow_upsample_mode, + ) + certainty = F.interpolate( + certainty, + size=sizes[ins // 2], + mode=self.flow_upsample_mode, + ) + if self.detach: + flow = flow.detach() + certainty = certainty.detach() + #torch.cuda.empty_cache() + return corresps + + +class RegressionMatcher(nn.Module): + def __init__( + self, + encoder, + decoder, + h=448, + w=448, + sample_mode = "threshold_balanced", + upsample_preds = False, + symmetric = False, + name = None, + attenuate_cert = None, + ): + super().__init__() + self.attenuate_cert = attenuate_cert + self.encoder = encoder + self.decoder = decoder + self.name = name + self.w_resized = w + self.h_resized = h + self.og_transforms = get_tuple_transform_ops(resize=None, normalize=True) + self.sample_mode = sample_mode + self.upsample_preds = upsample_preds + self.upsample_res = (14*16*6, 14*16*6) + self.symmetric = symmetric + self.sample_thresh = 0.05 + + def get_output_resolution(self): + if not self.upsample_preds: + return self.h_resized, self.w_resized + else: + return self.upsample_res + + def extract_backbone_features(self, batch, batched = True, upsample = False): + x_q = batch["im_A"] + x_s = batch["im_B"] + if batched: + X = torch.cat((x_q, x_s), dim = 0) + feature_pyramid = self.encoder(X, upsample = upsample) + else: + feature_pyramid = self.encoder(x_q, upsample = upsample), self.encoder(x_s, upsample = upsample) + return feature_pyramid + + def sample( + self, + matches, + certainty, + num=10000, + ): + if "threshold" in self.sample_mode: + upper_thresh = self.sample_thresh + certainty = certainty.clone() + certainty[certainty > upper_thresh] = 1 + matches, certainty = ( + matches.reshape(-1, 4), + certainty.reshape(-1), + ) + expansion_factor = 4 if "balanced" in self.sample_mode else 1 + good_samples = torch.multinomial(certainty, + num_samples = min(expansion_factor*num, len(certainty)), + replacement=False) + good_matches, good_certainty = matches[good_samples], certainty[good_samples] + if "balanced" not in self.sample_mode: + return good_matches, good_certainty + density = kde(good_matches, std=0.1) + p = 1 / (density+1) + p[density < 10] = 1e-7 # Basically should have at least 10 perfect neighbours, or around 100 ok ones + balanced_samples = torch.multinomial(p, + num_samples = min(num,len(good_certainty)), + replacement=False) + return good_matches[balanced_samples], good_certainty[balanced_samples] + + def forward(self, batch, batched = True, upsample = False, scale_factor = 1): + feature_pyramid = self.extract_backbone_features(batch, batched=batched, upsample = upsample) + if batched: + f_q_pyramid = { + scale: f_scale.chunk(2)[0] for scale, f_scale in feature_pyramid.items() + } + f_s_pyramid = { + scale: f_scale.chunk(2)[1] for scale, f_scale in feature_pyramid.items() + } + else: + f_q_pyramid, f_s_pyramid = feature_pyramid + corresps = self.decoder(f_q_pyramid, + f_s_pyramid, + upsample = upsample, + **(batch["corresps"] if "corresps" in batch else {}), + scale_factor=scale_factor) + + return corresps + + def forward_symmetric(self, batch, batched = True, upsample = False, scale_factor = 1): + feature_pyramid = self.extract_backbone_features(batch, batched = batched, upsample = upsample) + f_q_pyramid = feature_pyramid + f_s_pyramid = { + scale: torch.cat((f_scale.chunk(2)[1], f_scale.chunk(2)[0]), dim = 0) + for scale, f_scale in feature_pyramid.items() + } + corresps = self.decoder(f_q_pyramid, + f_s_pyramid, + upsample = upsample, + **(batch["corresps"] if "corresps" in batch else {}), + scale_factor=scale_factor) + return corresps + + def conf_from_fb_consistency(self, flow_forward, flow_backward, th = 2): + # assumes that flow forward is of shape (..., H, W, 2) + has_batch = False + if len(flow_forward.shape) == 3: + flow_forward, flow_backward = flow_forward[None], flow_backward[None] + else: + has_batch = True + H,W = flow_forward.shape[-3:-1] + th_n = 2 * th / max(H,W) + coords = torch.stack(torch.meshgrid( + torch.linspace(-1 + 1 / W, 1 - 1 / W, W), + torch.linspace(-1 + 1 / H, 1 - 1 / H, H), indexing = "xy"), + dim = -1).to(flow_forward.device) + coords_fb = F.grid_sample( + flow_backward.permute(0, 3, 1, 2), + flow_forward, + align_corners=False, mode="bilinear").permute(0, 2, 3, 1) + diff = (coords - coords_fb).norm(dim=-1) + in_th = (diff < th_n).float() + if not has_batch: + in_th = in_th[0] + return in_th + + def to_pixel_coordinates(self, coords, H_A, W_A, H_B = None, W_B = None): + if coords.shape[-1] == 2: + return self._to_pixel_coordinates(coords, H_A, W_A) + + if isinstance(coords, (list, tuple)): + kpts_A, kpts_B = coords[0], coords[1] + else: + kpts_A, kpts_B = coords[...,:2], coords[...,2:] + return self._to_pixel_coordinates(kpts_A, H_A, W_A), self._to_pixel_coordinates(kpts_B, H_B, W_B) + + def _to_pixel_coordinates(self, coords, H, W): + kpts = torch.stack((W/2 * (coords[...,0]+1), H/2 * (coords[...,1]+1)),axis=-1) + return kpts + + def to_normalized_coordinates(self, coords, H_A, W_A, H_B, W_B): + if isinstance(coords, (list, tuple)): + kpts_A, kpts_B = coords[0], coords[1] + else: + kpts_A, kpts_B = coords[...,:2], coords[...,2:] + kpts_A = torch.stack((2/W_A * kpts_A[...,0] - 1, 2/H_A * kpts_A[...,1] - 1),axis=-1) + kpts_B = torch.stack((2/W_B * kpts_B[...,0] - 1, 2/H_B * kpts_B[...,1] - 1),axis=-1) + return kpts_A, kpts_B + + def match_keypoints(self, x_A, x_B, warp, certainty, return_tuple = True, return_inds = False): + x_A_to_B = F.grid_sample(warp[...,-2:].permute(2,0,1)[None], x_A[None,None], align_corners = False, mode = "bilinear")[0,:,0].mT + cert_A_to_B = F.grid_sample(certainty[None,None,...], x_A[None,None], align_corners = False, mode = "bilinear")[0,0,0] + D = torch.cdist(x_A_to_B, x_B) + inds_A, inds_B = torch.nonzero((D == D.min(dim=-1, keepdim = True).values) * (D == D.min(dim=-2, keepdim = True).values) * (cert_A_to_B[:,None] > self.sample_thresh), as_tuple = True) + + if return_tuple: + if return_inds: + return inds_A, inds_B + else: + return x_A[inds_A], x_B[inds_B] + else: + if return_inds: + return torch.cat((inds_A, inds_B),dim=-1) + else: + return torch.cat((x_A[inds_A], x_B[inds_B]),dim=-1) + + @torch.inference_mode() + def match( + self, + im_A_input, + im_B_input, + *args, + batched=False, + device=None, + ): + if device is None: + device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') + + # Check if inputs are file paths or already loaded images + if isinstance(im_A_input, (str, os.PathLike)): + im_A = Image.open(im_A_input).convert("RGB") + else: + im_A = im_A_input + + if isinstance(im_B_input, (str, os.PathLike)): + im_B = Image.open(im_B_input).convert("RGB") + else: + im_B = im_B_input + + symmetric = self.symmetric + self.train(False) + with torch.no_grad(): + if not batched: + b = 1 + w, h = im_A.size + w2, h2 = im_B.size + # Get images in good format + ws = self.w_resized + hs = self.h_resized + + test_transform = get_tuple_transform_ops( + resize=(hs, ws), normalize=True, clahe=False + ) + im_A, im_B = test_transform((im_A, im_B)) + batch = {"im_A": im_A[None].to(device), "im_B": im_B[None].to(device)} + else: + b, c, h, w = im_A.shape + b, c, h2, w2 = im_B.shape + assert w == w2 and h == h2, "For batched images we assume same size" + batch = {"im_A": im_A.to(device), "im_B": im_B.to(device)} + if h != self.h_resized or self.w_resized != w: + warn("Model resolution and batch resolution differ, may produce unexpected results") + hs, ws = h, w + finest_scale = 1 + # Run matcher + if symmetric: + corresps = self.forward_symmetric(batch) + else: + corresps = self.forward(batch, batched=True) + + if self.upsample_preds: + hs, ws = self.upsample_res + + if self.attenuate_cert: + low_res_certainty = F.interpolate( + corresps[16]["certainty"], size=(hs, ws), align_corners=False, mode="bilinear" + ) + cert_clamp = 0 + factor = 0.5 + low_res_certainty = factor * low_res_certainty * (low_res_certainty < cert_clamp) + + if self.upsample_preds: + finest_corresps = corresps[finest_scale] + torch.cuda.empty_cache() + test_transform = get_tuple_transform_ops( + resize=(hs, ws), normalize=True + ) + if isinstance(im_A_input, (str, os.PathLike)): + im_A, im_B = test_transform( + (Image.open(im_A_input).convert('RGB'), Image.open(im_B_input).convert('RGB'))) + else: + im_A, im_B = test_transform((im_A_input, im_B_input)) + + im_A, im_B = im_A[None].to(device), im_B[None].to(device) + scale_factor = math.sqrt(self.upsample_res[0] * self.upsample_res[1] / (self.w_resized * self.h_resized)) + batch = {"im_A": im_A, "im_B": im_B, "corresps": finest_corresps} + if symmetric: + corresps = self.forward_symmetric(batch, upsample=True, batched=True, scale_factor=scale_factor) + else: + corresps = self.forward(batch, batched=True, upsample=True, scale_factor=scale_factor) + + im_A_to_im_B = corresps[finest_scale]["flow"] + certainty = corresps[finest_scale]["certainty"] - (low_res_certainty if self.attenuate_cert else 0) + if finest_scale != 1: + im_A_to_im_B = F.interpolate( + im_A_to_im_B, size=(hs, ws), align_corners=False, mode="bilinear" + ) + certainty = F.interpolate( + certainty, size=(hs, ws), align_corners=False, mode="bilinear" + ) + im_A_to_im_B = im_A_to_im_B.permute( + 0, 2, 3, 1 + ) + # Create im_A meshgrid + im_A_coords = torch.meshgrid( + ( + torch.linspace(-1 + 1 / hs, 1 - 1 / hs, hs, device=device), + torch.linspace(-1 + 1 / ws, 1 - 1 / ws, ws, device=device), + ), + indexing='ij' + ) + im_A_coords = torch.stack((im_A_coords[1], im_A_coords[0])) + im_A_coords = im_A_coords[None].expand(b, 2, hs, ws) + certainty = certainty.sigmoid() # logits -> probs + im_A_coords = im_A_coords.permute(0, 2, 3, 1) + if (im_A_to_im_B.abs() > 1).any() and True: + wrong = (im_A_to_im_B.abs() > 1).sum(dim=-1) > 0 + certainty[wrong[:, None]] = 0 + im_A_to_im_B = torch.clamp(im_A_to_im_B, -1, 1) + if symmetric: + A_to_B, B_to_A = im_A_to_im_B.chunk(2) + q_warp = torch.cat((im_A_coords, A_to_B), dim=-1) + im_B_coords = im_A_coords + s_warp = torch.cat((B_to_A, im_B_coords), dim=-1) + warp = torch.cat((q_warp, s_warp), dim=2) + certainty = torch.cat(certainty.chunk(2), dim=3) + else: + warp = torch.cat((im_A_coords, im_A_to_im_B), dim=-1) + if batched: + return ( + warp, + certainty[:, 0] + ) + else: + return ( + warp[0], + certainty[0, 0], + ) + + def visualize_warp(self, warp, certainty, im_A = None, im_B = None, + im_A_path = None, im_B_path = None, device = "cuda", symmetric = True, save_path = None, unnormalize = False): + #assert symmetric == True, "Currently assuming bidirectional warp, might update this if someone complains ;)" + H,W2,_ = warp.shape + W = W2//2 if symmetric else W2 + if im_A is None: + from PIL import Image + im_A, im_B = Image.open(im_A_path).convert("RGB"), Image.open(im_B_path).convert("RGB") + if not isinstance(im_A, torch.Tensor): + im_A = im_A.resize((W,H)) + im_B = im_B.resize((W,H)) + x_B = (torch.tensor(np.array(im_B)) / 255).to(device).permute(2, 0, 1) + if symmetric: + x_A = (torch.tensor(np.array(im_A)) / 255).to(device).permute(2, 0, 1) + else: + if symmetric: + x_A = im_A + x_B = im_B + im_A_transfer_rgb = F.grid_sample( + x_B[None], warp[:,:W, 2:][None], mode="bilinear", align_corners=False + )[0] + if symmetric: + im_B_transfer_rgb = F.grid_sample( + x_A[None], warp[:, W:, :2][None], mode="bilinear", align_corners=False + )[0] + warp_im = torch.cat((im_A_transfer_rgb,im_B_transfer_rgb),dim=2) + white_im = torch.ones((H,2*W),device=device) + else: + warp_im = im_A_transfer_rgb + white_im = torch.ones((H, W), device = device) + vis_im = certainty * warp_im + (1 - certainty) * white_im + if save_path is not None: + from romatch.utils import tensor_to_pil + tensor_to_pil(vis_im, unnormalize=unnormalize).save(save_path) + return vis_im diff --git a/submodules/RoMa/romatch/models/model_zoo/__init__.py b/submodules/RoMa/romatch/models/model_zoo/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..d0470ca3f0c3b8064b1b2f01663dfb13742d7a10 --- /dev/null +++ b/submodules/RoMa/romatch/models/model_zoo/__init__.py @@ -0,0 +1,73 @@ +from typing import Union +import torch +from .roma_models import roma_model, tiny_roma_v1_model + +weight_urls = { + "romatch": { + "outdoor": "https://github.com/Parskatt/storage/releases/download/roma/roma_outdoor.pth", + "indoor": "https://github.com/Parskatt/storage/releases/download/roma/roma_indoor.pth", + }, + "tiny_roma_v1": { + "outdoor": "https://github.com/Parskatt/storage/releases/download/roma/tiny_roma_v1_outdoor.pth", + }, + "dinov2": "https://dl.fbaipublicfiles.com/dinov2/dinov2_vitl14/dinov2_vitl14_pretrain.pth", #hopefully this doesnt change :D +} + +def tiny_roma_v1_outdoor(device, weights = None, xfeat = None): + if weights is None: + weights = torch.hub.load_state_dict_from_url( + weight_urls["tiny_roma_v1"]["outdoor"], + map_location=device) + if xfeat is None: + xfeat = torch.hub.load( + 'verlab/accelerated_features', + 'XFeat', + pretrained = True, + top_k = 4096).net + + return tiny_roma_v1_model(weights = weights, xfeat = xfeat).to(device) + +def roma_outdoor(device, weights=None, dinov2_weights=None, coarse_res: Union[int,tuple[int,int]] = 560, upsample_res: Union[int,tuple[int,int]] = 864, amp_dtype: torch.dtype = torch.float16): + if isinstance(coarse_res, int): + coarse_res = (coarse_res, coarse_res) + if isinstance(upsample_res, int): + upsample_res = (upsample_res, upsample_res) + + if str(device) == 'cpu': + amp_dtype = torch.float32 + + assert coarse_res[0] % 14 == 0, "Needs to be multiple of 14 for backbone" + assert coarse_res[1] % 14 == 0, "Needs to be multiple of 14 for backbone" + + if weights is None: + weights = torch.hub.load_state_dict_from_url(weight_urls["romatch"]["outdoor"], + map_location=device) + if dinov2_weights is None: + dinov2_weights = torch.hub.load_state_dict_from_url(weight_urls["dinov2"], + map_location=device) + model = roma_model(resolution=coarse_res, upsample_preds=True, + weights=weights,dinov2_weights = dinov2_weights,device=device, amp_dtype=amp_dtype) + model.upsample_res = upsample_res + print(f"Using coarse resolution {coarse_res}, and upsample res {model.upsample_res}") + return model + +def roma_indoor(device, weights=None, dinov2_weights=None, coarse_res: Union[int,tuple[int,int]] = 560, upsample_res: Union[int,tuple[int,int]] = 864, amp_dtype: torch.dtype = torch.float16): + if isinstance(coarse_res, int): + coarse_res = (coarse_res, coarse_res) + if isinstance(upsample_res, int): + upsample_res = (upsample_res, upsample_res) + + assert coarse_res[0] % 14 == 0, "Needs to be multiple of 14 for backbone" + assert coarse_res[1] % 14 == 0, "Needs to be multiple of 14 for backbone" + + if weights is None: + weights = torch.hub.load_state_dict_from_url(weight_urls["romatch"]["indoor"], + map_location=device) + if dinov2_weights is None: + dinov2_weights = torch.hub.load_state_dict_from_url(weight_urls["dinov2"], + map_location=device) + model = roma_model(resolution=coarse_res, upsample_preds=True, + weights=weights,dinov2_weights = dinov2_weights,device=device, amp_dtype=amp_dtype) + model.upsample_res = upsample_res + print(f"Using coarse resolution {coarse_res}, and upsample res {model.upsample_res}") + return model diff --git a/submodules/RoMa/romatch/models/model_zoo/roma_models.py b/submodules/RoMa/romatch/models/model_zoo/roma_models.py new file mode 100644 index 0000000000000000000000000000000000000000..4f8a08fc26d760a09f048bdd98bf8a8fffc8202c --- /dev/null +++ b/submodules/RoMa/romatch/models/model_zoo/roma_models.py @@ -0,0 +1,170 @@ +import warnings +import torch.nn as nn +import torch +from romatch.models.matcher import * +from romatch.models.transformer import Block, TransformerDecoder, MemEffAttention +from romatch.models.encoders import * +from romatch.models.tiny import TinyRoMa + +def tiny_roma_v1_model(weights = None, freeze_xfeat=False, exact_softmax=False, xfeat = None): + model = TinyRoMa( + xfeat = xfeat, + freeze_xfeat=freeze_xfeat, + exact_softmax=exact_softmax) + if weights is not None: + model.load_state_dict(weights) + return model + +def roma_model(resolution, upsample_preds, device = None, weights=None, dinov2_weights=None, amp_dtype: torch.dtype=torch.float16, **kwargs): + # romatch weights and dinov2 weights are loaded seperately, as dinov2 weights are not parameters + #torch.backends.cuda.matmul.allow_tf32 = True # allow tf32 on matmul TODO: these probably ruin stuff, should be careful + #torch.backends.cudnn.allow_tf32 = True # allow tf32 on cudnn + warnings.filterwarnings('ignore', category=UserWarning, message='TypedStorage is deprecated') + gp_dim = 512 + feat_dim = 512 + decoder_dim = gp_dim + feat_dim + cls_to_coord_res = 64 + coordinate_decoder = TransformerDecoder( + nn.Sequential(*[Block(decoder_dim, 8, attn_class=MemEffAttention) for _ in range(5)]), + decoder_dim, + cls_to_coord_res**2 + 1, + is_classifier=True, + amp = True, + pos_enc = False,) + dw = True + hidden_blocks = 8 + kernel_size = 5 + displacement_emb = "linear" + disable_local_corr_grad = True + + conv_refiner = nn.ModuleDict( + { + "16": ConvRefiner( + 2 * 512+128+(2*7+1)**2, + 2 * 512+128+(2*7+1)**2, + 2 + 1, + kernel_size=kernel_size, + dw=dw, + hidden_blocks=hidden_blocks, + displacement_emb=displacement_emb, + displacement_emb_dim=128, + local_corr_radius = 7, + corr_in_other = True, + amp = True, + disable_local_corr_grad = disable_local_corr_grad, + bn_momentum = 0.01, + ), + "8": ConvRefiner( + 2 * 512+64+(2*3+1)**2, + 2 * 512+64+(2*3+1)**2, + 2 + 1, + kernel_size=kernel_size, + dw=dw, + hidden_blocks=hidden_blocks, + displacement_emb=displacement_emb, + displacement_emb_dim=64, + local_corr_radius = 3, + corr_in_other = True, + amp = True, + disable_local_corr_grad = disable_local_corr_grad, + bn_momentum = 0.01, + ), + "4": ConvRefiner( + 2 * 256+32+(2*2+1)**2, + 2 * 256+32+(2*2+1)**2, + 2 + 1, + kernel_size=kernel_size, + dw=dw, + hidden_blocks=hidden_blocks, + displacement_emb=displacement_emb, + displacement_emb_dim=32, + local_corr_radius = 2, + corr_in_other = True, + amp = True, + disable_local_corr_grad = disable_local_corr_grad, + bn_momentum = 0.01, + ), + "2": ConvRefiner( + 2 * 64+16, + 128+16, + 2 + 1, + kernel_size=kernel_size, + dw=dw, + hidden_blocks=hidden_blocks, + displacement_emb=displacement_emb, + displacement_emb_dim=16, + amp = True, + disable_local_corr_grad = disable_local_corr_grad, + bn_momentum = 0.01, + ), + "1": ConvRefiner( + 2 * 9 + 6, + 24, + 2 + 1, + kernel_size=kernel_size, + dw=dw, + hidden_blocks = hidden_blocks, + displacement_emb = displacement_emb, + displacement_emb_dim = 6, + amp = True, + disable_local_corr_grad = disable_local_corr_grad, + bn_momentum = 0.01, + ), + } + ) + kernel_temperature = 0.2 + learn_temperature = False + no_cov = True + kernel = CosKernel + only_attention = False + basis = "fourier" + gp16 = GP( + kernel, + T=kernel_temperature, + learn_temperature=learn_temperature, + only_attention=only_attention, + gp_dim=gp_dim, + basis=basis, + no_cov=no_cov, + ) + gps = nn.ModuleDict({"16": gp16}) + proj16 = nn.Sequential(nn.Conv2d(1024, 512, 1, 1), nn.BatchNorm2d(512)) + proj8 = nn.Sequential(nn.Conv2d(512, 512, 1, 1), nn.BatchNorm2d(512)) + proj4 = nn.Sequential(nn.Conv2d(256, 256, 1, 1), nn.BatchNorm2d(256)) + proj2 = nn.Sequential(nn.Conv2d(128, 64, 1, 1), nn.BatchNorm2d(64)) + proj1 = nn.Sequential(nn.Conv2d(64, 9, 1, 1), nn.BatchNorm2d(9)) + proj = nn.ModuleDict({ + "16": proj16, + "8": proj8, + "4": proj4, + "2": proj2, + "1": proj1, + }) + displacement_dropout_p = 0.0 + gm_warp_dropout_p = 0.0 + decoder = Decoder(coordinate_decoder, + gps, + proj, + conv_refiner, + detach=True, + scales=["16", "8", "4", "2", "1"], + displacement_dropout_p = displacement_dropout_p, + gm_warp_dropout_p = gm_warp_dropout_p) + + encoder = CNNandDinov2( + cnn_kwargs = dict( + pretrained=False, + amp = True), + amp = True, + use_vgg = True, + dinov2_weights = dinov2_weights, + amp_dtype=amp_dtype, + ) + h,w = resolution + symmetric = True + attenuate_cert = True + sample_mode = "threshold_balanced" + matcher = RegressionMatcher(encoder, decoder, h=h, w=w, upsample_preds=upsample_preds, + symmetric = symmetric, attenuate_cert = attenuate_cert, sample_mode = sample_mode, **kwargs).to(device) + matcher.load_state_dict(weights) + return matcher diff --git a/submodules/RoMa/romatch/models/tiny.py b/submodules/RoMa/romatch/models/tiny.py new file mode 100644 index 0000000000000000000000000000000000000000..88f44af6c9a6255831734d096167724f89d040ce --- /dev/null +++ b/submodules/RoMa/romatch/models/tiny.py @@ -0,0 +1,304 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +import os +import torch +from pathlib import Path +import math +import numpy as np + +from torch import nn +from PIL import Image +from torchvision.transforms import ToTensor +from romatch.utils.kde import kde + +class BasicLayer(nn.Module): + """ + Basic Convolutional Layer: Conv2d -> BatchNorm -> ReLU + """ + def __init__(self, in_channels, out_channels, kernel_size=3, stride=1, padding=1, dilation=1, bias=False, relu = True): + super().__init__() + self.layer = nn.Sequential( + nn.Conv2d( in_channels, out_channels, kernel_size, padding = padding, stride=stride, dilation=dilation, bias = bias), + nn.BatchNorm2d(out_channels, affine=False), + nn.ReLU(inplace = True) if relu else nn.Identity() + ) + + def forward(self, x): + return self.layer(x) + +class TinyRoMa(nn.Module): + """ + Implementation of architecture described in + "XFeat: Accelerated Features for Lightweight Image Matching, CVPR 2024." + """ + + def __init__(self, xfeat = None, + freeze_xfeat = True, + sample_mode = "threshold_balanced", + symmetric = False, + exact_softmax = False): + super().__init__() + del xfeat.heatmap_head, xfeat.keypoint_head, xfeat.fine_matcher + if freeze_xfeat: + xfeat.train(False) + self.xfeat = [xfeat]# hide params from ddp + else: + self.xfeat = nn.ModuleList([xfeat]) + self.freeze_xfeat = freeze_xfeat + match_dim = 256 + self.coarse_matcher = nn.Sequential( + BasicLayer(64+64+2, match_dim,), + BasicLayer(match_dim, match_dim,), + BasicLayer(match_dim, match_dim,), + BasicLayer(match_dim, match_dim,), + nn.Conv2d(match_dim, 3, kernel_size=1, bias=True, padding=0)) + fine_match_dim = 64 + self.fine_matcher = nn.Sequential( + BasicLayer(24+24+2, fine_match_dim,), + BasicLayer(fine_match_dim, fine_match_dim,), + BasicLayer(fine_match_dim, fine_match_dim,), + BasicLayer(fine_match_dim, fine_match_dim,), + nn.Conv2d(fine_match_dim, 3, kernel_size=1, bias=True, padding=0),) + self.sample_mode = sample_mode + self.sample_thresh = 0.05 + self.symmetric = symmetric + self.exact_softmax = exact_softmax + + @property + def device(self): + return self.fine_matcher[-1].weight.device + + def preprocess_tensor(self, x): + """ Guarantee that image is divisible by 32 to avoid aliasing artifacts. """ + H, W = x.shape[-2:] + _H, _W = (H//32) * 32, (W//32) * 32 + rh, rw = H/_H, W/_W + + x = F.interpolate(x, (_H, _W), mode='bilinear', align_corners=False) + return x, rh, rw + + def forward_single(self, x): + with torch.inference_mode(self.freeze_xfeat or not self.training): + xfeat = self.xfeat[0] + with torch.no_grad(): + x = x.mean(dim=1, keepdim = True) + x = xfeat.norm(x) + + #main backbone + x1 = xfeat.block1(x) + x2 = xfeat.block2(x1 + xfeat.skip1(x)) + x3 = xfeat.block3(x2) + x4 = xfeat.block4(x3) + x5 = xfeat.block5(x4) + x4 = F.interpolate(x4, (x3.shape[-2], x3.shape[-1]), mode='bilinear') + x5 = F.interpolate(x5, (x3.shape[-2], x3.shape[-1]), mode='bilinear') + feats = xfeat.block_fusion( x3 + x4 + x5 ) + if self.freeze_xfeat: + return x2.clone(), feats.clone() + return x2, feats + + def to_pixel_coordinates(self, coords, H_A, W_A, H_B = None, W_B = None): + if coords.shape[-1] == 2: + return self._to_pixel_coordinates(coords, H_A, W_A) + + if isinstance(coords, (list, tuple)): + kpts_A, kpts_B = coords[0], coords[1] + else: + kpts_A, kpts_B = coords[...,:2], coords[...,2:] + return self._to_pixel_coordinates(kpts_A, H_A, W_A), self._to_pixel_coordinates(kpts_B, H_B, W_B) + + def _to_pixel_coordinates(self, coords, H, W): + kpts = torch.stack((W/2 * (coords[...,0]+1), H/2 * (coords[...,1]+1)),axis=-1) + return kpts + + def pos_embed(self, corr_volume: torch.Tensor): + B, H1, W1, H0, W0 = corr_volume.shape + grid = torch.stack( + torch.meshgrid( + torch.linspace(-1+1/W1,1-1/W1, W1), + torch.linspace(-1+1/H1,1-1/H1, H1), + indexing = "xy"), + dim = -1).float().to(corr_volume).reshape(H1*W1, 2) + down = 4 + if not self.training and not self.exact_softmax: + grid_lr = torch.stack( + torch.meshgrid( + torch.linspace(-1+down/W1,1-down/W1, W1//down), + torch.linspace(-1+down/H1,1-down/H1, H1//down), + indexing = "xy"), + dim = -1).float().to(corr_volume).reshape(H1*W1 //down**2, 2) + cv = corr_volume + best_match = cv.reshape(B,H1*W1,H0,W0).argmax(dim=1) # B, HW, H, W + P_lowres = torch.cat((cv[:,::down,::down].reshape(B,H1*W1 // down**2,H0,W0), best_match[:,None]),dim=1).softmax(dim=1) + pos_embeddings = torch.einsum('bchw,cd->bdhw', P_lowres[:,:-1], grid_lr) + pos_embeddings += P_lowres[:,-1] * grid[best_match].permute(0,3,1,2) + #print("hej") + else: + P = corr_volume.reshape(B,H1*W1,H0,W0).softmax(dim=1) # B, HW, H, W + pos_embeddings = torch.einsum('bchw,cd->bdhw', P, grid) + return pos_embeddings + + def visualize_warp(self, warp, certainty, im_A = None, im_B = None, + im_A_path = None, im_B_path = None, symmetric = True, save_path = None, unnormalize = False): + device = warp.device + H,W2,_ = warp.shape + W = W2//2 if symmetric else W2 + if im_A is None: + from PIL import Image + im_A, im_B = Image.open(im_A_path).convert("RGB"), Image.open(im_B_path).convert("RGB") + if not isinstance(im_A, torch.Tensor): + im_A = im_A.resize((W,H)) + im_B = im_B.resize((W,H)) + x_B = (torch.tensor(np.array(im_B)) / 255).to(device).permute(2, 0, 1) + if symmetric: + x_A = (torch.tensor(np.array(im_A)) / 255).to(device).permute(2, 0, 1) + else: + if symmetric: + x_A = im_A + x_B = im_B + im_A_transfer_rgb = F.grid_sample( + x_B[None], warp[:,:W, 2:][None], mode="bilinear", align_corners=False + )[0] + if symmetric: + im_B_transfer_rgb = F.grid_sample( + x_A[None], warp[:, W:, :2][None], mode="bilinear", align_corners=False + )[0] + warp_im = torch.cat((im_A_transfer_rgb,im_B_transfer_rgb),dim=2) + white_im = torch.ones((H,2*W),device=device) + else: + warp_im = im_A_transfer_rgb + white_im = torch.ones((H, W), device = device) + vis_im = certainty * warp_im + (1 - certainty) * white_im + if save_path is not None: + from romatch.utils import tensor_to_pil + tensor_to_pil(vis_im, unnormalize=unnormalize).save(save_path) + return vis_im + + def corr_volume(self, feat0, feat1): + """ + input: + feat0 -> torch.Tensor(B, C, H, W) + feat1 -> torch.Tensor(B, C, H, W) + return: + corr_volume -> torch.Tensor(B, H, W, H, W) + """ + B, C, H0, W0 = feat0.shape + B, C, H1, W1 = feat1.shape + feat0 = feat0.view(B, C, H0*W0) + feat1 = feat1.view(B, C, H1*W1) + corr_volume = torch.einsum('bci,bcj->bji', feat0, feat1).reshape(B, H1, W1, H0 , W0)/math.sqrt(C) #16*16*16 + return corr_volume + + @torch.inference_mode() + def match_from_path(self, im0_path, im1_path): + device = self.device + im0 = ToTensor()(Image.open(im0_path))[None].to(device) + im1 = ToTensor()(Image.open(im1_path))[None].to(device) + return self.match(im0, im1, batched = False) + + @torch.inference_mode() + def match(self, im0, im1, *args, batched = True): + # stupid + if isinstance(im0, (str, Path)): + return self.match_from_path(im0, im1) + elif isinstance(im0, Image.Image): + batched = False + device = self.device + im0 = ToTensor()(im0)[None].to(device) + im1 = ToTensor()(im1)[None].to(device) + + B,C,H0,W0 = im0.shape + B,C,H1,W1 = im1.shape + self.train(False) + corresps = self.forward({"im_A":im0, "im_B":im1}) + #return 1,1 + flow = F.interpolate( + corresps[4]["flow"], + size = (H0, W0), + mode = "bilinear", align_corners = False).permute(0,2,3,1).reshape(B,H0,W0,2) + grid = torch.stack( + torch.meshgrid( + torch.linspace(-1+1/W0,1-1/W0, W0), + torch.linspace(-1+1/H0,1-1/H0, H0), + indexing = "xy"), + dim = -1).float().to(flow.device).expand(B, H0, W0, 2) + + certainty = F.interpolate(corresps[4]["certainty"], size = (H0,W0), mode = "bilinear", align_corners = False) + warp, cert = torch.cat((grid, flow), dim = -1), certainty[:,0].sigmoid() + if batched: + return warp, cert + else: + return warp[0], cert[0] + + def sample( + self, + matches, + certainty, + num=5_000, + ): + H,W,_ = matches.shape + if "threshold" in self.sample_mode: + upper_thresh = self.sample_thresh + certainty = certainty.clone() + certainty[certainty > upper_thresh] = 1 + matches, certainty = ( + matches.reshape(-1, 4), + certainty.reshape(-1), + ) + expansion_factor = 4 if "balanced" in self.sample_mode else 1 + good_samples = torch.multinomial(certainty, + num_samples = min(expansion_factor*num, len(certainty)), + replacement=False) + good_matches, good_certainty = matches[good_samples], certainty[good_samples] + if "balanced" not in self.sample_mode: + return good_matches, good_certainty + use_half = True if matches.device.type == "cuda" else False + down = 1 if matches.device.type == "cuda" else 8 + density = kde(good_matches, std=0.1, half = use_half, down = down) + p = 1 / (density+1) + p[density < 10] = 1e-7 # Basically should have at least 10 perfect neighbours, or around 100 ok ones + balanced_samples = torch.multinomial(p, + num_samples = min(num,len(good_certainty)), + replacement=False) + return good_matches[balanced_samples], good_certainty[balanced_samples] + + + def forward(self, batch): + """ + input: + x -> torch.Tensor(B, C, H, W) grayscale or rgb images + return: + + """ + im0 = batch["im_A"] + im1 = batch["im_B"] + corresps = {} + im0, rh0, rw0 = self.preprocess_tensor(im0) + im1, rh1, rw1 = self.preprocess_tensor(im1) + B, C, H0, W0 = im0.shape + B, C, H1, W1 = im1.shape + to_normalized = torch.tensor((2/W1, 2/H1, 1)).to(im0.device)[None,:,None,None] + + if im0.shape[-2:] == im1.shape[-2:]: + x = torch.cat([im0, im1], dim=0) + x = self.forward_single(x) + feats_x0_c, feats_x1_c = x[1].chunk(2) + feats_x0_f, feats_x1_f = x[0].chunk(2) + else: + feats_x0_f, feats_x0_c = self.forward_single(im0) + feats_x1_f, feats_x1_c = self.forward_single(im1) + corr_volume = self.corr_volume(feats_x0_c, feats_x1_c) + coarse_warp = self.pos_embed(corr_volume) + coarse_matches = torch.cat((coarse_warp, torch.zeros_like(coarse_warp[:,-1:])), dim=1) + feats_x1_c_warped = F.grid_sample(feats_x1_c, coarse_matches.permute(0, 2, 3, 1)[...,:2], mode = 'bilinear', align_corners = False) + coarse_matches_delta = self.coarse_matcher(torch.cat((feats_x0_c, feats_x1_c_warped, coarse_warp), dim=1)) + coarse_matches = coarse_matches + coarse_matches_delta * to_normalized + corresps[8] = {"flow": coarse_matches[:,:2], "certainty": coarse_matches[:,2:]} + coarse_matches_up = F.interpolate(coarse_matches, size = feats_x0_f.shape[-2:], mode = "bilinear", align_corners = False) + coarse_matches_up_detach = coarse_matches_up.detach()#note the detach + feats_x1_f_warped = F.grid_sample(feats_x1_f, coarse_matches_up_detach.permute(0, 2, 3, 1)[...,:2], mode = 'bilinear', align_corners = False) + fine_matches_delta = self.fine_matcher(torch.cat((feats_x0_f, feats_x1_f_warped, coarse_matches_up_detach[:,:2]), dim=1)) + fine_matches = coarse_matches_up_detach+fine_matches_delta * to_normalized + corresps[4] = {"flow": fine_matches[:,:2], "certainty": fine_matches[:,2:]} + return corresps \ No newline at end of file diff --git a/submodules/RoMa/romatch/models/transformer/__init__.py b/submodules/RoMa/romatch/models/transformer/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..983f03ccc51cdbcef6166a160fe50652a81418d7 --- /dev/null +++ b/submodules/RoMa/romatch/models/transformer/__init__.py @@ -0,0 +1,48 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + +from romatch.utils.utils import get_grid, get_autocast_params +from .layers.block import Block +from .layers.attention import MemEffAttention +from .dinov2 import vit_large + +class TransformerDecoder(nn.Module): + def __init__(self, blocks, hidden_dim, out_dim, is_classifier = False, *args, + amp = False, pos_enc = True, learned_embeddings = False, embedding_dim = None, amp_dtype = torch.float16, **kwargs) -> None: + super().__init__(*args, **kwargs) + self.blocks = blocks + self.to_out = nn.Linear(hidden_dim, out_dim) + self.hidden_dim = hidden_dim + self.out_dim = out_dim + self._scales = [16] + self.is_classifier = is_classifier + self.amp = amp + self.amp_dtype = amp_dtype + self.pos_enc = pos_enc + self.learned_embeddings = learned_embeddings + if self.learned_embeddings: + self.learned_pos_embeddings = nn.Parameter(nn.init.kaiming_normal_(torch.empty((1, hidden_dim, embedding_dim, embedding_dim)))) + + def scales(self): + return self._scales.copy() + + def forward(self, gp_posterior, features, old_stuff, new_scale): + autocast_device, autocast_enabled, autocast_dtype = get_autocast_params(gp_posterior.device, enabled=self.amp, dtype=self.amp_dtype) + with torch.autocast(autocast_device, enabled=autocast_enabled, dtype = autocast_dtype): + B,C,H,W = gp_posterior.shape + x = torch.cat((gp_posterior, features), dim = 1) + B,C,H,W = x.shape + grid = get_grid(B, H, W, x.device).reshape(B,H*W,2) + if self.learned_embeddings: + pos_enc = F.interpolate(self.learned_pos_embeddings, size = (H,W), mode = 'bilinear', align_corners = False).permute(0,2,3,1).reshape(1,H*W,C) + else: + pos_enc = 0 + tokens = x.reshape(B,C,H*W).permute(0,2,1) + pos_enc + z = self.blocks(tokens) + out = self.to_out(z) + out = out.permute(0,2,1).reshape(B, self.out_dim, H, W) + warp, certainty = out[:, :-1], out[:, -1:] + return warp, certainty, None + + diff --git a/submodules/RoMa/romatch/models/transformer/dinov2.py b/submodules/RoMa/romatch/models/transformer/dinov2.py new file mode 100644 index 0000000000000000000000000000000000000000..b556c63096d17239c8603d5fe626c331963099fd --- /dev/null +++ b/submodules/RoMa/romatch/models/transformer/dinov2.py @@ -0,0 +1,359 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the license found in the +# LICENSE file in the root directory of this source tree. + +# References: +# https://github.com/facebookresearch/dino/blob/main/vision_transformer.py +# https://github.com/rwightman/pytorch-image-models/tree/master/timm/models/vision_transformer.py + +from functools import partial +import math +import logging +from typing import Sequence, Tuple, Union, Callable + +import torch +import torch.nn as nn +import torch.utils.checkpoint +from torch.nn.init import trunc_normal_ + +from .layers import Mlp, PatchEmbed, SwiGLUFFNFused, MemEffAttention, NestedTensorBlock as Block + + + +def named_apply(fn: Callable, module: nn.Module, name="", depth_first=True, include_root=False) -> nn.Module: + if not depth_first and include_root: + fn(module=module, name=name) + for child_name, child_module in module.named_children(): + child_name = ".".join((name, child_name)) if name else child_name + named_apply(fn=fn, module=child_module, name=child_name, depth_first=depth_first, include_root=True) + if depth_first and include_root: + fn(module=module, name=name) + return module + + +class BlockChunk(nn.ModuleList): + def forward(self, x): + for b in self: + x = b(x) + return x + + +class DinoVisionTransformer(nn.Module): + def __init__( + self, + img_size=224, + patch_size=16, + in_chans=3, + embed_dim=768, + depth=12, + num_heads=12, + mlp_ratio=4.0, + qkv_bias=True, + ffn_bias=True, + proj_bias=True, + drop_path_rate=0.0, + drop_path_uniform=False, + init_values=None, # for layerscale: None or 0 => no layerscale + embed_layer=PatchEmbed, + act_layer=nn.GELU, + block_fn=Block, + ffn_layer="mlp", + block_chunks=1, + ): + """ + Args: + img_size (int, tuple): input image size + patch_size (int, tuple): patch size + in_chans (int): number of input channels + embed_dim (int): embedding dimension + depth (int): depth of transformer + num_heads (int): number of attention heads + mlp_ratio (int): ratio of mlp hidden dim to embedding dim + qkv_bias (bool): enable bias for qkv if True + proj_bias (bool): enable bias for proj in attn if True + ffn_bias (bool): enable bias for ffn if True + drop_path_rate (float): stochastic depth rate + drop_path_uniform (bool): apply uniform drop rate across blocks + weight_init (str): weight init scheme + init_values (float): layer-scale init values + embed_layer (nn.Module): patch embedding layer + act_layer (nn.Module): MLP activation layer + block_fn (nn.Module): transformer block class + ffn_layer (str): "mlp", "swiglu", "swiglufused" or "identity" + block_chunks: (int) split block sequence into block_chunks units for FSDP wrap + """ + super().__init__() + norm_layer = partial(nn.LayerNorm, eps=1e-6) + + self.num_features = self.embed_dim = embed_dim # num_features for consistency with other models + self.num_tokens = 1 + self.n_blocks = depth + self.num_heads = num_heads + self.patch_size = patch_size + + self.patch_embed = embed_layer(img_size=img_size, patch_size=patch_size, in_chans=in_chans, embed_dim=embed_dim) + num_patches = self.patch_embed.num_patches + + self.cls_token = nn.Parameter(torch.zeros(1, 1, embed_dim)) + self.pos_embed = nn.Parameter(torch.zeros(1, num_patches + self.num_tokens, embed_dim)) + + if drop_path_uniform is True: + dpr = [drop_path_rate] * depth + else: + dpr = [x.item() for x in torch.linspace(0, drop_path_rate, depth)] # stochastic depth decay rule + + if ffn_layer == "mlp": + ffn_layer = Mlp + elif ffn_layer == "swiglufused" or ffn_layer == "swiglu": + ffn_layer = SwiGLUFFNFused + elif ffn_layer == "identity": + + def f(*args, **kwargs): + return nn.Identity() + + ffn_layer = f + else: + raise NotImplementedError + + blocks_list = [ + block_fn( + dim=embed_dim, + num_heads=num_heads, + mlp_ratio=mlp_ratio, + qkv_bias=qkv_bias, + proj_bias=proj_bias, + ffn_bias=ffn_bias, + drop_path=dpr[i], + norm_layer=norm_layer, + act_layer=act_layer, + ffn_layer=ffn_layer, + init_values=init_values, + ) + for i in range(depth) + ] + if block_chunks > 0: + self.chunked_blocks = True + chunked_blocks = [] + chunksize = depth // block_chunks + for i in range(0, depth, chunksize): + # this is to keep the block index consistent if we chunk the block list + chunked_blocks.append([nn.Identity()] * i + blocks_list[i : i + chunksize]) + self.blocks = nn.ModuleList([BlockChunk(p) for p in chunked_blocks]) + else: + self.chunked_blocks = False + self.blocks = nn.ModuleList(blocks_list) + + self.norm = norm_layer(embed_dim) + self.head = nn.Identity() + + self.mask_token = nn.Parameter(torch.zeros(1, embed_dim)) + + self.init_weights() + for param in self.parameters(): + param.requires_grad = False + + @property + def device(self): + return self.cls_token.device + + def init_weights(self): + trunc_normal_(self.pos_embed, std=0.02) + nn.init.normal_(self.cls_token, std=1e-6) + named_apply(init_weights_vit_timm, self) + + def interpolate_pos_encoding(self, x, w, h): + previous_dtype = x.dtype + npatch = x.shape[1] - 1 + N = self.pos_embed.shape[1] - 1 + if npatch == N and w == h: + return self.pos_embed + pos_embed = self.pos_embed.float() + class_pos_embed = pos_embed[:, 0] + patch_pos_embed = pos_embed[:, 1:] + dim = x.shape[-1] + w0 = w // self.patch_size + h0 = h // self.patch_size + # we add a small number to avoid floating point error in the interpolation + # see discussion at https://github.com/facebookresearch/dino/issues/8 + w0, h0 = w0 + 0.1, h0 + 0.1 + + patch_pos_embed = nn.functional.interpolate( + patch_pos_embed.reshape(1, int(math.sqrt(N)), int(math.sqrt(N)), dim).permute(0, 3, 1, 2), + scale_factor=(w0 / math.sqrt(N), h0 / math.sqrt(N)), + mode="bicubic", + ) + + assert int(w0) == patch_pos_embed.shape[-2] and int(h0) == patch_pos_embed.shape[-1] + patch_pos_embed = patch_pos_embed.permute(0, 2, 3, 1).view(1, -1, dim) + return torch.cat((class_pos_embed.unsqueeze(0), patch_pos_embed), dim=1).to(previous_dtype) + + def prepare_tokens_with_masks(self, x, masks=None): + B, nc, w, h = x.shape + x = self.patch_embed(x) + if masks is not None: + x = torch.where(masks.unsqueeze(-1), self.mask_token.to(x.dtype).unsqueeze(0), x) + + x = torch.cat((self.cls_token.expand(x.shape[0], -1, -1), x), dim=1) + x = x + self.interpolate_pos_encoding(x, w, h) + + return x + + def forward_features_list(self, x_list, masks_list): + x = [self.prepare_tokens_with_masks(x, masks) for x, masks in zip(x_list, masks_list)] + for blk in self.blocks: + x = blk(x) + + all_x = x + output = [] + for x, masks in zip(all_x, masks_list): + x_norm = self.norm(x) + output.append( + { + "x_norm_clstoken": x_norm[:, 0], + "x_norm_patchtokens": x_norm[:, 1:], + "x_prenorm": x, + "masks": masks, + } + ) + return output + + def forward_features(self, x, masks=None): + if isinstance(x, list): + return self.forward_features_list(x, masks) + + x = self.prepare_tokens_with_masks(x, masks) + + for blk in self.blocks: + x = blk(x) + + x_norm = self.norm(x) + return { + "x_norm_clstoken": x_norm[:, 0], + "x_norm_patchtokens": x_norm[:, 1:], + "x_prenorm": x, + "masks": masks, + } + + def _get_intermediate_layers_not_chunked(self, x, n=1): + x = self.prepare_tokens_with_masks(x) + # If n is an int, take the n last blocks. If it's a list, take them + output, total_block_len = [], len(self.blocks) + blocks_to_take = range(total_block_len - n, total_block_len) if isinstance(n, int) else n + for i, blk in enumerate(self.blocks): + x = blk(x) + if i in blocks_to_take: + output.append(x) + assert len(output) == len(blocks_to_take), f"only {len(output)} / {len(blocks_to_take)} blocks found" + return output + + def _get_intermediate_layers_chunked(self, x, n=1): + x = self.prepare_tokens_with_masks(x) + output, i, total_block_len = [], 0, len(self.blocks[-1]) + # If n is an int, take the n last blocks. If it's a list, take them + blocks_to_take = range(total_block_len - n, total_block_len) if isinstance(n, int) else n + for block_chunk in self.blocks: + for blk in block_chunk[i:]: # Passing the nn.Identity() + x = blk(x) + if i in blocks_to_take: + output.append(x) + i += 1 + assert len(output) == len(blocks_to_take), f"only {len(output)} / {len(blocks_to_take)} blocks found" + return output + + def get_intermediate_layers( + self, + x: torch.Tensor, + n: Union[int, Sequence] = 1, # Layers or n last layers to take + reshape: bool = False, + return_class_token: bool = False, + norm=True, + ) -> Tuple[Union[torch.Tensor, Tuple[torch.Tensor]]]: + if self.chunked_blocks: + outputs = self._get_intermediate_layers_chunked(x, n) + else: + outputs = self._get_intermediate_layers_not_chunked(x, n) + if norm: + outputs = [self.norm(out) for out in outputs] + class_tokens = [out[:, 0] for out in outputs] + outputs = [out[:, 1:] for out in outputs] + if reshape: + B, _, w, h = x.shape + outputs = [ + out.reshape(B, w // self.patch_size, h // self.patch_size, -1).permute(0, 3, 1, 2).contiguous() + for out in outputs + ] + if return_class_token: + return tuple(zip(outputs, class_tokens)) + return tuple(outputs) + + def forward(self, *args, is_training=False, **kwargs): + ret = self.forward_features(*args, **kwargs) + if is_training: + return ret + else: + return self.head(ret["x_norm_clstoken"]) + + +def init_weights_vit_timm(module: nn.Module, name: str = ""): + """ViT weight initialization, original timm impl (for reproducibility)""" + if isinstance(module, nn.Linear): + trunc_normal_(module.weight, std=0.02) + if module.bias is not None: + nn.init.zeros_(module.bias) + + +def vit_small(patch_size=16, **kwargs): + model = DinoVisionTransformer( + patch_size=patch_size, + embed_dim=384, + depth=12, + num_heads=6, + mlp_ratio=4, + block_fn=partial(Block, attn_class=MemEffAttention), + **kwargs, + ) + return model + + +def vit_base(patch_size=16, **kwargs): + model = DinoVisionTransformer( + patch_size=patch_size, + embed_dim=768, + depth=12, + num_heads=12, + mlp_ratio=4, + block_fn=partial(Block, attn_class=MemEffAttention), + **kwargs, + ) + return model + + +def vit_large(patch_size=16, **kwargs): + model = DinoVisionTransformer( + patch_size=patch_size, + embed_dim=1024, + depth=24, + num_heads=16, + mlp_ratio=4, + block_fn=partial(Block, attn_class=MemEffAttention), + **kwargs, + ) + return model + + +def vit_giant2(patch_size=16, **kwargs): + """ + Close to ViT-giant, with embed-dim 1536 and 24 heads => embed-dim per head 64 + """ + model = DinoVisionTransformer( + patch_size=patch_size, + embed_dim=1536, + depth=40, + num_heads=24, + mlp_ratio=4, + block_fn=partial(Block, attn_class=MemEffAttention), + **kwargs, + ) + return model \ No newline at end of file diff --git a/submodules/RoMa/romatch/models/transformer/layers/__init__.py b/submodules/RoMa/romatch/models/transformer/layers/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..31f196aacac5be8a7c537a3dfa8f97084671b466 --- /dev/null +++ b/submodules/RoMa/romatch/models/transformer/layers/__init__.py @@ -0,0 +1,12 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the license found in the +# LICENSE file in the root directory of this source tree. + +from .dino_head import DINOHead +from .mlp import Mlp +from .patch_embed import PatchEmbed +from .swiglu_ffn import SwiGLUFFN, SwiGLUFFNFused +from .block import NestedTensorBlock +from .attention import MemEffAttention diff --git a/submodules/RoMa/romatch/models/transformer/layers/attention.py b/submodules/RoMa/romatch/models/transformer/layers/attention.py new file mode 100644 index 0000000000000000000000000000000000000000..1f9b0c94b40967dfdff4f261c127cbd21328c905 --- /dev/null +++ b/submodules/RoMa/romatch/models/transformer/layers/attention.py @@ -0,0 +1,81 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the license found in the +# LICENSE file in the root directory of this source tree. + +# References: +# https://github.com/facebookresearch/dino/blob/master/vision_transformer.py +# https://github.com/rwightman/pytorch-image-models/tree/master/timm/models/vision_transformer.py + +import logging + +from torch import Tensor +from torch import nn + + +logger = logging.getLogger("dinov2") + + +try: + from xformers.ops import memory_efficient_attention, unbind, fmha + + XFORMERS_AVAILABLE = True +except ImportError: + logger.warning("xFormers not available") + XFORMERS_AVAILABLE = False + + +class Attention(nn.Module): + def __init__( + self, + dim: int, + num_heads: int = 8, + qkv_bias: bool = False, + proj_bias: bool = True, + attn_drop: float = 0.0, + proj_drop: float = 0.0, + ) -> None: + super().__init__() + self.num_heads = num_heads + head_dim = dim // num_heads + self.scale = head_dim**-0.5 + + self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias) + self.attn_drop = nn.Dropout(attn_drop) + self.proj = nn.Linear(dim, dim, bias=proj_bias) + self.proj_drop = nn.Dropout(proj_drop) + + def forward(self, x: Tensor) -> Tensor: + B, N, C = x.shape + qkv = self.qkv(x).reshape(B, N, 3, self.num_heads, C // self.num_heads).permute(2, 0, 3, 1, 4) + + q, k, v = qkv[0] * self.scale, qkv[1], qkv[2] + attn = q @ k.transpose(-2, -1) + + attn = attn.softmax(dim=-1) + attn = self.attn_drop(attn) + + x = (attn @ v).transpose(1, 2).reshape(B, N, C) + x = self.proj(x) + x = self.proj_drop(x) + return x + + +class MemEffAttention(Attention): + def forward(self, x: Tensor, attn_bias=None) -> Tensor: + if not XFORMERS_AVAILABLE: + assert attn_bias is None, "xFormers is required for nested tensors usage" + return super().forward(x) + + B, N, C = x.shape + qkv = self.qkv(x).reshape(B, N, 3, self.num_heads, C // self.num_heads) + + q, k, v = unbind(qkv, 2) + + x = memory_efficient_attention(q, k, v, attn_bias=attn_bias) + x = x.reshape([B, N, C]) + + x = self.proj(x) + x = self.proj_drop(x) + return x diff --git a/submodules/RoMa/romatch/models/transformer/layers/block.py b/submodules/RoMa/romatch/models/transformer/layers/block.py new file mode 100644 index 0000000000000000000000000000000000000000..a711a1f2ee00c8a6b5e79504f41f13145450af79 --- /dev/null +++ b/submodules/RoMa/romatch/models/transformer/layers/block.py @@ -0,0 +1,252 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the license found in the +# LICENSE file in the root directory of this source tree. + +# References: +# https://github.com/facebookresearch/dino/blob/master/vision_transformer.py +# https://github.com/rwightman/pytorch-image-models/tree/master/timm/layers/patch_embed.py + +import logging +from typing import Callable, List, Any, Tuple, Dict + +import torch +from torch import nn, Tensor + +from .attention import Attention, MemEffAttention +from .drop_path import DropPath +from .layer_scale import LayerScale +from .mlp import Mlp + + +logger = logging.getLogger("dinov2") + + +try: + from xformers.ops import fmha + from xformers.ops import scaled_index_add, index_select_cat + + XFORMERS_AVAILABLE = True +except ImportError: + # logger.warning("xFormers not available") + XFORMERS_AVAILABLE = False + + +class Block(nn.Module): + def __init__( + self, + dim: int, + num_heads: int, + mlp_ratio: float = 4.0, + qkv_bias: bool = False, + proj_bias: bool = True, + ffn_bias: bool = True, + drop: float = 0.0, + attn_drop: float = 0.0, + init_values=None, + drop_path: float = 0.0, + act_layer: Callable[..., nn.Module] = nn.GELU, + norm_layer: Callable[..., nn.Module] = nn.LayerNorm, + attn_class: Callable[..., nn.Module] = Attention, + ffn_layer: Callable[..., nn.Module] = Mlp, + ) -> None: + super().__init__() + # print(f"biases: qkv: {qkv_bias}, proj: {proj_bias}, ffn: {ffn_bias}") + self.norm1 = norm_layer(dim) + self.attn = attn_class( + dim, + num_heads=num_heads, + qkv_bias=qkv_bias, + proj_bias=proj_bias, + attn_drop=attn_drop, + proj_drop=drop, + ) + self.ls1 = LayerScale(dim, init_values=init_values) if init_values else nn.Identity() + self.drop_path1 = DropPath(drop_path) if drop_path > 0.0 else nn.Identity() + + self.norm2 = norm_layer(dim) + mlp_hidden_dim = int(dim * mlp_ratio) + self.mlp = ffn_layer( + in_features=dim, + hidden_features=mlp_hidden_dim, + act_layer=act_layer, + drop=drop, + bias=ffn_bias, + ) + self.ls2 = LayerScale(dim, init_values=init_values) if init_values else nn.Identity() + self.drop_path2 = DropPath(drop_path) if drop_path > 0.0 else nn.Identity() + + self.sample_drop_ratio = drop_path + + def forward(self, x: Tensor) -> Tensor: + def attn_residual_func(x: Tensor) -> Tensor: + return self.ls1(self.attn(self.norm1(x))) + + def ffn_residual_func(x: Tensor) -> Tensor: + return self.ls2(self.mlp(self.norm2(x))) + + if self.training and self.sample_drop_ratio > 0.1: + # the overhead is compensated only for a drop path rate larger than 0.1 + x = drop_add_residual_stochastic_depth( + x, + residual_func=attn_residual_func, + sample_drop_ratio=self.sample_drop_ratio, + ) + x = drop_add_residual_stochastic_depth( + x, + residual_func=ffn_residual_func, + sample_drop_ratio=self.sample_drop_ratio, + ) + elif self.training and self.sample_drop_ratio > 0.0: + x = x + self.drop_path1(attn_residual_func(x)) + x = x + self.drop_path1(ffn_residual_func(x)) # FIXME: drop_path2 + else: + x = x + attn_residual_func(x) + x = x + ffn_residual_func(x) + return x + + +def drop_add_residual_stochastic_depth( + x: Tensor, + residual_func: Callable[[Tensor], Tensor], + sample_drop_ratio: float = 0.0, +) -> Tensor: + # 1) extract subset using permutation + b, n, d = x.shape + sample_subset_size = max(int(b * (1 - sample_drop_ratio)), 1) + brange = (torch.randperm(b, device=x.device))[:sample_subset_size] + x_subset = x[brange] + + # 2) apply residual_func to get residual + residual = residual_func(x_subset) + + x_flat = x.flatten(1) + residual = residual.flatten(1) + + residual_scale_factor = b / sample_subset_size + + # 3) add the residual + x_plus_residual = torch.index_add(x_flat, 0, brange, residual.to(dtype=x.dtype), alpha=residual_scale_factor) + return x_plus_residual.view_as(x) + + +def get_branges_scales(x, sample_drop_ratio=0.0): + b, n, d = x.shape + sample_subset_size = max(int(b * (1 - sample_drop_ratio)), 1) + brange = (torch.randperm(b, device=x.device))[:sample_subset_size] + residual_scale_factor = b / sample_subset_size + return brange, residual_scale_factor + + +def add_residual(x, brange, residual, residual_scale_factor, scaling_vector=None): + if scaling_vector is None: + x_flat = x.flatten(1) + residual = residual.flatten(1) + x_plus_residual = torch.index_add(x_flat, 0, brange, residual.to(dtype=x.dtype), alpha=residual_scale_factor) + else: + x_plus_residual = scaled_index_add( + x, brange, residual.to(dtype=x.dtype), scaling=scaling_vector, alpha=residual_scale_factor + ) + return x_plus_residual + + +attn_bias_cache: Dict[Tuple, Any] = {} + + +def get_attn_bias_and_cat(x_list, branges=None): + """ + this will perform the index select, cat the tensors, and provide the attn_bias from cache + """ + batch_sizes = [b.shape[0] for b in branges] if branges is not None else [x.shape[0] for x in x_list] + all_shapes = tuple((b, x.shape[1]) for b, x in zip(batch_sizes, x_list)) + if all_shapes not in attn_bias_cache.keys(): + seqlens = [] + for b, x in zip(batch_sizes, x_list): + for _ in range(b): + seqlens.append(x.shape[1]) + attn_bias = fmha.BlockDiagonalMask.from_seqlens(seqlens) + attn_bias._batch_sizes = batch_sizes + attn_bias_cache[all_shapes] = attn_bias + + if branges is not None: + cat_tensors = index_select_cat([x.flatten(1) for x in x_list], branges).view(1, -1, x_list[0].shape[-1]) + else: + tensors_bs1 = tuple(x.reshape([1, -1, *x.shape[2:]]) for x in x_list) + cat_tensors = torch.cat(tensors_bs1, dim=1) + + return attn_bias_cache[all_shapes], cat_tensors + + +def drop_add_residual_stochastic_depth_list( + x_list: List[Tensor], + residual_func: Callable[[Tensor, Any], Tensor], + sample_drop_ratio: float = 0.0, + scaling_vector=None, +) -> Tensor: + # 1) generate random set of indices for dropping samples in the batch + branges_scales = [get_branges_scales(x, sample_drop_ratio=sample_drop_ratio) for x in x_list] + branges = [s[0] for s in branges_scales] + residual_scale_factors = [s[1] for s in branges_scales] + + # 2) get attention bias and index+concat the tensors + attn_bias, x_cat = get_attn_bias_and_cat(x_list, branges) + + # 3) apply residual_func to get residual, and split the result + residual_list = attn_bias.split(residual_func(x_cat, attn_bias=attn_bias)) # type: ignore + + outputs = [] + for x, brange, residual, residual_scale_factor in zip(x_list, branges, residual_list, residual_scale_factors): + outputs.append(add_residual(x, brange, residual, residual_scale_factor, scaling_vector).view_as(x)) + return outputs + + +class NestedTensorBlock(Block): + def forward_nested(self, x_list: List[Tensor]) -> List[Tensor]: + """ + x_list contains a list of tensors to nest together and run + """ + assert isinstance(self.attn, MemEffAttention) + + if self.training and self.sample_drop_ratio > 0.0: + + def attn_residual_func(x: Tensor, attn_bias=None) -> Tensor: + return self.attn(self.norm1(x), attn_bias=attn_bias) + + def ffn_residual_func(x: Tensor, attn_bias=None) -> Tensor: + return self.mlp(self.norm2(x)) + + x_list = drop_add_residual_stochastic_depth_list( + x_list, + residual_func=attn_residual_func, + sample_drop_ratio=self.sample_drop_ratio, + scaling_vector=self.ls1.gamma if isinstance(self.ls1, LayerScale) else None, + ) + x_list = drop_add_residual_stochastic_depth_list( + x_list, + residual_func=ffn_residual_func, + sample_drop_ratio=self.sample_drop_ratio, + scaling_vector=self.ls2.gamma if isinstance(self.ls1, LayerScale) else None, + ) + return x_list + else: + + def attn_residual_func(x: Tensor, attn_bias=None) -> Tensor: + return self.ls1(self.attn(self.norm1(x), attn_bias=attn_bias)) + + def ffn_residual_func(x: Tensor, attn_bias=None) -> Tensor: + return self.ls2(self.mlp(self.norm2(x))) + + attn_bias, x = get_attn_bias_and_cat(x_list) + x = x + attn_residual_func(x, attn_bias=attn_bias) + x = x + ffn_residual_func(x) + return attn_bias.split(x) + + def forward(self, x_or_x_list): + if isinstance(x_or_x_list, Tensor): + return super().forward(x_or_x_list) + elif isinstance(x_or_x_list, list): + assert XFORMERS_AVAILABLE, "Please install xFormers for nested tensors usage" + return self.forward_nested(x_or_x_list) + else: + raise AssertionError diff --git a/submodules/RoMa/romatch/models/transformer/layers/dino_head.py b/submodules/RoMa/romatch/models/transformer/layers/dino_head.py new file mode 100644 index 0000000000000000000000000000000000000000..7212db92a4fd8d4c7230e284e551a0234e9d8623 --- /dev/null +++ b/submodules/RoMa/romatch/models/transformer/layers/dino_head.py @@ -0,0 +1,59 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the license found in the +# LICENSE file in the root directory of this source tree. + +import torch +import torch.nn as nn +from torch.nn.init import trunc_normal_ +from torch.nn.utils import weight_norm + + +class DINOHead(nn.Module): + def __init__( + self, + in_dim, + out_dim, + use_bn=False, + nlayers=3, + hidden_dim=2048, + bottleneck_dim=256, + mlp_bias=True, + ): + super().__init__() + nlayers = max(nlayers, 1) + self.mlp = _build_mlp(nlayers, in_dim, bottleneck_dim, hidden_dim=hidden_dim, use_bn=use_bn, bias=mlp_bias) + self.apply(self._init_weights) + self.last_layer = weight_norm(nn.Linear(bottleneck_dim, out_dim, bias=False)) + self.last_layer.weight_g.data.fill_(1) + + def _init_weights(self, m): + if isinstance(m, nn.Linear): + trunc_normal_(m.weight, std=0.02) + if isinstance(m, nn.Linear) and m.bias is not None: + nn.init.constant_(m.bias, 0) + + def forward(self, x): + x = self.mlp(x) + eps = 1e-6 if x.dtype == torch.float16 else 1e-12 + x = nn.functional.normalize(x, dim=-1, p=2, eps=eps) + x = self.last_layer(x) + return x + + +def _build_mlp(nlayers, in_dim, bottleneck_dim, hidden_dim=None, use_bn=False, bias=True): + if nlayers == 1: + return nn.Linear(in_dim, bottleneck_dim, bias=bias) + else: + layers = [nn.Linear(in_dim, hidden_dim, bias=bias)] + if use_bn: + layers.append(nn.BatchNorm1d(hidden_dim)) + layers.append(nn.GELU()) + for _ in range(nlayers - 2): + layers.append(nn.Linear(hidden_dim, hidden_dim, bias=bias)) + if use_bn: + layers.append(nn.BatchNorm1d(hidden_dim)) + layers.append(nn.GELU()) + layers.append(nn.Linear(hidden_dim, bottleneck_dim, bias=bias)) + return nn.Sequential(*layers) diff --git a/submodules/RoMa/romatch/models/transformer/layers/drop_path.py b/submodules/RoMa/romatch/models/transformer/layers/drop_path.py new file mode 100644 index 0000000000000000000000000000000000000000..af05625984dd14682cc96a63bf0c97bab1f123b1 --- /dev/null +++ b/submodules/RoMa/romatch/models/transformer/layers/drop_path.py @@ -0,0 +1,35 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the license found in the +# LICENSE file in the root directory of this source tree. + +# References: +# https://github.com/facebookresearch/dino/blob/master/vision_transformer.py +# https://github.com/rwightman/pytorch-image-models/tree/master/timm/layers/drop.py + + +from torch import nn + + +def drop_path(x, drop_prob: float = 0.0, training: bool = False): + if drop_prob == 0.0 or not training: + return x + keep_prob = 1 - drop_prob + shape = (x.shape[0],) + (1,) * (x.ndim - 1) # work with diff dim tensors, not just 2D ConvNets + random_tensor = x.new_empty(shape).bernoulli_(keep_prob) + if keep_prob > 0.0: + random_tensor.div_(keep_prob) + output = x * random_tensor + return output + + +class DropPath(nn.Module): + """Drop paths (Stochastic Depth) per sample (when applied in main path of residual blocks).""" + + def __init__(self, drop_prob=None): + super(DropPath, self).__init__() + self.drop_prob = drop_prob + + def forward(self, x): + return drop_path(x, self.drop_prob, self.training) diff --git a/submodules/RoMa/romatch/models/transformer/layers/layer_scale.py b/submodules/RoMa/romatch/models/transformer/layers/layer_scale.py new file mode 100644 index 0000000000000000000000000000000000000000..ca5daa52bd81d3581adeb2198ea5b7dba2a3aea1 --- /dev/null +++ b/submodules/RoMa/romatch/models/transformer/layers/layer_scale.py @@ -0,0 +1,28 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the license found in the +# LICENSE file in the root directory of this source tree. + +# Modified from: https://github.com/huggingface/pytorch-image-models/blob/main/timm/models/vision_transformer.py#L103-L110 + +from typing import Union + +import torch +from torch import Tensor +from torch import nn + + +class LayerScale(nn.Module): + def __init__( + self, + dim: int, + init_values: Union[float, Tensor] = 1e-5, + inplace: bool = False, + ) -> None: + super().__init__() + self.inplace = inplace + self.gamma = nn.Parameter(init_values * torch.ones(dim)) + + def forward(self, x: Tensor) -> Tensor: + return x.mul_(self.gamma) if self.inplace else x * self.gamma diff --git a/submodules/RoMa/romatch/models/transformer/layers/mlp.py b/submodules/RoMa/romatch/models/transformer/layers/mlp.py new file mode 100644 index 0000000000000000000000000000000000000000..5e4b315f972f9a9f54aef1e4ef4e81b52976f018 --- /dev/null +++ b/submodules/RoMa/romatch/models/transformer/layers/mlp.py @@ -0,0 +1,41 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the license found in the +# LICENSE file in the root directory of this source tree. + +# References: +# https://github.com/facebookresearch/dino/blob/master/vision_transformer.py +# https://github.com/rwightman/pytorch-image-models/tree/master/timm/layers/mlp.py + + +from typing import Callable, Optional + +from torch import Tensor, nn + + +class Mlp(nn.Module): + def __init__( + self, + in_features: int, + hidden_features: Optional[int] = None, + out_features: Optional[int] = None, + act_layer: Callable[..., nn.Module] = nn.GELU, + drop: float = 0.0, + bias: bool = True, + ) -> None: + super().__init__() + out_features = out_features or in_features + hidden_features = hidden_features or in_features + self.fc1 = nn.Linear(in_features, hidden_features, bias=bias) + self.act = act_layer() + self.fc2 = nn.Linear(hidden_features, out_features, bias=bias) + self.drop = nn.Dropout(drop) + + def forward(self, x: Tensor) -> Tensor: + x = self.fc1(x) + x = self.act(x) + x = self.drop(x) + x = self.fc2(x) + x = self.drop(x) + return x diff --git a/submodules/RoMa/romatch/models/transformer/layers/patch_embed.py b/submodules/RoMa/romatch/models/transformer/layers/patch_embed.py new file mode 100644 index 0000000000000000000000000000000000000000..574abe41175568d700a389b8b96d1ba554914779 --- /dev/null +++ b/submodules/RoMa/romatch/models/transformer/layers/patch_embed.py @@ -0,0 +1,89 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the license found in the +# LICENSE file in the root directory of this source tree. + +# References: +# https://github.com/facebookresearch/dino/blob/master/vision_transformer.py +# https://github.com/rwightman/pytorch-image-models/tree/master/timm/layers/patch_embed.py + +from typing import Callable, Optional, Tuple, Union + +from torch import Tensor +import torch.nn as nn + + +def make_2tuple(x): + if isinstance(x, tuple): + assert len(x) == 2 + return x + + assert isinstance(x, int) + return (x, x) + + +class PatchEmbed(nn.Module): + """ + 2D image to patch embedding: (B,C,H,W) -> (B,N,D) + + Args: + img_size: Image size. + patch_size: Patch token size. + in_chans: Number of input image channels. + embed_dim: Number of linear projection output channels. + norm_layer: Normalization layer. + """ + + def __init__( + self, + img_size: Union[int, Tuple[int, int]] = 224, + patch_size: Union[int, Tuple[int, int]] = 16, + in_chans: int = 3, + embed_dim: int = 768, + norm_layer: Optional[Callable] = None, + flatten_embedding: bool = True, + ) -> None: + super().__init__() + + image_HW = make_2tuple(img_size) + patch_HW = make_2tuple(patch_size) + patch_grid_size = ( + image_HW[0] // patch_HW[0], + image_HW[1] // patch_HW[1], + ) + + self.img_size = image_HW + self.patch_size = patch_HW + self.patches_resolution = patch_grid_size + self.num_patches = patch_grid_size[0] * patch_grid_size[1] + + self.in_chans = in_chans + self.embed_dim = embed_dim + + self.flatten_embedding = flatten_embedding + + self.proj = nn.Conv2d(in_chans, embed_dim, kernel_size=patch_HW, stride=patch_HW) + self.norm = norm_layer(embed_dim) if norm_layer else nn.Identity() + + def forward(self, x: Tensor) -> Tensor: + _, _, H, W = x.shape + patch_H, patch_W = self.patch_size + + assert H % patch_H == 0, f"Input image height {H} is not a multiple of patch height {patch_H}" + assert W % patch_W == 0, f"Input image width {W} is not a multiple of patch width: {patch_W}" + + x = self.proj(x) # B C H W + H, W = x.size(2), x.size(3) + x = x.flatten(2).transpose(1, 2) # B HW C + x = self.norm(x) + if not self.flatten_embedding: + x = x.reshape(-1, H, W, self.embed_dim) # B H W C + return x + + def flops(self) -> float: + Ho, Wo = self.patches_resolution + flops = Ho * Wo * self.embed_dim * self.in_chans * (self.patch_size[0] * self.patch_size[1]) + if self.norm is not None: + flops += Ho * Wo * self.embed_dim + return flops diff --git a/submodules/RoMa/romatch/models/transformer/layers/swiglu_ffn.py b/submodules/RoMa/romatch/models/transformer/layers/swiglu_ffn.py new file mode 100644 index 0000000000000000000000000000000000000000..b3324b266fb0a50ccf8c3a0ede2ae10ac4dfa03e --- /dev/null +++ b/submodules/RoMa/romatch/models/transformer/layers/swiglu_ffn.py @@ -0,0 +1,63 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Callable, Optional + +from torch import Tensor, nn +import torch.nn.functional as F + + +class SwiGLUFFN(nn.Module): + def __init__( + self, + in_features: int, + hidden_features: Optional[int] = None, + out_features: Optional[int] = None, + act_layer: Callable[..., nn.Module] = None, + drop: float = 0.0, + bias: bool = True, + ) -> None: + super().__init__() + out_features = out_features or in_features + hidden_features = hidden_features or in_features + self.w12 = nn.Linear(in_features, 2 * hidden_features, bias=bias) + self.w3 = nn.Linear(hidden_features, out_features, bias=bias) + + def forward(self, x: Tensor) -> Tensor: + x12 = self.w12(x) + x1, x2 = x12.chunk(2, dim=-1) + hidden = F.silu(x1) * x2 + return self.w3(hidden) + + +try: + from xformers.ops import SwiGLU + + XFORMERS_AVAILABLE = True +except ImportError: + SwiGLU = SwiGLUFFN + XFORMERS_AVAILABLE = False + + +class SwiGLUFFNFused(SwiGLU): + def __init__( + self, + in_features: int, + hidden_features: Optional[int] = None, + out_features: Optional[int] = None, + act_layer: Callable[..., nn.Module] = None, + drop: float = 0.0, + bias: bool = True, + ) -> None: + out_features = out_features or in_features + hidden_features = hidden_features or in_features + hidden_features = (int(hidden_features * 2 / 3) + 7) // 8 * 8 + super().__init__( + in_features=in_features, + hidden_features=hidden_features, + out_features=out_features, + bias=bias, + ) diff --git a/submodules/RoMa/romatch/train/__init__.py b/submodules/RoMa/romatch/train/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..90269dc0f345a575e0ba21f5afa34202c7e6b433 --- /dev/null +++ b/submodules/RoMa/romatch/train/__init__.py @@ -0,0 +1 @@ +from .train import train_k_epochs diff --git a/submodules/RoMa/romatch/train/train.py b/submodules/RoMa/romatch/train/train.py new file mode 100644 index 0000000000000000000000000000000000000000..7cb02ed1e816fd39f174f76ec15bce49ae2a3da8 --- /dev/null +++ b/submodules/RoMa/romatch/train/train.py @@ -0,0 +1,102 @@ +from tqdm import tqdm +from romatch.utils.utils import to_cuda +import romatch +import torch +import wandb + +def log_param_statistics(named_parameters, norm_type = 2): + named_parameters = list(named_parameters) + grads = [p.grad for n, p in named_parameters if p.grad is not None] + weight_norms = [p.norm(p=norm_type) for n, p in named_parameters if p.grad is not None] + names = [n for n,p in named_parameters if p.grad is not None] + param_norm = torch.stack(weight_norms).norm(p=norm_type) + device = grads[0].device + grad_norms = torch.stack([torch.norm(g.detach(), norm_type).to(device) for g in grads]) + nans_or_infs = torch.isinf(grad_norms) | torch.isnan(grad_norms) + nan_inf_names = [name for name, naninf in zip(names, nans_or_infs) if naninf] + total_grad_norm = torch.norm(grad_norms, norm_type) + if torch.any(nans_or_infs): + print(f"These params have nan or inf grads: {nan_inf_names}") + wandb.log({"grad_norm": total_grad_norm.item()}, step = romatch.GLOBAL_STEP) + wandb.log({"param_norm": param_norm.item()}, step = romatch.GLOBAL_STEP) + +def train_step(train_batch, model, objective, optimizer, grad_scaler, grad_clip_norm = 1.,**kwargs): + optimizer.zero_grad() + out = model(train_batch) + l = objective(out, train_batch) + grad_scaler.scale(l).backward() + grad_scaler.unscale_(optimizer) + log_param_statistics(model.named_parameters()) + torch.nn.utils.clip_grad_norm_(model.parameters(), grad_clip_norm) # what should max norm be? + grad_scaler.step(optimizer) + grad_scaler.update() + wandb.log({"grad_scale": grad_scaler._scale.item()}, step = romatch.GLOBAL_STEP) + if grad_scaler._scale < 1.: + grad_scaler._scale = torch.tensor(1.).to(grad_scaler._scale) + romatch.GLOBAL_STEP = romatch.GLOBAL_STEP + romatch.STEP_SIZE # increment global step + return {"train_out": out, "train_loss": l.item()} + + +def train_k_steps( + n_0, k, dataloader, model, objective, optimizer, lr_scheduler, grad_scaler, progress_bar=True, grad_clip_norm = 1., warmup = None, ema_model = None, pbar_n_seconds = 1, +): + for n in tqdm(range(n_0, n_0 + k), disable=(not progress_bar) or romatch.RANK > 0, mininterval=pbar_n_seconds): + batch = next(dataloader) + model.train(True) + batch = to_cuda(batch) + train_step( + train_batch=batch, + model=model, + objective=objective, + optimizer=optimizer, + lr_scheduler=lr_scheduler, + grad_scaler=grad_scaler, + n=n, + grad_clip_norm = grad_clip_norm, + ) + if ema_model is not None: + ema_model.update() + if warmup is not None: + with warmup.dampening(): + lr_scheduler.step() + else: + lr_scheduler.step() + [wandb.log({f"lr_group_{grp}": lr}) for grp, lr in enumerate(lr_scheduler.get_last_lr())] + + +def train_epoch( + dataloader=None, + model=None, + objective=None, + optimizer=None, + lr_scheduler=None, + epoch=None, +): + model.train(True) + print(f"At epoch {epoch}") + for batch in tqdm(dataloader, mininterval=5.0): + batch = to_cuda(batch) + train_step( + train_batch=batch, model=model, objective=objective, optimizer=optimizer + ) + lr_scheduler.step() + return { + "model": model, + "optimizer": optimizer, + "lr_scheduler": lr_scheduler, + "epoch": epoch, + } + + +def train_k_epochs( + start_epoch, end_epoch, dataloader, model, objective, optimizer, lr_scheduler +): + for epoch in range(start_epoch, end_epoch + 1): + train_epoch( + dataloader=dataloader, + model=model, + objective=objective, + optimizer=optimizer, + lr_scheduler=lr_scheduler, + epoch=epoch, + ) diff --git a/submodules/RoMa/romatch/utils/__init__.py b/submodules/RoMa/romatch/utils/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..2709f5e586150289085a4e2cbd458bc443fab7f3 --- /dev/null +++ b/submodules/RoMa/romatch/utils/__init__.py @@ -0,0 +1,16 @@ +from .utils import ( + pose_auc, + get_pose, + compute_relative_pose, + compute_pose_error, + estimate_pose, + estimate_pose_uncalibrated, + rotate_intrinsic, + get_tuple_transform_ops, + get_depth_tuple_transform_ops, + warp_kpts, + numpy_to_pil, + tensor_to_pil, + recover_pose, + signed_left_to_right_epipolar_distance, +) diff --git a/submodules/RoMa/romatch/utils/kde.py b/submodules/RoMa/romatch/utils/kde.py new file mode 100644 index 0000000000000000000000000000000000000000..46ed2e5e106bbca93e703f39f3ad3af350666e34 --- /dev/null +++ b/submodules/RoMa/romatch/utils/kde.py @@ -0,0 +1,13 @@ +import torch + + +def kde(x, std = 0.1, half = True, down = None): + # use a gaussian kernel to estimate density + if half: + x = x.half() # Do it in half precision TODO: remove hardcoding + if down is not None: + scores = (-torch.cdist(x,x[::down])**2/(2*std**2)).exp() + else: + scores = (-torch.cdist(x,x)**2/(2*std**2)).exp() + density = scores.sum(dim=-1) + return density \ No newline at end of file diff --git a/submodules/RoMa/romatch/utils/local_correlation.py b/submodules/RoMa/romatch/utils/local_correlation.py new file mode 100644 index 0000000000000000000000000000000000000000..fe1322a20bf82d0331159f958241cb87f75f4e21 --- /dev/null +++ b/submodules/RoMa/romatch/utils/local_correlation.py @@ -0,0 +1,48 @@ +import torch +import torch.nn.functional as F + +def local_correlation( + feature0, + feature1, + local_radius, + padding_mode="zeros", + flow = None, + sample_mode = "bilinear", +): + r = local_radius + K = (2*r+1)**2 + B, c, h, w = feature0.size() + corr = torch.empty((B,K,h,w), device = feature0.device, dtype=feature0.dtype) + if flow is None: + # If flow is None, assume feature0 and feature1 are aligned + coords = torch.meshgrid( + ( + torch.linspace(-1 + 1 / h, 1 - 1 / h, h, device=feature0.device), + torch.linspace(-1 + 1 / w, 1 - 1 / w, w, device=feature0.device), + ), + indexing = 'ij' + ) + coords = torch.stack((coords[1], coords[0]), dim=-1)[ + None + ].expand(B, h, w, 2) + else: + coords = flow.permute(0,2,3,1) # If using flow, sample around flow target. + local_window = torch.meshgrid( + ( + torch.linspace(-2*local_radius/h, 2*local_radius/h, 2*r+1, device=feature0.device), + torch.linspace(-2*local_radius/w, 2*local_radius/w, 2*r+1, device=feature0.device), + ), + indexing = 'ij' + ) + local_window = torch.stack((local_window[1], local_window[0]), dim=-1)[ + None + ].expand(1, 2*r+1, 2*r+1, 2).reshape(1, (2*r+1)**2, 2) + for _ in range(B): + with torch.no_grad(): + local_window_coords = (coords[_,:,:,None]+local_window[:,None,None]).reshape(1,h,w*(2*r+1)**2,2) + window_feature = F.grid_sample( + feature1[_:_+1], local_window_coords, padding_mode=padding_mode, align_corners=False, mode = sample_mode, # + ) + window_feature = window_feature.reshape(c,h,w,(2*r+1)**2) + corr[_] = (feature0[_,...,None]/(c**.5)*window_feature).sum(dim=0).permute(2,0,1) + return corr diff --git a/submodules/RoMa/romatch/utils/transforms.py b/submodules/RoMa/romatch/utils/transforms.py new file mode 100644 index 0000000000000000000000000000000000000000..ea6476bd816a31df36f7d1b5417853637b65474b --- /dev/null +++ b/submodules/RoMa/romatch/utils/transforms.py @@ -0,0 +1,118 @@ +from typing import Dict +import numpy as np +import torch +import kornia.augmentation as K +from kornia.geometry.transform import warp_perspective + +# Adapted from Kornia +class GeometricSequential: + def __init__(self, *transforms, align_corners=True) -> None: + self.transforms = transforms + self.align_corners = align_corners + + def __call__(self, x, mode="bilinear"): + b, c, h, w = x.shape + M = torch.eye(3, device=x.device)[None].expand(b, 3, 3) + for t in self.transforms: + if np.random.rand() < t.p: + M = M.matmul( + t.compute_transformation(x, t.generate_parameters((b, c, h, w)), None) + ) + return ( + warp_perspective( + x, M, dsize=(h, w), mode=mode, align_corners=self.align_corners + ), + M, + ) + + def apply_transform(self, x, M, mode="bilinear"): + b, c, h, w = x.shape + return warp_perspective( + x, M, dsize=(h, w), align_corners=self.align_corners, mode=mode + ) + + +class RandomPerspective(K.RandomPerspective): + def generate_parameters(self, batch_shape: torch.Size) -> Dict[str, torch.Tensor]: + distortion_scale = torch.as_tensor( + self.distortion_scale, device=self._device, dtype=self._dtype + ) + return self.random_perspective_generator( + batch_shape[0], + batch_shape[-2], + batch_shape[-1], + distortion_scale, + self.same_on_batch, + self.device, + self.dtype, + ) + + def random_perspective_generator( + self, + batch_size: int, + height: int, + width: int, + distortion_scale: torch.Tensor, + same_on_batch: bool = False, + device: torch.device = torch.device("cpu"), + dtype: torch.dtype = torch.float32, + ) -> Dict[str, torch.Tensor]: + r"""Get parameters for ``perspective`` for a random perspective transform. + + Args: + batch_size (int): the tensor batch size. + height (int) : height of the image. + width (int): width of the image. + distortion_scale (torch.Tensor): it controls the degree of distortion and ranges from 0 to 1. + same_on_batch (bool): apply the same transformation across the batch. Default: False. + device (torch.device): the device on which the random numbers will be generated. Default: cpu. + dtype (torch.dtype): the data type of the generated random numbers. Default: float32. + + Returns: + params Dict[str, torch.Tensor]: parameters to be passed for transformation. + - start_points (torch.Tensor): element-wise perspective source areas with a shape of (B, 4, 2). + - end_points (torch.Tensor): element-wise perspective target areas with a shape of (B, 4, 2). + + Note: + The generated random numbers are not reproducible across different devices and dtypes. + """ + if not (distortion_scale.dim() == 0 and 0 <= distortion_scale <= 1): + raise AssertionError( + f"'distortion_scale' must be a scalar within [0, 1]. Got {distortion_scale}." + ) + if not ( + type(height) is int and height > 0 and type(width) is int and width > 0 + ): + raise AssertionError( + f"'height' and 'width' must be integers. Got {height}, {width}." + ) + + start_points: torch.Tensor = torch.tensor( + [[[0.0, 0], [width - 1, 0], [width - 1, height - 1], [0, height - 1]]], + device=distortion_scale.device, + dtype=distortion_scale.dtype, + ).expand(batch_size, -1, -1) + + # generate random offset not larger than half of the image + fx = distortion_scale * width / 2 + fy = distortion_scale * height / 2 + + factor = torch.stack([fx, fy], dim=0).view(-1, 1, 2) + offset = (torch.rand_like(start_points) - 0.5) * 2 + end_points = start_points + factor * offset + + return dict(start_points=start_points, end_points=end_points) + + + +class RandomErasing: + def __init__(self, p = 0., scale = 0.) -> None: + self.p = p + self.scale = scale + self.random_eraser = K.RandomErasing(scale = (0.02, scale), p = p) + def __call__(self, image, depth): + if self.p > 0: + image = self.random_eraser(image) + depth = self.random_eraser(depth, params=self.random_eraser._params) + return image, depth + \ No newline at end of file diff --git a/submodules/RoMa/romatch/utils/utils.py b/submodules/RoMa/romatch/utils/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..1c522b16b7020779a0ea58b28973f2f609145838 --- /dev/null +++ b/submodules/RoMa/romatch/utils/utils.py @@ -0,0 +1,654 @@ +import warnings +import numpy as np +import cv2 +import math +import torch +from torchvision import transforms +from torchvision.transforms.functional import InterpolationMode +import torch.nn.functional as F +from PIL import Image +import kornia + +def recover_pose(E, kpts0, kpts1, K0, K1, mask): + best_num_inliers = 0 + K0inv = np.linalg.inv(K0[:2,:2]) + K1inv = np.linalg.inv(K1[:2,:2]) + + kpts0_n = (K0inv @ (kpts0-K0[None,:2,2]).T).T + kpts1_n = (K1inv @ (kpts1-K1[None,:2,2]).T).T + + for _E in np.split(E, len(E) / 3): + n, R, t, _ = cv2.recoverPose(_E, kpts0_n, kpts1_n, np.eye(3), 1e9, mask=mask) + if n > best_num_inliers: + best_num_inliers = n + ret = (R, t, mask.ravel() > 0) + return ret + + + +# Code taken from https://github.com/PruneTruong/DenseMatching/blob/40c29a6b5c35e86b9509e65ab0cd12553d998e5f/validation/utils_pose_estimation.py +# --- GEOMETRY --- +def estimate_pose(kpts0, kpts1, K0, K1, norm_thresh, conf=0.99999): + if len(kpts0) < 5: + return None + K0inv = np.linalg.inv(K0[:2,:2]) + K1inv = np.linalg.inv(K1[:2,:2]) + + kpts0 = (K0inv @ (kpts0-K0[None,:2,2]).T).T + kpts1 = (K1inv @ (kpts1-K1[None,:2,2]).T).T + E, mask = cv2.findEssentialMat( + kpts0, kpts1, np.eye(3), threshold=norm_thresh, prob=conf + ) + + ret = None + if E is not None: + best_num_inliers = 0 + + for _E in np.split(E, len(E) / 3): + n, R, t, _ = cv2.recoverPose(_E, kpts0, kpts1, np.eye(3), 1e9, mask=mask) + if n > best_num_inliers: + best_num_inliers = n + ret = (R, t, mask.ravel() > 0) + return ret + +def estimate_pose_uncalibrated(kpts0, kpts1, K0, K1, norm_thresh, conf=0.99999): + if len(kpts0) < 5: + return None + method = cv2.USAC_ACCURATE + F, mask = cv2.findFundamentalMat( + kpts0, kpts1, ransacReprojThreshold=norm_thresh, confidence=conf, method=method, maxIters=10000 + ) + E = K1.T@F@K0 + ret = None + if E is not None: + best_num_inliers = 0 + K0inv = np.linalg.inv(K0[:2,:2]) + K1inv = np.linalg.inv(K1[:2,:2]) + + kpts0_n = (K0inv @ (kpts0-K0[None,:2,2]).T).T + kpts1_n = (K1inv @ (kpts1-K1[None,:2,2]).T).T + + for _E in np.split(E, len(E) / 3): + n, R, t, _ = cv2.recoverPose(_E, kpts0_n, kpts1_n, np.eye(3), 1e9, mask=mask) + if n > best_num_inliers: + best_num_inliers = n + ret = (R, t, mask.ravel() > 0) + return ret + +def unnormalize_coords(x_n,h,w): + x = torch.stack( + (w * (x_n[..., 0] + 1) / 2, h * (x_n[..., 1] + 1) / 2), dim=-1 + ) # [-1+1/h, 1-1/h] -> [0.5, h-0.5] + return x + + +def rotate_intrinsic(K, n): + base_rot = np.array([[0, 1, 0], [-1, 0, 0], [0, 0, 1]]) + rot = np.linalg.matrix_power(base_rot, n) + return rot @ K + + +def rotate_pose_inplane(i_T_w, rot): + rotation_matrices = [ + np.array( + [ + [np.cos(r), -np.sin(r), 0.0, 0.0], + [np.sin(r), np.cos(r), 0.0, 0.0], + [0.0, 0.0, 1.0, 0.0], + [0.0, 0.0, 0.0, 1.0], + ], + dtype=np.float32, + ) + for r in [np.deg2rad(d) for d in (0, 270, 180, 90)] + ] + return np.dot(rotation_matrices[rot], i_T_w) + + +def scale_intrinsics(K, scales): + scales = np.diag([1.0 / scales[0], 1.0 / scales[1], 1.0]) + return np.dot(scales, K) + + +def to_homogeneous(points): + return np.concatenate([points, np.ones_like(points[:, :1])], axis=-1) + + +def angle_error_mat(R1, R2): + cos = (np.trace(np.dot(R1.T, R2)) - 1) / 2 + cos = np.clip(cos, -1.0, 1.0) # numercial errors can make it out of bounds + return np.rad2deg(np.abs(np.arccos(cos))) + + +def angle_error_vec(v1, v2): + n = np.linalg.norm(v1) * np.linalg.norm(v2) + return np.rad2deg(np.arccos(np.clip(np.dot(v1, v2) / n, -1.0, 1.0))) + + +def compute_pose_error(T_0to1, R, t): + R_gt = T_0to1[:3, :3] + t_gt = T_0to1[:3, 3] + error_t = angle_error_vec(t.squeeze(), t_gt) + error_t = np.minimum(error_t, 180 - error_t) # ambiguity of E estimation + error_R = angle_error_mat(R, R_gt) + return error_t, error_R + + +def pose_auc(errors, thresholds): + sort_idx = np.argsort(errors) + errors = np.array(errors.copy())[sort_idx] + recall = (np.arange(len(errors)) + 1) / len(errors) + errors = np.r_[0.0, errors] + recall = np.r_[0.0, recall] + aucs = [] + for t in thresholds: + last_index = np.searchsorted(errors, t) + r = np.r_[recall[:last_index], recall[last_index - 1]] + e = np.r_[errors[:last_index], t] + aucs.append(np.trapz(r, x=e) / t) + return aucs + + +# From Patch2Pix https://github.com/GrumpyZhou/patch2pix +def get_depth_tuple_transform_ops_nearest_exact(resize=None): + ops = [] + if resize: + ops.append(TupleResizeNearestExact(resize)) + return TupleCompose(ops) + +def get_depth_tuple_transform_ops(resize=None, normalize=True, unscale=False): + ops = [] + if resize: + ops.append(TupleResize(resize, mode=InterpolationMode.BILINEAR)) + return TupleCompose(ops) + + +def get_tuple_transform_ops(resize=None, normalize=True, unscale=False, clahe = False, colorjiggle_params = None): + ops = [] + if resize: + ops.append(TupleResize(resize)) + ops.append(TupleToTensorScaled()) + if normalize: + ops.append( + TupleNormalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) + ) # Imagenet mean/std + return TupleCompose(ops) + +class ToTensorScaled(object): + """Convert a RGB PIL Image to a CHW ordered Tensor, scale the range to [0, 1]""" + + def __call__(self, im): + if not isinstance(im, torch.Tensor): + im = np.array(im, dtype=np.float32).transpose((2, 0, 1)) + im /= 255.0 + return torch.from_numpy(im) + else: + return im + + def __repr__(self): + return "ToTensorScaled(./255)" + + +class TupleToTensorScaled(object): + def __init__(self): + self.to_tensor = ToTensorScaled() + + def __call__(self, im_tuple): + return [self.to_tensor(im) for im in im_tuple] + + def __repr__(self): + return "TupleToTensorScaled(./255)" + + +class ToTensorUnscaled(object): + """Convert a RGB PIL Image to a CHW ordered Tensor""" + + def __call__(self, im): + return torch.from_numpy(np.array(im, dtype=np.float32).transpose((2, 0, 1))) + + def __repr__(self): + return "ToTensorUnscaled()" + + +class TupleToTensorUnscaled(object): + """Convert a RGB PIL Image to a CHW ordered Tensor""" + + def __init__(self): + self.to_tensor = ToTensorUnscaled() + + def __call__(self, im_tuple): + return [self.to_tensor(im) for im in im_tuple] + + def __repr__(self): + return "TupleToTensorUnscaled()" + +class TupleResizeNearestExact: + def __init__(self, size): + self.size = size + def __call__(self, im_tuple): + return [F.interpolate(im, size = self.size, mode = 'nearest-exact') for im in im_tuple] + + def __repr__(self): + return "TupleResizeNearestExact(size={})".format(self.size) + + +class TupleResize(object): + def __init__(self, size, mode=InterpolationMode.BICUBIC): + self.size = size + self.resize = transforms.Resize(size, mode) + def __call__(self, im_tuple): + return [self.resize(im) for im in im_tuple] + + def __repr__(self): + return "TupleResize(size={})".format(self.size) + +class Normalize: + def __call__(self,im): + mean = im.mean(dim=(1,2), keepdims=True) + std = im.std(dim=(1,2), keepdims=True) + return (im-mean)/std + + +class TupleNormalize(object): + def __init__(self, mean, std): + self.mean = mean + self.std = std + self.normalize = transforms.Normalize(mean=mean, std=std) + + def __call__(self, im_tuple): + c,h,w = im_tuple[0].shape + if c > 3: + warnings.warn(f"Number of channels c={c} > 3, assuming first 3 are rgb") + return [self.normalize(im[:3]) for im in im_tuple] + + def __repr__(self): + return "TupleNormalize(mean={}, std={})".format(self.mean, self.std) + + +class TupleCompose(object): + def __init__(self, transforms): + self.transforms = transforms + + def __call__(self, im_tuple): + for t in self.transforms: + im_tuple = t(im_tuple) + return im_tuple + + def __repr__(self): + format_string = self.__class__.__name__ + "(" + for t in self.transforms: + format_string += "\n" + format_string += " {0}".format(t) + format_string += "\n)" + return format_string + +@torch.no_grad() +def cls_to_flow(cls, deterministic_sampling = True): + B,C,H,W = cls.shape + device = cls.device + res = round(math.sqrt(C)) + G = torch.meshgrid( + *[torch.linspace(-1+1/res, 1-1/res, steps = res, device = device) for _ in range(2)], + indexing = 'ij' + ) + G = torch.stack([G[1],G[0]],dim=-1).reshape(C,2) + if deterministic_sampling: + sampled_cls = cls.max(dim=1).indices + else: + sampled_cls = torch.multinomial(cls.permute(0,2,3,1).reshape(B*H*W,C).softmax(dim=-1), 1).reshape(B,H,W) + flow = G[sampled_cls] + return flow + +@torch.no_grad() +def cls_to_flow_refine(cls): + B,C,H,W = cls.shape + device = cls.device + res = round(math.sqrt(C)) + G = torch.meshgrid( + *[torch.linspace(-1+1/res, 1-1/res, steps = res, device = device) for _ in range(2)], + indexing = 'ij' + ) + G = torch.stack([G[1],G[0]],dim=-1).reshape(C,2) + # FIXME: below softmax line causes mps to bug, don't know why. + if device.type == 'mps': + cls = cls.log_softmax(dim=1).exp() + else: + cls = cls.softmax(dim=1) + mode = cls.max(dim=1).indices + + index = torch.stack((mode-1, mode, mode+1, mode - res, mode + res), dim = 1).clamp(0,C - 1).long() + neighbours = torch.gather(cls, dim = 1, index = index)[...,None] + flow = neighbours[:,0] * G[index[:,0]] + neighbours[:,1] * G[index[:,1]] + neighbours[:,2] * G[index[:,2]] + neighbours[:,3] * G[index[:,3]] + neighbours[:,4] * G[index[:,4]] + tot_prob = neighbours.sum(dim=1) + flow = flow / tot_prob + return flow + + +def get_gt_warp(depth1, depth2, T_1to2, K1, K2, depth_interpolation_mode = 'bilinear', relative_depth_error_threshold = 0.05, H = None, W = None): + + if H is None: + B,H,W = depth1.shape + else: + B = depth1.shape[0] + with torch.no_grad(): + x1_n = torch.meshgrid( + *[ + torch.linspace( + -1 + 1 / n, 1 - 1 / n, n, device=depth1.device + ) + for n in (B, H, W) + ], + indexing = 'ij' + ) + x1_n = torch.stack((x1_n[2], x1_n[1]), dim=-1).reshape(B, H * W, 2) + mask, x2 = warp_kpts( + x1_n.double(), + depth1.double(), + depth2.double(), + T_1to2.double(), + K1.double(), + K2.double(), + depth_interpolation_mode = depth_interpolation_mode, + relative_depth_error_threshold = relative_depth_error_threshold, + ) + prob = mask.float().reshape(B, H, W) + x2 = x2.reshape(B, H, W, 2) + return x2, prob + +@torch.no_grad() +def warp_kpts(kpts0, depth0, depth1, T_0to1, K0, K1, smooth_mask = False, return_relative_depth_error = False, depth_interpolation_mode = "bilinear", relative_depth_error_threshold = 0.05): + """Warp kpts0 from I0 to I1 with depth, K and Rt + Also check covisibility and depth consistency. + Depth is consistent if relative error < 0.2 (hard-coded). + # https://github.com/zju3dv/LoFTR/blob/94e98b695be18acb43d5d3250f52226a8e36f839/src/loftr/utils/geometry.py adapted from here + Args: + kpts0 (torch.Tensor): [N, L, 2] - , should be normalized in (-1,1) + depth0 (torch.Tensor): [N, H, W], + depth1 (torch.Tensor): [N, H, W], + T_0to1 (torch.Tensor): [N, 3, 4], + K0 (torch.Tensor): [N, 3, 3], + K1 (torch.Tensor): [N, 3, 3], + Returns: + calculable_mask (torch.Tensor): [N, L] + warped_keypoints0 (torch.Tensor): [N, L, 2] + """ + ( + n, + h, + w, + ) = depth0.shape + if depth_interpolation_mode == "combined": + # Inspired by approach in inloc, try to fill holes from bilinear interpolation by nearest neighbour interpolation + if smooth_mask: + raise NotImplementedError("Combined bilinear and NN warp not implemented") + valid_bilinear, warp_bilinear = warp_kpts(kpts0, depth0, depth1, T_0to1, K0, K1, + smooth_mask = smooth_mask, + return_relative_depth_error = return_relative_depth_error, + depth_interpolation_mode = "bilinear", + relative_depth_error_threshold = relative_depth_error_threshold) + valid_nearest, warp_nearest = warp_kpts(kpts0, depth0, depth1, T_0to1, K0, K1, + smooth_mask = smooth_mask, + return_relative_depth_error = return_relative_depth_error, + depth_interpolation_mode = "nearest-exact", + relative_depth_error_threshold = relative_depth_error_threshold) + nearest_valid_bilinear_invalid = (~valid_bilinear).logical_and(valid_nearest) + warp = warp_bilinear.clone() + warp[nearest_valid_bilinear_invalid] = warp_nearest[nearest_valid_bilinear_invalid] + valid = valid_bilinear | valid_nearest + return valid, warp + + + kpts0_depth = F.grid_sample(depth0[:, None], kpts0[:, :, None], mode = depth_interpolation_mode, align_corners=False)[ + :, 0, :, 0 + ] + kpts0 = torch.stack( + (w * (kpts0[..., 0] + 1) / 2, h * (kpts0[..., 1] + 1) / 2), dim=-1 + ) # [-1+1/h, 1-1/h] -> [0.5, h-0.5] + # Sample depth, get calculable_mask on depth != 0 + nonzero_mask = kpts0_depth != 0 + + # Unproject + kpts0_h = ( + torch.cat([kpts0, torch.ones_like(kpts0[:, :, [0]])], dim=-1) + * kpts0_depth[..., None] + ) # (N, L, 3) + kpts0_n = K0.inverse() @ kpts0_h.transpose(2, 1) # (N, 3, L) + kpts0_cam = kpts0_n + + # Rigid Transform + w_kpts0_cam = T_0to1[:, :3, :3] @ kpts0_cam + T_0to1[:, :3, [3]] # (N, 3, L) + w_kpts0_depth_computed = w_kpts0_cam[:, 2, :] + + # Project + w_kpts0_h = (K1 @ w_kpts0_cam).transpose(2, 1) # (N, L, 3) + w_kpts0 = w_kpts0_h[:, :, :2] / ( + w_kpts0_h[:, :, [2]] + 1e-4 + ) # (N, L, 2), +1e-4 to avoid zero depth + + # Covisible Check + h, w = depth1.shape[1:3] + covisible_mask = ( + (w_kpts0[:, :, 0] > 0) + * (w_kpts0[:, :, 0] < w - 1) + * (w_kpts0[:, :, 1] > 0) + * (w_kpts0[:, :, 1] < h - 1) + ) + w_kpts0 = torch.stack( + (2 * w_kpts0[..., 0] / w - 1, 2 * w_kpts0[..., 1] / h - 1), dim=-1 + ) # from [0.5,h-0.5] -> [-1+1/h, 1-1/h] + # w_kpts0[~covisible_mask, :] = -5 # xd + + w_kpts0_depth = F.grid_sample( + depth1[:, None], w_kpts0[:, :, None], mode=depth_interpolation_mode, align_corners=False + )[:, 0, :, 0] + + relative_depth_error = ( + (w_kpts0_depth - w_kpts0_depth_computed) / w_kpts0_depth + ).abs() + if not smooth_mask: + consistent_mask = relative_depth_error < relative_depth_error_threshold + else: + consistent_mask = (-relative_depth_error/smooth_mask).exp() + valid_mask = nonzero_mask * covisible_mask * consistent_mask + if return_relative_depth_error: + return relative_depth_error, w_kpts0 + else: + return valid_mask, w_kpts0 + +imagenet_mean = torch.tensor([0.485, 0.456, 0.406]) +imagenet_std = torch.tensor([0.229, 0.224, 0.225]) + + +def numpy_to_pil(x: np.ndarray): + """ + Args: + x: Assumed to be of shape (h,w,c) + """ + if isinstance(x, torch.Tensor): + x = x.detach().cpu().numpy() + if x.max() <= 1.01: + x *= 255 + x = x.astype(np.uint8) + return Image.fromarray(x) + + +def tensor_to_pil(x, unnormalize=False): + if unnormalize: + x = x * (imagenet_std[:, None, None].to(x.device)) + (imagenet_mean[:, None, None].to(x.device)) + x = x.detach().permute(1, 2, 0).cpu().numpy() + x = np.clip(x, 0.0, 1.0) + return numpy_to_pil(x) + + +def to_cuda(batch): + for key, value in batch.items(): + if isinstance(value, torch.Tensor): + batch[key] = value.cuda() + return batch + + +def to_cpu(batch): + for key, value in batch.items(): + if isinstance(value, torch.Tensor): + batch[key] = value.cpu() + return batch + + +def get_pose(calib): + w, h = np.array(calib["imsize"])[0] + return np.array(calib["K"]), np.array(calib["R"]), np.array(calib["T"]).T, h, w + + +def compute_relative_pose(R1, t1, R2, t2): + rots = R2 @ (R1.T) + trans = -rots @ t1 + t2 + return rots, trans + +@torch.no_grad() +def reset_opt(opt): + for group in opt.param_groups: + for p in group['params']: + if p.requires_grad: + state = opt.state[p] + # State initialization + + # Exponential moving average of gradient values + state['exp_avg'] = torch.zeros_like(p) + # Exponential moving average of squared gradient values + state['exp_avg_sq'] = torch.zeros_like(p) + # Exponential moving average of gradient difference + state['exp_avg_diff'] = torch.zeros_like(p) + + +def flow_to_pixel_coords(flow, h1, w1): + flow = ( + torch.stack( + ( + w1 * (flow[..., 0] + 1) / 2, + h1 * (flow[..., 1] + 1) / 2, + ), + axis=-1, + ) + ) + return flow + +to_pixel_coords = flow_to_pixel_coords # just an alias + +def flow_to_normalized_coords(flow, h1, w1): + flow = ( + torch.stack( + ( + 2 * (flow[..., 0]) / w1 - 1, + 2 * (flow[..., 1]) / h1 - 1, + ), + axis=-1, + ) + ) + return flow + +to_normalized_coords = flow_to_normalized_coords # just an alias + +def warp_to_pixel_coords(warp, h1, w1, h2, w2): + warp1 = warp[..., :2] + warp1 = ( + torch.stack( + ( + w1 * (warp1[..., 0] + 1) / 2, + h1 * (warp1[..., 1] + 1) / 2, + ), + axis=-1, + ) + ) + warp2 = warp[..., 2:] + warp2 = ( + torch.stack( + ( + w2 * (warp2[..., 0] + 1) / 2, + h2 * (warp2[..., 1] + 1) / 2, + ), + axis=-1, + ) + ) + return torch.cat((warp1,warp2), dim=-1) + + + +def signed_point_line_distance(point, line, eps: float = 1e-9): + r"""Return the distance from points to lines. + + Args: + point: (possibly homogeneous) points :math:`(*, N, 2 or 3)`. + line: lines coefficients :math:`(a, b, c)` with shape :math:`(*, N, 3)`, where :math:`ax + by + c = 0`. + eps: Small constant for safe sqrt. + + Returns: + the computed distance with shape :math:`(*, N)`. + """ + + if not point.shape[-1] in (2, 3): + raise ValueError(f"pts must be a (*, 2 or 3) tensor. Got {point.shape}") + + if not line.shape[-1] == 3: + raise ValueError(f"lines must be a (*, 3) tensor. Got {line.shape}") + + numerator = (line[..., 0] * point[..., 0] + line[..., 1] * point[..., 1] + line[..., 2]) + denominator = line[..., :2].norm(dim=-1) + + return numerator / (denominator + eps) + + +def signed_left_to_right_epipolar_distance(pts1, pts2, Fm): + r"""Return one-sided epipolar distance for correspondences given the fundamental matrix. + + This method measures the distance from points in the right images to the epilines + of the corresponding points in the left images as they reflect in the right images. + + Args: + pts1: correspondences from the left images with shape + :math:`(*, N, 2 or 3)`. If they are not homogeneous, converted automatically. + pts2: correspondences from the right images with shape + :math:`(*, N, 2 or 3)`. If they are not homogeneous, converted automatically. + Fm: Fundamental matrices with shape :math:`(*, 3, 3)`. Called Fm to + avoid ambiguity with torch.nn.functional. + + Returns: + the computed Symmetrical distance with shape :math:`(*, N)`. + """ + import kornia + if (len(Fm.shape) < 3) or not Fm.shape[-2:] == (3, 3): + raise ValueError(f"Fm must be a (*, 3, 3) tensor. Got {Fm.shape}") + + if pts1.shape[-1] == 2: + pts1 = kornia.geometry.convert_points_to_homogeneous(pts1) + + F_t = Fm.transpose(dim0=-2, dim1=-1) + line1_in_2 = pts1 @ F_t + + return signed_point_line_distance(pts2, line1_in_2) + +def get_grid(b, h, w, device): + grid = torch.meshgrid( + *[ + torch.linspace(-1 + 1 / n, 1 - 1 / n, n, device=device) + for n in (b, h, w) + ], + indexing = 'ij' + ) + grid = torch.stack((grid[2], grid[1]), dim=-1).reshape(b, h, w, 2) + return grid + + +def get_autocast_params(device=None, enabled=False, dtype=None): + if device is None: + autocast_device = "cuda" if torch.cuda.is_available() else "cpu" + else: + #strip :X from device + autocast_device = str(device).split(":")[0] + if 'cuda' in str(device): + out_dtype = dtype + enabled = True + else: + out_dtype = torch.bfloat16 + enabled = False + # mps is not supported + autocast_device = "cpu" + return autocast_device, enabled, out_dtype \ No newline at end of file diff --git a/submodules/RoMa/setup.py b/submodules/RoMa/setup.py new file mode 100644 index 0000000000000000000000000000000000000000..7ec18f3bbb71b85d943fdfeed3ed5c47033aebbc --- /dev/null +++ b/submodules/RoMa/setup.py @@ -0,0 +1,9 @@ +from setuptools import setup, find_packages + +setup( + name="romatch", + packages=find_packages(include=("romatch*",)), + version="0.0.1", + author="Johan Edstedt", + install_requires=open("requirements.txt", "r").read().split("\n"), +) diff --git a/submodules/gaussian-splatting/.gitignore b/submodules/gaussian-splatting/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..114376106621fc03ff8f923c03536e9dafd0d3f5 --- /dev/null +++ b/submodules/gaussian-splatting/.gitignore @@ -0,0 +1,8 @@ +*.pyc +.vscode +output +build +diff_rasterization/diff_rast.egg-info +diff_rasterization/dist +tensorboard_3d +screenshots \ No newline at end of file diff --git a/submodules/gaussian-splatting/.gitmodules b/submodules/gaussian-splatting/.gitmodules new file mode 100644 index 0000000000000000000000000000000000000000..cafb9acf7dd40829fa53e8991088d7cef617f2d5 --- /dev/null +++ b/submodules/gaussian-splatting/.gitmodules @@ -0,0 +1,13 @@ +[submodule "submodules/simple-knn"] + path = submodules/simple-knn + url = https://gitlab.inria.fr/bkerbl/simple-knn.git +[submodule "submodules/diff-gaussian-rasterization"] + path = submodules/diff-gaussian-rasterization + url = https://github.com/graphdeco-inria/diff-gaussian-rasterization.git + branch = dr_aa +[submodule "SIBR_viewers"] + path = SIBR_viewers + url = https://gitlab.inria.fr/sibr/sibr_core.git +[submodule "submodules/fused-ssim"] + path = submodules/fused-ssim + url = https://github.com/rahul-goel/fused-ssim.git diff --git a/submodules/gaussian-splatting/LICENSE.md b/submodules/gaussian-splatting/LICENSE.md new file mode 100644 index 0000000000000000000000000000000000000000..18445c6d34aedbf1ab9d282223f8f10ce38cd79a --- /dev/null +++ b/submodules/gaussian-splatting/LICENSE.md @@ -0,0 +1,91 @@ +Gaussian-Splatting License +=========================== + +**Inria** and **the Max Planck Institut for Informatik (MPII)** hold all the ownership rights on the *Software* named **gaussian-splatting**. +The *Software* is in the process of being registered with the Agence pour la Protection des +Programmes (APP). + +The *Software* is still being developed by the *Licensor*. + +*Licensor*'s goal is to allow the research community to use, test and evaluate +the *Software*. + +## 1. Definitions + +*Licensee* means any person or entity that uses the *Software* and distributes +its *Work*. + +*Licensor* means the owners of the *Software*, i.e Inria and MPII + +*Software* means the original work of authorship made available under this +License ie gaussian-splatting. + +*Work* means the *Software* and any additions to or derivative works of the +*Software* that are made available under this License. + + +## 2. Purpose +This license is intended to define the rights granted to the *Licensee* by +Licensors under the *Software*. + +## 3. Rights granted + +For the above reasons Licensors have decided to distribute the *Software*. +Licensors grant non-exclusive rights to use the *Software* for research purposes +to research users (both academic and industrial), free of charge, without right +to sublicense.. The *Software* may be used "non-commercially", i.e., for research +and/or evaluation purposes only. + +Subject to the terms and conditions of this License, you are granted a +non-exclusive, royalty-free, license to reproduce, prepare derivative works of, +publicly display, publicly perform and distribute its *Work* and any resulting +derivative works in any form. + +## 4. Limitations + +**4.1 Redistribution.** You may reproduce or distribute the *Work* only if (a) you do +so under this License, (b) you include a complete copy of this License with +your distribution, and (c) you retain without modification any copyright, +patent, trademark, or attribution notices that are present in the *Work*. + +**4.2 Derivative Works.** You may specify that additional or different terms apply +to the use, reproduction, and distribution of your derivative works of the *Work* +("Your Terms") only if (a) Your Terms provide that the use limitation in +Section 2 applies to your derivative works, and (b) you identify the specific +derivative works that are subject to Your Terms. Notwithstanding Your Terms, +this License (including the redistribution requirements in Section 3.1) will +continue to apply to the *Work* itself. + +**4.3** Any other use without of prior consent of Licensors is prohibited. Research +users explicitly acknowledge having received from Licensors all information +allowing to appreciate the adequacy between of the *Software* and their needs and +to undertake all necessary precautions for its execution and use. + +**4.4** The *Software* is provided both as a compiled library file and as source +code. In case of using the *Software* for a publication or other results obtained +through the use of the *Software*, users are strongly encouraged to cite the +corresponding publications as explained in the documentation of the *Software*. + +## 5. Disclaimer + +THE USER CANNOT USE, EXPLOIT OR DISTRIBUTE THE *SOFTWARE* FOR COMMERCIAL PURPOSES +WITHOUT PRIOR AND EXPLICIT CONSENT OF LICENSORS. YOU MUST CONTACT INRIA FOR ANY +UNAUTHORIZED USE: stip-sophia.transfert@inria.fr . ANY SUCH ACTION WILL +CONSTITUTE A FORGERY. THIS *SOFTWARE* IS PROVIDED "AS IS" WITHOUT ANY WARRANTIES +OF ANY NATURE AND ANY EXPRESS OR IMPLIED WARRANTIES, WITH REGARDS TO COMMERCIAL +USE, PROFESSIONNAL USE, LEGAL OR NOT, OR OTHER, OR COMMERCIALISATION OR +ADAPTATION. UNLESS EXPLICITLY PROVIDED BY LAW, IN NO EVENT, SHALL INRIA OR THE +AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES, LOSS OF USE, DATA, OR PROFITS OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING FROM, OUT OF OR +IN CONNECTION WITH THE *SOFTWARE* OR THE USE OR OTHER DEALINGS IN THE *SOFTWARE*. + +## 6. Files subject to permissive licenses +The contents of the file ```utils/loss_utils.py``` are based on publicly available code authored by Evan Su, which falls under the permissive MIT license. + +Title: pytorch-ssim\ +Project code: https://github.com/Po-Hsun-Su/pytorch-ssim\ +Copyright Evan Su, 2017\ +License: https://github.com/Po-Hsun-Su/pytorch-ssim/blob/master/LICENSE.txt (MIT) \ No newline at end of file diff --git a/submodules/gaussian-splatting/README.md b/submodules/gaussian-splatting/README.md new file mode 100644 index 0000000000000000000000000000000000000000..eb2cf6c09d61425e22bf492f36e0922db9d8311a --- /dev/null +++ b/submodules/gaussian-splatting/README.md @@ -0,0 +1,615 @@ +# 3D Gaussian Splatting for Real-Time Radiance Field Rendering +Bernhard Kerbl*, Georgios Kopanas*, Thomas LeimkΓΌhler, George Drettakis (* indicates equal contribution)
+| [Webpage](https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/) | [Full Paper](https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/3d_gaussian_splatting_high.pdf) | [Video](https://youtu.be/T_kXY43VZnk) | [Other GRAPHDECO Publications](http://www-sop.inria.fr/reves/publis/gdindex.php) | [FUNGRAPH project page](https://fungraph.inria.fr) |
+| [T&T+DB COLMAP (650MB)](https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/datasets/input/tandt_db.zip) | [Pre-trained Models (14 GB)](https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/datasets/pretrained/models.zip) | [Viewers for Windows (60MB)](https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/binaries/viewers.zip) | [Evaluation Images (7 GB)](https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/evaluation/images.zip) |
+![Teaser image](assets/teaser.png) + +This repository contains the official authors implementation associated with the paper "3D Gaussian Splatting for Real-Time Radiance Field Rendering", which can be found [here](https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/). We further provide the reference images used to create the error metrics reported in the paper, as well as recently created, pre-trained models. + + + + + + +Abstract: *Radiance Field methods have recently revolutionized novel-view synthesis of scenes captured with multiple photos or videos. However, achieving high visual quality still requires neural networks that are costly to train and render, while recent faster methods inevitably trade off speed for quality. For unbounded and complete scenes (rather than isolated objects) and 1080p resolution rendering, no current method can achieve real-time display rates. We introduce three key elements that allow us to achieve state-of-the-art visual quality while maintaining competitive training times and importantly allow high-quality real-time (β‰₯ 30 fps) novel-view synthesis at 1080p resolution. First, starting from sparse points produced during camera calibration, we represent the scene with 3D Gaussians that preserve desirable properties of continuous volumetric radiance fields for scene optimization while avoiding unnecessary computation in empty space; Second, we perform interleaved optimization/density control of the 3D Gaussians, notably optimizing anisotropic covariance to achieve an accurate representation of the scene; Third, we develop a fast visibility-aware rendering algorithm that supports anisotropic splatting and both accelerates training and allows realtime rendering. We demonstrate state-of-the-art visual quality and real-time rendering on several established datasets.* + +
+
+

BibTeX

+
@Article{kerbl3Dgaussians,
+      author       = {Kerbl, Bernhard and Kopanas, Georgios and Leimk{\"u}hler, Thomas and Drettakis, George},
+      title        = {3D Gaussian Splatting for Real-Time Radiance Field Rendering},
+      journal      = {ACM Transactions on Graphics},
+      number       = {4},
+      volume       = {42},
+      month        = {July},
+      year         = {2023},
+      url          = {https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/}
+}
+
+
+ + + +## Funding and Acknowledgments + +This research was funded by the ERC Advanced grant FUNGRAPH No 788065. The authors are grateful to Adobe for generous donations, the OPAL infrastructure from UniversitΓ© CΓ΄te d’Azur and for the HPC resources from GENCI–IDRIS (Grant 2022-AD011013409). The authors thank the anonymous reviewers for their valuable feedback, P. Hedman and A. Tewari for proofreading earlier drafts also T. MΓΌller, A. Yu and S. Fridovich-Keil for helping with the comparisons. + +## NEW FEATURES ! + +We have limited resources for maintaining and updating the code. However, we have added a few new features since the original release that are inspired by some of the excellent work many other researchers have been doing on 3DGS. We will be adding other features within the ability of our resources. + +**Update of October 2024**: We integrated [training speed acceleration](#training-speed-acceleration) and made it compatible with [depth regularization](#depth-regularization), [anti-aliasing](#anti-aliasing) and [exposure compensation](#exposure-compensation). We have enhanced the SIBR real time viewer by correcting bugs and adding features in the [Top View](#sibr-top-view) that allows visualization of input and user cameras. + +**Update of Spring 2024**: +Orange Labs has kindly added [OpenXR support](#openxr-support) for VR viewing. + +## Step-by-step Tutorial + +Jonathan Stephens made a fantastic step-by-step tutorial for setting up Gaussian Splatting on your machine, along with instructions for creating usable datasets from videos. If the instructions below are too dry for you, go ahead and check it out [here](https://www.youtube.com/watch?v=UXtuigy_wYc). + +## Colab + +User [camenduru](https://github.com/camenduru) was kind enough to provide a Colab template that uses this repo's source (status: August 2023!) for quick and easy access to the method. Please check it out [here](https://github.com/camenduru/gaussian-splatting-colab). + +## Cloning the Repository + +The repository contains submodules, thus please check it out with +```shell +# SSH +git clone git@github.com:graphdeco-inria/gaussian-splatting.git --recursive +``` +or +```shell +# HTTPS +git clone https://github.com/graphdeco-inria/gaussian-splatting --recursive +``` + +## Overview + +The codebase has 4 main components: +- A PyTorch-based optimizer to produce a 3D Gaussian model from SfM inputs +- A network viewer that allows to connect to and visualize the optimization process +- An OpenGL-based real-time viewer to render trained models in real-time. +- A script to help you turn your own images into optimization-ready SfM data sets + +The components have different requirements w.r.t. both hardware and software. They have been tested on Windows 10 and Ubuntu Linux 22.04. Instructions for setting up and running each of them are found in the sections below. + + + + +## Optimizer + +The optimizer uses PyTorch and CUDA extensions in a Python environment to produce trained models. + +### Hardware Requirements + +- CUDA-ready GPU with Compute Capability 7.0+ +- 24 GB VRAM (to train to paper evaluation quality) +- Please see FAQ for smaller VRAM configurations + +### Software Requirements +- Conda (recommended for easy setup) +- C++ Compiler for PyTorch extensions (we used Visual Studio 2019 for Windows) +- CUDA SDK 11 for PyTorch extensions, install *after* Visual Studio (we used 11.8, **known issues with 11.6**) +- C++ Compiler and CUDA SDK must be compatible + +### Setup + +#### Local Setup + +Our default, provided install method is based on Conda package and environment management: +```shell +SET DISTUTILS_USE_SDK=1 # Windows only +conda env create --file environment.yml +conda activate gaussian_splatting +``` +Please note that this process assumes that you have CUDA SDK **11** installed, not **12**. For modifications, see below. + +Tip: Downloading packages and creating a new environment with Conda can require a significant amount of disk space. By default, Conda will use the main system hard drive. You can avoid this by specifying a different package download location and an environment on a different drive: + +```shell +conda config --add pkgs_dirs / +conda env create --file environment.yml --prefix //gaussian_splatting +conda activate //gaussian_splatting +``` + +#### Modifications + +If you can afford the disk space, we recommend using our environment files for setting up a training environment identical to ours. If you want to make modifications, please note that major version changes might affect the results of our method. However, our (limited) experiments suggest that the codebase works just fine inside a more up-to-date environment (Python 3.8, PyTorch 2.0.0, CUDA 12). Make sure to create an environment where PyTorch and its CUDA runtime version match and the installed CUDA SDK has no major version difference with PyTorch's CUDA version. + +#### Known Issues + +Some users experience problems building the submodules on Windows (```cl.exe: File not found``` or similar). Please consider the workaround for this problem from the FAQ. + +### Running + +To run the optimizer, simply use + +```shell +python train.py -s +``` + +
+Command Line Arguments for train.py + + #### --source_path / -s + Path to the source directory containing a COLMAP or Synthetic NeRF data set. + #### --model_path / -m + Path where the trained model should be stored (```output/``` by default). + #### --images / -i + Alternative subdirectory for COLMAP images (```images``` by default). + #### --eval + Add this flag to use a MipNeRF360-style training/test split for evaluation. + #### --resolution / -r + Specifies resolution of the loaded images before training. If provided ```1, 2, 4``` or ```8```, uses original, 1/2, 1/4 or 1/8 resolution, respectively. For all other values, rescales the width to the given number while maintaining image aspect. **If not set and input image width exceeds 1.6K pixels, inputs are automatically rescaled to this target.** + #### --data_device + Specifies where to put the source image data, ```cuda``` by default, recommended to use ```cpu``` if training on large/high-resolution dataset, will reduce VRAM consumption, but slightly slow down training. Thanks to [HrsPythonix](https://github.com/HrsPythonix). + #### --white_background / -w + Add this flag to use white background instead of black (default), e.g., for evaluation of NeRF Synthetic dataset. + #### --sh_degree + Order of spherical harmonics to be used (no larger than 3). ```3``` by default. + #### --convert_SHs_python + Flag to make pipeline compute forward and backward of SHs with PyTorch instead of ours. + #### --convert_cov3D_python + Flag to make pipeline compute forward and backward of the 3D covariance with PyTorch instead of ours. + #### --debug + Enables debug mode if you experience erros. If the rasterizer fails, a ```dump``` file is created that you may forward to us in an issue so we can take a look. + #### --debug_from + Debugging is **slow**. You may specify an iteration (starting from 0) after which the above debugging becomes active. + #### --iterations + Number of total iterations to train for, ```30_000``` by default. + #### --ip + IP to start GUI server on, ```127.0.0.1``` by default. + #### --port + Port to use for GUI server, ```6009``` by default. + #### --test_iterations + Space-separated iterations at which the training script computes L1 and PSNR over test set, ```7000 30000``` by default. + #### --save_iterations + Space-separated iterations at which the training script saves the Gaussian model, ```7000 30000 ``` by default. + #### --checkpoint_iterations + Space-separated iterations at which to store a checkpoint for continuing later, saved in the model directory. + #### --start_checkpoint + Path to a saved checkpoint to continue training from. + #### --quiet + Flag to omit any text written to standard out pipe. + #### --feature_lr + Spherical harmonics features learning rate, ```0.0025``` by default. + #### --opacity_lr + Opacity learning rate, ```0.05``` by default. + #### --scaling_lr + Scaling learning rate, ```0.005``` by default. + #### --rotation_lr + Rotation learning rate, ```0.001``` by default. + #### --position_lr_max_steps + Number of steps (from 0) where position learning rate goes from ```initial``` to ```final```. ```30_000``` by default. + #### --position_lr_init + Initial 3D position learning rate, ```0.00016``` by default. + #### --position_lr_final + Final 3D position learning rate, ```0.0000016``` by default. + #### --position_lr_delay_mult + Position learning rate multiplier (cf. Plenoxels), ```0.01``` by default. + #### --densify_from_iter + Iteration where densification starts, ```500``` by default. + #### --densify_until_iter + Iteration where densification stops, ```15_000``` by default. + #### --densify_grad_threshold + Limit that decides if points should be densified based on 2D position gradient, ```0.0002``` by default. + #### --densification_interval + How frequently to densify, ```100``` (every 100 iterations) by default. + #### --opacity_reset_interval + How frequently to reset opacity, ```3_000``` by default. + #### --lambda_dssim + Influence of SSIM on total loss from 0 to 1, ```0.2``` by default. + #### --percent_dense + Percentage of scene extent (0--1) a point must exceed to be forcibly densified, ```0.01``` by default. + +
+
+ +Note that similar to MipNeRF360, we target images at resolutions in the 1-1.6K pixel range. For convenience, arbitrary-size inputs can be passed and will be automatically resized if their width exceeds 1600 pixels. We recommend to keep this behavior, but you may force training to use your higher-resolution images by setting ```-r 1```. + +The MipNeRF360 scenes are hosted by the paper authors [here](https://jonbarron.info/mipnerf360/). You can find our SfM data sets for Tanks&Temples and Deep Blending [here](https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/datasets/input/tandt_db.zip). If you do not provide an output model directory (```-m```), trained models are written to folders with randomized unique names inside the ```output``` directory. At this point, the trained models may be viewed with the real-time viewer (see further below). + +### Evaluation +By default, the trained models use all available images in the dataset. To train them while withholding a test set for evaluation, use the ```--eval``` flag. This way, you can render training/test sets and produce error metrics as follows: +```shell +python train.py -s --eval # Train with train/test split +python render.py -m # Generate renderings +python metrics.py -m # Compute error metrics on renderings +``` + +If you want to evaluate our [pre-trained models](https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/datasets/pretrained/models.zip), you will have to download the corresponding source data sets and indicate their location to ```render.py``` with an additional ```--source_path/-s``` flag. Note: The pre-trained models were created with the release codebase. This code base has been cleaned up and includes bugfixes, hence the metrics you get from evaluating them will differ from those in the paper. +```shell +python render.py -m -s +python metrics.py -m +``` + +
+Command Line Arguments for render.py + + #### --model_path / -m + Path to the trained model directory you want to create renderings for. + #### --skip_train + Flag to skip rendering the training set. + #### --skip_test + Flag to skip rendering the test set. + #### --quiet + Flag to omit any text written to standard out pipe. + + **The below parameters will be read automatically from the model path, based on what was used for training. However, you may override them by providing them explicitly on the command line.** + + #### --source_path / -s + Path to the source directory containing a COLMAP or Synthetic NeRF data set. + #### --images / -i + Alternative subdirectory for COLMAP images (```images``` by default). + #### --eval + Add this flag to use a MipNeRF360-style training/test split for evaluation. + #### --resolution / -r + Changes the resolution of the loaded images before training. If provided ```1, 2, 4``` or ```8```, uses original, 1/2, 1/4 or 1/8 resolution, respectively. For all other values, rescales the width to the given number while maintaining image aspect. ```1``` by default. + #### --white_background / -w + Add this flag to use white background instead of black (default), e.g., for evaluation of NeRF Synthetic dataset. + #### --convert_SHs_python + Flag to make pipeline render with computed SHs from PyTorch instead of ours. + #### --convert_cov3D_python + Flag to make pipeline render with computed 3D covariance from PyTorch instead of ours. + +
+ +
+Command Line Arguments for metrics.py + + #### --model_paths / -m + Space-separated list of model paths for which metrics should be computed. +
+
+ +We further provide the ```full_eval.py``` script. This script specifies the routine used in our evaluation and demonstrates the use of some additional parameters, e.g., ```--images (-i)``` to define alternative image directories within COLMAP data sets. If you have downloaded and extracted all the training data, you can run it like this: +```shell +python full_eval.py -m360 -tat -db +``` +In the current version, this process takes about 7h on our reference machine containing an A6000. If you want to do the full evaluation on our pre-trained models, you can specify their download location and skip training. +```shell +python full_eval.py -o --skip_training -m360 -tat -db +``` + +If you want to compute the metrics on our paper's [evaluation images](https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/evaluation/images.zip), you can also skip rendering. In this case it is not necessary to provide the source datasets. You can compute metrics for multiple image sets at a time. +```shell +python full_eval.py -m /garden ... --skip_training --skip_rendering +``` + +
+Command Line Arguments for full_eval.py + + #### --skip_training + Flag to skip training stage. + #### --skip_rendering + Flag to skip rendering stage. + #### --skip_metrics + Flag to skip metrics calculation stage. + #### --output_path + Directory to put renderings and results in, ```./eval``` by default, set to pre-trained model location if evaluating them. + #### --mipnerf360 / -m360 + Path to MipNeRF360 source datasets, required if training or rendering. + #### --tanksandtemples / -tat + Path to Tanks&Temples source datasets, required if training or rendering. + #### --deepblending / -db + Path to Deep Blending source datasets, required if training or rendering. +
+
+ +## Interactive Viewers +We provide two interactive viewers for our method: remote and real-time. Our viewing solutions are based on the [SIBR](https://sibr.gitlabpages.inria.fr/) framework, developed by the GRAPHDECO group for several novel-view synthesis projects. + +### Hardware Requirements +- OpenGL 4.5-ready GPU and drivers (or latest MESA software) +- 4 GB VRAM recommended +- CUDA-ready GPU with Compute Capability 7.0+ (only for Real-Time Viewer) + +### Software Requirements +- Visual Studio or g++, **not Clang** (we used Visual Studio 2019 for Windows) +- CUDA SDK 11, install *after* Visual Studio (we used 11.8) +- CMake (recent version, we used 3.24) +- 7zip (only on Windows) + +### Pre-built Windows Binaries +We provide pre-built binaries for Windows [here](https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/binaries/viewers.zip). We recommend using them on Windows for an efficient setup, since the building of SIBR involves several external dependencies that must be downloaded and compiled on-the-fly. + +### Installation from Source +If you cloned with submodules (e.g., using ```--recursive```), the source code for the viewers is found in ```SIBR_viewers```. The network viewer runs within the SIBR framework for Image-based Rendering applications. + +#### Windows +CMake should take care of your dependencies. +```shell +cd SIBR_viewers +cmake -Bbuild . +cmake --build build --target install --config RelWithDebInfo +``` +You may specify a different configuration, e.g. ```Debug``` if you need more control during development. + +#### Ubuntu 22.04 +You will need to install a few dependencies before running the project setup. +```shell +# Dependencies +sudo apt install -y libglew-dev libassimp-dev libboost-all-dev libgtk-3-dev libopencv-dev libglfw3-dev libavdevice-dev libavcodec-dev libeigen3-dev libxxf86vm-dev libembree-dev +# Project setup +cd SIBR_viewers +cmake -Bbuild . -DCMAKE_BUILD_TYPE=Release # add -G Ninja to build faster +cmake --build build -j24 --target install +``` + +#### Ubuntu 20.04 +Backwards compatibility with Focal Fossa is not fully tested, but building SIBR with CMake should still work after invoking +```shell +git checkout fossa_compatibility +``` + +### Navigation in SIBR Viewers +The SIBR interface provides several methods of navigating the scene. By default, you will be started with an FPS navigator, which you can control with ```W, A, S, D, Q, E``` for camera translation and ```I, K, J, L, U, O``` for rotation. Alternatively, you may want to use a Trackball-style navigator (select from the floating menu). You can also snap to a camera from the data set with the ```Snap to``` button or find the closest camera with ```Snap to closest```. The floating menues also allow you to change the navigation speed. You can use the ```Scaling Modifier``` to control the size of the displayed Gaussians, or show the initial point cloud. + +### Running the Network Viewer + + + +https://github.com/graphdeco-inria/gaussian-splatting/assets/40643808/90a2e4d3-cf2e-4633-b35f-bfe284e28ff7 + + + +After extracting or installing the viewers, you may run the compiled ```SIBR_remoteGaussian_app[_config]``` app in ```/bin```, e.g.: +```shell +.//bin/SIBR_remoteGaussian_app +``` +The network viewer allows you to connect to a running training process on the same or a different machine. If you are training on the same machine and OS, no command line parameters should be required: the optimizer communicates the location of the training data to the network viewer. By default, optimizer and network viewer will try to establish a connection on **localhost** on port **6009**. You can change this behavior by providing matching ```--ip``` and ```--port``` parameters to both the optimizer and the network viewer. If for some reason the path used by the optimizer to find the training data is not reachable by the network viewer (e.g., due to them running on different (virtual) machines), you may specify an override location to the viewer by using ```-s ```. + +
+Primary Command Line Arguments for Network Viewer + + #### --path / -s + Argument to override model's path to source dataset. + #### --ip + IP to use for connection to a running training script. + #### --port + Port to use for connection to a running training script. + #### --rendering-size + Takes two space separated numbers to define the resolution at which network rendering occurs, ```1200``` width by default. + Note that to enforce an aspect that differs from the input images, you need ```--force-aspect-ratio``` too. + #### --load_images + Flag to load source dataset images to be displayed in the top view for each camera. +
+
+ +### Running the Real-Time Viewer + + + + +https://github.com/graphdeco-inria/gaussian-splatting/assets/40643808/0940547f-1d82-4c2f-a616-44eabbf0f816 + + + + +After extracting or installing the viewers, you may run the compiled ```SIBR_gaussianViewer_app[_config]``` app in ```/bin```, e.g.: +```shell +.//bin/SIBR_gaussianViewer_app -m +``` + +It should suffice to provide the ```-m``` parameter pointing to a trained model directory. Alternatively, you can specify an override location for training input data using ```-s```. To use a specific resolution other than the auto-chosen one, specify ```--rendering-size ```. Combine it with ```--force-aspect-ratio``` if you want the exact resolution and don't mind image distortion. + +**To unlock the full frame rate, please disable V-Sync on your machine and also in the application (Menu → Display). In a multi-GPU system (e.g., laptop) your OpenGL/Display GPU should be the same as your CUDA GPU (e.g., by setting the application's GPU preference on Windows, see below) for maximum performance.** + +![Teaser image](assets/select.png) + +In addition to the initial point cloud and the splats, you also have the option to visualize the Gaussians by rendering them as ellipsoids from the floating menu. +SIBR has many other functionalities, please see the [documentation](https://sibr.gitlabpages.inria.fr/) for more details on the viewer, navigation options etc. There is also a Top View (available from the menu) that shows the placement of the input cameras and the original SfM point cloud; please note that Top View slows rendering when enabled. The real-time viewer also uses slightly more aggressive, fast culling, which can be toggled in the floating menu. If you ever encounter an issue that can be solved by turning fast culling off, please let us know. + +
+Primary Command Line Arguments for Real-Time Viewer + + #### --model-path / -m + Path to trained model. + #### --iteration + Specifies which of state to load if multiple are available. Defaults to latest available iteration. + #### --path / -s + Argument to override model's path to source dataset. + #### --rendering-size + Takes two space separated numbers to define the resolution at which real-time rendering occurs, ```1200``` width by default. Note that to enforce an aspect that differs from the input images, you need ```--force-aspect-ratio``` too. + #### --load_images + Flag to load source dataset images to be displayed in the top view for each camera. + #### --device + Index of CUDA device to use for rasterization if multiple are available, ```0``` by default. + #### --no_interop + Disables CUDA/GL interop forcibly. Use on systems that may not behave according to spec (e.g., WSL2 with MESA GL 4.5 software rendering). +
+
+ +## Processing your own Scenes + +Our COLMAP loaders expect the following dataset structure in the source path location: + +``` + +|---images +| |--- +| |--- +| |---... +|---sparse + |---0 + |---cameras.bin + |---images.bin + |---points3D.bin +``` + +For rasterization, the camera models must be either a SIMPLE_PINHOLE or PINHOLE camera. We provide a converter script ```convert.py```, to extract undistorted images and SfM information from input images. Optionally, you can use ImageMagick to resize the undistorted images. This rescaling is similar to MipNeRF360, i.e., it creates images with 1/2, 1/4 and 1/8 the original resolution in corresponding folders. To use them, please first install a recent version of COLMAP (ideally CUDA-powered) and ImageMagick. Put the images you want to use in a directory ```/input```. +``` + +|---input + |--- + |--- + |---... +``` + If you have COLMAP and ImageMagick on your system path, you can simply run +```shell +python convert.py -s [--resize] #If not resizing, ImageMagick is not needed +``` +Alternatively, you can use the optional parameters ```--colmap_executable``` and ```--magick_executable``` to point to the respective paths. Please note that on Windows, the executable should point to the COLMAP ```.bat``` file that takes care of setting the execution environment. Once done, `````` will contain the expected COLMAP data set structure with undistorted, resized input images, in addition to your original images and some temporary (distorted) data in the directory ```distorted```. + +If you have your own COLMAP dataset without undistortion (e.g., using ```OPENCV``` camera), you can try to just run the last part of the script: Put the images in ```input``` and the COLMAP info in a subdirectory ```distorted```: +``` + +|---input +| |--- +| |--- +| |---... +|---distorted + |---database.db + |---sparse + |---0 + |---... +``` +Then run +```shell +python convert.py -s --skip_matching [--resize] #If not resizing, ImageMagick is not needed +``` + +
+Command Line Arguments for convert.py + + #### --no_gpu + Flag to avoid using GPU in COLMAP. + #### --skip_matching + Flag to indicate that COLMAP info is available for images. + #### --source_path / -s + Location of the inputs. + #### --camera + Which camera model to use for the early matching steps, ```OPENCV``` by default. + #### --resize + Flag for creating resized versions of input images. + #### --colmap_executable + Path to the COLMAP executable (```.bat``` on Windows). + #### --magick_executable + Path to the ImageMagick executable. +
+
+ +### Training speed acceleration + +We integrated the drop-in replacements from [Taming-3dgs](https://humansensinglab.github.io/taming-3dgs/)1 with [fused ssim](https://github.com/rahul-goel/fused-ssim/tree/main) into the original codebase to speed up training times. Once installed, the accelerated rasterizer delivers a **$\times$ 1.6 training time speedup** using `--optimizer_type default` and a **$\times$ 2.7 training time speedup** using `--optimizer_type sparse_adam`. + +To get faster training times you must first install the accelerated rasterizer to your environment: + +```bash +pip uninstall diff-gaussian-rasterization -y +cd submodules/diff-gaussian-rasterization +rm -r build +git checkout 3dgs_accel +pip install . +``` + +Then you can add the following parameter to use the sparse adam optimizer when running `train.py`: + +```bash +--optimizer_type sparse_adam +``` + +*Note that this custom rasterizer has a different behaviour than the original version, for more details on training times please see [stats for training times](results.md/#training-times-comparisons)*. + +*1. Mallick and Goel, et al. β€˜Taming 3DGS: High-Quality Radiance Fields with Limited Resources’. SIGGRAPH Asia 2024 Conference Papers, 2024, https://doi.org/10.1145/3680528.3687694, [github](https://github.com/humansensinglab/taming-3dgs)* + + +### Depth regularization + +To have better reconstructed scenes we use depth maps as priors during optimization with each input images. It works best on untextured parts ex: roads and can remove floaters. Several papers have used similar ideas to improve various aspects of 3DGS; (e.g. [DepthRegularizedGS](https://robot0321.github.io/DepthRegGS/index.html), [SparseGS](https://formycat.github.io/SparseGS-Real-Time-360-Sparse-View-Synthesis-using-Gaussian-Splatting/), [DNGaussian](https://fictionarry.github.io/DNGaussian/)). The depth regularization we integrated is that used in our [Hierarchical 3DGS](https://repo-sam.inria.fr/fungraph/hierarchical-3d-gaussians/) paper, but applied to the original 3DGS; for some scenes (e.g., the DeepBlending scenes) it improves quality significantly; for others it either makes a small difference or can even be worse. For example results showing the potential benefit and statistics on quality please see here: [Stats for depth regularization](results.md). + +When training on a synthetic dataset, depth maps can be produced and they do not require further processing to be used in our method. + +For real world datasets depth maps should be generated for each input images, to generate them please do the following: +1. Clone [Depth Anything v2](https://github.com/DepthAnything/Depth-Anything-V2?tab=readme-ov-file#usage): + ``` + git clone https://github.com/DepthAnything/Depth-Anything-V2.git + ``` +2. Download weights from [Depth-Anything-V2-Large](https://huggingface.co/depth-anything/Depth-Anything-V2-Large/resolve/main/depth_anything_v2_vitl.pth?download=true) and place it under `Depth-Anything-V2/checkpoints/` +3. Generate depth maps: + ``` + python Depth-Anything-V2/run.py --encoder vitl --pred-only --grayscale --img-path --outdir + ``` +5. Generate a `depth_params.json` file using: + ``` + python utils/make_depth_scale.py --base_dir --depths_dir + ``` + +A new parameter should be set when training if you want to use depth regularization `-d `. + +### Exposure compensation +To compensate for exposure changes in the different input images we optimize an affine transformation for each image just as in [Hierarchical 3dgs](https://repo-sam.inria.fr/fungraph/hierarchical-3d-gaussians/). + +This can greatly improve reconstruction results for "in the wild" captures, e.g., with a smartphone when the exposure setting of the camera is not fixed. For example results showing the potential benefit and statistics on quality please see here: [Stats for exposure compensation](results.md). + +Add the following parameters to enable it: +``` +--exposure_lr_init 0.001 --exposure_lr_final 0.0001 --exposure_lr_delay_steps 5000 --exposure_lr_delay_mult 0.001 --train_test_exp +``` +Again, other excellent papers have used similar ideas e.g. [NeRF-W](https://nerf-w.github.io/), [URF](https://urban-radiance-fields.github.io/). + +### Anti-aliasing +We added the EWA Filter from [Mip Splatting](https://niujinshuchong.github.io/mip-splatting/) in our codebase to remove aliasing. It is disabled by default but you can enable it by adding `--antialiasing` when training on a scene using `train.py` or rendering using `render.py`. Antialiasing can be toggled in the SIBR viewer, it is disabled by default but you should enable it when viewing a scene trained using `--antialiasing`. +![aa](/assets/aa_onoff.gif) +*this scene was trained using `--antialiasing`*. + +### SIBR: Top view +> `Views > Top view` + +The `Top view` renders the SfM point cloud in another view with the corresponding input cameras and the `Point view` user camera. This allows visualization of how far the viewer is from the input cameras for example. + +It is a 3D view so the user can navigate through it just as in the `Point view` (modes available: FPS, trackball, orbit). + + +![top view open](assets/top_view_open.gif) + +Options are available to customize this view, meshes can be disabled/enabled and their scales can be modified. + + +![top view options](assets/top_view_options.gif) +A useful additional functionality is to move to the position of an input image, and progressively fade out to the SfM point view in that position (e.g., to verify camera alignment). Views from input cameras can be displayed in the `Top view` (*note that `--images-path` must be set in the command line*). One can snap the `Top view` camera to the closest input camera from the user camera in the `Point view` by clicking `Top view settings > Cameras > Snap to closest`. + + +![top view image alpha](assets/top_view_image_alpha.gif) + +### OpenXR support + +OpenXR is supported in the branch `gaussian_code_release_openxr` +Within that branch, you can find documentation for VR support [here](https://gitlab.inria.fr/sibr/sibr_core/-/tree/gaussian_code_release_openxr?ref_type=heads). + + +## FAQ +- *Where do I get data sets, e.g., those referenced in ```full_eval.py```?* The MipNeRF360 data set is provided by the authors of the original paper on the project site. Note that two of the data sets cannot be openly shared and require you to consult the authors directly. For Tanks&Temples and Deep Blending, please use the download links provided at the top of the page. Alternatively, you may access the cloned data (status: August 2023!) from [HuggingFace](https://huggingface.co/camenduru/gaussian-splatting) + + +- *How can I use this for a much larger dataset, like a city district?* The current method was not designed for these, but given enough memory, it should work out. However, the approach can struggle in multi-scale detail scenes (extreme close-ups, mixed with far-away shots). This is usually the case in, e.g., driving data sets (cars close up, buildings far away). For such scenes, you can lower the ```--position_lr_init```, ```--position_lr_final``` and ```--scaling_lr``` (x0.3, x0.1, ...). The more extensive the scene, the lower these values should be. Below, we use default learning rates (left) and ```--position_lr_init 0.000016 --scaling_lr 0.001"``` (right). + +| ![Default learning rate result](assets/worse.png "title-1") | ![Reduced learning rate result](assets/better.png "title-2") | +| --- | --- | + +- *I'm on Windows and I can't manage to build the submodules, what do I do?* Consider following the steps in the excellent video tutorial [here](https://www.youtube.com/watch?v=UXtuigy_wYc), hopefully they should help. The order in which the steps are done is important! Alternatively, consider using the linked Colab template. + +- *It still doesn't work. It says something about ```cl.exe```. What do I do?* User Henry Pearce found a workaround. You can you try adding the visual studio path to your environment variables (your version number might differ); +```C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64``` +Then make sure you start a new conda prompt and cd to your repo location and try this; +``` +conda activate gaussian_splatting +cd /gaussian-splatting +pip install submodules\diff-gaussian-rasterization +pip install submodules\simple-knn +``` + +- *I'm on macOS/Puppy Linux/Greenhat and I can't manage to build, what do I do?* Sorry, we can't provide support for platforms outside of the ones we list in this README. Consider using the linked Colab template. + +- *I don't have 24 GB of VRAM for training, what do I do?* The VRAM consumption is determined by the number of points that are being optimized, which increases over time. If you only want to train to 7k iterations, you will need significantly less. To do the full training routine and avoid running out of memory, you can increase the ```--densify_grad_threshold```, ```--densification_interval``` or reduce the value of ```--densify_until_iter```. Note however that this will affect the quality of the result. Also try setting ```--test_iterations``` to ```-1``` to avoid memory spikes during testing. If ```--densify_grad_threshold``` is very high, no densification should occur and training should complete if the scene itself loads successfully. + +- *24 GB of VRAM for reference quality training is still a lot! Can't we do it with less?* Yes, most likely. By our calculations it should be possible with **way** less memory (~8GB). If we can find the time we will try to achieve this. If some PyTorch veteran out there wants to tackle this, we look forward to your pull request! + + +- *How can I use the differentiable Gaussian rasterizer for my own project?* Easy, it is included in this repo as a submodule ```diff-gaussian-rasterization```. Feel free to check out and install the package. It's not really documented, but using it from the Python side is very straightforward (cf. ```gaussian_renderer/__init__.py```). + +- *Wait, but `````` isn't optimized and could be much better?* There are several parts we didn't even have time to think about improving (yet). The performance you get with this prototype is probably a rather slow baseline for what is physically possible. + +- *Something is broken, how did this happen?* We tried hard to provide a solid and comprehensible basis to make use of the paper's method. We have refactored the code quite a bit, but we have limited capacity to test all possible usage scenarios. Thus, if part of the website, the code or the performance is lacking, please create an issue. If we find the time, we will do our best to address it. diff --git a/submodules/gaussian-splatting/SIBR_viewers/.gitignore b/submodules/gaussian-splatting/SIBR_viewers/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..3ffaa95079940db3a5c852f8c8fadd41efe8e722 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/.gitignore @@ -0,0 +1,45 @@ +extlibs/ +build/ +install/ +src/projects/* +cmake-gui.exe.stackdump +__pycache__/ + +# emacs garbage +\#* +.\#* + +# vim garbage +*.swp +*.swo +*.idea/ +*.log +*.sh +*.tmp + +hs_err_* + +# re include common public projects +!src/projects/ulr/ +!src/projects/dataset_tools/ + +# more vim garbage +# Swap +[._]*.s[a-v][a-z] +!*.svg # comment out if you don't need vector files +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim +Sessionx.vim + +# Temporary +.netrwhist +*~ +# Auto-generated tag files +tags +# Persistent undo +[._]*.un~ \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/CMakeLists.txt b/submodules/gaussian-splatting/SIBR_viewers/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..21a3fc85ddfd30e4b10d57a4bd7cb349baf0f612 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/CMakeLists.txt @@ -0,0 +1,213 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + +CMAKE_MINIMUM_REQUIRED(VERSION 3.22) + +set (CMAKE_SYSTEM_VERSION 10.0.15063.0 CACHE INTERNAL "Cmake system version" FORCE) +PROJECT(sibr_projects) + +set(REQUIRED_VERSION "3.22.0") +set(CHECKED_VERSION "3.27.0") + +if (CMAKE_VERSION VERSION_LESS REQUIRED_VERSION) + message(WARNING "Deprecated version of cmake. Please update to at least ${REQUIRED_VERSION} (${CHECKED_VERSION} recommended).") +elseif (CMAKE_VERSION VERSION_GREATER CHECKED_VERSION) + message(WARNING "Untested version of cmake. If you checked everything is working properly, please update ${CHECKED_VERSION} in the main CmakeLists.txt with the version you tested.") +endif() + +## Include cmake stuff (functions/macros) : Modules files +if(WIN32) +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/windows) +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/windows/Modules) +else() +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/linux) +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/linux/Modules) +endif() +set_property(GLOBAL PROPERTY USE_FOLDERS ON) + +## To maintain cmake versions compatibilities +include(cmake_policies) +setPolicies() + +include(git_describe) +git_describe(GIT_BRANCH SIBR_CORE_BRANCH GIT_COMMIT_HASH SIBR_CORE_COMMIT_HASH GIT_TAG SIBR_CORE_TAG GIT_VERSION SIBR_CORE_VERSION) + +message(STATUS "SIBR version :\n BRANCH ${SIBR_CORE_BRANCH}\n COMMIT_HASH ${SIBR_CORE_COMMIT_HASH}\n TAG ${SIBR_CORE_TAG}\n VERSION ${SIBR_CORE_VERSION}") + +if(NOT WIN32) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +endif() + + +if (WIN32) + ## Allow C++11 + other flags + include(CheckCXXCompilerFlag) + get_filename_component(currentBuildTool ${CMAKE_BUILD_TOOL} NAME_WE) # tool that can launch the native build system. returned value may be the full path + if(${currentBuildTool} MATCHES "(msdev|devenv|nmake|MSBuild)") + + add_compile_options("$<$:/W3;/DNOMINMAX;/MP;-D_USE_MATH_DEFINES>") + #add_definitions(/W3 /DNOMINMAX /MP -D_USE_MATH_DEFINES)# /D_ITERATOR_DEBUG_LEVEL=1 because you need all external DLl to compile with this flag too + set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo;Release;Debug" CACHE STRING "" FORCE) + set(CMAKE_CXX_STANDARD 14) + set(CMAKE_CXX_STANDARD_REQUIRED ON) + set(CMAKE_CXX_EXTENSIONS OFF) + elseif(${currentBuildTool} MATCHES "(make|gmake)") + add_definitions("-Wall -Wno-unknown-pragmas -Wno-sign-compare -g -std=c++14 -D__forceinline=\"inline\ __attribute__((always_inline))\"") + # CHECK_CXX_COMPILER_FLAG("-std=gnu++11" COMPILER_SUPPORTS_CXX11) + # CHECK_CXX_COMPILER_FLAG("-std=gnu++0x" COMPILER_SUPPORTS_CXX0X) + # if(COMPILER_SUPPORTS_CXX11) + # add_definitions(-std=gnu++11) + # elseif(COMPILER_SUPPORTS_CXX0X) + # add_definitions(-std=gnu++0x) + # else() + # message(SEND_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++14 support. Please use a different C++ compiler.") + # endif() + elseif(APPLE) ## \todo TODO: do a better test and send error on unsupported c++14 compiler + add_definitions(-std=c++14 -stdlib=libc++) + endif() +else() + ## Allow C++11 + other flags + include(CheckCXXCompilerFlag) + get_filename_component(currentBuildTool ${CMAKE_BUILD_TOOL} NAME_WE) # tool that can launch the native build system. returned value may be the full path + if(${currentBuildTool} MATCHES "(msdev|devenv|nmake|MSBuild)") + + add_compile_options("$<$:/W3;/DNOMINMAX;/MP;-D_USE_MATH_DEFINES>") + #add_definitions(/W3 /DNOMINMAX /MP -D_USE_MATH_DEFINES)# /D_ITERATOR_DEBUG_LEVEL=1 because you need all external DLl to compile with this flag too + set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo;Release;Debug" CACHE STRING "" FORCE) + set(CMAKE_CXX_STANDARD 14) + set(CMAKE_CXX_STANDARD_REQUIRED ON) + set(CMAKE_CXX_EXTENSIONS OFF) + elseif(${currentBuildTool} MATCHES "(make|gmake|ninja)") + add_definitions("-fpermissive -fPIC -Wall -Wno-unknown-pragmas -Wno-sign-compare -g -std=c++17 -D__forceinline=\"inline\ __attribute__((always_inline))\"") + elseif(APPLE) ## \todo TODO: do a better test and send error on unsupported c++14 compiler + add_definitions(-std=c++17 -stdlib=libc++) + endif() +endif() + +set(INSTALL_STANDALONE ON) + +## Set default build output binaries (used also in sub CMakeLists.txt) : +set(BIN_BUILT_DIR "bin") +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(ARCHI_BUILT_DIR "x64") + set(LIB_BUILT_DIR "lib64") +else() + set(ARCHI_BUILT_DIR "x86") + set(LIB_BUILT_DIR "lib") +endif() + +option(SEPARATE_CONFIGURATIONS "Clearer separation between configurations" OFF) +SET(CMAKE_INSTALL_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/install) +SET(CMAKE_INSTALL_PREFIX ${CMAKE_INSTALL_ROOT}) + +if(DEFINED CMAKE_BUILD_TYPE) ## for mono config type (make/nmake/ninja based) + if(${CMAKE_BUILD_TYPE} MATCHES "Debug") + set(CMAKE_DEBUG_POSTFIX "_d") + elseif(${CMAKE_BUILD_TYPE} MATCHES "RelWithDebInfo") + set(CMAKE_RELWITHDEBINFO_POSTFIX "_rwdi") + elseif(${CMAKE_BUILD_TYPE} MATCHES "MinSizeRel") + set(CMAKE_MINSIZEREL_POSTFIX "_msr") + elseif(${CMAKE_BUILD_TYPE} MATCHES "Release") + set(CMAKE_RELEASE_POSTFIX "") + endif() + + if(SEPARATE_CONFIGURATIONS) + SET(CMAKE_INSTALL_PREFIX_${CMAKE_BUILD_TYPE} ${CMAKE_INSTALL_ROOT}/${CMAKE_BUILD_TYPE}) + else() + SET(CMAKE_INSTALL_PREFIX_${CMAKE_BUILD_TYPE} ${CMAKE_INSTALL_ROOT}) + endif() + + MESSAGE(STATUS "Install path set to ${CMAKE_INSTALL_PREFIX}.") + SET(CMAKE_OUTPUT_LIB_${CMAKE_BUILD_TYPE} ${CMAKE_INSTALL_PREFIX_${CMAKE_BUILD_TYPE}}/lib) + SET(CMAKE_OUTPUT_BIN_${CMAKE_BUILD_TYPE} ${CMAKE_INSTALL_PREFIX_${CMAKE_BUILD_TYPE}}/bin) + + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${CMAKE_BUILD_TYPE} ${CMAKE_OUTPUT_LIB_${CMAKE_BUILD_TYPE}}) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${CMAKE_BUILD_TYPE} ${CMAKE_OUTPUT_LIB_${CMAKE_BUILD_TYPE}}) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CMAKE_BUILD_TYPE} ${CMAKE_OUTPUT_BIN_${CMAKE_BUILD_TYPE}}) + set(CMAKE_PDB_OUTPUT_DIRECTORY_${CMAKE_BUILD_TYPE} ${CMAKE_OUTPUT_BIN_${CMAKE_BUILD_TYPE}}) +endif() +foreach(CONFIG_TYPES ${CMAKE_CONFIGURATION_TYPES}) ## for multi config types (MSVC based) + string(TOUPPER ${CONFIG_TYPES} CONFIG_TYPES_UC) + if(${CONFIG_TYPES} MATCHES "Debug") + set(CMAKE_DEBUG_POSTFIX "_d") + elseif(${CONFIG_TYPES} MATCHES "RelWithDebInfo") + set(CMAKE_RELWITHDEBINFO_POSTFIX "_rwdi") + elseif(${CONFIG_TYPES} MATCHES "MinSizeRel") + set(CMAKE_MINSIZEREL_POSTFIX "_msr") + elseif(${CMAKE_BUILD_TYPE} MATCHES "Release") + set(CMAKE_RELEASE_POSTFIX "") + endif() + + if(SEPARATE_CONFIGURATIONS) + SET(CMAKE_INSTALL_PREFIX_${CONFIG_TYPES_UC} ${CMAKE_INSTALL_ROOT}/${CONFIG_TYPES}) + else() + SET(CMAKE_INSTALL_PREFIX_${CONFIG_TYPES_UC} ${CMAKE_INSTALL_ROOT}) + endif() + + MESSAGE(STATUS "Install path for ${CONFIG_TYPES} set to ${CMAKE_INSTALL_PREFIX_${CONFIG_TYPES_UC}}.") + SET(CMAKE_OUTPUT_LIB_${CONFIG_TYPES_UC} ${CMAKE_INSTALL_PREFIX_${CONFIG_TYPES_UC}}/lib) + SET(CMAKE_OUTPUT_BIN_${CONFIG_TYPES_UC} ${CMAKE_INSTALL_PREFIX_${CONFIG_TYPES_UC}}/bin) + + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${CONFIG_TYPES_UC} ${CMAKE_OUTPUT_LIB_${CONFIG_TYPES_UC}}) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${CONFIG_TYPES_UC} ${CMAKE_OUTPUT_LIB_${CONFIG_TYPES_UC}}) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CONFIG_TYPES_UC} ${CMAKE_OUTPUT_BIN_${CONFIG_TYPES_UC}}) + set(CMAKE_PDB_OUTPUT_DIRECTORY_${CONFIG_TYPES_UC} ${CMAKE_OUTPUT_BIN_${CONFIG_TYPES_UC}}) +endforeach() + + +# Settings for RPATH +if (NOT WIN32) + # Default config of Fedora at INRIA has no LD_LIBRARY_PATH (for security reasons I guess) + # So at least I had "./" in RPATH and found link paths + #set(CMAKE_SKIP_RPATH TRUE) + #SET(CMAKE_SKIP_BUILD_RPATH FALSE) + SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) + + SET(CMAKE_INSTALL_RPATH "$ORIGIN") + #SET(CMAKE_INSTALL_RPATH "./") + #SET(CMAKE_INSTALL_RPATH "./:/usr/lib64/:/usr/lib/:/usr/local/lib64/:/usr/local/lib/") # This one causes be a problem -> a "default" version of libGL (swrast) is located in /usr/lib64 and was selected instead of nvidia one (in /usr/lib64/nividia) + + SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +endif() + + +set(SIBR_PROGRAMARGS "" CACHE STRING "Default program arguments used in Visual Studio target properties") +if ("${SIBR_PROGRAMARGS}" STREQUAL "") + if (DEFINED ENV{SIBR_PROGRAMARGS}) + set(SIBR_PROGRAMARGS "$ENV{SIBR_PROGRAMARGS}" CACHE STRING "Default program arguments used in Visual Studio target properties" FORCE) + message( STATUS "Using program options found in environment variable 'SIBR_PROGRAMARGS' => '${SIBR_PROGRAMARGS}'") + else() + message( + "Note you can provide default program options for Visual Studio target properties by either setting" + " a value for the cmake cached variable 'SIBR_PROGRAMARGS' or by setting a new environment " + "variable 'SIBR_PROGRAMARGS'") + endif() +endif() + +add_custom_target(PREBUILD ALL) + +## Include all projects +set(SIBR_PROJECTS_SAMPLES_SUBPAGE_REF "") +set(SIBR_PROJECTS_OURS_SUBPAGE_REF "") +set(SIBR_PROJECTS_TOOLBOX_SUBPAGE_REF "") +set(SIBR_PROJECTS_OTHERS_SUBPAGE_REF "") +set(SIBR_PROJECTS_SAMPLES_REF_REF "") +set(SIBR_PROJECTS_OURS_REF_REF "") +set(SIBR_PROJECTS_TOOLBOX_REF_REF "") +set(SIBR_PROJECTS_OTHERS_REF_REF "") +set(DOXY_APP_SPECIFIC_IMG_PATH "") +set(DOXY_DOC_EXCLUDE_PATTERNS_DIRS "") +ADD_SUBDIRECTORY(src) + + +## handle documentation +if (WIN32) +ADD_SUBDIRECTORY(docs) +endif() diff --git a/submodules/gaussian-splatting/SIBR_viewers/LICENSE.md b/submodules/gaussian-splatting/SIBR_viewers/LICENSE.md new file mode 100644 index 0000000000000000000000000000000000000000..0ae59dae71d0f61caa31d7465d2472c0b3186df4 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/LICENSE.md @@ -0,0 +1,204 @@ +SIBR License +============ + +The sibr system is licensed under the Apache 2.0 license, except for some projects in specific branches (in src/projects) that have separate licenses in those directories. + +Please verify the LICENSE.md file for those directories. + +-------------- + + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + + Copyright 2024 Inria / Universite Cote d'Azur + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + diff --git a/submodules/gaussian-splatting/SIBR_viewers/README.md b/submodules/gaussian-splatting/SIBR_viewers/README.md new file mode 100644 index 0000000000000000000000000000000000000000..381d6b036a7e2990df7e6bd4ae7a04a64a431b2b --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/README.md @@ -0,0 +1,142 @@ +# SIBR Core + +**SIBR** is a System for Image-Based Rendering. +It is built around the *sibr-core* in this repo and several *Projects* implementing published research papers. +For more complete documentation, see here: [SIBR Documentation](https://sibr.gitlabpages.inria.fr) + +This **SIBR core** repository provides : +- a basic Image-Based Renderer +- a per-pixel implementation of Unstructured Lumigraph (ULR) +- several dataset tools & pipelines do process input images + +Details on how to run in the documentation and in the section below. +If you use this code in a publication, please cite the system as follows: + +``` +@misc{sibr2020, + author = "Bonopera, Sebastien and Esnault, Jerome and Prakash, Siddhant and Rodriguez, Simon and Thonat, Theo and Benadel, Mehdi and Chaurasia, Gaurav and Philip, Julien and Drettakis, George", + title = "sibr: A System for Image Based Rendering", + year = "2020", + url = "https://gitlab.inria.fr/sibr/sibr_core" +} +``` + +## Setup + +**Note**: The current release is for *Windows 10* only. We are planning a Linux release soon. + +#### Binary distribution + +The easiest way to use SIBR is to download the binary distribution. All steps described below, including all preprocessing for your datasets will work using this code. + +Download the distribution from the page: https://sibr.gitlabpages.inria.fr/download.html (Core, 57Mb); unzip the file and rename the directory "install". + +#### Install requirements + +- [**Visual Studio 2019**](https://visualstudio.microsoft.com/fr/downloads/) +- [**Cmake 3.16+**](https://cmake.org/download) +- [**7zip**](https://www.7-zip.org) +- [**Python 3.8+**](https://www.python.org/downloads/) for shaders installation scripts and dataset preprocess scripts +- [**Doxygen 1.8.17+**](https://www.doxygen.nl/download.html#srcbin) for documentation +- [**CUDA 10.1+**](https://developer.nvidia.com/cuda-downloads) and [**CUDnn**](https://developer.nvidia.com/cudnn) if projects requires it + +Make sure Python, CUDA and Doxygen are in the PATH + +If you have Chocolatey, you can grab most of these with this command: + +```sh +choco install cmake 7zip python3 doxygen.install cuda + +## Visual Studio is available on Chocolatey, +## though we do advise to set it from Visual Studio Installer and to choose your licensing accordingly +choco install visualstudio2019community +``` + +#### Generation of the solution + +- Checkout this repository's master branch: + + ```sh + ## through HTTPS + git clone https://gitlab.inria.fr/sibr/sibr_core.git -b master + ## through SSH + git clone git@gitlab.inria.fr:sibr/sibr_core.git -b master + ``` +- Run Cmake-gui once, select the repo root as a source directory, `build/` as the build directory. Configure, select the Visual Studio C++ Win64 compiler +- Select the projects you want to generate among the BUILD elements in the list (you can group Cmake flags by categories to access those faster) +- Generate + +#### Compilation + +- Open the generated Visual Studio solution (`build/sibr_projects.sln`) +- Build the `ALL_BUILD` target, and then the `INSTALL` target +- The compiled executables will be put in `install/bin` +- TODO: are the DLLs properly installed? + +#### Compilation of the documentation + +- Open the generated Visual Studio solution (`build/sibr_projects.sln`) +- Build the `DOCUMENTATION` target +- Run `install/docs/index.html` in a browser + + +## Scripts + +Some scripts will require you to install `PIL`, and `convert` from `ImageMagick`. + +```sh +## To install pillow +python -m pip install pillow + +## If you have Chocolatey, you can install imagemagick from this command +choco install imagemagick +``` + +## Troubleshooting + +#### Bugs and Issues + +We will track bugs and issues through the Issues interface on gitlab. Inria gitlab does not allow creation of external accounts, so if you have an issue/bug please email sibr@inria.fr and we will either create a guest account or create the issue on our side. + +#### Cmake complaining about the version + +if you are the first to use a very recent Cmake version, you will have to update `CHECKED_VERSION` in the root `CmakeLists.txt`. + +#### Weird OpenCV error + +you probably selected the 32-bits compiler in Cmake-gui. + +#### `Cmd.exe failed with error 009` or similar + +make sure Python is installed and in the path. + +#### `BUILD_ALL` or `INSTALL` fail because of a project you don't really need + +build and install each project separately by selecting the proper targets. + +#### Error in CUDA headers under Visual Studio 2019 + +make sure CUDA >= 10.1 (first version to support VS2019) is installed. + +## To run an example + +For more details, please see the documentation: http://sibr.gitlabpages.inria.fr + +Download a dataset from: https://repo-sam.inria.fr/fungraph/sibr-datasets/ + +e.g., the *sibr-museum-front* dataset in the *DATASETS_PATH* directory. + +``` +wget https://repo-sam.inria.fr/fungraph/sibr-datasets/museum_front27_ulr.zip +``` + +Once you have built the system or downloaded the binaries (see above), go to *install/bin* and you can run: +``` + sibr_ulrv2_app.exe --path DATASETS_PATH/sibr-museum-front +``` + +You will have an interactive viewer and you can navigate freely in the captured scene. +Our default interactive viewer has a main view running the algorithm and a top view to visualize the position of the calibrated cameras. By default you are in WASD mode, and can toggle to trackball using the "y" key. Please see the page [Interface](https://sibr.gitlabpages.inria.fr/docs/nightly/howto_sibr_useful_objects.html) for more details on the interface. + +Please see the documentation on how to create a dataset from your own scene, and the various other IBR algorithms available. + diff --git a/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/MSVCsetUserCommand.cmake b/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/MSVCsetUserCommand.cmake new file mode 100644 index 0000000000000000000000000000000000000000..bc49770d644ca2803a9d52f9186d952b40fafdf8 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/MSVCsetUserCommand.cmake @@ -0,0 +1,149 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +if(__MSVCsetUserCommand_cmake_INCLUDED__) + return() +else() + set(__MSVCsetUserCommand_cmake_INCLUDED__ ON) +endif() + +## Allow to configure the Debugger settings of visual studio +## Note: Using this command under linux doesn't affect anything +## On run Debug Windows local : visual will try to load a specific COMMAND with ARGS in the provided WORKING_DIR +## +## usage: +## MSVCsetUserCommand( +## [COMMAND | [ PATH [FILE ] ] ] +## ARGS +## WORKING_DIR +## ) +## +## Warning 1 : All arugments () must be passed under quotes +## Warning 2 : WORKING_DIR path arg have to finish with remain slah '/' +## Warning 3 : use COMMAND for external app OR PATH (optionaly with FILE) option(s) to set your built/installed/moved target +## +## Example 1: +## include(MSVCsetUserCommand) +## MSVCsetUserCommand( UnityRenderingPlugin +## COMMAND "C:/Program Files (x86)/Unity/Editor/Unity.exe" +## ARGS "-force-opengl -projectPath \"${CMAKE_HOME_DIRECTORY}/UnityPlugins/RenderingPluginExample/UnityProject\"" +## WORKING_DIR "${CMAKE_HOME_DIRECTORY}/UnityPlugins/RenderingPluginExample/UnityProject" +## VERBOSE +## ) +## +## Example 2: +## include(MSVCsetUserCommand) +## MSVCsetUserCommand( ibrApp +## PATH "C:/Program Files (x86)/workspace/IBR/install" +## FILE "ibrApp${CMAKE_EXECUTABLE_SUFFIX}" ## this option line is optional since the target name didn't change between build and install step +## ARGS "-path \"${CMAKE_HOME_DIRECTORY}/dataset\"" +## WORKING_DIR "${CMAKE_HOME_DIRECTORY}" +## VERBOSE +## ) +## +function(MSVCsetUserCommand targetName) + cmake_parse_arguments(MSVCsuc "VERBOSE" "PATH;FILE;COMMAND;ARGS;WORKING_DIR" "" ${ARGN} ) + + ## If no arguments are given, do not create an unecessary .vcxproj.user file + set(MSVCsuc_DEFAULT OFF) + + if(MSVCsuc_PATH AND MSVCsuc_DEFAULT) + set(MSVCsuc_DEFAULT OFF) + endif() + + if(MSVCsuc_FILE AND MSVCsuc_DEFAULT) + set(MSVCsuc_DEFAULT OFF) + endif() + + if(NOT MSVCsuc_COMMAND) + if(MSVCsuc_PATH AND MSVCsuc_FILE) + set(MSVCsuc_COMMAND "${MSVCsuc_PATH}\\${MSVCsuc_FILE}") + elseif(MSVCsuc_PATH) + set(MSVCsuc_COMMAND "${MSVCsuc_PATH}\\$(TargetFileName)") + else() + set(MSVCsuc_COMMAND "$(TargetPath)") ## => $(TargetDir)\$(TargetName)$(TargetExt) + endif() + elseif(MSVCsuc_DEFAULT) + set(MSVCsuc_DEFAULT OFF) + endif() + + # NOTE: there was a typo here. there is an else if written after else statement + # changing the order of the else if statement + if(MSVCsuc_WORKING_DIR) + file(TO_NATIVE_PATH ${MSVCsuc_WORKING_DIR} MSVCsuc_WORKING_DIR) + elseif(MSVCsuc_DEFAULT) + set(MSVCsuc_DEFAULT OFF) + else() + set(MSVCsuc_WORKING_DIR "$(ProjectDir)") + endif() + + if(NOT MSVCsuc_ARGS) + set(MSVCsuc_ARGS "") + elseif(MSVCsuc_DEFAULT) + set(MSVCsuc_DEFAULT OFF) + endif() + + if(MSVC10 OR (MSVC AND MSVC_VERSION GREATER 1600)) # 2010 or newer + + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(PLATEFORM_BITS x64) + else() + set(PLATEFORM_BITS Win32) + endif() + + if(NOT MSVCsuc_DEFAULT AND PLATEFORM_BITS) + + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${targetName}.vcxproj.user" + " + + + ${MSVCsuc_COMMAND} + ${MSVCsuc_ARGS} + WindowsLocalDebugger + ${MSVCsuc_WORKING_DIR} + + + ${MSVCsuc_COMMAND} + ${MSVCsuc_ARGS} + WindowsLocalDebugger + ${MSVCsuc_WORKING_DIR} + + + ${MSVCsuc_COMMAND} + ${MSVCsuc_ARGS} + WindowsLocalDebugger + ${MSVCsuc_WORKING_DIR} + + + ${MSVCsuc_COMMAND} + ${MSVCsuc_ARGS} + WindowsLocalDebugger + ${MSVCsuc_WORKING_DIR} + +" + ) + if(MSVCsuc_VERBOSE) + message(STATUS "[MSVCsetUserCommand] Write ${CMAKE_CURRENT_BINARY_DIR}/${targetName}.vcxproj.user file") + message(STATUS " to execute ${MSVCsuc_COMMAND} ${MSVCsuc_ARGS}") + message(STATUS " from derectory ${MSVCsuc_WORKING_DIR}") + message(STATUS " on visual studio run debugger button") + endif() + + else() + message(WARNING "PLATEFORM_BITS is undefined...") + endif() + + else() + if(MSVCsuc_VERBOSE) + message(WARNING "MSVCsetUserCommand is disable because too old MSVC is used (need MSVC10 2010 or newer)") + endif() + endif() + +endfunction() diff --git a/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/Modules/FindASSIMP.cmake b/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/Modules/FindASSIMP.cmake new file mode 100644 index 0000000000000000000000000000000000000000..edfbb33b78e3cd57bc0fc2c1c6e2a349c32a5bb7 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/Modules/FindASSIMP.cmake @@ -0,0 +1,114 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +## Try to find the ASSIMP library +## Once done this will define +## +## ASSIMP_FOUND - system has ASSIMP +## ASSIMP_INCLUDE_DIR - The ASSIMP include directory +## ASSIMP_LIBRARIES - The libraries needed to use ASSIMP +## ASSIMP_CMD - the full path of ASSIMP executable +## ASSIMP_DYNAMIC_LIB - the Assimp dynamic lib (available only on windows as .dll file for the moment) +## +## Edited for using a bugfixed version of Assimp + +if(NOT ASSIMP_DIR) + set(ASSIMP_DIR "$ENV{ASSIMP_DIR}" CACHE PATH "ASSIMP root directory") + message("NO ASSIMP DIR " ASSIMP_DIR ) + file(TO_CMAKE_PATH "/data/graphdeco/share/usr/local" ASSIMP_DIR) + set(ASSIMP_DIR "/data/graphdeco/share/usr/local" ) + message("SETTING ASSIMP DIR " ASSIMP_DIR ) +endif() +if(ASSIMP_DIR) + file(TO_CMAKE_PATH ${ASSIMP_DIR} ASSIMP_DIR) + file(TO_CMAKE_PATH "/data/graphdeco/share/usr/local" ASSIMP_DIR) + message("ASSIMP DIR " ASSIMP_DIR ) +endif() + + +## set the LIB POSTFIX to find in a right directory according to what kind of compiler we use (32/64bits) +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(ASSIMP_SEARCH_LIB "lib64") + set(ASSIMP_SEARCH_BIN "bin64") + set(ASSIMP_SEARCH_LIB_PATHSUFFIXE "x64") +else() + set(ASSIMP_SEARCH_LIB "lib32") + set(ASSIMP_SEARCH_BIN "bin32") + set(ASSIMP_SEARCH_LIB_PATHSUFFIXE "x86") +endif() + +set(PROGRAMFILESx86 "PROGRAMFILES(x86)") + + +FIND_PATH(ASSIMP_INCLUDE_DIR + NAMES assimp/config.h + PATHS + ${ASSIMP_DIR} + ## linux + /usr + /usr/include + /usr/local + /opt/local + ## windows + "$ENV{PROGRAMFILES}/Assimp" + "$ENV{${PROGRAMFILESx86}}/Assimp" + "$ENV{ProgramW6432}/Assimp" + PATH_SUFFIXES include +) + + +FIND_LIBRARY(ASSIMP_LIBRARY + NAMES assimp-vc140-mt assimp + PATHS + ${ASSIMP_DIR}/${ASSIMP_SEARCH_LIB} + ${ASSIMP_DIR}/lib + ${ASSIMP_DIR}/lib64 + ## linux + /usr/${ASSIMP_SEARCH_LIB} + /usr/local/${ASSIMP_SEARCH_LIB} + /opt/local/${ASSIMP_SEARCH_LIB} + /usr/lib + /usr/lib64 + /usr/local/lib + /opt/local/lib + ## windows + "$ENV{PROGRAMFILES}/Assimp/${ASSIMP_SEARCH_LIB}" + "$ENV{${PROGRAMFILESx86}}/Assimp/${ASSIMP_SEARCH_LIB}" + "$ENV{ProgramW6432}/Assimp/${ASSIMP_SEARCH_LIB}" + "$ENV{PROGRAMFILES}/Assimp/lib" + "$ENV{${PROGRAMFILESx86}}/Assimp/lib" + "$ENV{ProgramW6432}/Assimp/lib" + PATH_SUFFIXES ${ASSIMP_SEARCH_LIB_PATHSUFFIXE} +) +set(ASSIMP_LIBRARIES ${ASSIMP_LIBRARY}) + + +if(ASSIMP_LIBRARY) + get_filename_component(ASSIMP_LIBRARY_DIR ${ASSIMP_LIBRARY} PATH) + if(WIN32) + file(GLOB ASSIMP_DYNAMIC_LIB "${ASSIMP_LIBRARY_DIR}/assimp*.dll") + if(NOT ASSIMP_DYNAMIC_LIB) + message("ASSIMP_DYNAMIC_LIB is missing... at ${ASSIMP_LIBRARY_DIR}") + endif() + endif() + set(ASSIMP_DYNAMIC_LIB ${ASSIMP_DYNAMIC_LIB} CACHE PATH "Windows dll location") +endif() + +MARK_AS_ADVANCED(ASSIMP_DYNAMIC_LIB ASSIMP_INCLUDE_DIR ASSIMP_LIBRARIES) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(ASSIMP + REQUIRED_VARS ASSIMP_INCLUDE_DIR ASSIMP_LIBRARIES + FAIL_MESSAGE "ASSIMP wasn't found correctly. Set ASSIMP_DIR to the root SDK installation directory." +) + +if(NOT ASSIMP_FOUND) + set(ASSIMP_DIR "" CACHE STRING "Path to ASSIMP install directory") +endif() diff --git a/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/Modules/FindEGL.cmake b/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/Modules/FindEGL.cmake new file mode 100644 index 0000000000000000000000000000000000000000..41d45cb08d09903887d17f564c6ab50e34723e28 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/Modules/FindEGL.cmake @@ -0,0 +1,161 @@ +#.rst: +# FindEGL +# ------- +# +# Try to find EGL. +# +# This will define the following variables: +# +# ``EGL_FOUND`` +# True if (the requested version of) EGL is available +# ``EGL_VERSION`` +# The version of EGL; note that this is the API version defined in the +# headers, rather than the version of the implementation (eg: Mesa) +# ``EGL_LIBRARIES`` +# This can be passed to target_link_libraries() instead of the ``EGL::EGL`` +# target +# ``EGL_INCLUDE_DIRS`` +# This should be passed to target_include_directories() if the target is not +# used for linking +# ``EGL_DEFINITIONS`` +# This should be passed to target_compile_options() if the target is not +# used for linking +# +# If ``EGL_FOUND`` is TRUE, it will also define the following imported target: +# +# ``EGL::EGL`` +# The EGL library +# +# In general we recommend using the imported target, as it is easier to use. +# Bear in mind, however, that if the target is in the link interface of an +# exported library, it must be made available by the package config file. +# +# Since pre-1.0.0. + +#============================================================================= +# Copyright 2014 Alex Merry +# Copyright 2014 Martin GrÀßlin +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#============================================================================= + +include(CheckCXXSourceCompiles) +include(CMakePushCheckState) + +# Use pkg-config to get the directories and then use these values +# in the FIND_PATH() and FIND_LIBRARY() calls +find_package(PkgConfig) +pkg_check_modules(PKG_EGL QUIET egl) + +set(EGL_DEFINITIONS ${PKG_EGL_CFLAGS_OTHER}) + +find_path(EGL_INCLUDE_DIR + NAMES + EGL/egl.h + HINTS + ${PKG_EGL_INCLUDE_DIRS} +) +find_library(EGL_LIBRARY + NAMES + EGL + HINTS + ${PKG_EGL_LIBRARY_DIRS} +) + +# NB: We do *not* use the version information from pkg-config, as that +# is the implementation version (eg: the Mesa version) +if(EGL_INCLUDE_DIR) + # egl.h has defines of the form EGL_VERSION_x_y for each supported + # version; so the header for EGL 1.1 will define EGL_VERSION_1_0 and + # EGL_VERSION_1_1. Finding the highest supported version involves + # finding all these defines and selecting the highest numbered. + file(READ "${EGL_INCLUDE_DIR}/EGL/egl.h" _EGL_header_contents) + string(REGEX MATCHALL + "[ \t]EGL_VERSION_[0-9_]+" + _EGL_version_lines + "${_EGL_header_contents}" + ) + unset(_EGL_header_contents) + foreach(_EGL_version_line ${_EGL_version_lines}) + string(REGEX REPLACE + "[ \t]EGL_VERSION_([0-9_]+)" + "\\1" + _version_candidate + "${_EGL_version_line}" + ) + string(REPLACE "_" "." _version_candidate "${_version_candidate}") + if(NOT DEFINED EGL_VERSION OR EGL_VERSION VERSION_LESS _version_candidate) + set(EGL_VERSION "${_version_candidate}") + endif() + endforeach() + unset(_EGL_version_lines) +endif() + +cmake_push_check_state(RESET) +list(APPEND CMAKE_REQUIRED_LIBRARIES "${EGL_LIBRARY}") +list(APPEND CMAKE_REQUIRED_INCLUDES "${EGL_INCLUDE_DIR}") + +check_cxx_source_compiles(" +#include + +int main(int argc, char *argv[]) { + EGLint x = 0; EGLDisplay dpy = 0; EGLContext ctx = 0; + eglDestroyContext(dpy, ctx); +}" HAVE_EGL) + +cmake_pop_check_state() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(EGL + FOUND_VAR + EGL_FOUND + REQUIRED_VARS + EGL_LIBRARY + EGL_INCLUDE_DIR + HAVE_EGL + VERSION_VAR + EGL_VERSION +) + +if(EGL_FOUND AND NOT TARGET EGL::EGL) + add_library(EGL::EGL UNKNOWN IMPORTED) + set_target_properties(EGL::EGL PROPERTIES + IMPORTED_LOCATION "${EGL_LIBRARY}" + INTERFACE_COMPILE_OPTIONS "${EGL_DEFINITIONS}" + INTERFACE_INCLUDE_DIRECTORIES "${EGL_INCLUDE_DIR}" + ) +endif() + +mark_as_advanced(EGL_LIBRARY EGL_INCLUDE_DIR HAVE_EGL) + +# compatibility variables +set(EGL_LIBRARIES ${EGL_LIBRARY}) +set(EGL_INCLUDE_DIRS ${EGL_INCLUDE_DIR}) +set(EGL_VERSION_STRING ${EGL_VERSION}) + +include(FeatureSummary) +set_package_properties(EGL PROPERTIES + URL "https://www.khronos.org/egl/" + DESCRIPTION "A platform-agnostic mechanism for creating rendering surfaces for use with other graphics libraries, such as OpenGL|ES and OpenVG." +) diff --git a/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/Modules/FindEmbree.cmake b/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/Modules/FindEmbree.cmake new file mode 100644 index 0000000000000000000000000000000000000000..0d07237f6670f3b27592dbdaecf883a531b8c346 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/Modules/FindEmbree.cmake @@ -0,0 +1,94 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + +## Important Note: +## This is not an official Find*cmake. It has been written for searching through +## a custom path (EMBREE_DIR) before checking elsewhere. +## +## FindEMBREE.cmake +## Find EMBREE's includes and library +## +## This module defines : +## [in] EMBREE_DIR, The base directory to search for EMBREE (as cmake var or env var) +## [out] EMBREE_INCLUDE_DIR where to find EMBREE.h +## [out] EMBREE_LIBRARIES, EMBREE_LIBRARY, libraries to link against to use EMBREE +## [out] EMBREE_FOUND, If false, do not try to use EMBREE. +## + + +if(NOT EMBREE_DIR) + set(EMBREE_DIR "$ENV{EMBREE_DIR}" CACHE PATH "EMBREE root directory") +endif() +if(EMBREE_DIR) + file(TO_CMAKE_PATH ${EMBREE_DIR} EMBREE_DIR) +endif() + + +## set the LIB POSTFIX to find in a right directory according to what kind of compiler we use (32/64bits) +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(EMBREE_SEARCH_LIB "lib64") + set(EMBREE_SEARCH_BIN "bin64") + set(EMBREE_SEARCH_LIB_PATHSUFFIXE "x64") +else() + set(EMBREE_SEARCH_LIB "lib32") + set(EMBREE_SEARCH_BIN "bin32") + set(EMBREE_SEARCH_LIB_PATHSUFFIXE "x86") +endif() + +set(PROGRAMFILESx86 "PROGRAMFILES(x86)") + +FIND_PATH(EMBREE_INCLUDE_DIR + NAMES embree3/rtcore_geometry.h + PATHS + ${EMBREE_DIR} + ## linux + /usr + /usr/local + /opt/local + ## windows + "$ENV{PROGRAMFILES}/EMBREE" + "$ENV{${PROGRAMFILESx86}}/EMBREE" + "$ENV{ProgramW6432}/EMBREE" + PATH_SUFFIXES include +) + +FIND_LIBRARY(EMBREE_LIBRARY + NAMES embree3 + PATHS + ${EMBREE_DIR}/${EMBREE_SEARCH_LIB} + ${EMBREE_DIR}/lib + ## linux + /usr/${EMBREE_SEARCH_LIB} + /usr/local/${EMBREE_SEARCH_LIB} + /opt/local/${EMBREE_SEARCH_LIB} + /usr/lib + /usr/local/lib + /opt/local/lib + ## windows + "$ENV{PROGRAMFILES}/EMBREE/${EMBREE_SEARCH_LIB}" + "$ENV{${PROGRAMFILESx86}}/EMBREE/${EMBREE_SEARCH_LIB}" + "$ENV{ProgramW6432}/EMBREE/${EMBREE_SEARCH_LIB}" + "$ENV{PROGRAMFILES}/EMBREE/lib" + "$ENV{${PROGRAMFILESx86}}/EMBREE/lib" + "$ENV{ProgramW6432}/EMBREE/lib" + PATH_SUFFIXES ${EMBREE_SEARCH_LIB_PATHSUFFIXE} +) +set(EMBREE_LIBRARIES ${EMBREE_LIBRARY}) + +MARK_AS_ADVANCED(EMBREE_INCLUDE_DIR EMBREE_LIBRARIES) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(EMBREE + REQUIRED_VARS EMBREE_INCLUDE_DIR EMBREE_LIBRARIES + FAIL_MESSAGE "EMBREE wasn't found correctly. Set EMBREE_DIR to the root SDK installation directory." +) + +if(NOT EMBREE_FOUND) + set(EMBREE_DIR "" CACHE STRING "Path to EMBREE install directory") +endif() diff --git a/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/Modules/FindFFMPEG.cmake b/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/Modules/FindFFMPEG.cmake new file mode 100644 index 0000000000000000000000000000000000000000..e60cee8d812f574226c71ff38ec461872f7e63d1 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/Modules/FindFFMPEG.cmake @@ -0,0 +1,110 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +## Try to find the FFMPEG library +## Once done this will define +## +## FFMPEG_FOUND - system has FFmpeg +## FFMPEG_INCLUDE_DIR - The FFmpeg include directory +## FFMPEG_LIBRARIES - The libraries needed to use FFmpeg +## FFMPEG_DYNAMIC_LIBS - DLLs for windows + + +if(NOT FFMPEG_DIR) + set(FFMPEG_DIR "$ENV{FFMPEG_DIR}" CACHE PATH "FFMPEG_DIR root directory") +endif() + +if(FFMPEG_DIR) + file(TO_CMAKE_PATH ${FFMPEG_DIR} FFMPEG_DIR) +endif() + +MACRO(FFMPEG_FIND varname shortname headername) + + # Path to include dirs + FIND_PATH(FFMPEG_${varname}_INCLUDE_DIRS + NAMES "lib${shortname}/${headername}" + PATHS + "${FFMPEG_DIR}/include" # modify this to adapt according to OS/compiler + "/usr/include" + "/usr/include/ffmpeg" + ) + + #Add libraries + IF(${FFMPEG_${varname}_INCLUDE_DIRS} STREQUAL "FFMPEG_${varname}_INCLUDE_DIR-NOTFOUND") + MESSAGE(STATUS "Can't find includes for ${shortname}...") + ELSE() + FIND_LIBRARY(FFMPEG_${varname}_LIBRARIES + NAMES ${shortname} + PATHS + ${FFMPEG_DIR}/lib + "/usr/lib" + "/usr/lib64" + "/usr/local/lib" + "/usr/local/lib64" + ) + + # set libraries and other variables + SET(FFMPEG_${varname}_FOUND 1) + SET(FFMPEG_${varname}_INCLUDE_DIRS ${FFMPEG_${varname}_INCLUDE_DIR}) + SET(FFMPEG_${varname}_LIBS ${FFMPEG_${varname}_LIBRARIES}) + ENDIF() + ENDMACRO(FFMPEG_FIND) + +#Calls to ffmpeg_find to get librarires ------------------------------ +FFMPEG_FIND(LIBAVFORMAT avformat avformat.h) +FFMPEG_FIND(LIBAVDEVICE avdevice avdevice.h) +FFMPEG_FIND(LIBAVCODEC avcodec avcodec.h) +FFMPEG_FIND(LIBAVUTIL avutil avutil.h) +FFMPEG_FIND(LIBSWSCALE swscale swscale.h) + +# check if libs are found and set FFMPEG related variables +#SET(FFMPEG_FOUND "NO") +IF(FFMPEG_LIBAVFORMAT_FOUND + AND FFMPEG_LIBAVDEVICE_FOUND + AND FFMPEG_LIBAVCODEC_FOUND + AND FFMPEG_LIBAVUTIL_FOUND + AND FFMPEG_LIBSWSCALE_FOUND) + + # All ffmpeg libs are here + SET(FFMPEG_FOUND "YES") + SET(FFMPEG_INCLUDE_DIR ${FFMPEG_LIBAVFORMAT_INCLUDE_DIRS}) + SET(FFMPEG_LIBRARY_DIRS ${FFMPEG_LIBAVFORMAT_LIBRARY_DIRS}) + SET(FFMPEG_LIBRARIES + ${FFMPEG_LIBAVFORMAT_LIBS} + ${FFMPEG_LIBAVDEVICE_LIBS} + ${FFMPEG_LIBAVCODEC_LIBS} + ${FFMPEG_LIBAVUTIL_LIBS} + ${FFMPEG_LIBSWSCALE_LIBS} ) + + # add dynamic libraries + if(WIN32) + file(GLOB FFMPEG_DYNAMIC_LIBS "${FFMPEG_DIR}/bin/*.dll") + if(NOT FFMPEG_DYNAMIC_LIBS) + message("FFMPEG_DYNAMIC_LIBS is missing...") + endif() + set(FFMPEG_DYNAMIC_LIBS ${FFMPEG_DYNAMIC_LIBS} CACHE PATH "Windows dll location") +endif() + + mark_as_advanced(FFMPEG_INCLUDE_DIR FFMPEG_LIBRARY_DIRS FFMPEG_LIBRARIES FFMPEG_DYNAMIC_LIBS) +ELSE () + MESSAGE(STATUS "Could not find FFMPEG") +ENDIF() + + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(FFMPEG + REQUIRED_VARS FFMPEG_INCLUDE_DIR FFMPEG_LIBRARIES + FAIL_MESSAGE "FFmpeg wasn't found correctly. Set FFMPEG_DIR to the root SDK installation directory." +) + +if(NOT FFMPEG_FOUND) + set(FFMPEG_DIR "" CACHE STRING "Path to FFmpeg install directory") +endif() + diff --git a/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/Modules/FindGLFW.cmake b/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/Modules/FindGLFW.cmake new file mode 100644 index 0000000000000000000000000000000000000000..14263de4365a6ac72b55d874373a589e3d604933 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/Modules/FindGLFW.cmake @@ -0,0 +1,109 @@ +##============================================================================= +## +## Copyright (c) Kitware, Inc. +## All rights reserved. +## See LICENSE.txt for details. +## +## This software is distributed WITHOUT ANY WARRANTY; without even +## the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +## PURPOSE. See the above copyright notice for more information. +## +## Copyright 2016 Sandia Corporation. +## Copyright 2016 UT-Battelle, LLC. +## Copyright 2016 Los Alamos National Security. +## +## Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +## the U.S. Government retains certain rights in this software. +## Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National +## Laboratory (LANL), the U.S. Government retains certain rights in +## this software. +## +##============================================================================= +# Try to find EGL library and include dir. +# Once done this will define +# +# GLFW_FOUND +# GLFW_INCLUDE_DIR +# GLFW_LIBRARY +# + +include(FindPackageHandleStandardArgs) + +if (WIN32) + find_path( GLFW_INCLUDE_DIR + NAMES + GLFW/glfw3.h + PATHS + ${PROJECT_SOURCE_DIR}/shared_external/glfw/include + ${PROJECT_SOURCE_DIR}/../shared_external/glfw/include + ${GLFW_LOCATION}/include + $ENV{GLFW_LOCATION}/include + $ENV{PROGRAMFILES}/GLFW/include + ${GLFW_LOCATION} + $ENV{GLFW_LOCATION} + DOC "The directory where GLFW/glfw3.h resides" ) + if(ARCH STREQUAL "x86") + find_library( GLFW_LIBRARY + NAMES + glfw3 + PATHS + ${GLFW_LOCATION}/lib + $ENV{GLFW_LOCATION}/lib + $ENV{PROGRAMFILES}/GLFW/lib + DOC "The GLFW library") + else() + find_library( GLFW_LIBRARY + NAMES + glfw3 + PATHS + ${GLFW_LOCATION}/lib + $ENV{GLFW_LOCATION}/lib + $ENV{PROGRAMFILES}/GLFW/lib + DOC "The GLFW library") + endif() +endif () + +if (${CMAKE_HOST_UNIX}) + message("GFLW LOCATION " $ENV{GLFW_LOCATION} ) + find_path( GLFW_INCLUDE_DIR + NAMES + GLFW/glfw3.h + PATHS +# ${GLFW_LOCATION}/include + $ENV{GLFW_LOCATION}/include +# /usr/include +# /usr/local/include +# /sw/include +# /opt/local/include +# NO_DEFAULT_PATH + DOC "The directory where GLFW/glfw3.h resides" + ) + find_library( GLFW_LIBRARY + NAMES + glfw3 glfw + PATHS +# ${GLFW_LOCATION}/lib + $ENV{GLFW_LOCATION}/lib + $ENV{GLFW_LOCATION}/lib64 +# /usr/lib64 +# /usr/lib +# /usr/local/lib64 +# /usr/local/lib +# /sw/lib +# /opt/local/lib +# /usr/lib/x86_64-linux-gnu +# NO_DEFAULT_PATH + DOC "The GLFW library") + + set( GLFW_INCLUDE_DIR $ENV{GLFW_LOCATION}/include ) + set( GLFW_LIBRARY $ENV{GLFW_LOCATION}/lib64/libglfw3.a ) + message("*************==========> FindGLFW .cmake " ${GLFW_INCLUDE_DIR} " LIB " ${GLFW_LIBRARY} ) +endif () + +find_package_handle_standard_args(GLFW DEFAULT_MSG + GLFW_INCLUDE_DIR + GLFW_LIBRARY +) + +mark_as_advanced( GLFW_FOUND ) + diff --git a/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/Win3rdParty.cmake b/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/Win3rdParty.cmake new file mode 100644 index 0000000000000000000000000000000000000000..7e42fbb9f4353c2208ed3d6f44cf7acc3fccedc2 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/Win3rdParty.cmake @@ -0,0 +1,337 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +## This file should be include and use only on WIN32 OS and once +## It allow to auto check/download and use a preconfigured 3rdParty binaries for cmake usage +## It use the downloadAndExtractZipFile cmake module to work. +## +if(__Win3rdParty_cmake_INCLUDED__) + return() +else() + set(__Win3rdParty_cmake_INCLUDED__ ON) +endif() + + +## +## To be sure to reset an empty cached variable but keep any other kind of variables +## +## Usage: +## check_cached_var( [FORCE]) +## +## is the cached cmake variable you need to reset +## is the new default value of the reseted cached cmake variable +## is the kind of GUI cache input can be : FILEPATH; PATH; STRING or BOOL +## is the associated GUI cache input documentation display in the GUI +## FORCE option could be use to reset a cached variable even if it is not empty. +## +macro(check_cached_var var resetedCachedValue cacheType cacheDoc) + # message(STATUS "inside check_cached_var macro. argn=${ARGN}") + cmake_parse_arguments(ccv "FORCE" "" "" ${ARGN}) + + if(ccv_FORCE) + set(FORCE FORCE) + else() + set(FORCE ) + endif() + + if(NOT ${var} OR ccv_FORCE) + unset(${var} CACHE) + # message(STATUS "setting new cache value. var ${var} = ${resetedCachedValue}") + set(${var} "${resetedCachedValue}" CACHE ${cacheType} "${cacheDoc}" ${FORCE}) + endif() +endmacro() + + +## +## Win3rdParty function allow to specify a directory which contain all necessary windows dependenties. +## By uploading 3rdParty directory (which contain dependencies, *.lib, *.dll... for a specific version of compiler) onto Gforge file tab, +## you get back an URL of download you can give to this function with a directory name. So you can provide multiple 3rdParty version of same dependencies (MSVC11, MSVC12...). +## By providing a prefix to this function, you allow to use different kind of 3rdParty which can be handled by CMAKE OPTIONS depending on what your framework need for example. +## +## Usage 1: +## Win3rdParty( MSVC +## [MSVC ] [...] +## [VCID] [DEFAULT_USE] [VERBOSE] ) +## +## * allow to identify which 3rdParty you process (prefix name) +## * MSVC flag could be MSVC11 or MSVC12 (any element of the MSVC_VERSIONS_LIST) and refer to a 3rdParty compiler with : +## * which will be the local pathName of the downloaded 3rdParty : relative to CMAKE_BINARY_DIR +## * which is the link location of the 3rdParty zip +## * VCID flag will make available a cache variable ${prefix}_WIN3RDPARTY_VCID +## * DEFAULT_USE flag [ON|OFF] may be used to set default value of cmake cached variable : _WIN3RDPARTY_USE [default to ON] +## +## WARNING: +## This function define CACHE variables you can use after : +## * ${prefix}_WIN3RDPARTY_USE : allow to check/downloaded win3rdParty dir (it will force the cached variables for this dependency folder generally _DIR>) +## * ${prefix}_WIN3RDPARTY_DIR : where is your local win3rdParty dir (the PATH) +## * ${prefix}_WIN3RDPARTY_VCID : [if VCID flag is used] the MSVC id (commonly used to prefix/suffix library name, see boost or CGAL) +## +## If you want to add a win3rdParty version, please: +## 1- build dependencies on your local side with the compiler you want +## 2- build your own zip with your built dependencies +## 3- upload it (onto the forge where the project is stored) and copy the link location in order to use it for this function +## 4- if you just introduced a new MSVC version, add it to the MSVC_VERSIONS_LIST bellow +## +## In a second pass, you can also use this function to set necessary cmake cached variables in order to let cmake find packages of these 3rdParty. +## +## Usage 2: +## win3rdParty( [VERBOSE] MULTI_SET|SET +## CHECK_CACHED_VAR [LIST] [DOC ] +## [ CHECK_CACHED_VAR [LIST] [DOC ] ] [...] +## +## * MULTI_SET or SET flags are used to tell cmake that all next arguments will use repeated flags with differents entries (SET mean we will provide only one set of arguments, without repetition) +## * CHECK_CACHED_VAR are the repeated flag which contain differents entries +## * is the cmake variable you want to be cached for the project +## * is the kind of cmake variable (couble be: FILEPATH; PATH; STRING or BOOL) => see check_cached_var. +## * LIST optional flag could be used with CHECK_CACHED_VAR when = STRING. It allow to handle multiple STRINGS value list. +## * is the value of the variable (if FILEPATH, PATH or STRING: use quotes, if BOOL : use ON/OFF) +## * DOC optional flag is used to have a tooltips info about this new cmake variable entry into the GUI (use quotes). +## +## Full example 1 : +## win3rdParty(COMMON MSVC11 "win3rdParty-MSVC11" "https://path.to/an.archive.7z" +## SET CHECK_CACHED_VAR SuiteSparse_DIR PATH "SuiteSparse-4.2.1" DOC "default empty doc" +## ) +## +## WARNING: +## For the 2nd usage (with MULTI_SET), if you planned to set some CACHED_VAR using/composed by ${prefix}_WIN3RDPARTY_* just set in this macro (usage 1), +## then (due to the not yet existing var) you will need to call this function 2 times : +## One for the 1st usage (downloading of the current compiler 3rdParty). +## One for the MLUTI_SET flag which will use existsing ${prefix}_WIN3RDPARTY_* cached var. +## +## Full example 2 : +## win3rdParty(COMMON MSVC11 "win3rdParty-MSVC11" "https://path.to/an.archive.7z") +## win3rdParty(COMMON MULTI_SET +## CHECK_CACHED_VAR CGAL_INCLUDE_DIR PATH "CGAL-4.3/include" DOC "default empty doc" +## CHECK_CACHED_VAR CGAL_LIBRARIES STRING LIST "debug;CGAL-4.3/lib${LIB_POSTFIX}/CGAL-${WIN3RDPARTY_COMMON_VCID}-mt-gd-4.3.lib;optimized;CGAL-4.3/lib${LIB_POSTFIX}/CGAL-${WIN3RDPARTY_COMMON_VCID}-mt-4.3.lib" +## +## +## WARNING: This function use internaly : +## * downloadAndExtractZipFile.cmake +## * parse_arguments_multi.cmake +## * check_cached_var macro +## +function(win3rdParty prefix ) + + # ARGV: list of all arguments given to the macro/function + # ARGN: list of remaining arguments + + if(NOT WIN32) + return() + endif() + + ## set the handled version of MSVC + ## if you plan to add a win3rdParty dir to download with a new MSVC version: build the win3rdParty dir and add the MSCV entry here. + set(MSVC_VERSIONS_LIST "MSVC17;MSVC11;MSVC12;MSVC14") + + #include(CMakeParseArguments) # CMakeParseArguments is obsolete since cmake 3.5 + # cmake_parse_arguments ( args) + # : options (flags) pass to the macro + # : options that neeed a value + # : options that neeed more than one value + cmake_parse_arguments(w3p "VCID" "VERBOSE;TIMEOUT;DEFAULT_USE" "${MSVC_VERSIONS_LIST};MULTI_SET;SET" ${ARGN}) + + # message(STATUS "value of w3p_VCID = ${w3p_VCID}") + # message(STATUS "value of w3p_VERBOSE = ${w3p_VERBOSE}") + # message(STATUS "value of w3p_TIMEOUT = ${w3p_TIMEOUT}") + # message(STATUS "value of w3p_DEFAULT_USE = ${w3p_DEFAULT_USE}") + + # foreach (loop_var ${MSVC_VERSIONS_LIST}) + # message(STATUS "value of w3p_${loop_var} = ${w3p_${loop_var}}") + # endforeach(loop_var) + + # message(STATUS "value of w3p_MULTI_SET = ${w3p_MULTI_SET}") + # message(STATUS "value of w3p_SET = ${w3p_SET}") + + # message("values for MSVC = ${w3p_MSVC14}") + + if(NOT w3p_TIMEOUT) + set(w3p_TIMEOUT 300) + endif() + + if(NOT DEFINED w3p_DEFAULT_USE) + set(w3p_DEFAULT_USE ON) + endif() + + + ## 1st use (check/update|download) : + set(${prefix}_WIN3RDPARTY_USE ${w3p_DEFAULT_USE} CACHE BOOL "Use required 3rdParty binaries from ${prefix}_WIN3RDPARTY_DIR or download it if not exist") + + + ## We want to test if each version of MSVC was filled by the function (see associated parameters) + ## As CMake is running only for one version of MSVC, if that MSVC version was filled, we get back associated parameters, + ## otherwise we can't use the downloadAndExtractZipFile with win3rdParty. + set(enableWin3rdParty OFF) + + foreach(MSVC_VER ${MSVC_VERSIONS_LIST}) + if(${MSVC_VER} AND w3p_${MSVC_VER} OR ${MSVC_TOOLSET_VERSION} EQUAL 143 AND ${MSVC_VER} STREQUAL "MSVC17") + list(LENGTH w3p_${MSVC_VER} count) + if("${count}" LESS "2") + #message(WARNING "You are using ${MSVC_VER} with ${prefix}_WIN3RDPARTY_USE=${${prefix}_WIN3RDPARTY_USE}, but win3rdParty function isn't filled for ${MSVC_VER}!") + else() + list(GET w3p_${MSVC_VER} 0 Win3rdPartyName) + list(GET w3p_${MSVC_VER} 1 Win3rdPartyUrl) + if(w3p_VCID) + ## try to get the VcId of MSVC. See also MSVC_VERSION cmake var in the doc. + string(REGEX REPLACE "MS([A-Za-z_0-9-]+)" "\\1" vcId ${MSVC_VER}) + string(TOLOWER ${vcId} vcId) + set(${prefix}_WIN3RDPARTY_VCID "${vcId}0" CACHE STRING "the MSVC id (commonly used to prefix/suffix library name, see boost or CGAL)") + mark_as_advanced(${prefix}_WIN3RDPARTY_VCID) + endif() + set(enableWin3rdParty ON) + set(suffixCompilerID ${MSVC_VER}) + break() + endif() + endif() + endforeach() + ## If previous step succeed to get MSVC dirname and URL of the current MSVC version, use it to auto download/update the win3rdParty dir + if(enableWin3rdParty AND ${prefix}_WIN3RDPARTY_USE) + + if(IS_ABSOLUTE "${Win3rdPartyName}") + else() + set(Win3rdPartyName "${CMAKE_BINARY_DIR}/${Win3rdPartyName}") + endif() + + if(NOT EXISTS "${Win3rdPartyName}") + file(MAKE_DIRECTORY ${Win3rdPartyName}) + endif() + + include(downloadAndExtractZipFile) + downloadAndExtractZipFile( "${Win3rdPartyUrl}" ## URL link location + "Win3rdParty-${prefix}-${suffixCompilerID}.7z" ## where download it: relative path, so default to CMAKE_BINARY_DIR + "${Win3rdPartyName}" ## where extract it : fullPath (default relative to CMAKE_BINARY_DIR) + CHECK_DIRTY_URL "${Win3rdPartyName}/Win3rdPartyUrl" ## last downloaded url file : fullPath (default relative to CMAKE_BINARY_DIR) + TIMEOUT ${w3p_TIMEOUT} + VERBOSE ${w3p_VERBOSE} + ) + file(GLOB checkDl "${Win3rdPartyName}/*") + list(LENGTH checkDl checkDlCount) + if("${checkDlCount}" GREATER "1") + else() + message("The downloadAndExtractZipFile didn't work...?") + set(enableWin3rdParty OFF) + endif() + endif() + + ## Try to auto set ${prefix}_WIN3RDPARTY_DIR or let user set it manually + set(${prefix}_WIN3RDPARTY_DIR "" CACHE PATH "windows ${Win3rdPartyName} dir to ${prefix} dependencies of the project") + + if(NOT ${prefix}_WIN3RDPARTY_DIR AND ${prefix}_WIN3RDPARTY_USE) + if(EXISTS "${Win3rdPartyName}") + unset(${prefix}_WIN3RDPARTY_DIR CACHE) + set(${prefix}_WIN3RDPARTY_DIR "${Win3rdPartyName}" CACHE PATH "dir to ${prefix} dependencies of the project") + endif() + endif() + + if(EXISTS ${${prefix}_WIN3RDPARTY_DIR}) + message(STATUS "Found a 3rdParty ${prefix} dir : ${${prefix}_WIN3RDPARTY_DIR}.") + set(enableWin3rdParty ON) + elseif(${prefix}_WIN3RDPARTY_USE) + message(WARNING "${prefix}_WIN3RDPARTY_USE=${${prefix}_WIN3RDPARTY_USE} but ${prefix}_WIN3RDPARTY_DIR=${${prefix}_WIN3RDPARTY_DIR}.") + set(enableWin3rdParty OFF) + endif() + + ## Final check + if(NOT enableWin3rdParty) + message("Disable ${prefix}_WIN3RDPARTY_USE (cmake cached var will be not set), due to a win3rdParty problem.") + message("You still can set ${prefix}_WIN3RDPARTY_DIR to an already downloaded Win3rdParty directory location.") + set(${prefix}_WIN3RDPARTY_USE OFF CACHE BOOL "Use required 3rdParty binaries from ${prefix}_WIN3RDPARTY_DIR or download it if not exist" FORCE) + endif() + + ## 2nd use : handle multi values args to set cached cmake variables in order to ease the next find_package call + if(${prefix}_WIN3RDPARTY_USE AND ${prefix}_WIN3RDPARTY_DIR) + if(w3p_VERBOSE) + message(STATUS "Try to set cmake cached variables for ${prefix} required libraries directly from : ${${prefix}_WIN3RDPARTY_DIR}.") + endif() + + include(parse_arguments_multi) + # message (STATUS "before defining an override of parse_arguments_multi_function") + function(parse_arguments_multi_function ) ## overloaded function to handle all CHECK_CACHED_VAR values list (see: parse_arguments_multi) + # message(STATUS "inside overloaded parse_arguments_multi_function defined in Win3rdParty.cmake") + # message(STATUS ${ARGN}) + ## we know the function take 3 args : var cacheType resetedCachedValue (see check_cached_var) + cmake_parse_arguments(pamf "" "DOC" "LIST" ${ARGN}) + + ## var and cacheType are mandatory (with the resetedCachedValue) + set(var ${ARGV0}) + set(cacheType ${ARGV1}) + # message(STATUS "var=${var} and cacheType=${cacheType} list=${pamf_LIST}") + if(pamf_DOC) + set(cacheDoc ${pamf_DOC}) + else() + set(cacheDoc "") + endif() + if(pamf_LIST) + set(value ${pamf_LIST}) + else() + # message("USING ARGV2 with value ${ARGV2}") + set(value ${ARGV2}) + endif() + # message("inside override function in Win3rdparty.cmake value+ ${value}") + if("${cacheType}" MATCHES "PATH" AND EXISTS "${${prefix}_WIN3RDPARTY_DIR}/${value}") + # message("math with path") + set(resetedCachedValue "${${prefix}_WIN3RDPARTY_DIR}/${value}") ## path relative to ${prefix}_WIN3RDPARTY_DIR + elseif ("${cacheType}" MATCHES "PATH" AND EXISTS "${${prefix}_WIN3RDPARTY_DIR}") + set(resetedCachedValue "${${prefix}_WIN3RDPARTY_DIR}") ## path relative to ${prefix}_WIN3RDPARTY_DIR + elseif("${cacheType}" MATCHES "STRING") + foreach(var IN LISTS value) + if(EXISTS "${${prefix}_WIN3RDPARTY_DIR}/${var}") + list(APPEND resetedCachedValue "${${prefix}_WIN3RDPARTY_DIR}/${var}") ## string item of the string list is a path => make relative to ${prefix}_WIN3RDPARTY_DIR + else() + list(APPEND resetedCachedValue ${var}) ## string item of the string list is not an existing path => simply use the item + endif() + endforeach() + else() + set(resetedCachedValue "${value}") ## could be a BOOL or a STRING + endif() + + ## call our macro to reset cmake cache variable if empty + check_cached_var(${var} "${resetedCachedValue}" ${cacheType} "${cacheDoc}" FORCE) + + endfunction() + # message (STATUS "after defining an override of parse_arguments_multi_function") + + if(w3p_MULTI_SET) + parse_arguments_multi(CHECK_CACHED_VAR w3p_MULTI_SET ${w3p_MULTI_SET}) ## internaly will call our overloaded parse_arguments_multi_function + elseif(w3p_SET) + # message("calling set version of parse_arguments_multi with w3p_set = ${w3p_SET}") + parse_arguments_multi(CHECK_CACHED_VAR w3p_SET ${w3p_SET}) + endif() + + endif() + +endfunction() + +## cmake variables introspection to globally activate/deactivate ${prefix}_WIN3RDPARTY_USE +## This "one shot" call (only one for the next cmake configure) will automatically then reset the global variable WIN3RDPARTY_USE to UserDefined (do nothing). +## use (call it) before and after the call of all your win3rdParty functions +function(Win3rdPartyGlobalCacheAction ) + set(WIN3RDPARTY_USE "UserDefined" CACHE STRING "Choose how to handle all cmake cached *_WIN3RDPARTY_USE for the next configure.\nCould be:\nUserDefined [default]\nActivateAll\nDesactivateAll" ) + set_property(CACHE WIN3RDPARTY_USE PROPERTY STRINGS "UserDefined;ActivateAll;DesactivateAll" ) + if(${WIN3RDPARTY_USE} MATCHES "UserDefined") + else() + if(${WIN3RDPARTY_USE} MATCHES "ActivateAll") + set(win3rdPvalue ON) + elseif(${WIN3RDPARTY_USE} MATCHES "DesactivateAll") + set(win3rdPvalue OFF) + endif() + get_cmake_property(_variableNames CACHE_VARIABLES) + foreach (_variableName ${_variableNames}) + string(REGEX MATCH "[A-Za-z_0-9-]+_WIN3RDPARTY_USE" win3rdpartyUseCacheVar ${_variableName}) + if(win3rdpartyUseCacheVar) + string(REGEX REPLACE "([A-Za-z_0-9-]+_WIN3RDPARTY_USE)" "\\1" win3rdpartyUseCacheVar ${_variableName}) + set(${win3rdpartyUseCacheVar} ${win3rdPvalue} CACHE BOOL "Use required 3rdParty binaries from ${prefix}_WIN3RDPARTY_DIR or download it if not exist" FORCE) + message(STATUS "${win3rdpartyUseCacheVar} cached variable set to ${win3rdPvalue}.") + endif() + endforeach() + set(WIN3RDPARTY_USE "UserDefined" CACHE STRING "Choose how to handle all cmake cached *_WIN3RDPARTY_USE for the next configure.\nCould be:\nUserDefined [default]\nActivateAll\nDesactivateAll" FORCE) + message(STATUS "reset WIN3RDPARTY_USE to UserDefined.") + endif() + mark_as_advanced(WIN3RDPARTY_USE) +endfunction() diff --git a/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/cmake_policies.cmake b/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/cmake_policies.cmake new file mode 100644 index 0000000000000000000000000000000000000000..679fd8427d4c503ac420fc566a2ec4ae5c2825fc --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/cmake_policies.cmake @@ -0,0 +1,19 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +if(__set_policies_INCLUDED__) + return() +else() + set(__set_policies_INCLUDED__ ON) +endif() + +macro(setPolicies) + # No more policies to enforce +endmacro() diff --git a/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/dependencies.cmake b/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/dependencies.cmake new file mode 100644 index 0000000000000000000000000000000000000000..28eb3ba31d43e80efad6f574fab7d072b1f95909 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/dependencies.cmake @@ -0,0 +1,324 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +## Included once for all sub project. +## It contain the whole cmake instructions to find necessary common dependencies. +## 3rdParty (provided by sibr_addlibrary win3rdParty or from external packages) are then available in cmake sub projects. +## +## Do not include this file more than once but you can modify it to fit to your own project. +## So please, read it carefully because you can use on of these dependencies for your project or appen new one. +## +## As it is included after camke options, you can use conditional if()/endif() to encapsulate your 3rdParty. +## + +## win3rdParty function allowing to auto check/download/update binaries dependencies for current windows compiler +## Please open this file in order to get more documentation and usage examples. +include(Win3rdParty) + +include(sibr_library) + +Win3rdPartyGlobalCacheAction() + +find_package(OpenGL REQUIRED) + +set(OpenGL_GL_PREFERENCE "GLVND") + +############ +## Find GLEW +############ +##for headless rendering +find_package(EGL QUIET) + +if(EGL_FOUND) + add_definitions(-DGLEW_EGL) + message("Activating EGL support for headless GLFW/GLEW") +else() + message("EGL not found : EGL support for headless GLFW/GLEW is disabled") +endif() + +if (MSVC11 OR MSVC12) + set(glew_multiset_arguments + CHECK_CACHED_VAR GLEW_INCLUDE_DIR PATH "glew-1.10.0/include" DOC "default empty doc" + CHECK_CACHED_VAR GLEW_LIBRARIES STRING LIST "debug;glew-1.10.0/${LIB_BUILT_DIR}/glew32d.lib;optimized;glew-1.10.0/${LIB_BUILT_DIR}/glew32.lib" DOC "default empty doc" + ) +elseif (MSVC14 OR MSVC17) + set(glew_multiset_arguments + CHECK_CACHED_VAR GLEW_INCLUDE_DIR PATH "glew-2.0.0/include" DOC "default empty doc" + CHECK_CACHED_VAR GLEW_SHARED_LIBRARY_RELEASE PATH "glew-2.0.0/${LIB_BUILT_DIR}/glew32.lib" + CHECK_CACHED_VAR GLEW_STATIC_LIBRARY_RELEASE PATH "glew-2.0.0/${LIB_BUILT_DIR}/glew32s.lib" + CHECK_CACHED_VAR GLEW_SHARED_LIBRARY_DEBUG PATH "glew-2.0.0/${LIB_BUILT_DIR}/glew32d.lib" + CHECK_CACHED_VAR GLEW_STATIC_LIBRARY_DEBUG PATH "glew-2.0.0/${LIB_BUILT_DIR}/glew32sd.lib" + ) +else () + message("There is no provided GLEW library for your compiler, relying on find_package to find it") +endif() +sibr_addlibrary(NAME GLEW #VERBOSE ON + MSVC11 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC11-splitted%20version/glew-1.10.0.7z" + MSVC12 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC11-splitted%20version/glew-1.10.0.7z" + MSVC14 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC15-splitted%20version/glew-2.0.0.7z" # using recompiled version of glew + MULTI_SET ${glew_multiset_arguments} +) +set(GLEW_VERBOSE ON) +FIND_PACKAGE(GLEW REQUIRED) +IF(GLEW_FOUND) + INCLUDE_DIRECTORIES(${GLEW_INCLUDE_DIR}) +ELSE(GLEW_FOUND) + MESSAGE("GLEW not found. Set GLEW_DIR to base directory of GLEW.") +ENDIF(GLEW_FOUND) + + +############## +## Find ASSIMP +############## +if (MSVC11 OR MSVC12) + set(assimp_set_arguments + CHECK_CACHED_VAR ASSIMP_DIR PATH "Assimp_3.1_fix" + ) +elseif (MSVC14 OR MSVC17) + set(assimp_set_arguments + CHECK_CACHED_VAR ASSIMP_DIR PATH "Assimp-4.1.0" + ) +else () + message("There is no provided ASSIMP library for your compiler, relying on find_package to find it") +endif() + +sibr_addlibrary(NAME ASSIMP #VERBOSE ON + MSVC11 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC11-splitted%20version/Assimp_3.1_fix.7z" + MSVC12 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC11-splitted%20version/Assimp_3.1_fix.7z" + MSVC14 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC15-splitted%20version/Assimp-4.1.0.7z" + MULTI_SET + ${assimp_set_arguments} +) + +find_package(ASSIMP REQUIRED) +include_directories(${ASSIMP_INCLUDE_DIR}) + +################ +## Find FFMPEG +################ +sibr_addlibrary(NAME FFMPEG + MSVC11 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC11-splitted%20version/ffmpeg.zip" + MSVC12 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC11-splitted%20version/ffmpeg.zip" + MSVC14 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC15-splitted%20version/ffmpeg-4.0.2-win64-win3rdParty.7z" + SET CHECK_CACHED_VAR FFMPEG_DIR PATH ${FFMPEG_WIN3RDPARTY_DIR} +) +find_package(FFMPEG) +include_directories(${FFMPEG_INCLUDE_DIR}) +## COMMENT OUT ALL FFMPEG FOR CLUSTER + +################### +## Find embree3 +################### +sibr_addlibrary( + NAME embree3 + MSVC11 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC11-splitted%20version/embree2.7.0.x64.windows.7z" + MSVC14 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC15-splitted%20version/embree-3.6.1.x64.vc14.windows.7z" # TODO SV: provide a valid version if required +) + +# CLUSTER +#find_package(embree 3.0 REQUIRED PATHS "/data/graphdeco/share/embree/usr/local/lib64/cmake/" ) +find_package(embree 3.0 ) + +################### +## Find eigen3 +################### +sibr_addlibrary( + NAME eigen3 + #MSVC11 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC11-splitted%20version/eigen-eigen-dc6cfdf9bcec.7z" + #MSVC14 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC11-splitted%20version/eigen-eigen-dc6cfdf9bcec.7z" # TODO SV: provide a valid version if required + MSVC11 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC15-splitted%20version/eigen3.7z" + MSVC14 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC15-splitted%20version/eigen3.7z" + SET CHECK_CACHED_VAR eigen3_DIR PATH "eigen/share/eigen3/cmake" +) +include_directories(/usr/include/eigen3) +add_definitions(-DEIGEN_INITIALIZE_MATRICES_BY_ZERO) + +############# +## Find Boost +############# +set(Boost_REQUIRED_COMPONENTS "system;chrono;filesystem;date_time" CACHE INTERNAL "Boost Required Components") + +if (WIN32) + # boost multiset arguments + if (MSVC11 OR MSVC12) + set(boost_multiset_arguments + CHECK_CACHED_VAR BOOST_ROOT PATH "boost_1_55_0" + CHECK_CACHED_VAR BOOST_INCLUDEDIR PATH "boost_1_55_0" + CHECK_CACHED_VAR BOOST_LIBRARYDIR PATH "boost_1_55_0/${LIB_BUILT_DIR}" + #CHECK_CACHED_VAR Boost_COMPILER STRING "-${Boost_WIN3RDPARTY_VCID}" DOC "vcid (eg: -vc110 for MSVC11)" + CHECK_CACHED_VAR Boost_COMPILER STRING "-vc110" DOC "vcid (eg: -vc110 for MSVC11)" # NOTE: if it doesnt work, uncomment this option and set the right value for VisualC id + ) + elseif (MSVC14 OR MSVC17) + set(boost_multiset_arguments + CHECK_CACHED_VAR BOOST_ROOT PATH "boost-1.71" + CHECK_CACHED_VAR BOOST_INCLUDEDIR PATH "boost-1.71" + CHECK_CACHED_VAR BOOST_LIBRARYDIR PATH "boost-1.71/${LIB_BUILT_DIR}" + CHECK_CACHED_VAR Boost_COMPILER STRING "-vc141" DOC "vcid (eg: -vc110 for MSVC11)" # NOTE: if it doesnt work, uncomment this option and set the right value for VisualC id + ) + + option(BOOST_MINIMAL_VERSION "Only get minimal Boost dependencies" ON) + + if(${BOOST_MINIMAL_VERSION}) + set(BOOST_MSVC14_ZIP "boost-1.71-ibr-minimal.7z") + else() + set(BOOST_MSVC14_ZIP "boost-1.71.7z") + endif() + else () + message("There is no provided Boost library for your compiler, relying on find_package to find it") + endif() + + sibr_addlibrary(NAME Boost VCID TIMEOUT 600 #VERBOSE ON + MSVC11 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC11-splitted%20version/boost_1_55_0.7z" + MSVC12 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC11-splitted%20version/boost_1_55_0.7z" + MSVC14 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC15-splitted%20version/${BOOST_MSVC14_ZIP}" # boost compatible with msvc14 + MULTI_SET ${boost_multiset_arguments} + CHECK_CACHED_VAR Boost_NO_SYSTEM_PATHS BOOL ON DOC "Set to ON to disable searching in locations not specified by these boost cached hint variables" + CHECK_CACHED_VAR Boost_NO_BOOST_CMAKE BOOL ON DOC "Set to ON to disable the search for boost-cmake (package cmake config file if boost was built with cmake)" + ) + if(NOT Boost_COMPILER AND Boost_WIN3RDPARTY_USE) + message(WARNING "Boost_COMPILER is not set and it's needed.") + endif() +endif() + +find_package(Boost 1.65.0 REQUIRED COMPONENTS ${Boost_REQUIRED_COMPONENTS}) +# for CLUSTER +##find_package(Boost 1.58.0 REQUIRED COMPONENTS ${Boost_REQUIRED_COMPONENTS}) + + +if(WIN32) + add_compile_options("$<$:/EHsc>") + #add_definitions(/EHsc) +endif() + +if(Boost_LIB_DIAGNOSTIC_DEFINITIONS) + add_definitions(${Boost_LIB_DIAGNOSTIC_DEFINITIONS}) +endif() + +#if(WIN32) + add_definitions(-DBOOST_ALL_DYN_LINK -DBOOST_ALL_NO_LIB) +#endif() + +include_directories(${BOOST_INCLUDEDIR} ${Boost_INCLUDE_DIRS}) +link_directories(${BOOST_LIBRARYDIR} ${Boost_LIBRARY_DIRS}) + + +############## +## Find OpenMP +############## +find_package(OpenMP) + +############## +## Find OpenCV +############## +if (WIN32) + if (${MSVC_TOOLSET_VERSION} EQUAL 143) + MESSAGE("SPECIAL OPENCV HANDLING") + set(opencv_set_arguments + CHECK_CACHED_VAR OpenCV_DIR PATH "install" ## see OpenCVConfig.cmake + ) + elseif (MSVC11 OR MSVC12) + set(opencv_set_arguments + CHECK_CACHED_VAR OpenCV_DIR PATH "opencv/build" ## see OpenCVConfig.cmake + ) + elseif (MSVC14) + set(opencv_set_arguments + CHECK_CACHED_VAR OpenCV_DIR PATH "opencv-4.5.0/build" ## see OpenCVConfig.cmake + ) + else () + message("There is no provided OpenCV library for your compiler, relying on find_package to find it") + endif() +else() + message("There is no provided OpenCV library for your compiler, relying on find_package to find it") +endif() + +sibr_addlibrary(NAME OpenCV #VERBOSE ON + MSVC11 "https://repo-sam.inria.fr/fungraph/dependencies/sibr/~0.9/opencv.7z" + MSVC12 "https://repo-sam.inria.fr/fungraph/dependencies/sibr/~0.9/opencv.7z" + MSVC14 "https://repo-sam.inria.fr/fungraph/dependencies/sibr/~0.9/opencv-4.5.0.7z" # opencv compatible with msvc14 and with contribs + MSVC17 "https://repo-sam.inria.fr/fungraph/dependencies/sibr/~0.9/opencv4-8.7z" + SET ${opencv_set_arguments} + ) +find_package(OpenCV 4.5 REQUIRED) ## Use directly the OpenCVConfig.cmake provided +## FOR CLUSTER +###find_package(OpenCV 4.5 REQUIRED PATHS "/data/graphdeco/share/opencv/usr/local/lib64/cmake/opencv4/" ) ## Use directly the OpenCVConfig.cmake provided + + ##https://stackoverflow.com/questions/24262081/cmake-relwithdebinfo-links-to-debug-libs +set_target_properties(${OpenCV_LIBS} PROPERTIES MAP_IMPORTED_CONFIG_RELWITHDEBINFO RELEASE) + +add_definitions(-DOPENCV_TRAITS_ENABLE_DEPRECATED) + +if(OpenCV_INCLUDE_DIRS) + foreach(inc ${OpenCV_INCLUDE_DIRS}) + if(NOT EXISTS ${inc}) + set(OpenCV_INCLUDE_DIR "" CACHE PATH "additional custom include DIR (in case of trouble to find it (fedora 17 opencv package))") + endif() + endforeach() + if(OpenCV_INCLUDE_DIR) + list(APPEND OpenCV_INCLUDE_DIRS ${OpenCV_INCLUDE_DIR}) + include_directories(${OpenCV_INCLUDE_DIRS}) + endif() +endif() + +################### +## Find GLFW +################### +sibr_addlibrary( + NAME glfw3 + MSVC11 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC15-splitted%20version/glfw-3.2.1.7z" + MSVC14 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC15-splitted%20version/glfw-3.2.1.7z" # TODO SV: provide a valid version if required + SET CHECK_CACHED_VAR glfw3_DIR PATH "glfw-3.2.1" +) + +### FOR CLUSTER COMMENT OUT lines above, uncomment lines below +##find_package(GLFW REQUIRED 3.3 ) +##message("***********=============> GLFW IS " ${GLFW_LIBRARY}) +##message("***********=============> GLFW IS " ${GLFW_LIBRARIES}) + +find_package(glfw3 REQUIRED) + +sibr_gitlibrary(TARGET imgui + GIT_REPOSITORY "https://gitlab.inria.fr/sibr/libs/imgui.git" + GIT_TAG "741fb3ab6c7e1f7cef23ad0501a06b7c2b354944" +) + +## FOR CLUSTER COMMENT OUT nativefiledialog +sibr_gitlibrary(TARGET nativefiledialog + GIT_REPOSITORY "https://gitlab.inria.fr/sibr/libs/nativefiledialog.git" + GIT_TAG "ae2fab73cf44bebdc08d997e307c8df30bb9acec" +) + + +sibr_gitlibrary(TARGET mrf + GIT_REPOSITORY "https://gitlab.inria.fr/sibr/libs/mrf.git" + GIT_TAG "30c3c9494a00b6346d72a9e37761824c6f2b7207" +) + +sibr_gitlibrary(TARGET nanoflann + GIT_REPOSITORY "https://gitlab.inria.fr/sibr/libs/nanoflann.git" + GIT_TAG "7a20a9ac0a1d34850fc3a9e398fc4a7618e8a69a" +) + +sibr_gitlibrary(TARGET picojson + GIT_REPOSITORY "https://gitlab.inria.fr/sibr/libs/picojson.git" + GIT_TAG "7cf8feee93c8383dddbcb6b64cf40b04e007c49f" +) + +sibr_gitlibrary(TARGET rapidxml + GIT_REPOSITORY "https://gitlab.inria.fr/sibr/libs/rapidxml.git" + GIT_TAG "069e87f5ec5ce1745253bd64d89644d6b894e516" +) + +sibr_gitlibrary(TARGET xatlas + GIT_REPOSITORY "https://gitlab.inria.fr/sibr/libs/xatlas.git" + GIT_TAG "0fbe06a5368da13fcdc3ee48d4bdb2919ed2a249" + INCLUDE_DIRS "source/xatlas" +) + +Win3rdPartyGlobalCacheAction() diff --git a/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/downloadAndExtractZipFile.cmake b/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/downloadAndExtractZipFile.cmake new file mode 100644 index 0000000000000000000000000000000000000000..7f5fc2bb080fc158840125e69c3d36d169b69235 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/downloadAndExtractZipFile.cmake @@ -0,0 +1,243 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +## downloadAndExtractZipFile cmake function +## Provide a way to download zip file from public internet ZIP_URL host +## and to extract it in a specific EXCTRATED_ZIP_PATH destination. +## This function use 7-Zip external tool to maximize the compatibles formats. +## This will be not download again if the EXCTRATED_ZIP_PATH already exist and DL_FORCE is set to OFF. +## This will try to unzip file if already exist in the ZIP_DL_PATH. +## +## If EXCTRATED_ZIP_PATH and/or ZIP_DL_PATH are not full path, +## it will be interpreted relative to CMAKE_BINARY_DIR +## +## Usage example : +## include(downloadAndExtractZipFile) +## downloadAndExtractZipFile( +## http://www.cs.cornell.edu/~snavely/bundler/distr/bundler-v0.4-source.zip +## ${CMAKE_BINARY_DIR}/Bundler/bundler-v0.4-source.zip +## ${CMAKE_BINARY_DIR}/Bundler +## [DL_FORCE ON|OFF] +## [TIMEOUT] +## [CHECK_DIRTY_URL] +## ) +## +## option DL_FORCE will redownload the zip file [deafult to OFF] +## option TIMEOUT will end the unzip process after this period of time [default to 600s] +## option CHECK_DIRTY_URL will write into the given file the downloaded URL and then, +## next time, if the URL was updated, it detect it with this file +## and will download the last version. This prevent to alway set manually DL_FORCE to ON... +## +if(__downloadAndExtractZipFile_cmake_INCLUDED__) + return() +else() + set(__downloadAndExtractZipFile_cmake_INCLUDED__ ON) +endif() + +function(downloadAndExtractZipFile ZIP_URL ZIP_DL_PATH EXCTRATED_ZIP_PATH) + + # message(STATUS "zipUrl=${ZIP_URL} zipDlPath=${ZIP_DL_PATH} extractedZipPath=${EXCTRATED_ZIP_PATH}") + cmake_parse_arguments(dwnlezf "" "VERBOSE;DL_FORCE;TIMEOUT;CHECK_DIRTY_URL" "" ${ARGN}) + + set(PROGRAMFILESx86 "PROGRAMFILES(x86)") + + ## Check entries mandatory args + if(IS_ABSOLUTE "${ZIP_DL_PATH}") + else() + set(ZIP_DL_PATH "${CMAKE_BINARY_DIR}/${ZIP_DL_PATH}") + endif() + if(IS_ABSOLUTE "${EXCTRATED_ZIP_PATH}") + else() + set(EXCTRATED_ZIP_PATH "${CMAKE_BINARY_DIR}/${EXCTRATED_ZIP_PATH}") + endif() + if(NOT EXISTS "${EXCTRATED_ZIP_PATH}") + file(MAKE_DIRECTORY ${EXCTRATED_ZIP_PATH}) + endif() + + # SB: Once, one of downloaded zip was corrupted by an error message coming from the server. + if(EXISTS "${ZIP_DL_PATH}") + # So I check for removing such corrupted files + message("Removing previous ${ZIP_DL_PATH} (might be corrupted)") + file(REMOVE "${ZIP_DL_PATH}") + if(EXISTS "${dwnlezf_CHECK_DIRTY_URL}") + # and remove the previous (corrupted) made 'Win3rdPartyUrl' file + file(REMOVE "${dwnlezf_CHECK_DIRTY_URL}") + endif() + endif() + + ## Check entries optional args + macro(readDirtyUrl ) + if(dwnlezf_CHECK_DIRTY_URL) + if(IS_ABSOLUTE "${dwnlezf_CHECK_DIRTY_URL}") + else() + set(dwnlezf_CHECK_DIRTY_URL "${CMAKE_BINARY_DIR}/${dwnlezf_CHECK_DIRTY_URL}") + endif() + get_filename_component(unzipDir ${EXCTRATED_ZIP_PATH} NAME) + get_filename_component(unzipPath ${EXCTRATED_ZIP_PATH} PATH) + message(STATUS "Checking ${unzipDir} [from ${unzipPath}]...") + if(EXISTS "${dwnlezf_CHECK_DIRTY_URL}") + get_filename_component(CHECK_DIRTY_URL_FILENAME ${dwnlezf_CHECK_DIRTY_URL} NAME) + file(STRINGS "${dwnlezf_CHECK_DIRTY_URL}" contents) + list(GET contents 0 downloadURL) + list(REMOVE_AT contents 0) + if("${downloadURL}" MATCHES "${ZIP_URL}") + if(dwnlezf_VERBOSE) + message(STATUS "Your downloaded version (URL) seems to be up to date. Let me check if nothing is missing... (see ${dwnlezf_CHECK_DIRTY_URL}).") + endif() + file(GLOB PATHNAME_PATTERN_LIST "${EXCTRATED_ZIP_PATH}/*") ## is there something inside the downloaded destination ? + unset(NAME_PATTERN_LIST) + foreach(realPathPattern ${PATHNAME_PATTERN_LIST}) + get_filename_component(itemName ${realPathPattern} NAME) + list(APPEND NAME_PATTERN_LIST ${itemName}) + endforeach() + if(NAME_PATTERN_LIST) + foreach(item ${contents}) + list(FIND NAME_PATTERN_LIST ${item} id) + if(${id} MATCHES "-1") + message(STATUS "${item} is missing, your downloaded version content changed, need to redownload it.") + set(ZIP_DL_FORCE ON) + break() + else() + list(REMOVE_AT NAME_PATTERN_LIST ${id}) + set(ZIP_DL_FORCE OFF) + endif() + endforeach() + if(NOT ZIP_DL_FORCE AND NAME_PATTERN_LIST) + message("Yours seems to be up to date (regarding to ${CHECK_DIRTY_URL_FILENAME})!\nBut there are additional files/folders into your downloaded destination (feel free to clean it if you want).") + foreach(item ${NAME_PATTERN_LIST}) + if(item) + message("${item}") + endif() + endforeach() + endif() + endif() + else() + set(ZIP_DL_FORCE ON) + message(STATUS "Your downloaded version is dirty (too old).") + endif() + else() + file(GLOB PATHNAME_PATTERN_LIST "${EXCTRATED_ZIP_PATH}/*") ## is there something inside the downloaded destination ? + if(NOT PATHNAME_PATTERN_LIST) + message("We found nothing into ${EXCTRATED_ZIP_PATH}, we will try to download it for you now.") + endif() + set(ZIP_DL_FORCE ON) + endif() + endif() + endmacro() + readDirtyUrl() + if(NOT ZIP_DL_FORCE) + return() ## do not need to further (as we are up to date, just exit the function + endif() + + macro(writeDirtyUrl ) + if(dwnlezf_CHECK_DIRTY_URL) + file(WRITE "${dwnlezf_CHECK_DIRTY_URL}" "${ZIP_URL}\n") + file(GLOB PATHNAME_PATTERN_LIST "${EXCTRATED_ZIP_PATH}/*") ## is there something inside the downloaded destination ? + unset(NAME_PATTERN_LIST) + foreach(realPathPattern ${PATHNAME_PATTERN_LIST}) + get_filename_component(itemName ${realPathPattern} NAME) + list(APPEND NAME_PATTERN_LIST ${itemName}) + endforeach() + if(NAME_PATTERN_LIST) + foreach(item ${NAME_PATTERN_LIST}) + file(APPEND "${dwnlezf_CHECK_DIRTY_URL}" "${item}\n") + endforeach() + endif() + endif() + endmacro() + + if(dwnlezf_DL_FORCE) + set(ZIP_DL_FORCE ON) + endif() + + if(NOT dwnlezf_TIMEOUT) + set(dwnlezf_TIMEOUT 600) + endif() + math(EXPR dwnlezf_TIMEOUT_MIN "${dwnlezf_TIMEOUT}/60") + + macro(unzip whichZipFile) + if(NOT SEVEN_ZIP_CMD) + find_program(SEVEN_ZIP_CMD NAMES 7z 7za p7zip DOC "7-zip executable" PATHS "$ENV{PROGRAMFILES}/7-Zip" "$ENV{${PROGRAMFILESx86}}/7-Zip" "$ENV{ProgramW6432}/7-Zip") + endif() + if(SEVEN_ZIP_CMD) + if(dwnlezf_VERBOSE) + message(STATUS "UNZIP: please, WAIT UNTIL ${SEVEN_ZIP_CMD} finished...\n(no more than ${dwnlezf_TIMEOUT_MIN} min)") + else() + message(STATUS "UNZIP...wait...") + endif() + execute_process( COMMAND ${SEVEN_ZIP_CMD} x ${whichZipFile} -y + WORKING_DIRECTORY ${EXCTRATED_ZIP_PATH} TIMEOUT ${dwnlezf_TIMEOUT} + RESULT_VARIABLE resVar OUTPUT_VARIABLE outVar ERROR_VARIABLE errVar + ) + if(${resVar} MATCHES "0") + if(dwnlezf_VERBOSE) + message(STATUS "SUCESS to unzip in ${EXCTRATED_ZIP_PATH}. Now we can remove the downloaded zip file.") + endif() + execute_process(COMMAND ${CMAKE_COMMAND} -E remove ${whichZipFile}) + mark_as_advanced(SEVEN_ZIP_CMD) + else() + message(WARNING "something wrong in ${EXCTRATED_ZIP_PATH}\n with \"${SEVEN_ZIP_CMD} x ${whichZipFile} -y\", redo or try to unzip by yourself...") + message("unzip: resVar=${resVar}") + message("unzip: outVar=${outVar}") + message("unzip: errVar=${errVar}") + message("unzip: failed or canceled or timeout") + endif() + else() + message(WARNING "You need 7zip (http://www.7-zip.org/download.html) to unzip the downloaded dir.") + set(SEVEN_ZIP_CMD "" CACHE FILEPATH "7-zip executable") + mark_as_advanced(CLEAR SEVEN_ZIP_CMD) + endif() + endmacro() + + if(dwnlezf_VERBOSE) + message(STATUS "Trying to look ${ZIP_DL_PATH} if a zip file exist...") + endif() + if(EXISTS "${ZIP_DL_PATH}") + + ## already downloaded, so just unzip it + unzip(${ZIP_DL_PATH}) + writeDirtyUrl() + + elseif(ZIP_DL_FORCE) + + ## the download part (+ unzip) + message(STATUS "Let me try to download package for you : ${ZIP_URL}") + if(dwnlezf_VERBOSE) + message(STATUS "Downloading...\n SRC=${ZIP_URL}\n DEST=${ZIP_DL_PATH}.tmp\n INACTIVITY_TIMEOUT=180s") + endif() + file(DOWNLOAD ${ZIP_URL} ${ZIP_DL_PATH}.tmp INACTIVITY_TIMEOUT 360 STATUS status SHOW_PROGRESS) + + list(GET status 0 numResult) + if(${numResult} MATCHES "0") + + if(dwnlezf_VERBOSE) + message(STATUS "Download succeed, so let me rename the tmp file to unzip it") + endif() + execute_process(COMMAND ${CMAKE_COMMAND} -E rename ${ZIP_DL_PATH}.tmp ${ZIP_DL_PATH}) + unzip(${ZIP_DL_PATH}) + writeDirtyUrl() + + else() + + list(GET status 1 errMsg) + message(WARNING "DOWNLOAD ${ZIP_URL} to ${ZIP_DL_PATH} failed\n:${errMsg}") + message(WARNING "OK, you need to download the ${ZIP_URL} manually and put it into ${ZIP_DL_PATH}") + message("Take a look at the project website page to check available URL.") + + endif() + + endif() + + ## clean up the tmp downloaded file + if(EXISTS "${ZIP_DL_PATH}.tmp") + execute_process(COMMAND ${CMAKE_COMMAND} -E remove ${ZIP_DL_PATH}.tmp) + endif() + +endfunction() diff --git a/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/git_describe.cmake b/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/git_describe.cmake new file mode 100644 index 0000000000000000000000000000000000000000..638d70bd9440fe80ff1844500d3acf8f05e669b8 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/git_describe.cmake @@ -0,0 +1,114 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +if(__git_describe_INCLUDED__) + return() +else() + set(__git_describe_INCLUDED__ ON) +endif() + +find_package(Git) +if(Git_FOUND) + message(STATUS "Git found: ${GIT_EXECUTABLE}") +else() + message(FATAL_ERROR "Git not found. Aborting") +endif() + +macro(git_describe) + cmake_parse_arguments(GIT_DESCRIBE "" "GIT_URL;GIT_BRANCH;GIT_COMMIT_HASH;GIT_TAG;GIT_VERSION;PATH" "" ${ARGN}) + + if(NOT GIT_DESCRIBE_PATH) + set(GIT_DESCRIBE_PATH ${CMAKE_SOURCE_DIR}) + endif() + + if(GIT_DESCRIBE_GIT_URL) + # Get the current remote + execute_process( + COMMAND git remote + WORKING_DIRECTORY ${GIT_DESCRIBE_PATH} + OUTPUT_VARIABLE GIT_DESCRIBE_GIT_REMOTE + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + + # Get the current remote + execute_process( + COMMAND git remote get-url ${GIT_DESCRIBE_GIT_REMOTE} + WORKING_DIRECTORY ${GIT_DESCRIBE_PATH} + OUTPUT_VARIABLE ${GIT_DESCRIBE_GIT_URL} + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + endif() + + if(GIT_DESCRIBE_GIT_BRANCH) + # Get the current working branch + execute_process( + COMMAND git rev-parse --abbrev-ref HEAD + WORKING_DIRECTORY ${GIT_DESCRIBE_PATH} + OUTPUT_VARIABLE ${GIT_DESCRIBE_GIT_BRANCH} + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + endif() + + if(GIT_DESCRIBE_GIT_COMMIT_HASH) + # Get the latest abbreviated commit hash of the working branch + execute_process( + COMMAND git rev-parse HEAD + WORKING_DIRECTORY ${GIT_DESCRIBE_PATH} + OUTPUT_VARIABLE ${GIT_DESCRIBE_GIT_COMMIT_HASH} + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + endif() + + if(GIT_DESCRIBE_GIT_TAG) + # Get the tag + execute_process( + COMMAND git describe --tags --exact-match + WORKING_DIRECTORY ${GIT_DESCRIBE_PATH} + OUTPUT_VARIABLE ${GIT_DESCRIBE_GIT_TAG} + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + endif() + + if(GIT_DESCRIBE_GIT_VERSION) + # Get the version from git describe + execute_process( + COMMAND git describe + WORKING_DIRECTORY ${GIT_DESCRIBE_PATH} + OUTPUT_VARIABLE ${GIT_DESCRIBE_GIT_VERSION} + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + + if(${GIT_DESCRIBE_GIT_VERSION} STREQUAL "") + execute_process( + COMMAND git rev-parse --abbrev-ref HEAD + WORKING_DIRECTORY ${GIT_DESCRIBE_PATH} + OUTPUT_VARIABLE GIT_DESCRIBE_GIT_VERSION_BRANCH + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + execute_process( + COMMAND git log -1 --format=%h + WORKING_DIRECTORY ${GIT_DESCRIBE_PATH} + OUTPUT_VARIABLE GIT_DESCRIBE_GIT_VERSION_COMMIT + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + + set(${GIT_DESCRIBE_GIT_VERSION} "${GIT_DESCRIBE_GIT_VERSION_BRANCH}-${GIT_DESCRIBE_GIT_VERSION_COMMIT}") + endif() + endif() + +endmacro() \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/include_once.cmake b/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/include_once.cmake new file mode 100644 index 0000000000000000000000000000000000000000..d28b39cfeb18e2369ccee1d9f038cfdd71958296 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/include_once.cmake @@ -0,0 +1,22 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +macro(include_once file) + get_filename_component(INCLUDE_ONCE_FILEPATH ${file} REALPATH) + string(REGEX REPLACE "(\\.|\\/+|\\:|\\\\+)" "_" INCLUDE_ONCE_FILEPATH ${INCLUDE_ONCE_FILEPATH}) + get_property(INCLUDED_${INCLUDE_ONCE_FILEPATH}_LOCAL GLOBAL PROPERTY INCLUDED_${INCLUDE_ONCE_FILEPATH}) + if (INCLUDED_${INCLUDE_ONCE_FILEPATH}_LOCAL) + return() + else() + set_property(GLOBAL PROPERTY INCLUDED_${INCLUDE_ONCE_FILEPATH} true) + + include(${file}) + endif() +endmacro() \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/install_runtime.cmake b/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/install_runtime.cmake new file mode 100644 index 0000000000000000000000000000000000000000..695c4b330955d0df7027b7a56a425b30a84acd53 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/install_runtime.cmake @@ -0,0 +1,887 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +## This file is mainly used to allow runtime installation +## There are some utilities cmake functions to ease the generic deployement (abstract common usage of cmake)... +## +## You cannot run your programm automaticaly from your CNAKE_BINARY_DIR when you build +## as it will miss all dependencies and ressources files... +## You have to run install target in order to test your programm. +## +## The only one function/macros you may use inside your sub-CMakeLists.txt (sub-project) is : +## ****************** +## ibr_install_target macro => see documentation at the end of this file +## ****************** +## It use these utilities cmake functions to abstract the installation in an uniform way for all sub-projects. +## +if(__install_runtime_cmake_INCLUDED__) + return() +else() + set(__install_runtime_cmake_INCLUDED__ ON) +endif() + + +## +## Allow to write a resource config file which contain additional ressource paths +## (used by IBR_Common Resource system to load shaders and potentialy images, plugins and so on) +## +## ADD option list all the paths to add in the file (relative paths are interpreted relative to working dir of the executable) +## INSTALL option to specify where we want to install this file +## +## Example usage: +## resourceFile(ADD "shaders" "${PROJECT_NAME}_rsc" INSTALL bin) +## +macro(resourceFile) + cmake_parse_arguments(rsc "" "INSTALL;FILE_PATH;CONFIG_TYPE" "ADD" ${ARGN}) ## both args are directory path + + if(rsc_ADD) + unset(IBR_RSC_FILE_CONTENT_LIST) + if(EXISTS "${rsc_FILE_PATH}") + file(READ "${rsc_FILE_PATH}" IBR_RSC_FILE_CONTENT) + string(REGEX REPLACE "\n" ";" IBR_RSC_FILE_CONTENT_LIST "${IBR_RSC_FILE_CONTENT}") + endif() + list(APPEND IBR_RSC_FILE_CONTENT_LIST "${rsc_ADD}") + list(REMOVE_DUPLICATES IBR_RSC_FILE_CONTENT_LIST) + file(WRITE "${rsc_FILE_PATH}" "") + foreach(rscDir ${IBR_RSC_FILE_CONTENT_LIST}) + file(APPEND "${rsc_FILE_PATH}" "${rscDir}\n") + endforeach() + unset(rsc_ADD) + endif() + + if(rsc_INSTALL) + install(FILES ${rsc_FILE_PATH} CONFIGURATIONS ${rsc_CONFIG_TYPE} DESTINATION ${rsc_INSTALL}) + unset(rsc_INSTALL) + endif() +endmacro() + + +## +## Install *.pdb generated file for the current cmake project +## assuming the output target name is the cmake project name. +## This macro is useful for crossplateform multi config mode. +## +## Usage Example: +## +## if(DEFINED CMAKE_BUILD_TYPE) ## for make/nmake based +## installPDB(${PROJECT_NAME} ${CMAKE_BUILD_TYPE} RUNTIME_DEST bin ARCHIVE_DEST lib LIBRARY_DEST lib) +## endif() +## foreach(CONFIG_TYPES ${CMAKE_CONFIGURATION_TYPES}) ## for multi config types (MSVC based) +## installPDB(${PROJECT_NAME} ${CONFIG_TYPES} RUNTIME_DEST bin ARCHIVE_DEST lib LIBRARY_DEST lib) +## endforeach() +## +macro(installPDB targetName configType) + cmake_parse_arguments(instpdb "" "COMPONENT" "ARCHIVE_DEST;LIBRARY_DEST;RUNTIME_DEST" ${ARGN}) ## both args are directory path + + if(NOT MSVC) + return() + endif() + + ## Check if DESTINATION are provided according to the TYPE of the given target (see install command doc to see correspodances) + get_target_property(type ${targetName} TYPE) + if(${type} MATCHES "EXECUTABLE" AND instpdb_RUNTIME_DEST) + set(pdb_DESTINATION ${instpdb_RUNTIME_DEST}) + elseif(${type} MATCHES "STATIC_LIBRARY" AND instpdb_ARCHIVE_DEST) + set(pdb_DESTINATION ${instpdb_ARCHIVE_DEST}) + elseif(${type} MATCHES "MODULE_LIBRARY" AND instpdb_LIBRARY_DEST) + set(pdb_DESTINATION ${instpdb_LIBRARY_DEST}) + elseif(${type} MATCHES "SHARED_LIBRARY") + if(WIN32 AND instpdb_RUNTIME_DEST) + set(pdb_DESTINATION ${instpdb_RUNTIME_DEST}) + else() + set(pdb_DESTINATION ${instpdb_LIBRARY_DEST}) + endif() + endif() + + if(NOT pdb_DESTINATION) + set(pdb_DESTINATION bin) ## default destination of the pdb file + endif() + + if(NOT instpdb_COMPONENT) + set(instpdb_COMPONENT ) + else() + set(instpdb_COMPONENT COMPONENT ${instpdb_COMPONENT}) + endif() + + string(TOUPPER ${configType} CONFIG_TYPES_UC) + get_target_property(PDB_PATH ${targetName} PDB_OUTPUT_DIRECTORY_${CONFIG_TYPES_UC}) + + get_target_property(confModePostfix ${targetName} ${CONFIG_TYPES_UC}_POSTFIX) + if(NOT confModePostfix) + set(confModePostfix "") + endif() + set_target_properties(${targetName} PROPERTIES PDB_NAME_${CONFIG_TYPES_UC} ${targetName}${confModePostfix}) + get_target_property(PDB_NAME ${targetName} PDB_NAME_${CONFIG_TYPES_UC})# if not set, this is empty + + if(EXISTS "${PDB_PATH}/${PDB_NAME}.pdb") + install(FILES "${PDB_PATH}/${PDB_NAME}.pdb" CONFIGURATIONS ${configType} DESTINATION ${pdb_DESTINATION} ${instpdb_COMPONENT} OPTIONAL) + endif() +endmacro() + + +## +## Add additional target to install a project independently and based on its component +## configMode is used to prevent default Release installation (we want also to install in other build/config type) +## +macro(installTargetProject targetOfProject targetOfInstallProject) + if(DEFINED CMAKE_BUILD_TYPE) ## for make/nmake based + set(configMode ${CMAKE_BUILD_TYPE}) + elseif(MSVC) + ## $(Configuration) will be one of the following : Debug, Release, MinSizeRel, RelWithDebInfo + set(configMode $(Configuration)) + endif() + if(configMode) + get_target_property(srcFiles ${targetOfProject} SOURCES) + add_custom_target( ${targetOfInstallProject} #ALL + ${CMAKE_COMMAND} -DBUILD_TYPE=${configMode} -DCOMPONENT=${targetOfInstallProject} -P ${CMAKE_BINARY_DIR}/cmake_install.cmake + DEPENDS ${srcFiles} + COMMENT "run the installation only for ${targetOfProject}" VERBATIM + ) + add_dependencies(${targetOfInstallProject} ${targetOfProject}) + + get_target_property(INSTALL_BUILD_FOLDER ${targetOfProject} FOLDER) + set_target_properties(${targetOfInstallProject} PROPERTIES FOLDER ${INSTALL_BUILD_FOLDER}) + endif() +endmacro() + +# Collect all currently added targets in all subdirectories +# +# Parameters: +# - _result the list containing all found targets +# - _dir root directory to start looking from +function(get_all_targets _result _dir) + get_property(_subdirs DIRECTORY "${_dir}" PROPERTY SUBDIRECTORIES) + foreach(_subdir IN LISTS _subdirs) + get_all_targets(${_result} "${_subdir}") + endforeach() + + get_directory_property(_sub_targets DIRECTORY "${_dir}" BUILDSYSTEM_TARGETS) + set(${_result} ${${_result}} ${_sub_targets} PARENT_SCOPE) +endfunction() + +## +## Add targets for building and installing subdirectories +macro(subdirectory_target target directory build_folder) + add_custom_target(${target} + COMMENT "run build for all projects in this directory" VERBATIM + ) + get_all_targets(ALL_TARGETS ${directory}) + add_dependencies(${target} ${ALL_TARGETS}) + add_custom_target(${target}_install + ${CMAKE_COMMAND} -DBUILD_TYPE=$ -DCOMPONENT=${target}_install -P ${CMAKE_BINARY_DIR}/cmake_install.cmake + COMMENT "run install for all projects in this directory" VERBATIM + ) + add_dependencies(${target}_install ${target}) + + set_target_properties(${target} PROPERTIES FOLDER ${build_folder}) + set_target_properties(${target}_install PROPERTIES FOLDER ${build_folder}) +endmacro() + + +## CMAKE install all required dependencies for an application (included system OS files like msvc*.dll for example) +## +## install_runtime( +## [TARGET name] +## [PLUGINS name [nameN ...] [PLUGIN_PATH_NAME currentPathName [FROM_REL_PATH matchDirFromCurrentPathName] [PLUGIN_PATH_DEST installDir] ] +## [PLUGINS ...] +## [DIRS path [pathN ...] ] +## [TARGET_LIBRARIES filePath [filePathN ...] ] +## [TARGET_PACKAGES packageName [packageNameN ...] ] +## [COMPONENT installComponentName] +## [PLAUSIBLES_POSTFIX Debug_postfix [MinSizeRel_postfix relWithDebInfo_postfix ...] ] +## [VERBOSE] +## ) +## +## installedFilePathTargetAppToResolve : the final installed targetApp absolute full file path name you want to resolve +## +## TARGET : The target app we want to install. If given, it's used to look for link libraries paths (best choice to use, strongly advised to use it) +## +## PLUGINS : Some application built use/load some plugins which can't be detect inside its binary, +## so, here you can specify which plugins the application use/load in order to install them +## and resolve also there dependencies. +## With PLUGINS multi FLAGS : +## PLUGIN_PATH_NAME : The current plugin full file path we want to install +## FROM_REL_PATH : [optional: default only the file is kept] From which matching dir of the plugin path we want to install (keep the directories structure) +## PLUGIN_PATH_DEST : [optional: default relative to executable directory] Where (full path to the install directory) we will install the plugin file (or file path) +## +## DIRS : A list of directories to looking for dependencies +## TARGET_LIBRARIES : DEPRECATED (use TARGET flag instead) : The cmake content variables used for the target_link_libraries( ...) +## TARGET_PACKAGES : DEPRECATED (use TARGET flag instead) : The cmake package names used for the findPackage(...) for your targetApp +## ADVICE: This flag add entries in cache (like: _DIR), it could be useful to fill these variable! +## COMPONENT : (default to runtime) Is the component name associated to the installation +## It is used when you want to install separatly some part of your projets (see install cmake doc) +## VERBOSE : For debug or to get more informations in the output console +## +## Usage: +## install_runtime(${CMAKE_INSTALL_PREFIX}/${EXECUTABLE_NAME}${CMAKE_EXECUTABLE_SUFFIX} +## VERBOSE +## TARGET ${PROJECT_NAME} +## PLAUSIBLES_POSTFIX _d +## PLUGINS +## PLUGIN_PATH_NAME ${PLUGIN_PATH_NAME}${CMAKE_SHARED_MODULE_SUFFIX} ## will be installed (default exec path if no PLUGINS_DEST) and then will be resolved +## FROM_REL_PATH plugins ## optional, used especially for keeping qt plugins tree structure +## PLUGIN_PATH_DEST ${CMAKE_INSTALL_PREFIX}/plugins ## (or relative path 'plugins' will be interpreted relative to installed executable) +## DIRS ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_BINARY_DIR} +## TARGET_LIBRARIES ${OPENGL_LIBRARIES} ## DEPRECATED (use TARGET flag instead) +## ${GLEW_LIBRARIES} +## ${GLUT_LIBRARIES} +## ${Boost_LIBRARIES} +## ${SuiteSparse_LIBRARIES} +## ${CGAL_LIBRARIES} +## TARGET_PACKAGES OPENGL ## DEPRECATED (use TARGET flag instead) +## GLEW +## GLUT +## CGAL +## Boost +## SuiteSparse +## ) +## +## For plugins part, it use our internal parse_arguments_multi.cmake +## +function(install_runtime installedFilePathTargetAppToResolve) + set(optionsArgs "VERBOSE") + set(oneValueArgs "COMPONENT;INSTALL_FOLDER;CONFIG_TYPE") + set(multiValueArgs "DIRS;PLUGINS;TARGET_LIBRARIES;TARGET_PACKAGES;TARGET;PLAUSIBLES_POSTFIX") + cmake_parse_arguments(inst_run "${optionsArgs}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) + + if(IS_ABSOLUTE ${installedFilePathTargetAppToResolve}) + else() + set(installedFilePathTargetAppToResolve ${inst_run_INSTALL_FOLDER}/${installedFilePathTargetAppToResolve}) + endif() + + get_filename_component(EXEC_NAME ${installedFilePathTargetAppToResolve} NAME_WE) + get_filename_component(EXEC_PATH ${installedFilePathTargetAppToResolve} PATH) + + if(NOT inst_run_COMPONENT) + set(inst_run_COMPONENT runtime) + endif() + + + ## Try to append as more possible as possible paths to find dependencies (deprecated since we can use target_properties to get back paths) + set(libPaths ) + foreach(libraryFileName ${inst_run_TARGET_LIBRARIES}) + if(IS_DIRECTORY "${libraryFileName}") + list(APPEND libPaths "${libraryFileName}") + else() + get_filename_component(libpath "${libraryFileName}" PATH) + if(EXISTS "${libpath}") + list(APPEND libPaths "${libpath}") + endif() + endif() + endforeach() + + ## This macro is used internaly here to recursilvely get path of LINK_LIBRARIES of each non imported target + ## Typically if you have 2 internal dependencies between cmake targets, we want cmake to be able to get back path where are these dependencies + macro(recurseDepList target) + get_target_property(linkLibs ${target} LINK_LIBRARIES) + foreach(lib ${linkLibs}) + string(FIND ${lib} ">" strId) ## cmake is using generator-expression? + if(TARGET ${lib}) + ## Skipping interface libraries as they're system ones + get_target_property(type ${lib} TYPE) + get_target_property(imported ${lib} IMPORTED) + if(type STREQUAL "INTERFACE_LIBRARY") + get_target_property(imp_loc ${lib} INTERFACE_IMPORTED_LOCATION) + if(imp_loc) + get_filename_component(imp_loc ${imp_loc} PATH) + list(APPEND targetLibPath ${imp_loc}) + endif() + get_target_property(loc ${lib} INTERFACE_LOCATION) + if(loc) + get_filename_component(loc ${loc} PATH) + list(APPEND targetLibPath ${loc}) + endif() + ## it's not a path but a single target name + ## for build-target which are part of the current cmake configuration : nothing to do as cmake already know the output path + ## for imported target, we need to look for theire imported location + elseif(imported) + get_target_property(imp_loc ${lib} IMPORTED_LOCATION) + if(imp_loc) + get_filename_component(imp_loc ${imp_loc} PATH) + list(APPEND targetLibPath ${imp_loc}) + endif() + get_target_property(loc ${lib} LOCATION) + if(loc) + get_filename_component(loc ${loc} PATH) + list(APPEND targetLibPath ${loc}) + endif() + else() + recurseDepList(${lib}) + endif() + elseif(NOT ${strId} MATCHES -1) ## mean cmake use generator-expression (CMAKE VERSION > 3.0) + string(REGEX MATCH ">:[@A-Za-z_:/.0-9-]+" targetLibPath ${lib}) + string(REGEX REPLACE ">:([@A-Za-z_:/.0-9-]+)" "\\1" targetLibPath ${targetLibPath}) + get_filename_component(targetLibPath ${targetLibPath} PATH) + elseif(EXISTS ${lib}) + set(targetLibPath ${lib}) + get_filename_component(targetLibPath ${targetLibPath} PATH) + else() + #message(STATUS "[install_runtime] skip link library : ${lib} , of target ${target}") + endif() + if(targetLibPath) + list(APPEND targetLinkLibsPathList ${targetLibPath}) + endif() + endforeach() + if(targetLinkLibsPathList) + list(REMOVE_DUPLICATES targetLinkLibsPathList) + endif() + endmacro() + if(inst_run_TARGET) + recurseDepList(${inst_run_TARGET}) + if(targetLinkLibsPathList) + list(APPEND libPaths ${targetLinkLibsPathList}) + endif() + endif() + + if(libPaths) + list(REMOVE_DUPLICATES libPaths) + foreach(libPath ${libPaths}) + get_filename_component(path ${libPath} PATH) + list(APPEND libPaths ${path}) + endforeach() + endif() + + + ## possible speciale dir(s) according to the build system and OS + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(BUILD_TYPES_FOR_DLL "x64") + if(WIN32) + list(APPEND BUILD_TYPES_FOR_DLL "Win64") + endif() + else() + set(BUILD_TYPES_FOR_DLL "x86") + if(WIN32) + list(APPEND BUILD_TYPES_FOR_DLL "Win32") + endif() + endif() + + + ## Try to append as more as possible paths to find dependencies (here, mainly for *.dll) + foreach(dir ${inst_run_DIRS} ${libPaths}) + if(EXISTS "${dir}/bin") + list(APPEND inst_run_DIRS "${dir}/bin") + elseif(EXISTS "${dir}") + list(APPEND inst_run_DIRS "${dir}") + endif() + endforeach() + list(REMOVE_DUPLICATES inst_run_DIRS) + foreach(dir ${inst_run_DIRS}) + if(EXISTS "${dir}") + list(APPEND argDirs ${dir}) + foreach(BUILD_TYPE_FOR_DLL ${BUILD_TYPES_FOR_DLL}) + if(EXISTS "${dir}/${BUILD_TYPE_FOR_DLL}") + list(APPEND argDirs "${dir}/${BUILD_TYPE_FOR_DLL}") + endif() + foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES}) ## for windows multi-generator (MSVC) + if(EXISTS "${dir}/${BUILD_TYPE_FOR_DLL}/${OUTPUTCONFIG}") + list(APPEND argDirs "${dir}/${BUILD_TYPE_FOR_DLL}/${OUTPUTCONFIG}") + endif() + endforeach() + if(CMAKE_BUILD_TYPE) ## for single generator (makefiles) + if(EXISTS "${dir}/${BUILD_TYPE_FOR_DLL}/${CMAKE_BUILD_TYPE}") + list(APPEND argDirs "${dir}/${BUILD_TYPE_FOR_DLL}/${CMAKE_BUILD_TYPE}") + endif() + endif() + endforeach() + foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES}) ## for windows multi-generator (MSVC) + if(EXISTS "${dir}/${OUTPUTCONFIG}") + list(APPEND argDirs "${dir}/${OUTPUTCONFIG}") + endif() + foreach(BUILD_TYPE_FOR_DLL ${BUILD_TYPES_FOR_DLL}) + if(EXISTS "${dir}/${OUTPUTCONFIG}/${BUILD_TYPE_FOR_DLL}") + list(APPEND argDirs "${dir}/${OUTPUTCONFIG}/${BUILD_TYPE_FOR_DLL}") + endif() + endforeach() + endforeach() + if(CMAKE_BUILD_TYPE) ## for single generator (makefiles) + if(EXISTS "${dir}/${CMAKE_BUILD_TYPE}") + list(APPEND argDirs "${dir}/${CMAKE_BUILD_TYPE}") + endif() + foreach(BUILD_TYPE_FOR_DLL ${BUILD_TYPES_FOR_DLL}) + if(EXISTS "${dir}/${CMAKE_BUILD_TYPE}/${BUILD_TYPE_FOR_DLL}") + list(APPEND argDirs "${dir}/${CMAKE_BUILD_TYPE}/${BUILD_TYPE_FOR_DLL}") + endif() + endforeach() + endif() + endif() + endforeach() + if(argDirs) + list(REMOVE_DUPLICATES argDirs) + endif() + + + ## Try to append as more possible paths to find dependencies (here, mainly for *.dll) + foreach(packageName ${inst_run_TARGET_PACKAGES}) + if(EXISTS "${${packageName}_DIR}") + list(APPEND packageDirs ${${packageName}_DIR}) + list(APPEND packageDirs ${${packageName}_DIR}/bin) + foreach(BUILD_TYPE_FOR_DLL ${BUILD_TYPES_FOR_DLL}) + if(EXISTS "${${packageName}_DIR}/bin/${BUILD_TYPE_FOR_DLL}") + list(APPEND packageDirs "${${packageName}_DIR}/bin/${BUILD_TYPE_FOR_DLL}") + endif() + foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES}) ## for windows multi-generator (MSVC) + if(EXISTS "${${packageName}_DIR}/bin/${BUILD_TYPE_FOR_DLL}/${OUTPUTCONFIG}") + list(APPEND packageDirs "${${packageName}_DIR}/bin/${BUILD_TYPE_FOR_DLL}/${OUTPUTCONFIG}") + endif() + endforeach() + if(CMAKE_BUILD_TYPE) ## for single generator (makefiles) + if(EXISTS "${${packageName}_DIR}/bin/${BUILD_TYPE_FOR_DLL}/${CMAKE_BUILD_TYPE}") + list(APPEND packageDirs "${${packageName}_DIR}/bin/${BUILD_TYPE_FOR_DLL}/${CMAKE_BUILD_TYPE}") + endif() + endif() + endforeach() + foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES}) ## for windows multi-generator (MSVC) + if(EXISTS "${${packageName}_DIR}/bin/${OUTPUTCONFIG}") + list(APPEND packageDirs "${${packageName}_DIR}/bin/${OUTPUTCONFIG}") + endif() + foreach(BUILD_TYPE_FOR_DLL ${BUILD_TYPES_FOR_DLL}) + if(EXISTS "${${packageName}_DIR}/bin/${OUTPUTCONFIG}/${BUILD_TYPE_FOR_DLL}") + list(APPEND packageDirs "${${packageName}_DIR}/bin/${OUTPUTCONFIG}/${BUILD_TYPE_FOR_DLL}") + endif() + endforeach() + endforeach() + if(CMAKE_BUILD_TYPE) ## for single generator (makefiles) + if(EXISTS "${${packageName}_DIR}/bin/${CMAKE_BUILD_TYPE}") + list(APPEND packageDirs "${${packageName}_DIR}/bin/${CMAKE_BUILD_TYPE}") + endif() + foreach(BUILD_TYPE_FOR_DLL ${BUILD_TYPES_FOR_DLL}) + if(EXISTS "${${packageName}_DIR}/bin/${CMAKE_BUILD_TYPE}/${BUILD_TYPE_FOR_DLL}") + list(APPEND packageDirs "${${packageName}_DIR}/bin/${CMAKE_BUILD_TYPE}/${BUILD_TYPE_FOR_DLL}") + endif() + endforeach() + endif() + else() + set(${packageName}_DIR "$ENV{${packageName}_DIR}" CACHE PATH "${packageName}_DIR root directory for looking for dirs containning *.dll") + endif() + endforeach() + if(packageDirs) + list(REMOVE_DUPLICATES packageDirs) + endif() + + + set(dirsToLookFor "${EXEC_PATH}") + if(packageDirs) + list(APPEND dirsToLookFor ${packageDirs}) + endif() + if(argDirs) + list(APPEND dirsToLookFor ${argDirs}) + endif() + get_property(used_LINK_DIRECTORIES DIRECTORY PROPERTY LINK_DIRECTORIES) + if (used_LINK_DIRECTORIES) + list(APPEND dirsToLookFor ${used_LINK_DIRECTORIES}) + list(REMOVE_DUPLICATES dirsToLookFor) + endif() + + + ## handle plugins + set(pluginsList "") + include(parse_arguments_multi) ## this function will process recursively items of the sub-list [default print messages] + function(parse_arguments_multi_function results) + cmake_parse_arguments(pamf "VERBOSE" "PLUGIN_PATH_DEST;FROM_REL_PATH;EXEC_PATH;COMPONENT" "" ${ARGN}) ## EXEC_PATH and COMPONENT are for exclusive internal use + list(REMOVE_DUPLICATES pamf_UNPARSED_ARGUMENTS) + foreach(PLUGIN_PATH_NAME ${pamf_UNPARSED_ARGUMENTS}) + if(EXISTS ${PLUGIN_PATH_NAME}) + if(IS_DIRECTORY ${PLUGIN_PATH_NAME}) + if(pamf_VERBOSE) + message(WARNING "${PLUGIN_PATH_NAME} IS_DIRECTORY, cannot installed a directory, please give a path filename") + endif() + else() + if(NOT pamf_PLUGIN_PATH_DEST) + set(PLUGIN_PATH_DEST ${pamf_EXEC_PATH}) ## the default dest value + else() + set(PLUGIN_PATH_DEST ${pamf_PLUGIN_PATH_DEST}) + endif() + + if(pamf_FROM_REL_PATH) + file(TO_CMAKE_PATH ${PLUGIN_PATH_NAME} PLUGIN_PATH_NAME) + get_filename_component(PLUGIN_PATH ${PLUGIN_PATH_NAME} PATH) + unset(PLUGIN_PATH_LIST) + unset(PLUGIN_PATH_LIST_COUNT) + unset(PLUGIN_REL_PATH_LIST) + unset(PLUGIN_REL_PATH) + string(REPLACE "/" ";" PLUGIN_PATH_LIST ${PLUGIN_PATH}) ## create a list of dir + list(FIND PLUGIN_PATH_LIST ${pamf_FROM_REL_PATH} id) + list(LENGTH PLUGIN_PATH_LIST PLUGIN_PATH_LIST_COUNT) + if(${id} GREATER 0) + math(EXPR id "${id}+1") ## matches relative path not include + math(EXPR PLUGIN_PATH_LIST_COUNT "${PLUGIN_PATH_LIST_COUNT}-1") ## the end of the list + foreach(i RANGE ${id} ${PLUGIN_PATH_LIST_COUNT}) + list(GET PLUGIN_PATH_LIST ${i} out) + list(APPEND PLUGIN_REL_PATH_LIST ${out}) + endforeach() + foreach(dir ${PLUGIN_REL_PATH_LIST}) + set(PLUGIN_REL_PATH "${PLUGIN_REL_PATH}/${dir}") + endforeach() + endif() + set(PLUGIN_PATH_DEST ${PLUGIN_PATH_DEST}${PLUGIN_REL_PATH}) + endif() + + install(FILES ${PLUGIN_PATH_NAME} CONFIGURATIONS ${inst_run_CONFIG_TYPE} DESTINATION ${PLUGIN_PATH_DEST} COMPONENT ${pamf_COMPONENT}) + get_filename_component(pluginName ${PLUGIN_PATH_NAME} NAME) + if(IS_ABSOLUTE ${PLUGIN_PATH_DEST}) + else() + set(PLUGIN_PATH_DEST ${inst_run_INSTALL_FOLDER}/${PLUGIN_PATH_DEST}) + endif() + list(APPEND pluginsList ${PLUGIN_PATH_DEST}/${pluginName}) + endif() + else() + message(WARNING "You need to provide a valid PLUGIN_PATH_NAME") + set(pluginsList ) + endif() + endforeach() + set(${results} ${pluginsList} PARENT_SCOPE) + endfunction() + + if(inst_run_VERBOSE) + list(APPEND extra_flags_to_add VERBOSE) + endif() + list(APPEND extra_flags_to_add EXEC_PATH ${EXEC_PATH} COMPONENT ${inst_run_COMPONENT}) ## for internal use inside overloaded function + list(LENGTH inst_run_PLUGINS inst_run_PLUGINS_count) + if(${inst_run_PLUGINS_count} GREATER 0) + parse_arguments_multi(PLUGIN_PATH_NAME inst_run_PLUGINS ${inst_run_PLUGINS} ## see internal overload parse_arguments_multi_function for processing each sub-list + NEED_RESULTS ${inst_run_PLUGINS_count} ## this is used to check when we are in the first loop (in order to reset parse_arguments_multi_results) + EXTRAS_FLAGS ${extra_flags_to_add} ## this is used to allow catching additional internal flags of our overloaded function + ) + endif() + + #message(parse_arguments_multi_results = ${parse_arguments_multi_results}) + list(APPEND pluginsList ${parse_arguments_multi_results}) + + + + ## Install rules for required system runtimes such as MSVCRxx.dll + set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP ON) + include(InstallRequiredSystemLibraries) + if(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS) + install(FILES ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} + CONFIGURATIONS ${inst_run_CONFIG_TYPE} + DESTINATION ${EXEC_PATH} + COMPONENT ${inst_run_COMPONENT} + ) + endif() + + ## print what we are doing to do + if(inst_run_VERBOSE) + message(STATUS "[install_runtime] On install target call, cmake will try to resolve dependencies for given app:\n ${installedFilePathTargetAppToResolve} (with plausible postfix: ${inst_run_PLAUSIBLES_POSTFIX})") + if(pluginsList) + message(STATUS " and also for plugins :") + foreach(plugin ${pluginsList}) + message(STATUS " ${plugin}") + endforeach() + endif() + message(STATUS " Looking for dependencies into:") + foreach(dir ${dirsToLookFor}) + message(STATUS " ${dir}") + endforeach() + endif() + + ## Install rules for required dependencies libs/plugins for the target app + ## will resolve all installed target files with config modes postfixes + string(TOUPPER ${inst_run_CONFIG_TYPE} inst_run_CONFIG_TYPE_UC) + get_target_property(postfix ${inst_run_TARGET} "${inst_run_CONFIG_TYPE_UC}_POSTFIX") + install(CODE "set(target \"${inst_run_TARGET}\")" COMPONENT ${inst_run_COMPONENT} CONFIGURATIONS ${CONFIG_TYPE}) + install(CODE "set(inst_run_CONFIG_TYPE \"${inst_run_CONFIG_TYPE}\")" COMPONENT ${inst_run_COMPONENT} CONFIGURATIONS ${CONFIG_TYPE}) + install(CODE "set(inst_run_INSTALL_FOLDER \"${inst_run_INSTALL_FOLDER}\")" COMPONENT ${inst_run_COMPONENT} CONFIGURATIONS ${CONFIG_TYPE}) + install(CODE "set(app \"${EXEC_PATH}/${EXEC_NAME}${postfix}${CMAKE_EXECUTABLE_SUFFIX}\")" COMPONENT ${inst_run_COMPONENT} CONFIGURATIONS ${CONFIG_TYPE}) + install(CODE "set(dirsToLookFor \"${dirsToLookFor}\")" COMPONENT ${inst_run_COMPONENT} CONFIGURATIONS ${CONFIG_TYPE}) + install(CODE + [[ + if("${CMAKE_INSTALL_CONFIG_NAME}" STREQUAL "${inst_run_CONFIG_TYPE}") + message(STATUS "Installing ${target} dependencies...") + + file(GET_RUNTIME_DEPENDENCIES + EXECUTABLES ${app} + RESOLVED_DEPENDENCIES_VAR _r_deps + UNRESOLVED_DEPENDENCIES_VAR _u_deps + CONFLICTING_DEPENDENCIES_PREFIX _c_deps + DIRECTORIES ${dirsToLookFor} + PRE_EXCLUDE_REGEXES "api-ms-*" + POST_EXCLUDE_REGEXES ".*system32/.*\\.dll" ".*SysWOW64/.*\\.dll" + ) + + if(_u_deps) + message(WARNING "There were unresolved dependencies for executable ${EXEC_FILE}: \"${_u_deps}\"!") + endif() + if(_c_deps_FILENAMES) + message(WARNING "There were conflicting dependencies for executable ${EXEC_FILE}: \"${_c_deps_FILENAMES}\"!") + endif() + + foreach(_file ${_r_deps}) + file(INSTALL + DESTINATION "${inst_run_INSTALL_FOLDER}/bin" + TYPE SHARED_LIBRARY + FOLLOW_SYMLINK_CHAIN + FILES "${_file}" + ) + endforeach() + endif() + ]] + COMPONENT ${inst_run_COMPONENT} CONFIGURATIONS ${CONFIG_TYPE} + ) + +endfunction() + +## High level macro to install resources in the correct folder +## +## EXECUTABLE: [opt] option to copy files as programs +## RELATIVE : [opt] copy files relatively to current folder +## TYPE : [opt] type and folder where to store the files +## FOLDER : [opt] subfolder to use +## FILES : [opt] contains a list of resources files to copy to install folder +macro(ibr_install_rsc target) + cmake_parse_arguments(install_rsc_${target} "EXECUTABLE;RELATIVE" "TYPE;FOLDER" "FILES" ${ARGN}) + set(rsc_target "${target}_${install_rsc_${target}_TYPE}") + + if(install_rsc_${target}_FOLDER) + set(rsc_folder "${install_rsc_${target}_TYPE}/${install_rsc_${target}_FOLDER}") + else() + set(rsc_folder "${install_rsc_${target}_TYPE}") + endif() + + add_custom_target(${rsc_target} + COMMENT "run the ${install_rsc_${target}_TYPE} installation only for ${target} (component ${rsc_target})" + VERBATIM) + foreach(scriptFile ${install_rsc_${target}_FILES}) + if(install_rsc_${target}_RELATIVE) + file(RELATIVE_PATH relativeFilename ${CMAKE_CURRENT_SOURCE_DIR} ${scriptFile}) + else() + get_filename_component(relativeFilename ${scriptFile} NAME) + endif() + + if(DEFINED CMAKE_BUILD_TYPE) ## for make/nmake based + add_custom_command(TARGET ${rsc_target} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E + copy_if_different ${scriptFile} ${CMAKE_INSTALL_PREFIX_${CMAKE_BUILD_TYPE}}/${rsc_folder}/${relativeFilename}) + endif() + foreach(CONFIG_TYPES ${CMAKE_CONFIGURATION_TYPES}) ## for multi config types (MSVC based) + string(TOUPPER ${CONFIG_TYPES} CONFIG_TYPES_UC) + add_custom_command(TARGET ${rsc_target} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E + copy_if_different ${scriptFile} ${CMAKE_INSTALL_PREFIX_${CONFIG_TYPES_UC}}/${rsc_folder}/${relativeFilename}) + endforeach() + endforeach() + + get_target_property(INSTALL_RSC_BUILD_FOLDER ${target} FOLDER) + set_target_properties(${rsc_target} PROPERTIES FOLDER ${INSTALL_RSC_BUILD_FOLDER}) + + add_dependencies(${target} ${rsc_target}) + add_dependencies(PREBUILD ${rsc_target}) + + if(DEFINED CMAKE_BUILD_TYPE) ## for make/nmake based + resourceFile(ADD ${rsc_folder} CONFIG_TYPE ${CMAKE_BUILD_TYPE} FILE_PATH "${CMAKE_INSTALL_PREFIX_${CMAKE_BUILD_TYPE}}/ibr_resources.ini") + + if(install_rsc_${target}_EXECUTABLE) + install( + PROGRAMS ${install_rsc_${target}_FILES} + CONFIGURATIONS ${CMAKE_BUILD_TYPE} + DESTINATION "${CMAKE_INSTALL_PREFIX_${CMAKE_BUILD_TYPE}}/${rsc_folder}" + ) + else() + install( + FILES ${install_rsc_${target}_FILES} + CONFIGURATIONS ${CMAKE_BUILD_TYPE} + DESTINATION "${CMAKE_INSTALL_PREFIX_${CMAKE_BUILD_TYPE}}/${rsc_folder}" + ) + endif() + endif() + foreach(CONFIG_TYPES ${CMAKE_CONFIGURATION_TYPES}) ## for multi config types (MSVC based) + string(TOUPPER ${CONFIG_TYPES} CONFIG_TYPES_UC) + resourceFile(ADD ${rsc_folder} CONFIG_TYPE ${CONFIG_TYPES} FILE_PATH "${CMAKE_INSTALL_PREFIX_${CONFIG_TYPES_UC}}/ibr_resources.ini") + + if(install_rsc_${target}_EXECUTABLE) + install( + PROGRAMS ${install_rsc_${target}_FILES} + CONFIGURATIONS ${CONFIG_TYPES} + DESTINATION "${CMAKE_INSTALL_PREFIX_${CONFIG_TYPES_UC}}/${rsc_folder}" + ) + else() + install( + FILES ${install_rsc_${target}_FILES} + CONFIGURATIONS ${CONFIG_TYPES} + DESTINATION "${CMAKE_INSTALL_PREFIX_${CONFIG_TYPES_UC}}/${rsc_folder}" + ) + endif() + endforeach() +endmacro() + + +## High level macro to install in an homogen way all our ibr targets (it use some functions inside this file) +## +## RSC_FILE_ADD : [opt] is used to auto write/append relative paths of target resources into a common file +## INSTALL_PDB : [opt] is used to auto install PDB file (when using MSVC according to the target type) +## STANDALONE : [opt] bool ON/OFF var to call install_runtime or not (for bundle resolution) +## DIRS : [opt] used if STANDALONE set to ON, see install_runtime doc +## PLUGINS: [opt] used if STANDALONE set to ON, see install_runtime doc +## MSVC_CMD : [opt] used to specify an absolute filePathName application to launch with the MSVC IDE Debugger associated to this target (project file) +## MSVC_ARGS : [opt] load the MSVC debugger with correct settings (app path, args, working dir) +## +macro(ibr_install_target target) + cmake_parse_arguments(ibrInst${target} "VERBOSE;INSTALL_PDB" "COMPONENT;MSVC_ARGS;STANDALONE;RSC_FOLDER" "SHADERS;RESOURCES;SCRIPTS;DIRS;PLUGINS" ${ARGN}) + + if(ibrInst${target}_RSC_FOLDER) + set(rsc_folder "${ibrInst${target}_RSC_FOLDER}") + else() + set(rsc_folder "${target}") + endif() + + if(ibrInst${target}_SHADERS) + ibr_install_rsc(${target} EXECUTABLE TYPE "shaders" FOLDER ${rsc_folder} FILES "${ibrInst${target}_SHADERS}") + endif() + + if(ibrInst${target}_RESOURCES) + ibr_install_rsc(${target} TYPE "resources" FOLDER ${rsc_folder} FILES "${ibrInst${target}_RESOURCES}") + endif() + + if(ibrInst${target}_SCRIPTS) + ibr_install_rsc(${target} EXECUTABLE TYPE "scripts" FOLDER ${rsc_folder} FILES "${ibrInst${target}_SCRIPTS}") + endif() + + if(ibrInst${target}_COMPONENT) + set(installCompArg COMPONENT ${ibrInst${target}_COMPONENT}) + ## Create a custom install target based on COMPONENT + installTargetProject(${target} ${ibrInst${target}_COMPONENT}) + endif() + + if(DEFINED CMAKE_BUILD_TYPE) ## for make/nmake based + set_target_properties(${target} PROPERTIES ${CMAKE_BUILD_TYPE}_POSTFIX "${CMAKE_${CMAKE_BUILD_TYPE}_POSTFIX}") + get_target_property(CURRENT_TARGET_BUILD_TYPE_POSTFIX ${target} ${CMAKE_BUILD_TYPE}_POSTFIX) + endif() + foreach(CONFIG_TYPES ${CMAKE_CONFIGURATION_TYPES}) ## for multi config types (MSVC based) + string(TOUPPER ${CONFIG_TYPES} CONFIG_TYPES_UC) + set_target_properties(${target} PROPERTIES ${CONFIG_TYPES_UC}_POSTFIX "${CMAKE_${CONFIG_TYPES_UC}_POSTFIX}") + get_target_property(CURRENT_TARGET_BUILD_TYPE_POSTFIX ${target} ${CONFIG_TYPES_UC}_POSTFIX) + endforeach() + + ## Specify default installation rules + if(DEFINED CMAKE_BUILD_TYPE) ## for make/nmake based + install(TARGETS ${target} + CONFIGURATIONS ${CMAKE_BUILD_TYPE} + LIBRARY DESTINATION ${CMAKE_LIBRARY_OUTPUT_DIRECTORY_${CMAKE_BUILD_TYPE}} ${installCompArg} + ARCHIVE DESTINATION ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${CMAKE_BUILD_TYPE}} ${installCompArg} + RUNTIME DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CMAKE_BUILD_TYPE}} ${installCompArg} + ) + install(TARGETS ${target} + CONFIGURATIONS ${CMAKE_BUILD_TYPE} + LIBRARY DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CMAKE_BUILD_TYPE}} ${installCompArg} + ARCHIVE DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CMAKE_BUILD_TYPE}} ${installCompArg} + ) + endif() + foreach(CONFIG_TYPES ${CMAKE_CONFIGURATION_TYPES}) ## for multi config types (MSVC based) + string(TOUPPER ${CONFIG_TYPES} CONFIG_TYPES_UC) + install(TARGETS ${target} + CONFIGURATIONS ${CONFIG_TYPES} + LIBRARY DESTINATION ${CMAKE_LIBRARY_OUTPUT_DIRECTORY_${CONFIG_TYPES_UC}} ${installCompArg} + ARCHIVE DESTINATION ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${CONFIG_TYPES_UC}} ${installCompArg} + RUNTIME DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CONFIG_TYPES_UC}} ${installCompArg} + ) + install(TARGETS ${target} + CONFIGURATIONS ${CONFIG_TYPES} + LIBRARY DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CONFIG_TYPES_UC}} ${installCompArg} + ARCHIVE DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CONFIG_TYPES_UC}} ${installCompArg} + ) + endforeach() + + if(ibrInst${target}_INSTALL_PDB) + if(DEFINED CMAKE_BUILD_TYPE) ## for make/nmake based + installPDB(${target} ${CMAKE_BUILD_TYPE} + LIBRARY_DEST ${CMAKE_LIBRARY_OUTPUT_DIRECTORY_${CMAKE_BUILD_TYPE}} + ARCHIVE_DEST ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${CMAKE_BUILD_TYPE}} + RUNTIME_DEST ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CMAKE_BUILD_TYPE}} + ) + endif() + foreach(CONFIG_TYPES ${CMAKE_CONFIGURATION_TYPES}) ## for multi config types (MSVC based) + string(TOUPPER ${CONFIG_TYPES} CONFIG_TYPES_UC) + installPDB(${target} ${CONFIG_TYPES} + LIBRARY_DEST ${CMAKE_LIBRARY_OUTPUT_DIRECTORY_${CONFIG_TYPES_UC}} + ARCHIVE_DEST ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${CONFIG_TYPES_UC}} + RUNTIME_DEST ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CONFIG_TYPES_UC}} + ) + endforeach() + endif() + + ## install dynamic necessary dependencies + if(ibrInst${target}_STANDALONE) + get_target_property(type ${target} TYPE) + if(${type} MATCHES "EXECUTABLE") + + if(ibrInst${target}_VERBOSE) + set(VERBOSE VERBOSE) + else() + set(VERBOSE ) + endif() + + if(DEFINED CMAKE_BUILD_TYPE) ## for make/nmake based + install_runtime(bin/${target}${CMAKE_EXECUTABLE_SUFFIX} ## default relative to CMAKE_INSTALL_PREFIX + INSTALL_FOLDER "${CMAKE_INSTALL_PREFIX_${CMAKE_BUILD_TYPE}}" + CONFIG_TYPE ${CMAKE_BUILD_TYPE} + ${VERBOSE} + TARGET ${target} + ${installCompArg} + PLUGINS ## will be installed + ${ibrInst${target}_PLUGINS} + DIRS ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CMAKE_BUILD_TYPE}} + ${ibrInst${target}_DIRS} + ) + endif() + foreach(CONFIG_TYPES ${CMAKE_CONFIGURATION_TYPES}) ## for multi config types (MSVC based) + string(TOUPPER ${CONFIG_TYPES} CONFIG_TYPES_UC) + install_runtime(bin/${target}${CMAKE_EXECUTABLE_SUFFIX} ## default relative to CMAKE_INSTALL_PREFIX + INSTALL_FOLDER "${CMAKE_INSTALL_PREFIX_${CONFIG_TYPES_UC}}" + CONFIG_TYPE ${CONFIG_TYPES} + ${VERBOSE} + TARGET ${target} + ${installCompArg} + PLUGINS ## will be installed + ${ibrInst${target}_PLUGINS} + DIRS ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CONFIG_TYPES_UC}} + ${ibrInst${target}_DIRS} + ) + endforeach() + else() + message(WARNING "STANDALONE option is only compatible with EXECUTABLES target type. Skip the STANDALONE installation process.") + endif() + endif() + + ## Provide a way to directly load the MSVC debugger with correct settings + if(MSVC) + if(ibrInst${target}_MSVC_CMD) ## command absolute filePathName is optional as the default is to use the installed target file application + set(msvcCmdArg COMMAND ${ibrInst${target}_MSVC_CMD}) ## flag following by the value (both to pass to the MSVCsetUserCommand function) + endif() + if(ibrInst${target}_MSVC_ARGS) ## args (between quotes) are optional + set(msvcArgsArg ARGS ${ibrInst${target}_MSVC_ARGS}) ## flag following by the value (both to pass to the MSVCsetUserCommand function) + endif() + get_target_property(type ${target} TYPE) + if( (ibrInst${target}_MSVC_CMD OR ibrInst${target}_MSVC_ARGS) OR (${type} MATCHES "EXECUTABLE") ) + include(MSVCsetUserCommand) + if(DEFINED CMAKE_BUILD_TYPE) ## for make/nmake based + MSVCsetUserCommand( ${target} + PATH ${CMAKE_OUTPUT_BIN_${CMAKE_BUILD_TYPE}} ##FILE option not necessary since it deduced from targetName + ARGS "${SIBR_PROGRAMARGS}" + ${msvcCmdArg} + #${msvcArgsArg} + WORKING_DIR ${CMAKE_OUTPUT_BIN_${CMAKE_BUILD_TYPE}} + ) + endif() + foreach(CONFIG_TYPES ${CMAKE_CONFIGURATION_TYPES}) ## for multi config types (MSVC based) + string(TOUPPER ${CONFIG_TYPES} CONFIG_TYPES_UC) + MSVCsetUserCommand( ${target} + PATH ${CMAKE_OUTPUT_BIN_${CONFIG_TYPES_UC}} ##FILE option not necessary since it deduced from targetName + ARGS "${SIBR_PROGRAMARGS}" + ${msvcCmdArg} + #${msvcArgsArg} + WORKING_DIR ${CMAKE_OUTPUT_BIN_${CONFIG_TYPES_UC}} + ) + endforeach() + elseif(NOT ${type} MATCHES "EXECUTABLE") + #message("Cannot set MSVCsetUserCommand with target ${target} without COMMAND parameter as it is not an executable (skip it)") + endif() + endif() + +endmacro() diff --git a/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/parse_arguments_multi.cmake b/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/parse_arguments_multi.cmake new file mode 100644 index 0000000000000000000000000000000000000000..4f19e414fd3dc12a6af222f2471eec7410f617ee --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/parse_arguments_multi.cmake @@ -0,0 +1,304 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +if(NOT WIN32 OR __parse_arguments_multi_cmake_INCLUDED__) + return() +else() + set(__parse_arguments_multi_cmake_INCLUDED__ ON) +endif() + +## This macro allow to process repeating multi value args from a given function which use cmake_parse_arguments module. +## +## cmake_parse_arguments multi args standard behavior: +## function(foo) +## cmake_parse_arguments(arg "" "" "MULTI" ${ARGN}) +## foreach(item IN LISTS arg_MULTI) +## message(STATUS "${item}") +## endforeach() +## endfunction() +## foo(MULTI x y MULTI z w) +## The above code outputs 'z' and 'w'. It originally expected it to output all of 'x' 'y' 'z' 'w'. +## +## Using this macro inside a function which want to handle repeating multi args values +## will recursively iterate onto the multi tags list to process each sub list. +## It take as 1st argument the subTag flag to separate sub list from the main multi list. +## It take as 2nd argument the nameList of the main multi list (the multiValuesArgs from cmake_parse_arguments: here it is MULTI in the example) +## and that's why it is important that it should be a macro and not a function (to get access to external variable). +## Then you give the content of this list allowing to be processed by the macro. +## +## parse_arguments_multi macro call a parse_arguments_multi_function which do actually the process from the given sub-list. +## By default this function only print infos about what variables you are trying to pass/process (only verbose messages), +## but, by overloading this cmake function, you will be able to externalize the process of your multi argument list. +## +## Usage (into a function) : +## parse_arguments_multi( +## [NEED_RESULTS ] [EXTRAS_FLAGS <...> <...> ...] +## ) +## +## Simple usage example [user point of view]: +## foo(MULTI +## SUB_MULTI x y +## SUB_MULTI z w +## ) +## +## Simple usage example [inside a function]: +## function(foo) +## cmake_parse_arguments(arg "" "" "MULTI" ${ARGN}) +## include(parse_arguments_multi) +## function(parse_arguments_multi_function ) +## #message("I'm an overloaded cmake function used by parse_arguments_multi") +## #message("I'm processing first part of my sub list: ${ARGN}") +## message("ARGV0=${ARGV0}") +## message("ARGV1=${ARGV1}") +## endfunction() +## parse_arguments_multi(SUB_MULTI arg_MULTI ${arg_MULTI}) ## this function will process recusively items of the sub-list [default print messages] +## endfunction() +## +## Will print: +## ARGV0=z +## ARGV1=w +## ARGV0=x +## ARGV1=y +## +## WARNING : DO NEVER ADD EXTRA THINGS TO parse_arguments_multi MACRO : +## parse_arguments_multi(SUB_MULTI arg_MULTI ${arg_MULTI} EXTRAS foo bar SOMTHING) => will failed !! +## use EXTRAS_FLAGS instead !! +## +## Advanced usage example [user point of view]: +## bar(C:/prout/test.exe VERBOSE +## PLUGINS +## PLUGIN_PATH_NAME x PLUGIN_PATH_DEST w +## PLUGIN_PATH_NAME a b PLUGIN_PATH_DEST y +## PLUGIN_PATH_NAME c +## ) +## +## Advanced usage example [inside a function]: +## function(bar execFilePathName) +## cmake_parse_arguments(arg "VERBOSE" "" "PLUGINS" ${ARGN}) +## +## include(parse_arguments_multi) +## function(parse_arguments_multi_function results) +## cmake_parse_arguments(pamf "VERBOSE" "PLUGIN_PATH_DEST;EXEC_PATH" "" ${ARGN}) ## EXEC_PATH is for internal use +## message("") +## message("I'm an overloaded cmake function used by parse_arguments_multi from install_runtime function") +## message("I'm processing first part of my sub list: ${ARGN}") +## message("PLUGIN_PATH_NAME = ${pamf_UNPARSED_ARGUMENTS}") +## message(pamf_VERBOSE = ${pamf_VERBOSE}) +## message("pamf_PLUGIN_PATH_DEST = ${pamf_PLUGIN_PATH_DEST}") +## message(pamf_EXEC_PATH = ${pamf_EXEC_PATH}) +## if(NOT ${pamf_PLUGIN_PATH_DEST}) +## set(pamf_PLUGIN_PATH_DEST ${pamf_EXEC_PATH}) +## endif() +## foreach(plugin ${pamf_UNPARSED_ARGUMENTS}) +## get_filename_component(pluginName ${plugin} NAME) +## list(APPEND pluginsList ${pamf_PLUGIN_PATH_DEST}/${pluginName}) +## endforeach() +## set(${results} ${pluginsList} PARENT_SCOPE) +## endfunction() +## +## if(arg_VERBOSE) +## list(APPEND extra_flags_to_add VERBOSE) ## here we transmit the VERNOSE flag +## endif() +## get_filename_component(EXEC_PATH ${execFilePathName} PATH) ## will be the default value if PLUGIN_PATH_DEST option is not provided +## list(APPEND extra_flags_to_add EXEC_PATH ${EXEC_PATH}) +## list(LENGTH arg_PLUGINS arg_PLUGINS_count) +## parse_arguments_multi(PLUGIN_PATH_NAME arg_PLUGINS ${arg_PLUGINS} +## NEED_RESULTS ${arg_PLUGINS_count} ## this is used to check when we are in the first loop (in order to reset parse_arguments_multi_results) +## EXTRAS_FLAGS ${extra_flags_to_add} ## this is used to allow catching VERBOSE and PLUGIN_PATH_DEST flags of our overloaded function +## ) +## endfunction() +## message(parse_arguments_multi_results = ${parse_arguments_multi_results}) ## list of the whole pluginsList +## #Will print w/x;a/y;b/y;C:/prout/c +## +## NOTE that here, since our overloaded function need to provide a result list, we use the other parse_arguments_multi_function signature (the which one with a results arg) +## + +function(parse_arguments_multi_function_default) ## used in case of you want to reset the default behavior of this function process + message("[default function] parse_arguments_multi_function(ARGC=${ARGC} ARGV=${ARGV} ARGN=${ARGN})") + message("This function is used by parse_arguments_multi and have to be overloaded to process sub list of multi values args") +endfunction() + +function(parse_arguments_multi_function ) ## => the function to overload + parse_arguments_multi_function_default(${ARGN}) +endfunction() + +## first default signature above +##------------------------------ +## second results signature behind + +function(parse_arguments_multi_function_default result) ## used in case of you want to reset the default behavior of this function process + message("[default function] parse_arguments_multi_function(ARGC=${ARGC} ARGV=${ARGV} ARGN=${ARGN})") + message("This function is used by parse_arguments_multi and have to be overloaded to process sub list of muluti values args") +endfunction() + +function(parse_arguments_multi_function result) ## => the function to overload + parse_arguments_multi_function_default(result ${ARGN}) +endfunction() + +## => the macro to use inside your function which use cmake_parse_arguments +# NOTE: entry point of parse_arguments_multi, which is called from win3rdPart) +macro(parse_arguments_multi multiArgsSubTag multiArgsList #<${multiArgsList}> the content of the list +) + # message (STATUS "") + # message(STATUS "calling parse_arguemnts_multi defined in parse_arguments_multi.cmake:141") + # message(STATUS "multiArgsSubTag = ${multiArgsSubTag}") # CHECK_CACHED_VAR + # message(STATUS "multiArgsList = ${multiArgsList}") # it contains the name of the variable which is holding the list i.e w3p_MULTI_SET + # message(STATUS "value of ${multiArgsList} = ${${multiArgsList}}") # a semicolon separated list of values passed to SET or MULTISET keyword in win3rdParty + # message(STATUS "actual values ARGN = ${ARGN}") # the same as ${${multiArgsList}} + + ## INFO + ## starting from CMake 3.5 cmake_parse_arguments is not a module anymore and now is a native CMake command. + ## the behaviour is different though + ## In CMake 3.4, if you pass multiple times a multi_value_keyword, CMake returns the values of the LAST match + ## In CMake 3.5 and above, CMake returns the whole list of values that were following that multi_value_keyword + ## example: + ## cmake_parse_arguments( + ## + ## "" # options + ## "" # one value keywords + ## "MY_MULTI_VALUE_TAG" + ## MY_MULTI_VALUE_TAG value1 value2 + ## MY_MULTI_VALUE_TAG value3 value4 + ## MY_MULTI_VALUE_TAG value5 value6 + ## ) + ## result in CMake 3.4 + ## _MY_MULTI_VALUE_TAG = "value5;value6" + ## + ## result in CMake 3.8 + ## _MY_MULTI_VALUE_TAG = "value5;value6" + + #include(CMakeParseArguments) #module CMakeParseArguments is obsolete since cmake 3.5 + # cmake_parse_arguments ( args) + # : options (flags) pass to the macro + # : options that neeed a value + # : options that neeed more than one value + cmake_parse_arguments(_pam "" "NEED_RESULTS" "${multiArgsSubTag};EXTRAS_FLAGS" ${ARGN}) + + ## multiArgsList is the name of the list used by the multiValuesOption flag from the cmake_parse_arguments of the user function + ## that's why we absolutly need to use MACRO here (and also for passing parse_arguments_multi_results when NEED_RESULTS flag is set) + + ## for debugging + #message("") + #message("[parse_arguments_multi] => ARGN = ${ARGN}") + #message("_pam_NEED_RESULTS=${_pam_NEED_RESULTS}") + #message("_pam_EXTRAS_FLAGS=${_pam_EXTRAS_FLAGS}") + # foreach(var ${_pam_${multiArgsSubTag}}) + # message("arg=${var}") + # endforeach() + + if (${CMAKE_VERSION} VERSION_GREATER "3.5") + # lets make ${_pam_${multiArgsSubTag}} behave as it is in version 3.4 + # that means, cmake_parse_arguments should have only the last values of a multi set for a given keyword + + # message("") + # message("values in multiArgsList") + # foreach(val ${${multiArgsList}}) + # message(STATUS ${val}) + # endforeach() + # message("end values in multiArgsList") + + + set(lastIndexFound OFF) + list(LENGTH ${multiArgsList} argnLength) + # message(${argnLength}) + math(EXPR argnLength "${argnLength}-1") # make last index a valid one + set(recordIndex 0) + set(records "") # clear records list + set(record0 "") # clear first record list + foreach(iter RANGE ${argnLength}) + list(GET ${multiArgsList} ${iter} value) + # message(STATUS "index=${iter} value=${value}") + if (${value} STREQUAL ${multiArgsSubTag}) + if (lastIndexFound) + list(APPEND records ${recordIndex}) # records store the list NAMES + math(EXPR recordIndex "${recordIndex}+1") + set(record${recordIndex} "") # clear record list + else () + set(lastIndexFound ON) + endif() + + set(lastIndex ${iter}) + else () + if (lastIndexFound) + # message(${value}) + list(APPEND record${recordIndex} ${value}) + endif() + endif() + endforeach() + + # save the last list of values + if (lastIndexFound) + list(APPEND records ${recordIndex}) # records store the list NAMES + endif() + + # set multiArgsList to make it behave like CMake 3.4 + # message("") + # message("using my records") + foreach(recordName ${records}) + # message(${recordName}) + # foreach(value ${record${recordName}}) + # message(${value}) + # endforeach() + # message("") + set(_pam_${multiArgsSubTag} ${record${recordName}}) + endforeach() + # message(${_pam_${multiArgsSubTag}}) + + # message("") + # message("using argn") + # foreach(value ${ARGN}) + # message(${value}) + # endforeach() + endif() # end if cmake > 3.5 + + # message("values with pam ${_pam_${multiArgsSubTag}}") + + ## check and init + list(LENGTH ${multiArgsList} globalListCount) # GLUT_TRACE: globalListCound=16 in CMake3.4 and CMake3.8 + # message(STATUS "nr items in multiArgsList: ${globalListCount}") + math(EXPR globalListCount "${globalListCount}-1") ## because it will contain [multiArgsSubTag + ${multiArgsList}] + if(_pam_NEED_RESULTS) + if(${globalListCount} EQUAL ${_pam_NEED_RESULTS}) + ## first time we enter into this macro (because we call it recursively) + unset(parse_arguments_multi_results) + endif() + endif() + + ## process the part of the multi agrs list + ## ${ARGN} shouldn't be passed to the function in order to avoid missmatch size list ${multiArgsList} and _pam_${multiArgsSubTag} + ## if you want to pass extra internal flags from your function to this callback, use EXTRAS_FLAGS + if(_pam_NEED_RESULTS) + parse_arguments_multi_function(parse_arguments_multi_function_result ${_pam_${multiArgsSubTag}} ${_pam_EXTRAS_FLAGS}) + list(APPEND parse_arguments_multi_results ${parse_arguments_multi_function_result}) + else() + # message(STATUS "about to call parse_arguments_multi_function in parse_arguments_multi.cmake:177 ${_pam_${multiArgsSubTag}} and extra flags ${_pam_EXTRAS_FLAGS}") + parse_arguments_multi_function(${_pam_${multiArgsSubTag}} ${_pam_EXTRAS_FLAGS}) + endif() + + ## remove just processed items from the main list to process (multiArgsList) + list(REVERSE ${multiArgsList}) + list(LENGTH _pam_${multiArgsSubTag} subTagListCount) + unset(ids) + foreach(id RANGE ${subTagListCount}) + list(APPEND ids ${id}) + endforeach() + list(REMOVE_AT ${multiArgsList} ${ids}) + list(REVERSE ${multiArgsList}) + + ## test if remain sub multi list to process (recursive call) or finish the process + list(LENGTH ${multiArgsList} mainTagListCount) + if(${mainTagListCount} GREATER 1) + ## do not pass ${ARGN} just because it will re pass the initial 2 inputs args and we wont as they was consumed (in order to avoir conflicts) + # message(STATUS "about to call a parse_arguments_multi but without knowing where the definition is going to be taken from") + parse_arguments_multi(${multiArgsSubTag} ${multiArgsList} ${${multiArgsList}} + NEED_RESULTS ${_pam_NEED_RESULTS} EXTRAS_FLAGS ${_pam_EXTRAS_FLAGS} + ) + endif() +endmacro() diff --git a/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/sibr_library.cmake b/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/sibr_library.cmake new file mode 100644 index 0000000000000000000000000000000000000000..08a30ad940dbd53f14640b53c5d410264d910cad --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/cmake/linux/sibr_library.cmake @@ -0,0 +1,174 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +# NOTE +# This feature is used to easily download, store and link external dependencies. This +# requires to prepare pre-compiled libraries (to download). For now, packages have +# only be prepare for Windows 64-bit with Visual Studio 2012. (You should re-build +# everything if you want to use another version of Visual Studio/ another compiler). + +# NOTE ABOUT UNIX SYSTEMS +# There is no need for "searching mechanism". This function is discard and your +# libraries should be installed is the standard folders that are: +# +# /usr/include/ +# /usr/lib/ +# /usr/lib64/ +# for packages downloaded using apt-get/yum +# +# /usr/local/include/ +# /usr/local/lib/ +# /usr/local/lib64/ +# for packages manually installed ("make install") +# +# if you encounter problems when linking (e.g. lib not found even if it is installed), +# please check these folders are in your search PATH environment variables. + +set(EXTLIBS_PACKAGE_FOLDER "${CMAKE_SOURCE_DIR}/extlibs") + +function(sibr_addlibrary) + if(NOT WIN32) + return() + endif() + + file(MAKE_DIRECTORY ${EXTLIBS_PACKAGE_FOLDER}) + cmake_parse_arguments(args "VCID" "VERBOSE;TIMEOUT;DEFAULT_USE;NAME;VERSION;MSVC11;MSVC12;MSVC14;MSVC17" "MULTI_SET;SET" ${ARGN}) + + + if (NOT "${args_VERSION}" MATCHES "") + message(WARNING "VERSION is not implemented yet") + endif() + + set(lcname "") + set(ucname "") + string(TOLOWER "${args_NAME}" lcname) + string(TOUPPER "${args_NAME}" ucname) + + set(LIB_PACKAGE_FOLDER "${EXTLIBS_PACKAGE_FOLDER}/${lcname}") + win3rdParty(${ucname} + $ + VERBOSE ${args_VERBOSE} + TIMEOUT ${args_TIMEOUT} + DEFAULT_USE ${args_DEFAULT_USE} + MSVC11 "${LIB_PACKAGE_FOLDER}" "${args_MSVC11}" + MSVC12 "${LIB_PACKAGE_FOLDER}" "${args_MSVC12}" + MSVC14 "${LIB_PACKAGE_FOLDER}" "${args_MSVC14}" # TODO SV: make sure to build this library if required + MSVC17 "${LIB_PACKAGE_FOLDER}" "${args_MSVC17}" + SET ${args_SET} + MULTI_SET ${args_MULTI_SET} + ) + + # Add include/ directory + # and lib/ directories + + # TODO SV: paths not matching with current hierarchy. example: libraw/libraw-0.17.1/include + # SR: The link directories will also be used to lookup for dependency DLLs to copy in the install directory. + # Some libraries put the DLLs in the bin/ directory, so we include those. + file(GLOB subdirs RELATIVE ${LIB_PACKAGE_FOLDER} ${LIB_PACKAGE_FOLDER}/*) + set(dirlist "") + foreach(dir ${subdirs}) + if(IS_DIRECTORY ${LIB_PACKAGE_FOLDER}/${dir}) + # message("adding ${LIB_PACKAGE_FOLDER}/${dir}/include/ to the include directories") + include_directories("${LIB_PACKAGE_FOLDER}/${dir}/include/") + # message("adding ${LIB_PACKAGE_FOLDER}/${dir}/lib[64] to the link directories") + link_directories("${LIB_PACKAGE_FOLDER}/${dir}/") + link_directories("${LIB_PACKAGE_FOLDER}/${dir}/lib/") + link_directories("${LIB_PACKAGE_FOLDER}/${dir}/lib64/") + link_directories("${LIB_PACKAGE_FOLDER}/${dir}/bin/") + endif() + endforeach() + +endfunction() + +include(FetchContent) +include(git_describe) +include(install_runtime) + +function(sibr_gitlibrary) + cmake_parse_arguments(args "" "TARGET;GIT_REPOSITORY;GIT_TAG;ROOT_DIR;SOURCE_DIR" "INCLUDE_DIRS" ${ARGN}) + if(NOT args_TARGET) + message(FATAL "Error on sibr_gitlibrary : please define your target name.") + return() + endif() + + if(NOT args_ROOT_DIR) + set(args_ROOT_DIR ${args_TARGET}) + endif() + + if(NOT args_SOURCE_DIR) + set(args_SOURCE_DIR ${args_TARGET}) + endif() + + if(args_GIT_REPOSITORY AND args_GIT_TAG) + if(EXISTS ${CMAKE_SOURCE_DIR}/extlibs/${args_ROOT_DIR}/${args_SOURCE_DIR}/.git) + git_describe( + PATH ${CMAKE_SOURCE_DIR}/extlibs/${args_ROOT_DIR}/${args_SOURCE_DIR} + GIT_URL SIBR_GITLIBRARY_URL + GIT_BRANCH SIBR_GITLIBRARY_BRANCH + GIT_COMMIT_HASH SIBR_GITLIBRARY_COMMIT_HASH + GIT_TAG SIBR_GITLIBRARY_TAG + ) + + if((SIBR_GITLIBRARY_URL STREQUAL args_GIT_REPOSITORY) AND + ((SIBR_GITLIBRARY_BRANCH STREQUAL args_GIT_TAG) OR + (SIBR_GITLIBRARY_TAG STREQUAL args_GIT_TAG) OR + (SIBR_GITLIBRARY_COMMIT_HASH STREQUAL args_GIT_TAG))) + message(STATUS "Library ${args_TARGET} already available, skipping.") + set(SIBR_GITLIBRARY_DECLARED ON) + else() + message(STATUS "Adding library ${args_TARGET} from git...") + endif() + endif() + + FetchContent_Declare(${args_TARGET} + GIT_REPOSITORY ${args_GIT_REPOSITORY} + GIT_TAG ${args_GIT_TAG} + GIT_SHALLOW ON + SOURCE_DIR ${CMAKE_SOURCE_DIR}/extlibs/${args_ROOT_DIR}/${args_SOURCE_DIR} + SUBBUILD_DIR ${CMAKE_SOURCE_DIR}/extlibs/${args_ROOT_DIR}/subbuild + BINARY_DIR ${CMAKE_SOURCE_DIR}/extlibs/${args_ROOT_DIR}/build + ) + FetchContent_GetProperties(${args_TARGET}) + string(TOLOWER "" lcTargetName) + + if((NOT SIBR_GITLIBRARY_DECLARED) AND (NOT ${lcTargetName}_POPULATED)) + message(STATUS "Populating library ${args_TARGET}...") + FetchContent_Populate(${args_TARGET} QUIET + GIT_REPOSITORY ${args_GIT_REPOSITORY} + GIT_TAG ${args_GIT_TAG} + SOURCE_DIR ${CMAKE_SOURCE_DIR}/extlibs/${args_ROOT_DIR}/${args_SOURCE_DIR} + SUBBUILD_DIR ${CMAKE_SOURCE_DIR}/extlibs/${args_ROOT_DIR}/subbuild + BINARY_DIR ${CMAKE_SOURCE_DIR}/extlibs/${args_ROOT_DIR}/build + ) + endif() + + add_subdirectory(${CMAKE_SOURCE_DIR}/extlibs/${args_ROOT_DIR}/${args_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/extlibs/${args_ROOT_DIR}/build) + + get_target_property(type ${args_TARGET} TYPE) + if(NOT (type STREQUAL "INTERFACE_LIBRARY")) + set_target_properties(${args_TARGET} PROPERTIES FOLDER "extlibs") + + ibr_install_target(${args_TARGET} + COMPONENT ${args_TARGET}_install ## will create custom target to install only this project + ) + endif() + + list(APPEND ${args_TARGET}_INCLUDE_DIRS ${EXTLIBS_PACKAGE_FOLDER}/${args_ROOT_DIR}) + list(APPEND ${args_TARGET}_INCLUDE_DIRS ${EXTLIBS_PACKAGE_FOLDER}/${args_ROOT_DIR}/${args_SOURCE_DIR}) + + foreach(args_INCLUDE_DIR ${args_INCLUDE_DIRS}) + list(APPEND ${args_TARGET}_INCLUDE_DIRS ${EXTLIBS_PACKAGE_FOLDER}/${args_ROOT_DIR}/${args_SOURCE_DIR}/${args_INCLUDE_DIR}) + endforeach() + + include_directories(${${args_TARGET}_INCLUDE_DIRS}) + else() + message(FATAL "Error on sibr_gitlibrary for target ${args_TARGET}: missing git tag or git url.") + endif() +endfunction() \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/MSVCsetUserCommand.cmake b/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/MSVCsetUserCommand.cmake new file mode 100644 index 0000000000000000000000000000000000000000..bc49770d644ca2803a9d52f9186d952b40fafdf8 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/MSVCsetUserCommand.cmake @@ -0,0 +1,149 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +if(__MSVCsetUserCommand_cmake_INCLUDED__) + return() +else() + set(__MSVCsetUserCommand_cmake_INCLUDED__ ON) +endif() + +## Allow to configure the Debugger settings of visual studio +## Note: Using this command under linux doesn't affect anything +## On run Debug Windows local : visual will try to load a specific COMMAND with ARGS in the provided WORKING_DIR +## +## usage: +## MSVCsetUserCommand( +## [COMMAND | [ PATH [FILE ] ] ] +## ARGS +## WORKING_DIR +## ) +## +## Warning 1 : All arugments () must be passed under quotes +## Warning 2 : WORKING_DIR path arg have to finish with remain slah '/' +## Warning 3 : use COMMAND for external app OR PATH (optionaly with FILE) option(s) to set your built/installed/moved target +## +## Example 1: +## include(MSVCsetUserCommand) +## MSVCsetUserCommand( UnityRenderingPlugin +## COMMAND "C:/Program Files (x86)/Unity/Editor/Unity.exe" +## ARGS "-force-opengl -projectPath \"${CMAKE_HOME_DIRECTORY}/UnityPlugins/RenderingPluginExample/UnityProject\"" +## WORKING_DIR "${CMAKE_HOME_DIRECTORY}/UnityPlugins/RenderingPluginExample/UnityProject" +## VERBOSE +## ) +## +## Example 2: +## include(MSVCsetUserCommand) +## MSVCsetUserCommand( ibrApp +## PATH "C:/Program Files (x86)/workspace/IBR/install" +## FILE "ibrApp${CMAKE_EXECUTABLE_SUFFIX}" ## this option line is optional since the target name didn't change between build and install step +## ARGS "-path \"${CMAKE_HOME_DIRECTORY}/dataset\"" +## WORKING_DIR "${CMAKE_HOME_DIRECTORY}" +## VERBOSE +## ) +## +function(MSVCsetUserCommand targetName) + cmake_parse_arguments(MSVCsuc "VERBOSE" "PATH;FILE;COMMAND;ARGS;WORKING_DIR" "" ${ARGN} ) + + ## If no arguments are given, do not create an unecessary .vcxproj.user file + set(MSVCsuc_DEFAULT OFF) + + if(MSVCsuc_PATH AND MSVCsuc_DEFAULT) + set(MSVCsuc_DEFAULT OFF) + endif() + + if(MSVCsuc_FILE AND MSVCsuc_DEFAULT) + set(MSVCsuc_DEFAULT OFF) + endif() + + if(NOT MSVCsuc_COMMAND) + if(MSVCsuc_PATH AND MSVCsuc_FILE) + set(MSVCsuc_COMMAND "${MSVCsuc_PATH}\\${MSVCsuc_FILE}") + elseif(MSVCsuc_PATH) + set(MSVCsuc_COMMAND "${MSVCsuc_PATH}\\$(TargetFileName)") + else() + set(MSVCsuc_COMMAND "$(TargetPath)") ## => $(TargetDir)\$(TargetName)$(TargetExt) + endif() + elseif(MSVCsuc_DEFAULT) + set(MSVCsuc_DEFAULT OFF) + endif() + + # NOTE: there was a typo here. there is an else if written after else statement + # changing the order of the else if statement + if(MSVCsuc_WORKING_DIR) + file(TO_NATIVE_PATH ${MSVCsuc_WORKING_DIR} MSVCsuc_WORKING_DIR) + elseif(MSVCsuc_DEFAULT) + set(MSVCsuc_DEFAULT OFF) + else() + set(MSVCsuc_WORKING_DIR "$(ProjectDir)") + endif() + + if(NOT MSVCsuc_ARGS) + set(MSVCsuc_ARGS "") + elseif(MSVCsuc_DEFAULT) + set(MSVCsuc_DEFAULT OFF) + endif() + + if(MSVC10 OR (MSVC AND MSVC_VERSION GREATER 1600)) # 2010 or newer + + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(PLATEFORM_BITS x64) + else() + set(PLATEFORM_BITS Win32) + endif() + + if(NOT MSVCsuc_DEFAULT AND PLATEFORM_BITS) + + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${targetName}.vcxproj.user" + " + + + ${MSVCsuc_COMMAND} + ${MSVCsuc_ARGS} + WindowsLocalDebugger + ${MSVCsuc_WORKING_DIR} + + + ${MSVCsuc_COMMAND} + ${MSVCsuc_ARGS} + WindowsLocalDebugger + ${MSVCsuc_WORKING_DIR} + + + ${MSVCsuc_COMMAND} + ${MSVCsuc_ARGS} + WindowsLocalDebugger + ${MSVCsuc_WORKING_DIR} + + + ${MSVCsuc_COMMAND} + ${MSVCsuc_ARGS} + WindowsLocalDebugger + ${MSVCsuc_WORKING_DIR} + +" + ) + if(MSVCsuc_VERBOSE) + message(STATUS "[MSVCsetUserCommand] Write ${CMAKE_CURRENT_BINARY_DIR}/${targetName}.vcxproj.user file") + message(STATUS " to execute ${MSVCsuc_COMMAND} ${MSVCsuc_ARGS}") + message(STATUS " from derectory ${MSVCsuc_WORKING_DIR}") + message(STATUS " on visual studio run debugger button") + endif() + + else() + message(WARNING "PLATEFORM_BITS is undefined...") + endif() + + else() + if(MSVCsuc_VERBOSE) + message(WARNING "MSVCsetUserCommand is disable because too old MSVC is used (need MSVC10 2010 or newer)") + endif() + endif() + +endfunction() diff --git a/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/Modules/FindASSIMP.cmake b/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/Modules/FindASSIMP.cmake new file mode 100644 index 0000000000000000000000000000000000000000..f92c8c003c3b109037ae39f316b17a360b44093a --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/Modules/FindASSIMP.cmake @@ -0,0 +1,104 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +## Try to find the ASSIMP library +## Once done this will define +## +## ASSIMP_FOUND - system has ASSIMP +## ASSIMP_INCLUDE_DIR - The ASSIMP include directory +## ASSIMP_LIBRARIES - The libraries needed to use ASSIMP +## ASSIMP_CMD - the full path of ASSIMP executable +## ASSIMP_DYNAMIC_LIB - the Assimp dynamic lib (available only on windows as .dll file for the moment) +## +## Edited for using a bugfixed version of Assimp + +if(NOT ASSIMP_DIR) + set(ASSIMP_DIR "$ENV{ASSIMP_DIR}" CACHE PATH "ASSIMP root directory") +endif() +if(ASSIMP_DIR) + file(TO_CMAKE_PATH ${ASSIMP_DIR} ASSIMP_DIR) +endif() + + +## set the LIB POSTFIX to find in a right directory according to what kind of compiler we use (32/64bits) +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(ASSIMP_SEARCH_LIB "lib64") + set(ASSIMP_SEARCH_BIN "bin64") + set(ASSIMP_SEARCH_LIB_PATHSUFFIXE "x64") +else() + set(ASSIMP_SEARCH_LIB "lib32") + set(ASSIMP_SEARCH_BIN "bin32") + set(ASSIMP_SEARCH_LIB_PATHSUFFIXE "x86") +endif() + +set(PROGRAMFILESx86 "PROGRAMFILES(x86)") + + +FIND_PATH(ASSIMP_INCLUDE_DIR + NAMES assimp/config.h + PATHS + ${ASSIMP_DIR} + ## linux + /usr + /usr/local + /opt/local + ## windows + "$ENV{PROGRAMFILES}/Assimp" + "$ENV{${PROGRAMFILESx86}}/Assimp" + "$ENV{ProgramW6432}/Assimp" + PATH_SUFFIXES include +) + + +FIND_LIBRARY(ASSIMP_LIBRARY + NAMES assimp-vc140-mt + PATHS + ${ASSIMP_DIR}/${ASSIMP_SEARCH_LIB} + ${ASSIMP_DIR}/lib + ${ASSIMP_DIR}/lib64 + ## linux + /usr/${ASSIMP_SEARCH_LIB} + /usr/local/${ASSIMP_SEARCH_LIB} + /opt/local/${ASSIMP_SEARCH_LIB} + /usr/lib + /usr/local/lib + /opt/local/lib + ## windows + "$ENV{PROGRAMFILES}/Assimp/${ASSIMP_SEARCH_LIB}" + "$ENV{${PROGRAMFILESx86}}/Assimp/${ASSIMP_SEARCH_LIB}" + "$ENV{ProgramW6432}/Assimp/${ASSIMP_SEARCH_LIB}" + "$ENV{PROGRAMFILES}/Assimp/lib" + "$ENV{${PROGRAMFILESx86}}/Assimp/lib" + "$ENV{ProgramW6432}/Assimp/lib" + PATH_SUFFIXES ${ASSIMP_SEARCH_LIB_PATHSUFFIXE} +) +set(ASSIMP_LIBRARIES ${ASSIMP_LIBRARY}) + + +if(ASSIMP_LIBRARY) + get_filename_component(ASSIMP_LIBRARY_DIR ${ASSIMP_LIBRARY} PATH) + file(GLOB ASSIMP_DYNAMIC_LIB "${ASSIMP_LIBRARY_DIR}/assimp*.dll") + if(NOT ASSIMP_DYNAMIC_LIB) + message("ASSIMP_DYNAMIC_LIB is missing... at ${ASSIMP_LIBRARY_DIR}") + endif() + set(ASSIMP_DYNAMIC_LIB ${ASSIMP_DYNAMIC_LIB} CACHE PATH "Windows dll location") +endif() + +MARK_AS_ADVANCED(ASSIMP_DYNAMIC_LIB ASSIMP_INCLUDE_DIR ASSIMP_LIBRARIES) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(ASSIMP + REQUIRED_VARS ASSIMP_INCLUDE_DIR ASSIMP_LIBRARIES + FAIL_MESSAGE "ASSIMP wasn't found correctly. Set ASSIMP_DIR to the root SDK installation directory." +) + +if(NOT ASSIMP_FOUND) + set(ASSIMP_DIR "" CACHE STRING "Path to ASSIMP install directory") +endif() diff --git a/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/Modules/FindEmbree.cmake b/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/Modules/FindEmbree.cmake new file mode 100644 index 0000000000000000000000000000000000000000..27908b58240afe19eee4e7466eda9c8557f8f0ae --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/Modules/FindEmbree.cmake @@ -0,0 +1,95 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +## Important Note: +## This is not an official Find*cmake. It has been written for searching through +## a custom path (EMBREE_DIR) before checking elsewhere. +## +## FindEMBREE.cmake +## Find EMBREE's includes and library +## +## This module defines : +## [in] EMBREE_DIR, The base directory to search for EMBREE (as cmake var or env var) +## [out] EMBREE_INCLUDE_DIR where to find EMBREE.h +## [out] EMBREE_LIBRARIES, EMBREE_LIBRARY, libraries to link against to use EMBREE +## [out] EMBREE_FOUND, If false, do not try to use EMBREE. +## + + +if(NOT EMBREE_DIR) + set(EMBREE_DIR "$ENV{EMBREE_DIR}" CACHE PATH "EMBREE root directory") +endif() +if(EMBREE_DIR) + file(TO_CMAKE_PATH ${EMBREE_DIR} EMBREE_DIR) +endif() + + +## set the LIB POSTFIX to find in a right directory according to what kind of compiler we use (32/64bits) +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(EMBREE_SEARCH_LIB "lib64") + set(EMBREE_SEARCH_BIN "bin64") + set(EMBREE_SEARCH_LIB_PATHSUFFIXE "x64") +else() + set(EMBREE_SEARCH_LIB "lib32") + set(EMBREE_SEARCH_BIN "bin32") + set(EMBREE_SEARCH_LIB_PATHSUFFIXE "x86") +endif() + +set(PROGRAMFILESx86 "PROGRAMFILES(x86)") + +FIND_PATH(EMBREE_INCLUDE_DIR + NAMES embree3/rtcore_geometry.h + PATHS + ${EMBREE_DIR} + ## linux + /usr + /usr/local + /opt/local + ## windows + "$ENV{PROGRAMFILES}/EMBREE" + "$ENV{${PROGRAMFILESx86}}/EMBREE" + "$ENV{ProgramW6432}/EMBREE" + PATH_SUFFIXES include +) + +FIND_LIBRARY(EMBREE_LIBRARY + NAMES embree3 + PATHS + ${EMBREE_DIR}/${EMBREE_SEARCH_LIB} + ${EMBREE_DIR}/lib + ## linux + /usr/${EMBREE_SEARCH_LIB} + /usr/local/${EMBREE_SEARCH_LIB} + /opt/local/${EMBREE_SEARCH_LIB} + /usr/lib + /usr/local/lib + /opt/local/lib + ## windows + "$ENV{PROGRAMFILES}/EMBREE/${EMBREE_SEARCH_LIB}" + "$ENV{${PROGRAMFILESx86}}/EMBREE/${EMBREE_SEARCH_LIB}" + "$ENV{ProgramW6432}/EMBREE/${EMBREE_SEARCH_LIB}" + "$ENV{PROGRAMFILES}/EMBREE/lib" + "$ENV{${PROGRAMFILESx86}}/EMBREE/lib" + "$ENV{ProgramW6432}/EMBREE/lib" + PATH_SUFFIXES ${EMBREE_SEARCH_LIB_PATHSUFFIXE} +) +set(EMBREE_LIBRARIES ${EMBREE_LIBRARY}) + +MARK_AS_ADVANCED(EMBREE_INCLUDE_DIR EMBREE_LIBRARIES) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(EMBREE + REQUIRED_VARS EMBREE_INCLUDE_DIR EMBREE_LIBRARIES + FAIL_MESSAGE "EMBREE wasn't found correctly. Set EMBREE_DIR to the root SDK installation directory." +) + +if(NOT EMBREE_FOUND) + set(EMBREE_DIR "" CACHE STRING "Path to EMBREE install directory") +endif() diff --git a/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/Modules/FindFFmpeg.cmake b/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/Modules/FindFFmpeg.cmake new file mode 100644 index 0000000000000000000000000000000000000000..5b208b64e117989fd38a39d0e561f1cd041a0f42 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/Modules/FindFFmpeg.cmake @@ -0,0 +1,104 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +## Try to find the FFMPEG library +## Once done this will define +## +## FFMPEG_FOUND - system has FFmpeg +## FFMPEG_INCLUDE_DIR - The FFmpeg include directory +## FFMPEG_LIBRARIES - The libraries needed to use FFmpeg +## FFMPEG_DYNAMIC_LIBS - DLLs for windows + + +if(NOT FFMPEG_DIR) + set(FFMPEG_DIR "$ENV{FFMPEG_DIR}" CACHE PATH "FFMPEG_DIR root directory") +endif() + +if(FFMPEG_DIR) + file(TO_CMAKE_PATH ${FFMPEG_DIR} FFMPEG_DIR) +endif() + +MACRO(FFMPEG_FIND varname shortname headername) + + # Path to include dirs + FIND_PATH(FFMPEG_${varname}_INCLUDE_DIRS + NAMES "lib${shortname}/${headername}" + PATHS + "${FFMPEG_DIR}/include" # modify this to adapt according to OS/compiler + ) + + #Add libraries + IF(${FFMPEG_${varname}_INCLUDE_DIRS} STREQUAL "FFMPEG_${varname}_INCLUDE_DIR-NOTFOUND") + MESSAGE(STATUS "Can't find includes for ${shortname}...") + ELSE() + FIND_LIBRARY(FFMPEG_${varname}_LIBRARIES + NAMES ${shortname} + PATHS + ${FFMPEG_DIR}/lib + ) + + # set libraries and other variables + SET(FFMPEG_${varname}_FOUND 1) + SET(FFMPEG_${varname}_INCLUDE_DIRS ${FFMPEG_${varname}_INCLUDE_DIR}) + SET(FFMPEG_${varname}_LIBS ${FFMPEG_${varname}_LIBRARIES}) + ENDIF() + ENDMACRO(FFMPEG_FIND) + +#Calls to ffmpeg_find to get librarires ------------------------------ +FFMPEG_FIND(LIBAVFORMAT avformat avformat.h) +FFMPEG_FIND(LIBAVDEVICE avdevice avdevice.h) +FFMPEG_FIND(LIBAVCODEC avcodec avcodec.h) +FFMPEG_FIND(LIBAVUTIL avutil avutil.h) +FFMPEG_FIND(LIBSWSCALE swscale swscale.h) + +# check if libs are found and set FFMPEG related variables +#SET(FFMPEG_FOUND "NO") +IF(FFMPEG_LIBAVFORMAT_FOUND + AND FFMPEG_LIBAVDEVICE_FOUND + AND FFMPEG_LIBAVCODEC_FOUND + AND FFMPEG_LIBAVUTIL_FOUND + AND FFMPEG_LIBSWSCALE_FOUND) + + # All ffmpeg libs are here + SET(FFMPEG_FOUND "YES") + SET(FFMPEG_INCLUDE_DIR ${FFMPEG_LIBAVFORMAT_INCLUDE_DIRS}) + SET(FFMPEG_LIBRARY_DIRS ${FFMPEG_LIBAVFORMAT_LIBRARY_DIRS}) + SET(FFMPEG_LIBRARIES + ${FFMPEG_LIBAVFORMAT_LIBS} + ${FFMPEG_LIBAVDEVICE_LIBS} + ${FFMPEG_LIBAVCODEC_LIBS} + ${FFMPEG_LIBAVUTIL_LIBS} + ${FFMPEG_LIBSWSCALE_LIBS} ) + + # add dynamic libraries + if(WIN32) + file(GLOB FFMPEG_DYNAMIC_LIBS "${FFMPEG_DIR}/bin/*.dll") + if(NOT FFMPEG_DYNAMIC_LIBS) + message("FFMPEG_DYNAMIC_LIBS is missing...") + endif() + set(FFMPEG_DYNAMIC_LIBS ${FFMPEG_DYNAMIC_LIBS} CACHE PATH "Windows dll location") +endif() + + mark_as_advanced(FFMPEG_INCLUDE_DIR FFMPEG_LIBRARY_DIRS FFMPEG_LIBRARIES FFMPEG_DYNAMIC_LIBS) +ELSE () + MESSAGE(STATUS "Could not find FFMPEG") +ENDIF() + + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(FFMPEG + REQUIRED_VARS FFMPEG_INCLUDE_DIR FFMPEG_LIBRARIES + FAIL_MESSAGE "FFmpeg wasn't found correctly. Set FFMPEG_DIR to the root SDK installation directory." +) + +if(NOT FFMPEG_FOUND) + set(FFMPEG_DIR "" CACHE STRING "Path to FFmpeg install directory") +endif() + diff --git a/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/Win3rdParty.cmake b/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/Win3rdParty.cmake new file mode 100644 index 0000000000000000000000000000000000000000..7e42fbb9f4353c2208ed3d6f44cf7acc3fccedc2 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/Win3rdParty.cmake @@ -0,0 +1,337 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +## This file should be include and use only on WIN32 OS and once +## It allow to auto check/download and use a preconfigured 3rdParty binaries for cmake usage +## It use the downloadAndExtractZipFile cmake module to work. +## +if(__Win3rdParty_cmake_INCLUDED__) + return() +else() + set(__Win3rdParty_cmake_INCLUDED__ ON) +endif() + + +## +## To be sure to reset an empty cached variable but keep any other kind of variables +## +## Usage: +## check_cached_var( [FORCE]) +## +## is the cached cmake variable you need to reset +## is the new default value of the reseted cached cmake variable +## is the kind of GUI cache input can be : FILEPATH; PATH; STRING or BOOL +## is the associated GUI cache input documentation display in the GUI +## FORCE option could be use to reset a cached variable even if it is not empty. +## +macro(check_cached_var var resetedCachedValue cacheType cacheDoc) + # message(STATUS "inside check_cached_var macro. argn=${ARGN}") + cmake_parse_arguments(ccv "FORCE" "" "" ${ARGN}) + + if(ccv_FORCE) + set(FORCE FORCE) + else() + set(FORCE ) + endif() + + if(NOT ${var} OR ccv_FORCE) + unset(${var} CACHE) + # message(STATUS "setting new cache value. var ${var} = ${resetedCachedValue}") + set(${var} "${resetedCachedValue}" CACHE ${cacheType} "${cacheDoc}" ${FORCE}) + endif() +endmacro() + + +## +## Win3rdParty function allow to specify a directory which contain all necessary windows dependenties. +## By uploading 3rdParty directory (which contain dependencies, *.lib, *.dll... for a specific version of compiler) onto Gforge file tab, +## you get back an URL of download you can give to this function with a directory name. So you can provide multiple 3rdParty version of same dependencies (MSVC11, MSVC12...). +## By providing a prefix to this function, you allow to use different kind of 3rdParty which can be handled by CMAKE OPTIONS depending on what your framework need for example. +## +## Usage 1: +## Win3rdParty( MSVC +## [MSVC ] [...] +## [VCID] [DEFAULT_USE] [VERBOSE] ) +## +## * allow to identify which 3rdParty you process (prefix name) +## * MSVC flag could be MSVC11 or MSVC12 (any element of the MSVC_VERSIONS_LIST) and refer to a 3rdParty compiler with : +## * which will be the local pathName of the downloaded 3rdParty : relative to CMAKE_BINARY_DIR +## * which is the link location of the 3rdParty zip +## * VCID flag will make available a cache variable ${prefix}_WIN3RDPARTY_VCID +## * DEFAULT_USE flag [ON|OFF] may be used to set default value of cmake cached variable : _WIN3RDPARTY_USE [default to ON] +## +## WARNING: +## This function define CACHE variables you can use after : +## * ${prefix}_WIN3RDPARTY_USE : allow to check/downloaded win3rdParty dir (it will force the cached variables for this dependency folder generally _DIR>) +## * ${prefix}_WIN3RDPARTY_DIR : where is your local win3rdParty dir (the PATH) +## * ${prefix}_WIN3RDPARTY_VCID : [if VCID flag is used] the MSVC id (commonly used to prefix/suffix library name, see boost or CGAL) +## +## If you want to add a win3rdParty version, please: +## 1- build dependencies on your local side with the compiler you want +## 2- build your own zip with your built dependencies +## 3- upload it (onto the forge where the project is stored) and copy the link location in order to use it for this function +## 4- if you just introduced a new MSVC version, add it to the MSVC_VERSIONS_LIST bellow +## +## In a second pass, you can also use this function to set necessary cmake cached variables in order to let cmake find packages of these 3rdParty. +## +## Usage 2: +## win3rdParty( [VERBOSE] MULTI_SET|SET +## CHECK_CACHED_VAR [LIST] [DOC ] +## [ CHECK_CACHED_VAR [LIST] [DOC ] ] [...] +## +## * MULTI_SET or SET flags are used to tell cmake that all next arguments will use repeated flags with differents entries (SET mean we will provide only one set of arguments, without repetition) +## * CHECK_CACHED_VAR are the repeated flag which contain differents entries +## * is the cmake variable you want to be cached for the project +## * is the kind of cmake variable (couble be: FILEPATH; PATH; STRING or BOOL) => see check_cached_var. +## * LIST optional flag could be used with CHECK_CACHED_VAR when = STRING. It allow to handle multiple STRINGS value list. +## * is the value of the variable (if FILEPATH, PATH or STRING: use quotes, if BOOL : use ON/OFF) +## * DOC optional flag is used to have a tooltips info about this new cmake variable entry into the GUI (use quotes). +## +## Full example 1 : +## win3rdParty(COMMON MSVC11 "win3rdParty-MSVC11" "https://path.to/an.archive.7z" +## SET CHECK_CACHED_VAR SuiteSparse_DIR PATH "SuiteSparse-4.2.1" DOC "default empty doc" +## ) +## +## WARNING: +## For the 2nd usage (with MULTI_SET), if you planned to set some CACHED_VAR using/composed by ${prefix}_WIN3RDPARTY_* just set in this macro (usage 1), +## then (due to the not yet existing var) you will need to call this function 2 times : +## One for the 1st usage (downloading of the current compiler 3rdParty). +## One for the MLUTI_SET flag which will use existsing ${prefix}_WIN3RDPARTY_* cached var. +## +## Full example 2 : +## win3rdParty(COMMON MSVC11 "win3rdParty-MSVC11" "https://path.to/an.archive.7z") +## win3rdParty(COMMON MULTI_SET +## CHECK_CACHED_VAR CGAL_INCLUDE_DIR PATH "CGAL-4.3/include" DOC "default empty doc" +## CHECK_CACHED_VAR CGAL_LIBRARIES STRING LIST "debug;CGAL-4.3/lib${LIB_POSTFIX}/CGAL-${WIN3RDPARTY_COMMON_VCID}-mt-gd-4.3.lib;optimized;CGAL-4.3/lib${LIB_POSTFIX}/CGAL-${WIN3RDPARTY_COMMON_VCID}-mt-4.3.lib" +## +## +## WARNING: This function use internaly : +## * downloadAndExtractZipFile.cmake +## * parse_arguments_multi.cmake +## * check_cached_var macro +## +function(win3rdParty prefix ) + + # ARGV: list of all arguments given to the macro/function + # ARGN: list of remaining arguments + + if(NOT WIN32) + return() + endif() + + ## set the handled version of MSVC + ## if you plan to add a win3rdParty dir to download with a new MSVC version: build the win3rdParty dir and add the MSCV entry here. + set(MSVC_VERSIONS_LIST "MSVC17;MSVC11;MSVC12;MSVC14") + + #include(CMakeParseArguments) # CMakeParseArguments is obsolete since cmake 3.5 + # cmake_parse_arguments ( args) + # : options (flags) pass to the macro + # : options that neeed a value + # : options that neeed more than one value + cmake_parse_arguments(w3p "VCID" "VERBOSE;TIMEOUT;DEFAULT_USE" "${MSVC_VERSIONS_LIST};MULTI_SET;SET" ${ARGN}) + + # message(STATUS "value of w3p_VCID = ${w3p_VCID}") + # message(STATUS "value of w3p_VERBOSE = ${w3p_VERBOSE}") + # message(STATUS "value of w3p_TIMEOUT = ${w3p_TIMEOUT}") + # message(STATUS "value of w3p_DEFAULT_USE = ${w3p_DEFAULT_USE}") + + # foreach (loop_var ${MSVC_VERSIONS_LIST}) + # message(STATUS "value of w3p_${loop_var} = ${w3p_${loop_var}}") + # endforeach(loop_var) + + # message(STATUS "value of w3p_MULTI_SET = ${w3p_MULTI_SET}") + # message(STATUS "value of w3p_SET = ${w3p_SET}") + + # message("values for MSVC = ${w3p_MSVC14}") + + if(NOT w3p_TIMEOUT) + set(w3p_TIMEOUT 300) + endif() + + if(NOT DEFINED w3p_DEFAULT_USE) + set(w3p_DEFAULT_USE ON) + endif() + + + ## 1st use (check/update|download) : + set(${prefix}_WIN3RDPARTY_USE ${w3p_DEFAULT_USE} CACHE BOOL "Use required 3rdParty binaries from ${prefix}_WIN3RDPARTY_DIR or download it if not exist") + + + ## We want to test if each version of MSVC was filled by the function (see associated parameters) + ## As CMake is running only for one version of MSVC, if that MSVC version was filled, we get back associated parameters, + ## otherwise we can't use the downloadAndExtractZipFile with win3rdParty. + set(enableWin3rdParty OFF) + + foreach(MSVC_VER ${MSVC_VERSIONS_LIST}) + if(${MSVC_VER} AND w3p_${MSVC_VER} OR ${MSVC_TOOLSET_VERSION} EQUAL 143 AND ${MSVC_VER} STREQUAL "MSVC17") + list(LENGTH w3p_${MSVC_VER} count) + if("${count}" LESS "2") + #message(WARNING "You are using ${MSVC_VER} with ${prefix}_WIN3RDPARTY_USE=${${prefix}_WIN3RDPARTY_USE}, but win3rdParty function isn't filled for ${MSVC_VER}!") + else() + list(GET w3p_${MSVC_VER} 0 Win3rdPartyName) + list(GET w3p_${MSVC_VER} 1 Win3rdPartyUrl) + if(w3p_VCID) + ## try to get the VcId of MSVC. See also MSVC_VERSION cmake var in the doc. + string(REGEX REPLACE "MS([A-Za-z_0-9-]+)" "\\1" vcId ${MSVC_VER}) + string(TOLOWER ${vcId} vcId) + set(${prefix}_WIN3RDPARTY_VCID "${vcId}0" CACHE STRING "the MSVC id (commonly used to prefix/suffix library name, see boost or CGAL)") + mark_as_advanced(${prefix}_WIN3RDPARTY_VCID) + endif() + set(enableWin3rdParty ON) + set(suffixCompilerID ${MSVC_VER}) + break() + endif() + endif() + endforeach() + ## If previous step succeed to get MSVC dirname and URL of the current MSVC version, use it to auto download/update the win3rdParty dir + if(enableWin3rdParty AND ${prefix}_WIN3RDPARTY_USE) + + if(IS_ABSOLUTE "${Win3rdPartyName}") + else() + set(Win3rdPartyName "${CMAKE_BINARY_DIR}/${Win3rdPartyName}") + endif() + + if(NOT EXISTS "${Win3rdPartyName}") + file(MAKE_DIRECTORY ${Win3rdPartyName}) + endif() + + include(downloadAndExtractZipFile) + downloadAndExtractZipFile( "${Win3rdPartyUrl}" ## URL link location + "Win3rdParty-${prefix}-${suffixCompilerID}.7z" ## where download it: relative path, so default to CMAKE_BINARY_DIR + "${Win3rdPartyName}" ## where extract it : fullPath (default relative to CMAKE_BINARY_DIR) + CHECK_DIRTY_URL "${Win3rdPartyName}/Win3rdPartyUrl" ## last downloaded url file : fullPath (default relative to CMAKE_BINARY_DIR) + TIMEOUT ${w3p_TIMEOUT} + VERBOSE ${w3p_VERBOSE} + ) + file(GLOB checkDl "${Win3rdPartyName}/*") + list(LENGTH checkDl checkDlCount) + if("${checkDlCount}" GREATER "1") + else() + message("The downloadAndExtractZipFile didn't work...?") + set(enableWin3rdParty OFF) + endif() + endif() + + ## Try to auto set ${prefix}_WIN3RDPARTY_DIR or let user set it manually + set(${prefix}_WIN3RDPARTY_DIR "" CACHE PATH "windows ${Win3rdPartyName} dir to ${prefix} dependencies of the project") + + if(NOT ${prefix}_WIN3RDPARTY_DIR AND ${prefix}_WIN3RDPARTY_USE) + if(EXISTS "${Win3rdPartyName}") + unset(${prefix}_WIN3RDPARTY_DIR CACHE) + set(${prefix}_WIN3RDPARTY_DIR "${Win3rdPartyName}" CACHE PATH "dir to ${prefix} dependencies of the project") + endif() + endif() + + if(EXISTS ${${prefix}_WIN3RDPARTY_DIR}) + message(STATUS "Found a 3rdParty ${prefix} dir : ${${prefix}_WIN3RDPARTY_DIR}.") + set(enableWin3rdParty ON) + elseif(${prefix}_WIN3RDPARTY_USE) + message(WARNING "${prefix}_WIN3RDPARTY_USE=${${prefix}_WIN3RDPARTY_USE} but ${prefix}_WIN3RDPARTY_DIR=${${prefix}_WIN3RDPARTY_DIR}.") + set(enableWin3rdParty OFF) + endif() + + ## Final check + if(NOT enableWin3rdParty) + message("Disable ${prefix}_WIN3RDPARTY_USE (cmake cached var will be not set), due to a win3rdParty problem.") + message("You still can set ${prefix}_WIN3RDPARTY_DIR to an already downloaded Win3rdParty directory location.") + set(${prefix}_WIN3RDPARTY_USE OFF CACHE BOOL "Use required 3rdParty binaries from ${prefix}_WIN3RDPARTY_DIR or download it if not exist" FORCE) + endif() + + ## 2nd use : handle multi values args to set cached cmake variables in order to ease the next find_package call + if(${prefix}_WIN3RDPARTY_USE AND ${prefix}_WIN3RDPARTY_DIR) + if(w3p_VERBOSE) + message(STATUS "Try to set cmake cached variables for ${prefix} required libraries directly from : ${${prefix}_WIN3RDPARTY_DIR}.") + endif() + + include(parse_arguments_multi) + # message (STATUS "before defining an override of parse_arguments_multi_function") + function(parse_arguments_multi_function ) ## overloaded function to handle all CHECK_CACHED_VAR values list (see: parse_arguments_multi) + # message(STATUS "inside overloaded parse_arguments_multi_function defined in Win3rdParty.cmake") + # message(STATUS ${ARGN}) + ## we know the function take 3 args : var cacheType resetedCachedValue (see check_cached_var) + cmake_parse_arguments(pamf "" "DOC" "LIST" ${ARGN}) + + ## var and cacheType are mandatory (with the resetedCachedValue) + set(var ${ARGV0}) + set(cacheType ${ARGV1}) + # message(STATUS "var=${var} and cacheType=${cacheType} list=${pamf_LIST}") + if(pamf_DOC) + set(cacheDoc ${pamf_DOC}) + else() + set(cacheDoc "") + endif() + if(pamf_LIST) + set(value ${pamf_LIST}) + else() + # message("USING ARGV2 with value ${ARGV2}") + set(value ${ARGV2}) + endif() + # message("inside override function in Win3rdparty.cmake value+ ${value}") + if("${cacheType}" MATCHES "PATH" AND EXISTS "${${prefix}_WIN3RDPARTY_DIR}/${value}") + # message("math with path") + set(resetedCachedValue "${${prefix}_WIN3RDPARTY_DIR}/${value}") ## path relative to ${prefix}_WIN3RDPARTY_DIR + elseif ("${cacheType}" MATCHES "PATH" AND EXISTS "${${prefix}_WIN3RDPARTY_DIR}") + set(resetedCachedValue "${${prefix}_WIN3RDPARTY_DIR}") ## path relative to ${prefix}_WIN3RDPARTY_DIR + elseif("${cacheType}" MATCHES "STRING") + foreach(var IN LISTS value) + if(EXISTS "${${prefix}_WIN3RDPARTY_DIR}/${var}") + list(APPEND resetedCachedValue "${${prefix}_WIN3RDPARTY_DIR}/${var}") ## string item of the string list is a path => make relative to ${prefix}_WIN3RDPARTY_DIR + else() + list(APPEND resetedCachedValue ${var}) ## string item of the string list is not an existing path => simply use the item + endif() + endforeach() + else() + set(resetedCachedValue "${value}") ## could be a BOOL or a STRING + endif() + + ## call our macro to reset cmake cache variable if empty + check_cached_var(${var} "${resetedCachedValue}" ${cacheType} "${cacheDoc}" FORCE) + + endfunction() + # message (STATUS "after defining an override of parse_arguments_multi_function") + + if(w3p_MULTI_SET) + parse_arguments_multi(CHECK_CACHED_VAR w3p_MULTI_SET ${w3p_MULTI_SET}) ## internaly will call our overloaded parse_arguments_multi_function + elseif(w3p_SET) + # message("calling set version of parse_arguments_multi with w3p_set = ${w3p_SET}") + parse_arguments_multi(CHECK_CACHED_VAR w3p_SET ${w3p_SET}) + endif() + + endif() + +endfunction() + +## cmake variables introspection to globally activate/deactivate ${prefix}_WIN3RDPARTY_USE +## This "one shot" call (only one for the next cmake configure) will automatically then reset the global variable WIN3RDPARTY_USE to UserDefined (do nothing). +## use (call it) before and after the call of all your win3rdParty functions +function(Win3rdPartyGlobalCacheAction ) + set(WIN3RDPARTY_USE "UserDefined" CACHE STRING "Choose how to handle all cmake cached *_WIN3RDPARTY_USE for the next configure.\nCould be:\nUserDefined [default]\nActivateAll\nDesactivateAll" ) + set_property(CACHE WIN3RDPARTY_USE PROPERTY STRINGS "UserDefined;ActivateAll;DesactivateAll" ) + if(${WIN3RDPARTY_USE} MATCHES "UserDefined") + else() + if(${WIN3RDPARTY_USE} MATCHES "ActivateAll") + set(win3rdPvalue ON) + elseif(${WIN3RDPARTY_USE} MATCHES "DesactivateAll") + set(win3rdPvalue OFF) + endif() + get_cmake_property(_variableNames CACHE_VARIABLES) + foreach (_variableName ${_variableNames}) + string(REGEX MATCH "[A-Za-z_0-9-]+_WIN3RDPARTY_USE" win3rdpartyUseCacheVar ${_variableName}) + if(win3rdpartyUseCacheVar) + string(REGEX REPLACE "([A-Za-z_0-9-]+_WIN3RDPARTY_USE)" "\\1" win3rdpartyUseCacheVar ${_variableName}) + set(${win3rdpartyUseCacheVar} ${win3rdPvalue} CACHE BOOL "Use required 3rdParty binaries from ${prefix}_WIN3RDPARTY_DIR or download it if not exist" FORCE) + message(STATUS "${win3rdpartyUseCacheVar} cached variable set to ${win3rdPvalue}.") + endif() + endforeach() + set(WIN3RDPARTY_USE "UserDefined" CACHE STRING "Choose how to handle all cmake cached *_WIN3RDPARTY_USE for the next configure.\nCould be:\nUserDefined [default]\nActivateAll\nDesactivateAll" FORCE) + message(STATUS "reset WIN3RDPARTY_USE to UserDefined.") + endif() + mark_as_advanced(WIN3RDPARTY_USE) +endfunction() diff --git a/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/cmake_policies.cmake b/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/cmake_policies.cmake new file mode 100644 index 0000000000000000000000000000000000000000..679fd8427d4c503ac420fc566a2ec4ae5c2825fc --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/cmake_policies.cmake @@ -0,0 +1,19 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +if(__set_policies_INCLUDED__) + return() +else() + set(__set_policies_INCLUDED__ ON) +endif() + +macro(setPolicies) + # No more policies to enforce +endmacro() diff --git a/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/dependencies.cmake b/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/dependencies.cmake new file mode 100644 index 0000000000000000000000000000000000000000..947f88fb75a35ab86e65f8085e1302eea05695d6 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/dependencies.cmake @@ -0,0 +1,292 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +## Included once for all sub project. +## It contain the whole cmake instructions to find necessary common dependencies. +## 3rdParty (provided by sibr_addlibrary win3rdParty or from external packages) are then available in cmake sub projects. +## +## Do not include this file more than once but you can modify it to fit to your own project. +## So please, read it carefully because you can use on of these dependencies for your project or appen new one. +## +## As it is included after camke options, you can use conditional if()/endif() to encapsulate your 3rdParty. +## + +## win3rdParty function allowing to auto check/download/update binaries dependencies for current windows compiler +## Please open this file in order to get more documentation and usage examples. +include(Win3rdParty) + +include(sibr_library) + +Win3rdPartyGlobalCacheAction() + +find_package(OpenGL REQUIRED) + +############ +## Find GLEW +############ +if (MSVC11 OR MSVC12) + set(glew_multiset_arguments + CHECK_CACHED_VAR GLEW_INCLUDE_DIR PATH "glew-1.10.0/include" DOC "default empty doc" + CHECK_CACHED_VAR GLEW_LIBRARIES STRING LIST "debug;glew-1.10.0/${LIB_BUILT_DIR}/glew32d.lib;optimized;glew-1.10.0/${LIB_BUILT_DIR}/glew32.lib" DOC "default empty doc" + ) +elseif (MSVC14 OR MSVC17) + set(glew_multiset_arguments + CHECK_CACHED_VAR GLEW_INCLUDE_DIR PATH "glew-2.0.0/include" DOC "default empty doc" + CHECK_CACHED_VAR GLEW_SHARED_LIBRARY_RELEASE PATH "glew-2.0.0/${LIB_BUILT_DIR}/glew32.lib" + CHECK_CACHED_VAR GLEW_STATIC_LIBRARY_RELEASE PATH "glew-2.0.0/${LIB_BUILT_DIR}/glew32s.lib" + CHECK_CACHED_VAR GLEW_SHARED_LIBRARY_DEBUG PATH "glew-2.0.0/${LIB_BUILT_DIR}/glew32d.lib" + CHECK_CACHED_VAR GLEW_STATIC_LIBRARY_DEBUG PATH "glew-2.0.0/${LIB_BUILT_DIR}/glew32sd.lib" + ) +else () + message("There is no provided GLEW library for your version of MSVC") +endif() +sibr_addlibrary(NAME GLEW #VERBOSE ON + MSVC11 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC11-splitted%20version/glew-1.10.0.7z" + MSVC12 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC11-splitted%20version/glew-1.10.0.7z" + MSVC14 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC15-splitted%20version/glew-2.0.0.7z" # using recompiled version of glew + MULTI_SET ${glew_multiset_arguments} +) +set(GLEW_VERBOSE ON) +FIND_PACKAGE(GLEW REQUIRED) +IF(GLEW_FOUND) + INCLUDE_DIRECTORIES(${GLEW_INCLUDE_DIR}) +ELSE(GLEW_FOUND) + MESSAGE("GLEW not found. Set GLEW_DIR to base directory of GLEW.") +ENDIF(GLEW_FOUND) + + +############## +## Find ASSIMP +############## +if (MSVC11 OR MSVC12) + set(assimp_set_arguments + CHECK_CACHED_VAR ASSIMP_DIR PATH "Assimp_3.1_fix" + ) +elseif (MSVC14 OR MSVC17) + set(assimp_set_arguments + CHECK_CACHED_VAR ASSIMP_DIR PATH "Assimp-4.1.0" + ) +else () + message("There is no provided ASSIMP library for your version of MSVC") +endif() + +sibr_addlibrary(NAME ASSIMP #VERBOSE ON + MSVC11 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC11-splitted%20version/Assimp_3.1_fix.7z" + MSVC12 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC11-splitted%20version/Assimp_3.1_fix.7z" + MSVC14 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC15-splitted%20version/Assimp-4.1.0.7z" + MULTI_SET + ${assimp_set_arguments} +) + +find_package(ASSIMP REQUIRED) +include_directories(${ASSIMP_INCLUDE_DIR}) + +################ +## Find FFMPEG +################ +sibr_addlibrary(NAME FFMPEG + MSVC11 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC11-splitted%20version/ffmpeg.zip" + MSVC12 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC11-splitted%20version/ffmpeg.zip" + MSVC14 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC15-splitted%20version/ffmpeg-4.0.2-win64-win3rdParty.7z" + SET CHECK_CACHED_VAR FFMPEG_DIR PATH ${FFMPEG_WIN3RDPARTY_DIR} +) +find_package(FFMPEG QUIET) +include_directories(${FFMPEG_INCLUDE_DIR}) + +################### +## Find embree3 +################### +sibr_addlibrary( + NAME embree3 + MSVC11 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC11-splitted%20version/embree2.7.0.x64.windows.7z" + MSVC14 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC15-splitted%20version/embree-3.6.1.x64.vc14.windows.7z" # TODO SV: provide a valid version if required +) + +################### +## Find eigen3 +################### +sibr_addlibrary( + NAME eigen3 + #MSVC11 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC11-splitted%20version/eigen-eigen-dc6cfdf9bcec.7z" + #MSVC14 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC11-splitted%20version/eigen-eigen-dc6cfdf9bcec.7z" # TODO SV: provide a valid version if required + MSVC11 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC15-splitted%20version/eigen3.7z" + MSVC14 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC15-splitted%20version/eigen3.7z" + SET CHECK_CACHED_VAR eigen3_DIR PATH "eigen/share/eigen3/cmake" +) +include_directories(/usr/include/eigen3) +add_definitions(-DEIGEN_INITIALIZE_MATRICES_BY_ZERO) + +############# +## Find Boost +############# +set(Boost_REQUIRED_COMPONENTS "system;chrono;filesystem;date_time" CACHE INTERNAL "Boost Required Components") + +if (WIN32) + # boost multiset arguments + if (MSVC11 OR MSVC12) + set(boost_multiset_arguments + CHECK_CACHED_VAR BOOST_ROOT PATH "boost_1_55_0" + CHECK_CACHED_VAR BOOST_INCLUDEDIR PATH "boost_1_55_0" + CHECK_CACHED_VAR BOOST_LIBRARYDIR PATH "boost_1_55_0/${LIB_BUILT_DIR}" + #CHECK_CACHED_VAR Boost_COMPILER STRING "-${Boost_WIN3RDPARTY_VCID}" DOC "vcid (eg: -vc110 for MSVC11)" + CHECK_CACHED_VAR Boost_COMPILER STRING "-vc110" DOC "vcid (eg: -vc110 for MSVC11)" # NOTE: if it doesnt work, uncomment this option and set the right value for VisualC id + ) + elseif (MSVC14 OR MSVC17) + set(boost_multiset_arguments + CHECK_CACHED_VAR BOOST_ROOT PATH "boost-1.71" + CHECK_CACHED_VAR BOOST_INCLUDEDIR PATH "boost-1.71" + CHECK_CACHED_VAR BOOST_LIBRARYDIR PATH "boost-1.71/${LIB_BUILT_DIR}" + CHECK_CACHED_VAR Boost_COMPILER STRING "-vc141" DOC "vcid (eg: -vc110 for MSVC11)" # NOTE: if it doesnt work, uncomment this option and set the right value for VisualC id + ) + + option(BOOST_MINIMAL_VERSION "Only get minimal Boost dependencies" ON) + + if(${BOOST_MINIMAL_VERSION}) + set(BOOST_MSVC14_ZIP "boost-1.71-ibr-minimal.7z") + else() + set(BOOST_MSVC14_ZIP "boost-1.71.7z") + endif() + else () + message("There is no provided Boost library for your version of MSVC") + endif() + + sibr_addlibrary(NAME Boost VCID TIMEOUT 600 #VERBOSE ON + MSVC11 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC11-splitted%20version/boost_1_55_0.7z" + MSVC12 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC11-splitted%20version/boost_1_55_0.7z" + MSVC14 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC15-splitted%20version/${BOOST_MSVC14_ZIP}" # boost compatible with msvc14 + MULTI_SET ${boost_multiset_arguments} + CHECK_CACHED_VAR Boost_NO_SYSTEM_PATHS BOOL ON DOC "Set to ON to disable searching in locations not specified by these boost cached hint variables" + CHECK_CACHED_VAR Boost_NO_BOOST_CMAKE BOOL ON DOC "Set to ON to disable the search for boost-cmake (package cmake config file if boost was built with cmake)" + ) + if(NOT Boost_COMPILER AND Boost_WIN3RDPARTY_USE) + message(WARNING "Boost_COMPILER is not set and it's needed.") + endif() +endif() + +find_package(Boost 1.71.0 REQUIRED COMPONENTS ${Boost_REQUIRED_COMPONENTS}) + +if(WIN32) + add_compile_options("$<$:/EHsc>") + #add_definitions(/EHsc) +endif() + +if(Boost_LIB_DIAGNOSTIC_DEFINITIONS) + add_definitions(${Boost_LIB_DIAGNOSTIC_DEFINITIONS}) +endif() + +#if(WIN32) + add_definitions(-DBOOST_ALL_DYN_LINK -DBOOST_ALL_NO_LIB) +#endif() + +include_directories(${BOOST_INCLUDEDIR} ${Boost_INCLUDE_DIRS}) +link_directories(${BOOST_LIBRARYDIR} ${Boost_LIBRARY_DIRS}) + + +############## +## Find OpenMP +############## +find_package(OpenMP) + +sibr_addlibrary( + NAME NativeFileDialog + MSVC14 "https://repo-sam.inria.fr/fungraph/dependencies/sibr/~0.9/nfd.7z" +) + +############## +## Find OpenCV +############## +if (WIN32) + if (${MSVC_TOOLSET_VERSION} EQUAL 143) + MESSAGE("SPECIAL OPENCV HANDLING") + set(opencv_set_arguments + CHECK_CACHED_VAR OpenCV_DIR PATH "install" ## see OpenCVConfig.cmake + ) + elseif (MSVC11 OR MSVC12) + set(opencv_set_arguments + CHECK_CACHED_VAR OpenCV_DIR PATH "opencv/build" ## see OpenCVConfig.cmake + ) + elseif (MSVC14) + set(opencv_set_arguments + CHECK_CACHED_VAR OpenCV_DIR PATH "opencv-4.5.0/build" ## see OpenCVConfig.cmake + ) + else () + message("There is no provided OpenCV library for your compiler, relying on find_package to find it") + endif() +else() + message("There is no provided OpenCV library for your compiler, relying on find_package to find it") +endif() + +sibr_addlibrary(NAME OpenCV #VERBOSE ON + MSVC11 "https://repo-sam.inria.fr/fungraph/dependencies/sibr/~0.9/opencv.7z" + MSVC12 "https://repo-sam.inria.fr/fungraph/dependencies/sibr/~0.9/opencv.7z" + MSVC14 "https://repo-sam.inria.fr/fungraph/dependencies/sibr/~0.9/opencv-4.5.0.7z" # opencv compatible with msvc14 and with contribs + MSVC17 "https://repo-sam.inria.fr/fungraph/dependencies/sibr/~0.9/opencv4-8.7z" + SET ${opencv_set_arguments} + ) +find_package(OpenCV REQUIRED) ## Use directly the OpenCVConfig.cmake provided + + ##https://stackoverflow.com/questions/24262081/cmake-relwithdebinfo-links-to-debug-libs +set_target_properties(${OpenCV_LIBS} PROPERTIES MAP_IMPORTED_CONFIG_RELWITHDEBINFO RELEASE) + +add_definitions(-DOPENCV_TRAITS_ENABLE_DEPRECATED) + +if(OpenCV_INCLUDE_DIRS) + foreach(inc ${OpenCV_INCLUDE_DIRS}) + if(NOT EXISTS ${inc}) + set(OpenCV_INCLUDE_DIR "" CACHE PATH "additional custom include DIR (in case of trouble to find it (fedora 17 opencv package))") + endif() + endforeach() + if(OpenCV_INCLUDE_DIR) + list(APPEND OpenCV_INCLUDE_DIRS ${OpenCV_INCLUDE_DIR}) + include_directories(${OpenCV_INCLUDE_DIRS}) + endif() +endif() + +################### +## Find GLFW +################### +sibr_addlibrary( + NAME GLFW + MSVC11 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC15-splitted%20version/glfw-3.2.1.7z" + MSVC14 "https://repo-sam.inria.fr/fungraph/dependencies/ibr-common/win3rdParty-MSVC15-splitted%20version/glfw-3.2.1.7z" # TODO SV: provide a valid version if required +) + +sibr_gitlibrary(TARGET imgui + GIT_REPOSITORY "https://gitlab.inria.fr/sibr/libs/imgui.git" + GIT_TAG "e7f0fa31b9fa3ee4ecd2620b9951f131b4e377c6" +) + +sibr_gitlibrary(TARGET mrf + GIT_REPOSITORY "https://gitlab.inria.fr/sibr/libs/mrf.git" + GIT_TAG "564e5e0b395c788d2f8b2cf4f879fed2493faea7" +) + +sibr_gitlibrary(TARGET nanoflann + GIT_REPOSITORY "https://gitlab.inria.fr/sibr/libs/nanoflann.git" + GIT_TAG "7a20a9ac0a1d34850fc3a9e398fc4a7618e8a69a" +) + +sibr_gitlibrary(TARGET picojson + GIT_REPOSITORY "https://gitlab.inria.fr/sibr/libs/picojson.git" + GIT_TAG "7cf8feee93c8383dddbcb6b64cf40b04e007c49f" +) + +sibr_gitlibrary(TARGET rapidxml + GIT_REPOSITORY "https://gitlab.inria.fr/sibr/libs/rapidxml.git" + GIT_TAG "069e87f5ec5ce1745253bd64d89644d6b894e516" +) + +sibr_gitlibrary(TARGET xatlas + GIT_REPOSITORY "https://gitlab.inria.fr/sibr/libs/xatlas.git" + GIT_TAG "0fbe06a5368da13fcdc3ee48d4bdb2919ed2a249" + INCLUDE_DIRS "source/xatlas" +) + +Win3rdPartyGlobalCacheAction() diff --git a/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/downloadAndExtractZipFile.cmake b/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/downloadAndExtractZipFile.cmake new file mode 100644 index 0000000000000000000000000000000000000000..7f5fc2bb080fc158840125e69c3d36d169b69235 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/downloadAndExtractZipFile.cmake @@ -0,0 +1,243 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +## downloadAndExtractZipFile cmake function +## Provide a way to download zip file from public internet ZIP_URL host +## and to extract it in a specific EXCTRATED_ZIP_PATH destination. +## This function use 7-Zip external tool to maximize the compatibles formats. +## This will be not download again if the EXCTRATED_ZIP_PATH already exist and DL_FORCE is set to OFF. +## This will try to unzip file if already exist in the ZIP_DL_PATH. +## +## If EXCTRATED_ZIP_PATH and/or ZIP_DL_PATH are not full path, +## it will be interpreted relative to CMAKE_BINARY_DIR +## +## Usage example : +## include(downloadAndExtractZipFile) +## downloadAndExtractZipFile( +## http://www.cs.cornell.edu/~snavely/bundler/distr/bundler-v0.4-source.zip +## ${CMAKE_BINARY_DIR}/Bundler/bundler-v0.4-source.zip +## ${CMAKE_BINARY_DIR}/Bundler +## [DL_FORCE ON|OFF] +## [TIMEOUT] +## [CHECK_DIRTY_URL] +## ) +## +## option DL_FORCE will redownload the zip file [deafult to OFF] +## option TIMEOUT will end the unzip process after this period of time [default to 600s] +## option CHECK_DIRTY_URL will write into the given file the downloaded URL and then, +## next time, if the URL was updated, it detect it with this file +## and will download the last version. This prevent to alway set manually DL_FORCE to ON... +## +if(__downloadAndExtractZipFile_cmake_INCLUDED__) + return() +else() + set(__downloadAndExtractZipFile_cmake_INCLUDED__ ON) +endif() + +function(downloadAndExtractZipFile ZIP_URL ZIP_DL_PATH EXCTRATED_ZIP_PATH) + + # message(STATUS "zipUrl=${ZIP_URL} zipDlPath=${ZIP_DL_PATH} extractedZipPath=${EXCTRATED_ZIP_PATH}") + cmake_parse_arguments(dwnlezf "" "VERBOSE;DL_FORCE;TIMEOUT;CHECK_DIRTY_URL" "" ${ARGN}) + + set(PROGRAMFILESx86 "PROGRAMFILES(x86)") + + ## Check entries mandatory args + if(IS_ABSOLUTE "${ZIP_DL_PATH}") + else() + set(ZIP_DL_PATH "${CMAKE_BINARY_DIR}/${ZIP_DL_PATH}") + endif() + if(IS_ABSOLUTE "${EXCTRATED_ZIP_PATH}") + else() + set(EXCTRATED_ZIP_PATH "${CMAKE_BINARY_DIR}/${EXCTRATED_ZIP_PATH}") + endif() + if(NOT EXISTS "${EXCTRATED_ZIP_PATH}") + file(MAKE_DIRECTORY ${EXCTRATED_ZIP_PATH}) + endif() + + # SB: Once, one of downloaded zip was corrupted by an error message coming from the server. + if(EXISTS "${ZIP_DL_PATH}") + # So I check for removing such corrupted files + message("Removing previous ${ZIP_DL_PATH} (might be corrupted)") + file(REMOVE "${ZIP_DL_PATH}") + if(EXISTS "${dwnlezf_CHECK_DIRTY_URL}") + # and remove the previous (corrupted) made 'Win3rdPartyUrl' file + file(REMOVE "${dwnlezf_CHECK_DIRTY_URL}") + endif() + endif() + + ## Check entries optional args + macro(readDirtyUrl ) + if(dwnlezf_CHECK_DIRTY_URL) + if(IS_ABSOLUTE "${dwnlezf_CHECK_DIRTY_URL}") + else() + set(dwnlezf_CHECK_DIRTY_URL "${CMAKE_BINARY_DIR}/${dwnlezf_CHECK_DIRTY_URL}") + endif() + get_filename_component(unzipDir ${EXCTRATED_ZIP_PATH} NAME) + get_filename_component(unzipPath ${EXCTRATED_ZIP_PATH} PATH) + message(STATUS "Checking ${unzipDir} [from ${unzipPath}]...") + if(EXISTS "${dwnlezf_CHECK_DIRTY_URL}") + get_filename_component(CHECK_DIRTY_URL_FILENAME ${dwnlezf_CHECK_DIRTY_URL} NAME) + file(STRINGS "${dwnlezf_CHECK_DIRTY_URL}" contents) + list(GET contents 0 downloadURL) + list(REMOVE_AT contents 0) + if("${downloadURL}" MATCHES "${ZIP_URL}") + if(dwnlezf_VERBOSE) + message(STATUS "Your downloaded version (URL) seems to be up to date. Let me check if nothing is missing... (see ${dwnlezf_CHECK_DIRTY_URL}).") + endif() + file(GLOB PATHNAME_PATTERN_LIST "${EXCTRATED_ZIP_PATH}/*") ## is there something inside the downloaded destination ? + unset(NAME_PATTERN_LIST) + foreach(realPathPattern ${PATHNAME_PATTERN_LIST}) + get_filename_component(itemName ${realPathPattern} NAME) + list(APPEND NAME_PATTERN_LIST ${itemName}) + endforeach() + if(NAME_PATTERN_LIST) + foreach(item ${contents}) + list(FIND NAME_PATTERN_LIST ${item} id) + if(${id} MATCHES "-1") + message(STATUS "${item} is missing, your downloaded version content changed, need to redownload it.") + set(ZIP_DL_FORCE ON) + break() + else() + list(REMOVE_AT NAME_PATTERN_LIST ${id}) + set(ZIP_DL_FORCE OFF) + endif() + endforeach() + if(NOT ZIP_DL_FORCE AND NAME_PATTERN_LIST) + message("Yours seems to be up to date (regarding to ${CHECK_DIRTY_URL_FILENAME})!\nBut there are additional files/folders into your downloaded destination (feel free to clean it if you want).") + foreach(item ${NAME_PATTERN_LIST}) + if(item) + message("${item}") + endif() + endforeach() + endif() + endif() + else() + set(ZIP_DL_FORCE ON) + message(STATUS "Your downloaded version is dirty (too old).") + endif() + else() + file(GLOB PATHNAME_PATTERN_LIST "${EXCTRATED_ZIP_PATH}/*") ## is there something inside the downloaded destination ? + if(NOT PATHNAME_PATTERN_LIST) + message("We found nothing into ${EXCTRATED_ZIP_PATH}, we will try to download it for you now.") + endif() + set(ZIP_DL_FORCE ON) + endif() + endif() + endmacro() + readDirtyUrl() + if(NOT ZIP_DL_FORCE) + return() ## do not need to further (as we are up to date, just exit the function + endif() + + macro(writeDirtyUrl ) + if(dwnlezf_CHECK_DIRTY_URL) + file(WRITE "${dwnlezf_CHECK_DIRTY_URL}" "${ZIP_URL}\n") + file(GLOB PATHNAME_PATTERN_LIST "${EXCTRATED_ZIP_PATH}/*") ## is there something inside the downloaded destination ? + unset(NAME_PATTERN_LIST) + foreach(realPathPattern ${PATHNAME_PATTERN_LIST}) + get_filename_component(itemName ${realPathPattern} NAME) + list(APPEND NAME_PATTERN_LIST ${itemName}) + endforeach() + if(NAME_PATTERN_LIST) + foreach(item ${NAME_PATTERN_LIST}) + file(APPEND "${dwnlezf_CHECK_DIRTY_URL}" "${item}\n") + endforeach() + endif() + endif() + endmacro() + + if(dwnlezf_DL_FORCE) + set(ZIP_DL_FORCE ON) + endif() + + if(NOT dwnlezf_TIMEOUT) + set(dwnlezf_TIMEOUT 600) + endif() + math(EXPR dwnlezf_TIMEOUT_MIN "${dwnlezf_TIMEOUT}/60") + + macro(unzip whichZipFile) + if(NOT SEVEN_ZIP_CMD) + find_program(SEVEN_ZIP_CMD NAMES 7z 7za p7zip DOC "7-zip executable" PATHS "$ENV{PROGRAMFILES}/7-Zip" "$ENV{${PROGRAMFILESx86}}/7-Zip" "$ENV{ProgramW6432}/7-Zip") + endif() + if(SEVEN_ZIP_CMD) + if(dwnlezf_VERBOSE) + message(STATUS "UNZIP: please, WAIT UNTIL ${SEVEN_ZIP_CMD} finished...\n(no more than ${dwnlezf_TIMEOUT_MIN} min)") + else() + message(STATUS "UNZIP...wait...") + endif() + execute_process( COMMAND ${SEVEN_ZIP_CMD} x ${whichZipFile} -y + WORKING_DIRECTORY ${EXCTRATED_ZIP_PATH} TIMEOUT ${dwnlezf_TIMEOUT} + RESULT_VARIABLE resVar OUTPUT_VARIABLE outVar ERROR_VARIABLE errVar + ) + if(${resVar} MATCHES "0") + if(dwnlezf_VERBOSE) + message(STATUS "SUCESS to unzip in ${EXCTRATED_ZIP_PATH}. Now we can remove the downloaded zip file.") + endif() + execute_process(COMMAND ${CMAKE_COMMAND} -E remove ${whichZipFile}) + mark_as_advanced(SEVEN_ZIP_CMD) + else() + message(WARNING "something wrong in ${EXCTRATED_ZIP_PATH}\n with \"${SEVEN_ZIP_CMD} x ${whichZipFile} -y\", redo or try to unzip by yourself...") + message("unzip: resVar=${resVar}") + message("unzip: outVar=${outVar}") + message("unzip: errVar=${errVar}") + message("unzip: failed or canceled or timeout") + endif() + else() + message(WARNING "You need 7zip (http://www.7-zip.org/download.html) to unzip the downloaded dir.") + set(SEVEN_ZIP_CMD "" CACHE FILEPATH "7-zip executable") + mark_as_advanced(CLEAR SEVEN_ZIP_CMD) + endif() + endmacro() + + if(dwnlezf_VERBOSE) + message(STATUS "Trying to look ${ZIP_DL_PATH} if a zip file exist...") + endif() + if(EXISTS "${ZIP_DL_PATH}") + + ## already downloaded, so just unzip it + unzip(${ZIP_DL_PATH}) + writeDirtyUrl() + + elseif(ZIP_DL_FORCE) + + ## the download part (+ unzip) + message(STATUS "Let me try to download package for you : ${ZIP_URL}") + if(dwnlezf_VERBOSE) + message(STATUS "Downloading...\n SRC=${ZIP_URL}\n DEST=${ZIP_DL_PATH}.tmp\n INACTIVITY_TIMEOUT=180s") + endif() + file(DOWNLOAD ${ZIP_URL} ${ZIP_DL_PATH}.tmp INACTIVITY_TIMEOUT 360 STATUS status SHOW_PROGRESS) + + list(GET status 0 numResult) + if(${numResult} MATCHES "0") + + if(dwnlezf_VERBOSE) + message(STATUS "Download succeed, so let me rename the tmp file to unzip it") + endif() + execute_process(COMMAND ${CMAKE_COMMAND} -E rename ${ZIP_DL_PATH}.tmp ${ZIP_DL_PATH}) + unzip(${ZIP_DL_PATH}) + writeDirtyUrl() + + else() + + list(GET status 1 errMsg) + message(WARNING "DOWNLOAD ${ZIP_URL} to ${ZIP_DL_PATH} failed\n:${errMsg}") + message(WARNING "OK, you need to download the ${ZIP_URL} manually and put it into ${ZIP_DL_PATH}") + message("Take a look at the project website page to check available URL.") + + endif() + + endif() + + ## clean up the tmp downloaded file + if(EXISTS "${ZIP_DL_PATH}.tmp") + execute_process(COMMAND ${CMAKE_COMMAND} -E remove ${ZIP_DL_PATH}.tmp) + endif() + +endfunction() diff --git a/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/git_describe.cmake b/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/git_describe.cmake new file mode 100644 index 0000000000000000000000000000000000000000..638d70bd9440fe80ff1844500d3acf8f05e669b8 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/git_describe.cmake @@ -0,0 +1,114 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +if(__git_describe_INCLUDED__) + return() +else() + set(__git_describe_INCLUDED__ ON) +endif() + +find_package(Git) +if(Git_FOUND) + message(STATUS "Git found: ${GIT_EXECUTABLE}") +else() + message(FATAL_ERROR "Git not found. Aborting") +endif() + +macro(git_describe) + cmake_parse_arguments(GIT_DESCRIBE "" "GIT_URL;GIT_BRANCH;GIT_COMMIT_HASH;GIT_TAG;GIT_VERSION;PATH" "" ${ARGN}) + + if(NOT GIT_DESCRIBE_PATH) + set(GIT_DESCRIBE_PATH ${CMAKE_SOURCE_DIR}) + endif() + + if(GIT_DESCRIBE_GIT_URL) + # Get the current remote + execute_process( + COMMAND git remote + WORKING_DIRECTORY ${GIT_DESCRIBE_PATH} + OUTPUT_VARIABLE GIT_DESCRIBE_GIT_REMOTE + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + + # Get the current remote + execute_process( + COMMAND git remote get-url ${GIT_DESCRIBE_GIT_REMOTE} + WORKING_DIRECTORY ${GIT_DESCRIBE_PATH} + OUTPUT_VARIABLE ${GIT_DESCRIBE_GIT_URL} + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + endif() + + if(GIT_DESCRIBE_GIT_BRANCH) + # Get the current working branch + execute_process( + COMMAND git rev-parse --abbrev-ref HEAD + WORKING_DIRECTORY ${GIT_DESCRIBE_PATH} + OUTPUT_VARIABLE ${GIT_DESCRIBE_GIT_BRANCH} + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + endif() + + if(GIT_DESCRIBE_GIT_COMMIT_HASH) + # Get the latest abbreviated commit hash of the working branch + execute_process( + COMMAND git rev-parse HEAD + WORKING_DIRECTORY ${GIT_DESCRIBE_PATH} + OUTPUT_VARIABLE ${GIT_DESCRIBE_GIT_COMMIT_HASH} + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + endif() + + if(GIT_DESCRIBE_GIT_TAG) + # Get the tag + execute_process( + COMMAND git describe --tags --exact-match + WORKING_DIRECTORY ${GIT_DESCRIBE_PATH} + OUTPUT_VARIABLE ${GIT_DESCRIBE_GIT_TAG} + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + endif() + + if(GIT_DESCRIBE_GIT_VERSION) + # Get the version from git describe + execute_process( + COMMAND git describe + WORKING_DIRECTORY ${GIT_DESCRIBE_PATH} + OUTPUT_VARIABLE ${GIT_DESCRIBE_GIT_VERSION} + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + + if(${GIT_DESCRIBE_GIT_VERSION} STREQUAL "") + execute_process( + COMMAND git rev-parse --abbrev-ref HEAD + WORKING_DIRECTORY ${GIT_DESCRIBE_PATH} + OUTPUT_VARIABLE GIT_DESCRIBE_GIT_VERSION_BRANCH + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + execute_process( + COMMAND git log -1 --format=%h + WORKING_DIRECTORY ${GIT_DESCRIBE_PATH} + OUTPUT_VARIABLE GIT_DESCRIBE_GIT_VERSION_COMMIT + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + + set(${GIT_DESCRIBE_GIT_VERSION} "${GIT_DESCRIBE_GIT_VERSION_BRANCH}-${GIT_DESCRIBE_GIT_VERSION_COMMIT}") + endif() + endif() + +endmacro() \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/include_once.cmake b/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/include_once.cmake new file mode 100644 index 0000000000000000000000000000000000000000..d28b39cfeb18e2369ccee1d9f038cfdd71958296 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/include_once.cmake @@ -0,0 +1,22 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +macro(include_once file) + get_filename_component(INCLUDE_ONCE_FILEPATH ${file} REALPATH) + string(REGEX REPLACE "(\\.|\\/+|\\:|\\\\+)" "_" INCLUDE_ONCE_FILEPATH ${INCLUDE_ONCE_FILEPATH}) + get_property(INCLUDED_${INCLUDE_ONCE_FILEPATH}_LOCAL GLOBAL PROPERTY INCLUDED_${INCLUDE_ONCE_FILEPATH}) + if (INCLUDED_${INCLUDE_ONCE_FILEPATH}_LOCAL) + return() + else() + set_property(GLOBAL PROPERTY INCLUDED_${INCLUDE_ONCE_FILEPATH} true) + + include(${file}) + endif() +endmacro() \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/install_runtime.cmake b/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/install_runtime.cmake new file mode 100644 index 0000000000000000000000000000000000000000..3d4b74e6953c97975d9a7378643dbe8e877055b3 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/install_runtime.cmake @@ -0,0 +1,880 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +## This file is mainly used to allow runtime installation +## There are some utilities cmake functions to ease the generic deployement (abstract common usage of cmake)... +## +## You cannot run your programm automaticaly from your CNAKE_BINARY_DIR when you build +## as it will miss all dependencies and ressources files... +## You have to run install target in order to test your programm. +## +## The only one function/macros you may use inside your sub-CMakeLists.txt (sub-project) is : +## ****************** +## ibr_install_target macro => see documentation at the end of this file +## ****************** +## It use these utilities cmake functions to abstract the installation in an uniform way for all sub-projects. +## +if(__install_runtime_cmake_INCLUDED__) + return() +else() + set(__install_runtime_cmake_INCLUDED__ ON) +endif() + + +## +## Allow to write a resource config file which contain additional ressource paths +## (used by IBR_Common Resource system to load shaders and potentialy images, plugins and so on) +## +## ADD option list all the paths to add in the file (relative paths are interpreted relative to working dir of the executable) +## INSTALL option to specify where we want to install this file +## +## Example usage: +## resourceFile(ADD "shaders" "${PROJECT_NAME}_rsc" INSTALL bin) +## +macro(resourceFile) + cmake_parse_arguments(rsc "" "INSTALL;FILE_PATH;CONFIG_TYPE" "ADD" ${ARGN}) ## both args are directory path + + if(rsc_ADD) + unset(IBR_RSC_FILE_CONTENT_LIST) + if(EXISTS "${rsc_FILE_PATH}") + file(READ "${rsc_FILE_PATH}" IBR_RSC_FILE_CONTENT) + string(REGEX REPLACE "\n" ";" IBR_RSC_FILE_CONTENT_LIST "${IBR_RSC_FILE_CONTENT}") + endif() + list(APPEND IBR_RSC_FILE_CONTENT_LIST "${rsc_ADD}") + list(REMOVE_DUPLICATES IBR_RSC_FILE_CONTENT_LIST) + file(WRITE "${rsc_FILE_PATH}" "") + foreach(rscDir ${IBR_RSC_FILE_CONTENT_LIST}) + file(APPEND "${rsc_FILE_PATH}" "${rscDir}\n") + endforeach() + unset(rsc_ADD) + endif() + + if(rsc_INSTALL) + install(FILES ${rsc_FILE_PATH} CONFIGURATIONS ${rsc_CONFIG_TYPE} DESTINATION ${rsc_INSTALL}) + unset(rsc_INSTALL) + endif() +endmacro() + + +## +## Install *.pdb generated file for the current cmake project +## assuming the output target name is the cmake project name. +## This macro is useful for crossplateform multi config mode. +## +## Usage Example: +## +## if(DEFINED CMAKE_BUILD_TYPE) ## for make/nmake based +## installPDB(${PROJECT_NAME} ${CMAKE_BUILD_TYPE} RUNTIME_DEST bin ARCHIVE_DEST lib LIBRARY_DEST lib) +## endif() +## foreach(CONFIG_TYPES ${CMAKE_CONFIGURATION_TYPES}) ## for multi config types (MSVC based) +## installPDB(${PROJECT_NAME} ${CONFIG_TYPES} RUNTIME_DEST bin ARCHIVE_DEST lib LIBRARY_DEST lib) +## endforeach() +## +macro(installPDB targetName configType) + cmake_parse_arguments(instpdb "" "COMPONENT" "ARCHIVE_DEST;LIBRARY_DEST;RUNTIME_DEST" ${ARGN}) ## both args are directory path + + if(NOT MSVC) + return() + endif() + + ## Check if DESTINATION are provided according to the TYPE of the given target (see install command doc to see correspodances) + get_target_property(type ${targetName} TYPE) + if(${type} MATCHES "EXECUTABLE" AND instpdb_RUNTIME_DEST) + set(pdb_DESTINATION ${instpdb_RUNTIME_DEST}) + elseif(${type} MATCHES "STATIC_LIBRARY" AND instpdb_ARCHIVE_DEST) + set(pdb_DESTINATION ${instpdb_ARCHIVE_DEST}) + elseif(${type} MATCHES "MODULE_LIBRARY" AND instpdb_LIBRARY_DEST) + set(pdb_DESTINATION ${instpdb_LIBRARY_DEST}) + elseif(${type} MATCHES "SHARED_LIBRARY") + if(WIN32 AND instpdb_RUNTIME_DEST) + set(pdb_DESTINATION ${instpdb_RUNTIME_DEST}) + else() + set(pdb_DESTINATION ${instpdb_LIBRARY_DEST}) + endif() + endif() + + if(NOT pdb_DESTINATION) + set(pdb_DESTINATION bin) ## default destination of the pdb file + endif() + + if(NOT instpdb_COMPONENT) + set(instpdb_COMPONENT ) + else() + set(instpdb_COMPONENT COMPONENT ${instpdb_COMPONENT}) + endif() + + string(TOUPPER ${configType} CONFIG_TYPES_UC) + get_target_property(PDB_PATH ${targetName} PDB_OUTPUT_DIRECTORY_${CONFIG_TYPES_UC}) + + get_target_property(confModePostfix ${targetName} ${CONFIG_TYPES_UC}_POSTFIX) + if(NOT confModePostfix) + set(confModePostfix "") + endif() + set_target_properties(${targetName} PROPERTIES PDB_NAME_${CONFIG_TYPES_UC} ${targetName}${confModePostfix}) + get_target_property(PDB_NAME ${targetName} PDB_NAME_${CONFIG_TYPES_UC})# if not set, this is empty + + if(EXISTS "${PDB_PATH}/${PDB_NAME}.pdb") + install(FILES "${PDB_PATH}/${PDB_NAME}.pdb" CONFIGURATIONS ${configType} DESTINATION ${pdb_DESTINATION} ${instpdb_COMPONENT} OPTIONAL) + endif() +endmacro() + + +## +## Add additional target to install a project independently and based on its component +## configMode is used to prevent default Release installation (we want also to install in other build/config type) +## +macro(installTargetProject targetOfProject targetOfInstallProject) + if(DEFINED CMAKE_BUILD_TYPE) ## for make/nmake based + set(configMode ${CMAKE_BUILD_TYPE}) + elseif(MSVC) + ## $(Configuration) will be one of the following : Debug, Release, MinSizeRel, RelWithDebInfo + set(configMode $(Configuration)) + endif() + if(configMode) + get_target_property(srcFiles ${targetOfProject} SOURCES) + add_custom_target( ${targetOfInstallProject} #ALL + ${CMAKE_COMMAND} -DBUILD_TYPE=${configMode} -DCOMPONENT=${targetOfInstallProject} -P ${CMAKE_BINARY_DIR}/cmake_install.cmake + DEPENDS ${srcFiles} + COMMENT "run the installation only for ${targetOfProject}" VERBATIM + ) + add_dependencies(${targetOfInstallProject} ${targetOfProject}) + + get_target_property(INSTALL_BUILD_FOLDER ${targetOfProject} FOLDER) + set_target_properties(${targetOfInstallProject} PROPERTIES FOLDER ${INSTALL_BUILD_FOLDER}) + endif() +endmacro() + +# Collect all currently added targets in all subdirectories +# +# Parameters: +# - _result the list containing all found targets +# - _dir root directory to start looking from +function(get_all_targets _result _dir) + get_property(_subdirs DIRECTORY "${_dir}" PROPERTY SUBDIRECTORIES) + foreach(_subdir IN LISTS _subdirs) + get_all_targets(${_result} "${_subdir}") + endforeach() + + get_directory_property(_sub_targets DIRECTORY "${_dir}" BUILDSYSTEM_TARGETS) + set(${_result} ${${_result}} ${_sub_targets} PARENT_SCOPE) +endfunction() + +## +## Add targets for building and installing subdirectories +macro(subdirectory_target target directory build_folder) + add_custom_target(${target} + COMMENT "run build for all projects in this directory" VERBATIM + ) + get_all_targets(ALL_TARGETS ${directory}) + add_dependencies(${target} ${ALL_TARGETS}) + add_custom_target(${target}_install + ${CMAKE_COMMAND} -DBUILD_TYPE=$ -DCOMPONENT=${target}_install -P ${CMAKE_BINARY_DIR}/cmake_install.cmake + COMMENT "run install for all projects in this directory" VERBATIM + ) + add_dependencies(${target}_install ${target}) + + set_target_properties(${target} PROPERTIES FOLDER ${build_folder}) + set_target_properties(${target}_install PROPERTIES FOLDER ${build_folder}) +endmacro() + + +## CMAKE install all required dependencies for an application (included system OS files like msvc*.dll for example) +## +## install_runtime( +## [TARGET name] +## [PLUGINS name [nameN ...] [PLUGIN_PATH_NAME currentPathName [FROM_REL_PATH matchDirFromCurrentPathName] [PLUGIN_PATH_DEST installDir] ] +## [PLUGINS ...] +## [DIRS path [pathN ...] ] +## [TARGET_LIBRARIES filePath [filePathN ...] ] +## [TARGET_PACKAGES packageName [packageNameN ...] ] +## [COMPONENT installComponentName] +## [PLAUSIBLES_POSTFIX Debug_postfix [MinSizeRel_postfix relWithDebInfo_postfix ...] ] +## [VERBOSE] +## ) +## +## installedFilePathTargetAppToResolve : the final installed targetApp absolute full file path name you want to resolve +## +## TARGET : The target app we want to install. If given, it's used to look for link libraries paths (best choice to use, strongly advised to use it) +## +## PLUGINS : Some application built use/load some plugins which can't be detect inside its binary, +## so, here you can specify which plugins the application use/load in order to install them +## and resolve also there dependencies. +## With PLUGINS multi FLAGS : +## PLUGIN_PATH_NAME : The current plugin full file path we want to install +## FROM_REL_PATH : [optional: default only the file is kept] From which matching dir of the plugin path we want to install (keep the directories structure) +## PLUGIN_PATH_DEST : [optional: default relative to executable directory] Where (full path to the install directory) we will install the plugin file (or file path) +## +## DIRS : A list of directories to looking for dependencies +## TARGET_LIBRARIES : DEPRECATED (use TARGET flag instead) : The cmake content variables used for the target_link_libraries( ...) +## TARGET_PACKAGES : DEPRECATED (use TARGET flag instead) : The cmake package names used for the findPackage(...) for your targetApp +## ADVICE: This flag add entries in cache (like: _DIR), it could be useful to fill these variable! +## COMPONENT : (default to runtime) Is the component name associated to the installation +## It is used when you want to install separatly some part of your projets (see install cmake doc) +## VERBOSE : For debug or to get more informations in the output console +## +## Usage: +## install_runtime(${CMAKE_INSTALL_PREFIX}/${EXECUTABLE_NAME}${CMAKE_EXECUTABLE_SUFFIX} +## VERBOSE +## TARGET ${PROJECT_NAME} +## PLAUSIBLES_POSTFIX _d +## PLUGINS +## PLUGIN_PATH_NAME ${PLUGIN_PATH_NAME}${CMAKE_SHARED_MODULE_SUFFIX} ## will be installed (default exec path if no PLUGINS_DEST) and then will be resolved +## FROM_REL_PATH plugins ## optional, used especially for keeping qt plugins tree structure +## PLUGIN_PATH_DEST ${CMAKE_INSTALL_PREFIX}/plugins ## (or relative path 'plugins' will be interpreted relative to installed executable) +## DIRS ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_BINARY_DIR} +## TARGET_LIBRARIES ${OPENGL_LIBRARIES} ## DEPRECATED (use TARGET flag instead) +## ${GLEW_LIBRARIES} +## ${GLUT_LIBRARIES} +## ${Boost_LIBRARIES} +## ${SuiteSparse_LIBRARIES} +## ${CGAL_LIBRARIES} +## TARGET_PACKAGES OPENGL ## DEPRECATED (use TARGET flag instead) +## GLEW +## GLUT +## CGAL +## Boost +## SuiteSparse +## ) +## +## For plugins part, it use our internal parse_arguments_multi.cmake +## +function(install_runtime installedFilePathTargetAppToResolve) + set(optionsArgs "VERBOSE") + set(oneValueArgs "COMPONENT;INSTALL_FOLDER;CONFIG_TYPE") + set(multiValueArgs "DIRS;PLUGINS;TARGET_LIBRARIES;TARGET_PACKAGES;TARGET;PLAUSIBLES_POSTFIX") + cmake_parse_arguments(inst_run "${optionsArgs}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) + + if(IS_ABSOLUTE ${installedFilePathTargetAppToResolve}) + else() + set(installedFilePathTargetAppToResolve ${inst_run_INSTALL_FOLDER}/${installedFilePathTargetAppToResolve}) + endif() + + get_filename_component(EXEC_NAME ${installedFilePathTargetAppToResolve} NAME_WE) + get_filename_component(EXEC_PATH ${installedFilePathTargetAppToResolve} PATH) + + if(NOT inst_run_COMPONENT) + set(inst_run_COMPONENT runtime) + endif() + + + ## Try to append as more possible as possible paths to find dependencies (deprecated since we can use target_properties to get back paths) + set(libPaths ) + foreach(libraryFileName ${inst_run_TARGET_LIBRARIES}) + if(IS_DIRECTORY "${libraryFileName}") + list(APPEND libPaths "${libraryFileName}") + else() + get_filename_component(libpath "${libraryFileName}" PATH) + if(EXISTS "${libpath}") + list(APPEND libPaths "${libpath}") + endif() + endif() + endforeach() + + ## This macro is used internaly here to recursilvely get path of LINK_LIBRARIES of each non imported target + ## Typically if you have 2 internal dependencies between cmake targets, we want cmake to be able to get back path where are these dependencies + macro(recurseDepList target) + get_target_property(linkLibs ${target} LINK_LIBRARIES) + foreach(lib ${linkLibs}) + string(FIND ${lib} ">" strId) ## cmake is using generator-expression? + if(TARGET ${lib}) + ## Skipping interface libraries as they're system ones + get_target_property(type ${lib} TYPE) + get_target_property(imported ${lib} IMPORTED) + if(type STREQUAL "INTERFACE_LIBRARY") + get_target_property(imp_loc ${lib} INTERFACE_IMPORTED_LOCATION) + if(imp_loc) + get_filename_component(imp_loc ${imp_loc} PATH) + list(APPEND targetLibPath ${imp_loc}) + endif() + get_target_property(loc ${lib} INTERFACE_LOCATION) + if(loc) + get_filename_component(loc ${loc} PATH) + list(APPEND targetLibPath ${loc}) + endif() + ## it's not a path but a single target name + ## for build-target which are part of the current cmake configuration : nothing to do as cmake already know the output path + ## for imported target, we need to look for theire imported location + elseif(imported) + get_target_property(imp_loc ${lib} IMPORTED_LOCATION) + if(imp_loc) + get_filename_component(imp_loc ${imp_loc} PATH) + list(APPEND targetLibPath ${imp_loc}) + endif() + get_target_property(loc ${lib} LOCATION) + if(loc) + get_filename_component(loc ${loc} PATH) + list(APPEND targetLibPath ${loc}) + endif() + else() + recurseDepList(${lib}) + endif() + elseif(NOT ${strId} MATCHES -1) ## mean cmake use generator-expression (CMAKE VERSION > 3.0) + string(REGEX MATCH ">:[@A-Za-z_:/.0-9-]+" targetLibPath ${lib}) + string(REGEX REPLACE ">:([@A-Za-z_:/.0-9-]+)" "\\1" targetLibPath ${targetLibPath}) + get_filename_component(targetLibPath ${targetLibPath} PATH) + elseif(EXISTS ${lib}) + set(targetLibPath ${lib}) + get_filename_component(targetLibPath ${targetLibPath} PATH) + else() + #message(STATUS "[install_runtime] skip link library : ${lib} , of target ${target}") + endif() + if(targetLibPath) + list(APPEND targetLinkLibsPathList ${targetLibPath}) + endif() + endforeach() + if(targetLinkLibsPathList) + list(REMOVE_DUPLICATES targetLinkLibsPathList) + endif() + endmacro() + if(inst_run_TARGET) + recurseDepList(${inst_run_TARGET}) + if(targetLinkLibsPathList) + list(APPEND libPaths ${targetLinkLibsPathList}) + endif() + endif() + + if(libPaths) + list(REMOVE_DUPLICATES libPaths) + foreach(libPath ${libPaths}) + get_filename_component(path ${libPath} PATH) + list(APPEND libPaths ${path}) + endforeach() + endif() + + + ## possible speciale dir(s) according to the build system and OS + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(BUILD_TYPES_FOR_DLL "x64") + if(WIN32) + list(APPEND BUILD_TYPES_FOR_DLL "Win64") + endif() + else() + set(BUILD_TYPES_FOR_DLL "x86") + if(WIN32) + list(APPEND BUILD_TYPES_FOR_DLL "Win32") + endif() + endif() + + + ## Try to append as more as possible paths to find dependencies (here, mainly for *.dll) + foreach(dir ${inst_run_DIRS} ${libPaths}) + if(EXISTS "${dir}/bin") + list(APPEND inst_run_DIRS "${dir}/bin") + elseif(EXISTS "${dir}") + list(APPEND inst_run_DIRS "${dir}") + endif() + endforeach() + list(REMOVE_DUPLICATES inst_run_DIRS) + foreach(dir ${inst_run_DIRS}) + if(EXISTS "${dir}") + list(APPEND argDirs ${dir}) + foreach(BUILD_TYPE_FOR_DLL ${BUILD_TYPES_FOR_DLL}) + if(EXISTS "${dir}/${BUILD_TYPE_FOR_DLL}") + list(APPEND argDirs "${dir}/${BUILD_TYPE_FOR_DLL}") + endif() + foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES}) ## for windows multi-generator (MSVC) + if(EXISTS "${dir}/${BUILD_TYPE_FOR_DLL}/${OUTPUTCONFIG}") + list(APPEND argDirs "${dir}/${BUILD_TYPE_FOR_DLL}/${OUTPUTCONFIG}") + endif() + endforeach() + if(CMAKE_BUILD_TYPE) ## for single generator (makefiles) + if(EXISTS "${dir}/${BUILD_TYPE_FOR_DLL}/${CMAKE_BUILD_TYPE}") + list(APPEND argDirs "${dir}/${BUILD_TYPE_FOR_DLL}/${CMAKE_BUILD_TYPE}") + endif() + endif() + endforeach() + foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES}) ## for windows multi-generator (MSVC) + if(EXISTS "${dir}/${OUTPUTCONFIG}") + list(APPEND argDirs "${dir}/${OUTPUTCONFIG}") + endif() + foreach(BUILD_TYPE_FOR_DLL ${BUILD_TYPES_FOR_DLL}) + if(EXISTS "${dir}/${OUTPUTCONFIG}/${BUILD_TYPE_FOR_DLL}") + list(APPEND argDirs "${dir}/${OUTPUTCONFIG}/${BUILD_TYPE_FOR_DLL}") + endif() + endforeach() + endforeach() + if(CMAKE_BUILD_TYPE) ## for single generator (makefiles) + if(EXISTS "${dir}/${CMAKE_BUILD_TYPE}") + list(APPEND argDirs "${dir}/${CMAKE_BUILD_TYPE}") + endif() + foreach(BUILD_TYPE_FOR_DLL ${BUILD_TYPES_FOR_DLL}) + if(EXISTS "${dir}/${CMAKE_BUILD_TYPE}/${BUILD_TYPE_FOR_DLL}") + list(APPEND argDirs "${dir}/${CMAKE_BUILD_TYPE}/${BUILD_TYPE_FOR_DLL}") + endif() + endforeach() + endif() + endif() + endforeach() + if(argDirs) + list(REMOVE_DUPLICATES argDirs) + endif() + + + ## Try to append as more possible paths to find dependencies (here, mainly for *.dll) + foreach(packageName ${inst_run_TARGET_PACKAGES}) + if(EXISTS "${${packageName}_DIR}") + list(APPEND packageDirs ${${packageName}_DIR}) + list(APPEND packageDirs ${${packageName}_DIR}/bin) + foreach(BUILD_TYPE_FOR_DLL ${BUILD_TYPES_FOR_DLL}) + if(EXISTS "${${packageName}_DIR}/bin/${BUILD_TYPE_FOR_DLL}") + list(APPEND packageDirs "${${packageName}_DIR}/bin/${BUILD_TYPE_FOR_DLL}") + endif() + foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES}) ## for windows multi-generator (MSVC) + if(EXISTS "${${packageName}_DIR}/bin/${BUILD_TYPE_FOR_DLL}/${OUTPUTCONFIG}") + list(APPEND packageDirs "${${packageName}_DIR}/bin/${BUILD_TYPE_FOR_DLL}/${OUTPUTCONFIG}") + endif() + endforeach() + if(CMAKE_BUILD_TYPE) ## for single generator (makefiles) + if(EXISTS "${${packageName}_DIR}/bin/${BUILD_TYPE_FOR_DLL}/${CMAKE_BUILD_TYPE}") + list(APPEND packageDirs "${${packageName}_DIR}/bin/${BUILD_TYPE_FOR_DLL}/${CMAKE_BUILD_TYPE}") + endif() + endif() + endforeach() + foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES}) ## for windows multi-generator (MSVC) + if(EXISTS "${${packageName}_DIR}/bin/${OUTPUTCONFIG}") + list(APPEND packageDirs "${${packageName}_DIR}/bin/${OUTPUTCONFIG}") + endif() + foreach(BUILD_TYPE_FOR_DLL ${BUILD_TYPES_FOR_DLL}) + if(EXISTS "${${packageName}_DIR}/bin/${OUTPUTCONFIG}/${BUILD_TYPE_FOR_DLL}") + list(APPEND packageDirs "${${packageName}_DIR}/bin/${OUTPUTCONFIG}/${BUILD_TYPE_FOR_DLL}") + endif() + endforeach() + endforeach() + if(CMAKE_BUILD_TYPE) ## for single generator (makefiles) + if(EXISTS "${${packageName}_DIR}/bin/${CMAKE_BUILD_TYPE}") + list(APPEND packageDirs "${${packageName}_DIR}/bin/${CMAKE_BUILD_TYPE}") + endif() + foreach(BUILD_TYPE_FOR_DLL ${BUILD_TYPES_FOR_DLL}) + if(EXISTS "${${packageName}_DIR}/bin/${CMAKE_BUILD_TYPE}/${BUILD_TYPE_FOR_DLL}") + list(APPEND packageDirs "${${packageName}_DIR}/bin/${CMAKE_BUILD_TYPE}/${BUILD_TYPE_FOR_DLL}") + endif() + endforeach() + endif() + else() + set(${packageName}_DIR "$ENV{${packageName}_DIR}" CACHE PATH "${packageName}_DIR root directory for looking for dirs containning *.dll") + endif() + endforeach() + if(packageDirs) + list(REMOVE_DUPLICATES packageDirs) + endif() + + + set(dirsToLookFor "${EXEC_PATH}") + if(packageDirs) + list(APPEND dirsToLookFor ${packageDirs}) + endif() + if(argDirs) + list(APPEND dirsToLookFor ${argDirs}) + endif() + get_property(used_LINK_DIRECTORIES DIRECTORY PROPERTY LINK_DIRECTORIES) + if (used_LINK_DIRECTORIES) + list(APPEND dirsToLookFor ${used_LINK_DIRECTORIES}) + list(REMOVE_DUPLICATES dirsToLookFor) + endif() + + + ## handle plugins + set(pluginsList "") + include(parse_arguments_multi) ## this function will process recursively items of the sub-list [default print messages] + function(parse_arguments_multi_function results) + cmake_parse_arguments(pamf "VERBOSE" "PLUGIN_PATH_DEST;FROM_REL_PATH;EXEC_PATH;COMPONENT" "" ${ARGN}) ## EXEC_PATH and COMPONENT are for exclusive internal use + list(REMOVE_DUPLICATES pamf_UNPARSED_ARGUMENTS) + foreach(PLUGIN_PATH_NAME ${pamf_UNPARSED_ARGUMENTS}) + if(EXISTS ${PLUGIN_PATH_NAME}) + if(IS_DIRECTORY ${PLUGIN_PATH_NAME}) + if(pamf_VERBOSE) + message(WARNING "${PLUGIN_PATH_NAME} IS_DIRECTORY, cannot installed a directory, please give a path filename") + endif() + else() + if(NOT pamf_PLUGIN_PATH_DEST) + set(PLUGIN_PATH_DEST ${pamf_EXEC_PATH}) ## the default dest value + else() + set(PLUGIN_PATH_DEST ${pamf_PLUGIN_PATH_DEST}) + endif() + + if(pamf_FROM_REL_PATH) + file(TO_CMAKE_PATH ${PLUGIN_PATH_NAME} PLUGIN_PATH_NAME) + get_filename_component(PLUGIN_PATH ${PLUGIN_PATH_NAME} PATH) + unset(PLUGIN_PATH_LIST) + unset(PLUGIN_PATH_LIST_COUNT) + unset(PLUGIN_REL_PATH_LIST) + unset(PLUGIN_REL_PATH) + string(REPLACE "/" ";" PLUGIN_PATH_LIST ${PLUGIN_PATH}) ## create a list of dir + list(FIND PLUGIN_PATH_LIST ${pamf_FROM_REL_PATH} id) + list(LENGTH PLUGIN_PATH_LIST PLUGIN_PATH_LIST_COUNT) + if(${id} GREATER 0) + math(EXPR id "${id}+1") ## matches relative path not include + math(EXPR PLUGIN_PATH_LIST_COUNT "${PLUGIN_PATH_LIST_COUNT}-1") ## the end of the list + foreach(i RANGE ${id} ${PLUGIN_PATH_LIST_COUNT}) + list(GET PLUGIN_PATH_LIST ${i} out) + list(APPEND PLUGIN_REL_PATH_LIST ${out}) + endforeach() + foreach(dir ${PLUGIN_REL_PATH_LIST}) + set(PLUGIN_REL_PATH "${PLUGIN_REL_PATH}/${dir}") + endforeach() + endif() + set(PLUGIN_PATH_DEST ${PLUGIN_PATH_DEST}${PLUGIN_REL_PATH}) + endif() + + install(FILES ${PLUGIN_PATH_NAME} CONFIGURATIONS ${inst_run_CONFIG_TYPE} DESTINATION ${PLUGIN_PATH_DEST} COMPONENT ${pamf_COMPONENT}) + get_filename_component(pluginName ${PLUGIN_PATH_NAME} NAME) + if(IS_ABSOLUTE ${PLUGIN_PATH_DEST}) + else() + set(PLUGIN_PATH_DEST ${inst_run_INSTALL_FOLDER}/${PLUGIN_PATH_DEST}) + endif() + list(APPEND pluginsList ${PLUGIN_PATH_DEST}/${pluginName}) + endif() + else() + message(WARNING "You need to provide a valid PLUGIN_PATH_NAME") + set(pluginsList ) + endif() + endforeach() + set(${results} ${pluginsList} PARENT_SCOPE) + endfunction() + + if(inst_run_VERBOSE) + list(APPEND extra_flags_to_add VERBOSE) + endif() + list(APPEND extra_flags_to_add EXEC_PATH ${EXEC_PATH} COMPONENT ${inst_run_COMPONENT}) ## for internal use inside overloaded function + list(LENGTH inst_run_PLUGINS inst_run_PLUGINS_count) + if(${inst_run_PLUGINS_count} GREATER 0) + parse_arguments_multi(PLUGIN_PATH_NAME inst_run_PLUGINS ${inst_run_PLUGINS} ## see internal overload parse_arguments_multi_function for processing each sub-list + NEED_RESULTS ${inst_run_PLUGINS_count} ## this is used to check when we are in the first loop (in order to reset parse_arguments_multi_results) + EXTRAS_FLAGS ${extra_flags_to_add} ## this is used to allow catching additional internal flags of our overloaded function + ) + endif() + + #message(parse_arguments_multi_results = ${parse_arguments_multi_results}) + list(APPEND pluginsList ${parse_arguments_multi_results}) + + + + ## Install rules for required system runtimes such as MSVCRxx.dll + set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP ON) + include(InstallRequiredSystemLibraries) + if(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS) + install(FILES ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} + CONFIGURATIONS ${inst_run_CONFIG_TYPE} + DESTINATION ${EXEC_PATH} + COMPONENT ${inst_run_COMPONENT} + ) + endif() + + ## print what we are doing to do + if(inst_run_VERBOSE) + message(STATUS "[install_runtime] On install target call, cmake will try to resolve dependencies for given app:\n ${installedFilePathTargetAppToResolve} (with plausible postfix: ${inst_run_PLAUSIBLES_POSTFIX})") + if(pluginsList) + message(STATUS " and also for plugins :") + foreach(plugin ${pluginsList}) + message(STATUS " ${plugin}") + endforeach() + endif() + message(STATUS " Looking for dependencies into:") + foreach(dir ${dirsToLookFor}) + message(STATUS " ${dir}") + endforeach() + endif() + + ## Install rules for required dependencies libs/plugins for the target app + ## will resolve all installed target files with config modes postfixes + string(TOUPPER ${inst_run_CONFIG_TYPE} inst_run_CONFIG_TYPE_UC) + get_target_property(postfix ${inst_run_TARGET} "${inst_run_CONFIG_TYPE_UC}_POSTFIX") + install(CODE "set(target \"${inst_run_TARGET}\")" COMPONENT ${inst_run_COMPONENT} CONFIGURATIONS ${CONFIG_TYPE}) + install(CODE "set(inst_run_CONFIG_TYPE \"${inst_run_CONFIG_TYPE}\")" COMPONENT ${inst_run_COMPONENT} CONFIGURATIONS ${CONFIG_TYPE}) + install(CODE "set(inst_run_INSTALL_FOLDER \"${inst_run_INSTALL_FOLDER}\")" COMPONENT ${inst_run_COMPONENT} CONFIGURATIONS ${CONFIG_TYPE}) + install(CODE "set(app \"${EXEC_PATH}/${EXEC_NAME}${postfix}${CMAKE_EXECUTABLE_SUFFIX}\")" COMPONENT ${inst_run_COMPONENT} CONFIGURATIONS ${CONFIG_TYPE}) + install(CODE "set(dirsToLookFor \"${dirsToLookFor}\")" COMPONENT ${inst_run_COMPONENT} CONFIGURATIONS ${CONFIG_TYPE}) + install(CODE + [[ + if("${CMAKE_INSTALL_CONFIG_NAME}" STREQUAL "${inst_run_CONFIG_TYPE}") + message(STATUS "Installing ${target} dependencies...") + + file(GET_RUNTIME_DEPENDENCIES + EXECUTABLES ${app} + RESOLVED_DEPENDENCIES_VAR _r_deps + UNRESOLVED_DEPENDENCIES_VAR _u_deps + CONFLICTING_DEPENDENCIES_PREFIX _c_deps + DIRECTORIES ${dirsToLookFor} + PRE_EXCLUDE_REGEXES "api-ms-*" + POST_EXCLUDE_REGEXES ".*system32/.*\\.dll" ".*SysWOW64/.*\\.dll" + ) + + if(_u_deps) + message(WARNING "There were unresolved dependencies for executable ${EXEC_FILE}: \"${_u_deps}\"!") + endif() + if(_c_deps_FILENAMES) + message(WARNING "There were conflicting dependencies for executable ${EXEC_FILE}: \"${_c_deps_FILENAMES}\"!") + endif() + + foreach(_file ${_r_deps}) + file(INSTALL + DESTINATION "${inst_run_INSTALL_FOLDER}/bin" + TYPE SHARED_LIBRARY + FOLLOW_SYMLINK_CHAIN + FILES "${_file}" + ) + endforeach() + endif() + ]] + COMPONENT ${inst_run_COMPONENT} CONFIGURATIONS ${CONFIG_TYPE} + ) + + +endfunction() + +## High level macro to install resources in the correct folder +## +## EXECUTABLE: [opt] option to copy files as programs +## RELATIVE : [opt] copy files relatively to current folder +## TYPE : [opt] type and folder where to store the files +## FOLDER : [opt] subfolder to use +## FILES : [opt] contains a list of resources files to copy to install folder +macro(ibr_install_rsc target) + cmake_parse_arguments(install_rsc_${target} "EXECUTABLE;RELATIVE" "TYPE;FOLDER" "FILES" ${ARGN}) + set(rsc_target "${target}_${install_rsc_${target}_TYPE}") + + if(install_rsc_${target}_FOLDER) + set(rsc_folder "${install_rsc_${target}_TYPE}/${install_rsc_${target}_FOLDER}") + else() + set(rsc_folder "${install_rsc_${target}_TYPE}") + endif() + + add_custom_target(${rsc_target} + COMMENT "run the ${install_rsc_${target}_TYPE} installation only for ${target} (component ${rsc_target})" + VERBATIM) + foreach(scriptFile ${install_rsc_${target}_FILES}) + if(install_rsc_${target}_RELATIVE) + file(RELATIVE_PATH relativeFilename ${CMAKE_CURRENT_SOURCE_DIR} ${scriptFile}) + else() + get_filename_component(relativeFilename ${scriptFile} NAME) + endif() + + if(DEFINED CMAKE_BUILD_TYPE) ## for make/nmake based + add_custom_command(TARGET ${rsc_target} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E + copy_if_different ${scriptFile} ${CMAKE_INSTALL_PREFIX_${CMAKE_BUILD_TYPE}}/${rsc_folder}/${relativeFilename}) + endif() + foreach(CONFIG_TYPES ${CMAKE_CONFIGURATION_TYPES}) ## for multi config types (MSVC based) + string(TOUPPER ${CONFIG_TYPES} CONFIG_TYPES_UC) + add_custom_command(TARGET ${rsc_target} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E + copy_if_different ${scriptFile} ${CMAKE_INSTALL_PREFIX_${CONFIG_TYPES_UC}}/${rsc_folder}/${relativeFilename}) + endforeach() + endforeach() + + get_target_property(INSTALL_RSC_BUILD_FOLDER ${target} FOLDER) + set_target_properties(${rsc_target} PROPERTIES FOLDER ${INSTALL_RSC_BUILD_FOLDER}) + + add_dependencies(${target} ${rsc_target}) + add_dependencies(PREBUILD ${rsc_target}) + + if(DEFINED CMAKE_BUILD_TYPE) ## for make/nmake based + resourceFile(ADD ${rsc_folder} CONFIG_TYPE ${CMAKE_BUILD_TYPE} FILE_PATH "${CMAKE_INSTALL_PREFIX_${CMAKE_BUILD_TYPE}}/ibr_resources.ini") + + if(install_rsc_${target}_EXECUTABLE) + install( + PROGRAMS ${install_rsc_${target}_FILES} + CONFIGURATIONS ${CMAKE_BUILD_TYPE} + DESTINATION "${CMAKE_INSTALL_PREFIX_${CMAKE_BUILD_TYPE}}/${rsc_folder}" + ) + else() + install( + FILES ${install_rsc_${target}_FILES} + CONFIGURATIONS ${CMAKE_BUILD_TYPE} + DESTINATION "${CMAKE_INSTALL_PREFIX_${CMAKE_BUILD_TYPE}}/${rsc_folder}" + ) + endif() + endif() + foreach(CONFIG_TYPES ${CMAKE_CONFIGURATION_TYPES}) ## for multi config types (MSVC based) + string(TOUPPER ${CONFIG_TYPES} CONFIG_TYPES_UC) + resourceFile(ADD ${rsc_folder} CONFIG_TYPE ${CONFIG_TYPES} FILE_PATH "${CMAKE_INSTALL_PREFIX_${CONFIG_TYPES_UC}}/ibr_resources.ini") + + if(install_rsc_${target}_EXECUTABLE) + install( + PROGRAMS ${install_rsc_${target}_FILES} + CONFIGURATIONS ${CONFIG_TYPES} + DESTINATION "${CMAKE_INSTALL_PREFIX_${CONFIG_TYPES_UC}}/${rsc_folder}" + ) + else() + install( + FILES ${install_rsc_${target}_FILES} + CONFIGURATIONS ${CONFIG_TYPES} + DESTINATION "${CMAKE_INSTALL_PREFIX_${CONFIG_TYPES_UC}}/${rsc_folder}" + ) + endif() + endforeach() +endmacro() + + +## High level macro to install in an homogen way all our ibr targets (it use some functions inside this file) +## +## RSC_FILE_ADD : [opt] is used to auto write/append relative paths of target resources into a common file +## INSTALL_PDB : [opt] is used to auto install PDB file (when using MSVC according to the target type) +## STANDALONE : [opt] bool ON/OFF var to call install_runtime or not (for bundle resolution) +## DIRS : [opt] used if STANDALONE set to ON, see install_runtime doc +## PLUGINS: [opt] used if STANDALONE set to ON, see install_runtime doc +## MSVC_CMD : [opt] used to specify an absolute filePathName application to launch with the MSVC IDE Debugger associated to this target (project file) +## MSVC_ARGS : [opt] load the MSVC debugger with correct settings (app path, args, working dir) +## +macro(ibr_install_target target) + cmake_parse_arguments(ibrInst${target} "VERBOSE;INSTALL_PDB" "COMPONENT;MSVC_ARGS;STANDALONE;RSC_FOLDER" "SHADERS;RESOURCES;SCRIPTS;DIRS;PLUGINS" ${ARGN}) + + if(ibrInst${target}_RSC_FOLDER) + set(rsc_folder "${ibrInst${target}_RSC_FOLDER}") + else() + set(rsc_folder "${target}") + endif() + + if(ibrInst${target}_SHADERS) + ibr_install_rsc(${target} EXECUTABLE TYPE "shaders" FOLDER ${rsc_folder} FILES "${ibrInst${target}_SHADERS}") + endif() + + if(ibrInst${target}_RESOURCES) + ibr_install_rsc(${target} TYPE "resources" FOLDER ${rsc_folder} FILES "${ibrInst${target}_RESOURCES}") + endif() + + if(ibrInst${target}_SCRIPTS) + ibr_install_rsc(${target} EXECUTABLE TYPE "scripts" FOLDER ${rsc_folder} FILES "${ibrInst${target}_SCRIPTS}") + endif() + + if(ibrInst${target}_COMPONENT) + set(installCompArg COMPONENT ${ibrInst${target}_COMPONENT}) + ## Create a custom install target based on COMPONENT + installTargetProject(${target} ${ibrInst${target}_COMPONENT}) + endif() + + if(DEFINED CMAKE_BUILD_TYPE) ## for make/nmake based + string(TOUPPER ${CMAKE_BUILD_TYPE} CONFIG_TYPES_UC) + set_target_properties(${target} PROPERTIES ${CONFIG_TYPES_UC}_POSTFIX "${CMAKE_${CONFIG_TYPES_UC}_POSTFIX}") + get_target_property(CURRENT_TARGET_BUILD_TYPE_POSTFIX ${target} ${CONFIG_TYPES_UC}_POSTFIX) + endif() + foreach(CONFIG_TYPES ${CMAKE_CONFIGURATION_TYPES}) ## for multi config types (MSVC based) + string(TOUPPER ${CONFIG_TYPES} CONFIG_TYPES_UC) + set_target_properties(${target} PROPERTIES ${CONFIG_TYPES_UC}_POSTFIX "${CMAKE_${CONFIG_TYPES_UC}_POSTFIX}") + get_target_property(CURRENT_TARGET_BUILD_TYPE_POSTFIX ${target} ${CONFIG_TYPES_UC}_POSTFIX) + endforeach() + + ## Specify default installation rules + if(DEFINED CMAKE_BUILD_TYPE) ## for make/nmake based + string(TOUPPER ${CMAKE_BUILD_TYPE} CONFIG_TYPES_UC) + install(TARGETS ${target} + CONFIGURATIONS ${CMAKE_BUILD_TYPE} + LIBRARY DESTINATION ${CMAKE_LIBRARY_OUTPUT_DIRECTORY_${CMAKE_BUILD_TYPE}} ${installCompArg} + ARCHIVE DESTINATION ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${CMAKE_BUILD_TYPE}} ${installCompArg} + RUNTIME DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CMAKE_BUILD_TYPE}} ${installCompArg} + ) + endif() + foreach(CONFIG_TYPES ${CMAKE_CONFIGURATION_TYPES}) ## for multi config types (MSVC based) + string(TOUPPER ${CONFIG_TYPES} CONFIG_TYPES_UC) + install(TARGETS ${target} + CONFIGURATIONS ${CONFIG_TYPES} + LIBRARY DESTINATION ${CMAKE_LIBRARY_OUTPUT_DIRECTORY_${CONFIG_TYPES_UC}} ${installCompArg} + ARCHIVE DESTINATION ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${CONFIG_TYPES_UC}} ${installCompArg} + RUNTIME DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CONFIG_TYPES_UC}} ${installCompArg} + ) + endforeach() + + if(ibrInst${target}_INSTALL_PDB) + if(DEFINED CMAKE_BUILD_TYPE) ## for make/nmake based + installPDB(${target} ${CMAKE_BUILD_TYPE} + LIBRARY_DEST ${CMAKE_LIBRARY_OUTPUT_DIRECTORY_${CMAKE_BUILD_TYPE}} + ARCHIVE_DEST ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${CMAKE_BUILD_TYPE}} + RUNTIME_DEST ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CMAKE_BUILD_TYPE}} + ) + endif() + foreach(CONFIG_TYPES ${CMAKE_CONFIGURATION_TYPES}) ## for multi config types (MSVC based) + string(TOUPPER ${CONFIG_TYPES} CONFIG_TYPES_UC) + installPDB(${target} ${CONFIG_TYPES} + LIBRARY_DEST ${CMAKE_LIBRARY_OUTPUT_DIRECTORY_${CONFIG_TYPES_UC}} + ARCHIVE_DEST ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${CONFIG_TYPES_UC}} + RUNTIME_DEST ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CONFIG_TYPES_UC}} + ) + endforeach() + endif() + + ## install dynamic necessary dependencies + if(ibrInst${target}_STANDALONE) + get_target_property(type ${target} TYPE) + if(${type} MATCHES "EXECUTABLE") + + if(ibrInst${target}_VERBOSE) + set(VERBOSE VERBOSE) + else() + set(VERBOSE ) + endif() + + if(DEFINED CMAKE_BUILD_TYPE) ## for make/nmake based + install_runtime(bin/${target}${CMAKE_EXECUTABLE_SUFFIX} ## default relative to CMAKE_INSTALL_PREFIX + INSTALL_FOLDER "${CMAKE_INSTALL_PREFIX_${CMAKE_BUILD_TYPE}}" + CONFIG_TYPE ${CMAKE_BUILD_TYPE} + ${VERBOSE} + TARGET ${target} + ${installCompArg} + PLUGINS ## will be installed + ${ibrInst${target}_PLUGINS} + DIRS ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CONFIG_TYPES_UC}} + ${ibrInst${target}_DIRS} + ) + endif() + foreach(CONFIG_TYPES ${CMAKE_CONFIGURATION_TYPES}) ## for multi config types (MSVC based) + string(TOUPPER ${CONFIG_TYPES} CONFIG_TYPES_UC) + install_runtime(bin/${target}${CMAKE_EXECUTABLE_SUFFIX} ## default relative to CMAKE_INSTALL_PREFIX + INSTALL_FOLDER "${CMAKE_INSTALL_PREFIX_${CONFIG_TYPES_UC}}" + CONFIG_TYPE ${CONFIG_TYPES} + ${VERBOSE} + TARGET ${target} + ${installCompArg} + PLUGINS ## will be installed + ${ibrInst${target}_PLUGINS} + DIRS ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CONFIG_TYPES_UC}} + ${ibrInst${target}_DIRS} + ) + endforeach() + else() + message(WARNING "STANDALONE option is only compatible with EXECUTABLES target type. Skip the STANDALONE installation process.") + endif() + endif() + + ## Provide a way to directly load the MSVC debugger with correct settings + if(MSVC) + if(ibrInst${target}_MSVC_CMD) ## command absolute filePathName is optional as the default is to use the installed target file application + set(msvcCmdArg COMMAND ${ibrInst${target}_MSVC_CMD}) ## flag following by the value (both to pass to the MSVCsetUserCommand function) + endif() + if(ibrInst${target}_MSVC_ARGS) ## args (between quotes) are optional + set(msvcArgsArg ARGS ${ibrInst${target}_MSVC_ARGS}) ## flag following by the value (both to pass to the MSVCsetUserCommand function) + endif() + get_target_property(type ${target} TYPE) + if( (ibrInst${target}_MSVC_CMD OR ibrInst${target}_MSVC_ARGS) OR (${type} MATCHES "EXECUTABLE") ) + include(MSVCsetUserCommand) + if(DEFINED CMAKE_BUILD_TYPE) ## for make/nmake based + MSVCsetUserCommand( ${target} + PATH ${CMAKE_OUTPUT_BIN_${CMAKE_BUILD_TYPE}} ##FILE option not necessary since it deduced from targetName + ARGS "${SIBR_PROGRAMARGS}" + ${msvcCmdArg} + #${msvcArgsArg} + WORKING_DIR ${CMAKE_OUTPUT_BIN_${CMAKE_BUILD_TYPE}} + ) + endif() + foreach(CONFIG_TYPES ${CMAKE_CONFIGURATION_TYPES}) ## for multi config types (MSVC based) + string(TOUPPER ${CONFIG_TYPES} CONFIG_TYPES_UC) + MSVCsetUserCommand( ${target} + PATH ${CMAKE_OUTPUT_BIN_${CONFIG_TYPES_UC}} ##FILE option not necessary since it deduced from targetName + ARGS "${SIBR_PROGRAMARGS}" + ${msvcCmdArg} + #${msvcArgsArg} + WORKING_DIR ${CMAKE_OUTPUT_BIN_${CONFIG_TYPES_UC}} + ) + endforeach() + elseif(NOT ${type} MATCHES "EXECUTABLE") + #message("Cannot set MSVCsetUserCommand with target ${target} without COMMAND parameter as it is not an executable (skip it)") + endif() + endif() + +endmacro() diff --git a/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/parse_arguments_multi.cmake b/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/parse_arguments_multi.cmake new file mode 100644 index 0000000000000000000000000000000000000000..4f19e414fd3dc12a6af222f2471eec7410f617ee --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/parse_arguments_multi.cmake @@ -0,0 +1,304 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +if(NOT WIN32 OR __parse_arguments_multi_cmake_INCLUDED__) + return() +else() + set(__parse_arguments_multi_cmake_INCLUDED__ ON) +endif() + +## This macro allow to process repeating multi value args from a given function which use cmake_parse_arguments module. +## +## cmake_parse_arguments multi args standard behavior: +## function(foo) +## cmake_parse_arguments(arg "" "" "MULTI" ${ARGN}) +## foreach(item IN LISTS arg_MULTI) +## message(STATUS "${item}") +## endforeach() +## endfunction() +## foo(MULTI x y MULTI z w) +## The above code outputs 'z' and 'w'. It originally expected it to output all of 'x' 'y' 'z' 'w'. +## +## Using this macro inside a function which want to handle repeating multi args values +## will recursively iterate onto the multi tags list to process each sub list. +## It take as 1st argument the subTag flag to separate sub list from the main multi list. +## It take as 2nd argument the nameList of the main multi list (the multiValuesArgs from cmake_parse_arguments: here it is MULTI in the example) +## and that's why it is important that it should be a macro and not a function (to get access to external variable). +## Then you give the content of this list allowing to be processed by the macro. +## +## parse_arguments_multi macro call a parse_arguments_multi_function which do actually the process from the given sub-list. +## By default this function only print infos about what variables you are trying to pass/process (only verbose messages), +## but, by overloading this cmake function, you will be able to externalize the process of your multi argument list. +## +## Usage (into a function) : +## parse_arguments_multi( +## [NEED_RESULTS ] [EXTRAS_FLAGS <...> <...> ...] +## ) +## +## Simple usage example [user point of view]: +## foo(MULTI +## SUB_MULTI x y +## SUB_MULTI z w +## ) +## +## Simple usage example [inside a function]: +## function(foo) +## cmake_parse_arguments(arg "" "" "MULTI" ${ARGN}) +## include(parse_arguments_multi) +## function(parse_arguments_multi_function ) +## #message("I'm an overloaded cmake function used by parse_arguments_multi") +## #message("I'm processing first part of my sub list: ${ARGN}") +## message("ARGV0=${ARGV0}") +## message("ARGV1=${ARGV1}") +## endfunction() +## parse_arguments_multi(SUB_MULTI arg_MULTI ${arg_MULTI}) ## this function will process recusively items of the sub-list [default print messages] +## endfunction() +## +## Will print: +## ARGV0=z +## ARGV1=w +## ARGV0=x +## ARGV1=y +## +## WARNING : DO NEVER ADD EXTRA THINGS TO parse_arguments_multi MACRO : +## parse_arguments_multi(SUB_MULTI arg_MULTI ${arg_MULTI} EXTRAS foo bar SOMTHING) => will failed !! +## use EXTRAS_FLAGS instead !! +## +## Advanced usage example [user point of view]: +## bar(C:/prout/test.exe VERBOSE +## PLUGINS +## PLUGIN_PATH_NAME x PLUGIN_PATH_DEST w +## PLUGIN_PATH_NAME a b PLUGIN_PATH_DEST y +## PLUGIN_PATH_NAME c +## ) +## +## Advanced usage example [inside a function]: +## function(bar execFilePathName) +## cmake_parse_arguments(arg "VERBOSE" "" "PLUGINS" ${ARGN}) +## +## include(parse_arguments_multi) +## function(parse_arguments_multi_function results) +## cmake_parse_arguments(pamf "VERBOSE" "PLUGIN_PATH_DEST;EXEC_PATH" "" ${ARGN}) ## EXEC_PATH is for internal use +## message("") +## message("I'm an overloaded cmake function used by parse_arguments_multi from install_runtime function") +## message("I'm processing first part of my sub list: ${ARGN}") +## message("PLUGIN_PATH_NAME = ${pamf_UNPARSED_ARGUMENTS}") +## message(pamf_VERBOSE = ${pamf_VERBOSE}) +## message("pamf_PLUGIN_PATH_DEST = ${pamf_PLUGIN_PATH_DEST}") +## message(pamf_EXEC_PATH = ${pamf_EXEC_PATH}) +## if(NOT ${pamf_PLUGIN_PATH_DEST}) +## set(pamf_PLUGIN_PATH_DEST ${pamf_EXEC_PATH}) +## endif() +## foreach(plugin ${pamf_UNPARSED_ARGUMENTS}) +## get_filename_component(pluginName ${plugin} NAME) +## list(APPEND pluginsList ${pamf_PLUGIN_PATH_DEST}/${pluginName}) +## endforeach() +## set(${results} ${pluginsList} PARENT_SCOPE) +## endfunction() +## +## if(arg_VERBOSE) +## list(APPEND extra_flags_to_add VERBOSE) ## here we transmit the VERNOSE flag +## endif() +## get_filename_component(EXEC_PATH ${execFilePathName} PATH) ## will be the default value if PLUGIN_PATH_DEST option is not provided +## list(APPEND extra_flags_to_add EXEC_PATH ${EXEC_PATH}) +## list(LENGTH arg_PLUGINS arg_PLUGINS_count) +## parse_arguments_multi(PLUGIN_PATH_NAME arg_PLUGINS ${arg_PLUGINS} +## NEED_RESULTS ${arg_PLUGINS_count} ## this is used to check when we are in the first loop (in order to reset parse_arguments_multi_results) +## EXTRAS_FLAGS ${extra_flags_to_add} ## this is used to allow catching VERBOSE and PLUGIN_PATH_DEST flags of our overloaded function +## ) +## endfunction() +## message(parse_arguments_multi_results = ${parse_arguments_multi_results}) ## list of the whole pluginsList +## #Will print w/x;a/y;b/y;C:/prout/c +## +## NOTE that here, since our overloaded function need to provide a result list, we use the other parse_arguments_multi_function signature (the which one with a results arg) +## + +function(parse_arguments_multi_function_default) ## used in case of you want to reset the default behavior of this function process + message("[default function] parse_arguments_multi_function(ARGC=${ARGC} ARGV=${ARGV} ARGN=${ARGN})") + message("This function is used by parse_arguments_multi and have to be overloaded to process sub list of multi values args") +endfunction() + +function(parse_arguments_multi_function ) ## => the function to overload + parse_arguments_multi_function_default(${ARGN}) +endfunction() + +## first default signature above +##------------------------------ +## second results signature behind + +function(parse_arguments_multi_function_default result) ## used in case of you want to reset the default behavior of this function process + message("[default function] parse_arguments_multi_function(ARGC=${ARGC} ARGV=${ARGV} ARGN=${ARGN})") + message("This function is used by parse_arguments_multi and have to be overloaded to process sub list of muluti values args") +endfunction() + +function(parse_arguments_multi_function result) ## => the function to overload + parse_arguments_multi_function_default(result ${ARGN}) +endfunction() + +## => the macro to use inside your function which use cmake_parse_arguments +# NOTE: entry point of parse_arguments_multi, which is called from win3rdPart) +macro(parse_arguments_multi multiArgsSubTag multiArgsList #<${multiArgsList}> the content of the list +) + # message (STATUS "") + # message(STATUS "calling parse_arguemnts_multi defined in parse_arguments_multi.cmake:141") + # message(STATUS "multiArgsSubTag = ${multiArgsSubTag}") # CHECK_CACHED_VAR + # message(STATUS "multiArgsList = ${multiArgsList}") # it contains the name of the variable which is holding the list i.e w3p_MULTI_SET + # message(STATUS "value of ${multiArgsList} = ${${multiArgsList}}") # a semicolon separated list of values passed to SET or MULTISET keyword in win3rdParty + # message(STATUS "actual values ARGN = ${ARGN}") # the same as ${${multiArgsList}} + + ## INFO + ## starting from CMake 3.5 cmake_parse_arguments is not a module anymore and now is a native CMake command. + ## the behaviour is different though + ## In CMake 3.4, if you pass multiple times a multi_value_keyword, CMake returns the values of the LAST match + ## In CMake 3.5 and above, CMake returns the whole list of values that were following that multi_value_keyword + ## example: + ## cmake_parse_arguments( + ## + ## "" # options + ## "" # one value keywords + ## "MY_MULTI_VALUE_TAG" + ## MY_MULTI_VALUE_TAG value1 value2 + ## MY_MULTI_VALUE_TAG value3 value4 + ## MY_MULTI_VALUE_TAG value5 value6 + ## ) + ## result in CMake 3.4 + ## _MY_MULTI_VALUE_TAG = "value5;value6" + ## + ## result in CMake 3.8 + ## _MY_MULTI_VALUE_TAG = "value5;value6" + + #include(CMakeParseArguments) #module CMakeParseArguments is obsolete since cmake 3.5 + # cmake_parse_arguments ( args) + # : options (flags) pass to the macro + # : options that neeed a value + # : options that neeed more than one value + cmake_parse_arguments(_pam "" "NEED_RESULTS" "${multiArgsSubTag};EXTRAS_FLAGS" ${ARGN}) + + ## multiArgsList is the name of the list used by the multiValuesOption flag from the cmake_parse_arguments of the user function + ## that's why we absolutly need to use MACRO here (and also for passing parse_arguments_multi_results when NEED_RESULTS flag is set) + + ## for debugging + #message("") + #message("[parse_arguments_multi] => ARGN = ${ARGN}") + #message("_pam_NEED_RESULTS=${_pam_NEED_RESULTS}") + #message("_pam_EXTRAS_FLAGS=${_pam_EXTRAS_FLAGS}") + # foreach(var ${_pam_${multiArgsSubTag}}) + # message("arg=${var}") + # endforeach() + + if (${CMAKE_VERSION} VERSION_GREATER "3.5") + # lets make ${_pam_${multiArgsSubTag}} behave as it is in version 3.4 + # that means, cmake_parse_arguments should have only the last values of a multi set for a given keyword + + # message("") + # message("values in multiArgsList") + # foreach(val ${${multiArgsList}}) + # message(STATUS ${val}) + # endforeach() + # message("end values in multiArgsList") + + + set(lastIndexFound OFF) + list(LENGTH ${multiArgsList} argnLength) + # message(${argnLength}) + math(EXPR argnLength "${argnLength}-1") # make last index a valid one + set(recordIndex 0) + set(records "") # clear records list + set(record0 "") # clear first record list + foreach(iter RANGE ${argnLength}) + list(GET ${multiArgsList} ${iter} value) + # message(STATUS "index=${iter} value=${value}") + if (${value} STREQUAL ${multiArgsSubTag}) + if (lastIndexFound) + list(APPEND records ${recordIndex}) # records store the list NAMES + math(EXPR recordIndex "${recordIndex}+1") + set(record${recordIndex} "") # clear record list + else () + set(lastIndexFound ON) + endif() + + set(lastIndex ${iter}) + else () + if (lastIndexFound) + # message(${value}) + list(APPEND record${recordIndex} ${value}) + endif() + endif() + endforeach() + + # save the last list of values + if (lastIndexFound) + list(APPEND records ${recordIndex}) # records store the list NAMES + endif() + + # set multiArgsList to make it behave like CMake 3.4 + # message("") + # message("using my records") + foreach(recordName ${records}) + # message(${recordName}) + # foreach(value ${record${recordName}}) + # message(${value}) + # endforeach() + # message("") + set(_pam_${multiArgsSubTag} ${record${recordName}}) + endforeach() + # message(${_pam_${multiArgsSubTag}}) + + # message("") + # message("using argn") + # foreach(value ${ARGN}) + # message(${value}) + # endforeach() + endif() # end if cmake > 3.5 + + # message("values with pam ${_pam_${multiArgsSubTag}}") + + ## check and init + list(LENGTH ${multiArgsList} globalListCount) # GLUT_TRACE: globalListCound=16 in CMake3.4 and CMake3.8 + # message(STATUS "nr items in multiArgsList: ${globalListCount}") + math(EXPR globalListCount "${globalListCount}-1") ## because it will contain [multiArgsSubTag + ${multiArgsList}] + if(_pam_NEED_RESULTS) + if(${globalListCount} EQUAL ${_pam_NEED_RESULTS}) + ## first time we enter into this macro (because we call it recursively) + unset(parse_arguments_multi_results) + endif() + endif() + + ## process the part of the multi agrs list + ## ${ARGN} shouldn't be passed to the function in order to avoid missmatch size list ${multiArgsList} and _pam_${multiArgsSubTag} + ## if you want to pass extra internal flags from your function to this callback, use EXTRAS_FLAGS + if(_pam_NEED_RESULTS) + parse_arguments_multi_function(parse_arguments_multi_function_result ${_pam_${multiArgsSubTag}} ${_pam_EXTRAS_FLAGS}) + list(APPEND parse_arguments_multi_results ${parse_arguments_multi_function_result}) + else() + # message(STATUS "about to call parse_arguments_multi_function in parse_arguments_multi.cmake:177 ${_pam_${multiArgsSubTag}} and extra flags ${_pam_EXTRAS_FLAGS}") + parse_arguments_multi_function(${_pam_${multiArgsSubTag}} ${_pam_EXTRAS_FLAGS}) + endif() + + ## remove just processed items from the main list to process (multiArgsList) + list(REVERSE ${multiArgsList}) + list(LENGTH _pam_${multiArgsSubTag} subTagListCount) + unset(ids) + foreach(id RANGE ${subTagListCount}) + list(APPEND ids ${id}) + endforeach() + list(REMOVE_AT ${multiArgsList} ${ids}) + list(REVERSE ${multiArgsList}) + + ## test if remain sub multi list to process (recursive call) or finish the process + list(LENGTH ${multiArgsList} mainTagListCount) + if(${mainTagListCount} GREATER 1) + ## do not pass ${ARGN} just because it will re pass the initial 2 inputs args and we wont as they was consumed (in order to avoir conflicts) + # message(STATUS "about to call a parse_arguments_multi but without knowing where the definition is going to be taken from") + parse_arguments_multi(${multiArgsSubTag} ${multiArgsList} ${${multiArgsList}} + NEED_RESULTS ${_pam_NEED_RESULTS} EXTRAS_FLAGS ${_pam_EXTRAS_FLAGS} + ) + endif() +endmacro() diff --git a/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/sibr_library.cmake b/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/sibr_library.cmake new file mode 100644 index 0000000000000000000000000000000000000000..61f4219241ca249645e47604640fb2bb99c50668 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/cmake/windows/sibr_library.cmake @@ -0,0 +1,169 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +# NOTE +# This feature is used to easily download, store and link external dependencies. This +# requires to prepare pre-compiled libraries (to download). For now, packages have +# only be prepare for Windows 64-bit with Visual Studio 2012. (You should re-build +# everything if you want to use another version of Visual Studio/ another compiler). + +# NOTE ABOUT UNIX SYSTEMS +# There is no need for "searching mechanism". This function is discard and your +# libraries should be installed is the standard folders that are: +# +# /usr/include/ +# /usr/lib/ +# /usr/lib64/ +# for packages downloaded using apt-get/yum +# +# /usr/local/include/ +# /usr/local/lib/ +# /usr/local/lib64/ +# for packages manually installed ("make install") +# +# if you encounter problems when linking (e.g. lib not found even if it is installed), +# please check these folders are in your search PATH environment variables. + +set(EXTLIBS_PACKAGE_FOLDER "${CMAKE_SOURCE_DIR}/extlibs") + +function(sibr_addlibrary) + if(NOT WIN32) + return() + endif() + + file(MAKE_DIRECTORY ${EXTLIBS_PACKAGE_FOLDER}) + cmake_parse_arguments(args "VCID" "VERBOSE;TIMEOUT;DEFAULT_USE;NAME;VERSION;MSVC11;MSVC12;MSVC14;MSVC17" "MULTI_SET;SET" ${ARGN}) + + + if (NOT "${args_VERSION}" MATCHES "") + message(WARNING "VERSION is not implemented yet") + endif() + + set(lcname "") + set(ucname "") + string(TOLOWER "${args_NAME}" lcname) + string(TOUPPER "${args_NAME}" ucname) + + set(LIB_PACKAGE_FOLDER "${EXTLIBS_PACKAGE_FOLDER}/${lcname}") + win3rdParty(${ucname} + $ + VERBOSE ${args_VERBOSE} + TIMEOUT ${args_TIMEOUT} + DEFAULT_USE ${args_DEFAULT_USE} + MSVC11 "${LIB_PACKAGE_FOLDER}" "${args_MSVC11}" + MSVC12 "${LIB_PACKAGE_FOLDER}" "${args_MSVC12}" + MSVC14 "${LIB_PACKAGE_FOLDER}" "${args_MSVC14}" # TODO SV: make sure to build this library if required + MSVC17 "${LIB_PACKAGE_FOLDER}" "${args_MSVC17}" + SET ${args_SET} + MULTI_SET ${args_MULTI_SET} + ) + + # Add include/ directory + # and lib/ directories + + # TODO SV: paths not matching with current hierarchy. example: libraw/libraw-0.17.1/include + # SR: The link directories will also be used to lookup for dependency DLLs to copy in the install directory. + # Some libraries put the DLLs in the bin/ directory, so we include those. + file(GLOB subdirs RELATIVE ${LIB_PACKAGE_FOLDER} ${LIB_PACKAGE_FOLDER}/*) + set(dirlist "") + foreach(dir ${subdirs}) + if(IS_DIRECTORY ${LIB_PACKAGE_FOLDER}/${dir}) + # message("adding ${LIB_PACKAGE_FOLDER}/${dir}/include/ to the include directories") + include_directories("${LIB_PACKAGE_FOLDER}/${dir}/include/") + # message("adding ${LIB_PACKAGE_FOLDER}/${dir}/lib[64] to the link directories") + link_directories("${LIB_PACKAGE_FOLDER}/${dir}/") + link_directories("${LIB_PACKAGE_FOLDER}/${dir}/lib/") + link_directories("${LIB_PACKAGE_FOLDER}/${dir}/lib64/") + link_directories("${LIB_PACKAGE_FOLDER}/${dir}/bin/") + endif() + endforeach() + +endfunction() + +include(FetchContent) +include(git_describe) + +function(sibr_gitlibrary) + cmake_parse_arguments(args "" "TARGET;GIT_REPOSITORY;GIT_TAG;ROOT_DIR;SOURCE_DIR" "INCLUDE_DIRS" ${ARGN}) + if(NOT args_TARGET) + message(FATAL "Error on sibr_gitlibrary : please define your target name.") + return() + endif() + + if(NOT args_ROOT_DIR) + set(args_ROOT_DIR ${args_TARGET}) + endif() + + if(NOT args_SOURCE_DIR) + set(args_SOURCE_DIR ${args_TARGET}) + endif() + + if(args_GIT_REPOSITORY AND args_GIT_TAG) + if(EXISTS ${CMAKE_SOURCE_DIR}/extlibs/${args_ROOT_DIR}/${args_SOURCE_DIR}/.git) + git_describe( + PATH ${CMAKE_SOURCE_DIR}/extlibs/${args_ROOT_DIR}/${args_SOURCE_DIR} + GIT_URL SIBR_GITLIBRARY_URL + GIT_BRANCH SIBR_GITLIBRARY_BRANCH + GIT_COMMIT_HASH SIBR_GITLIBRARY_COMMIT_HASH + GIT_TAG SIBR_GITLIBRARY_TAG + ) + + if((SIBR_GITLIBRARY_URL STREQUAL args_GIT_REPOSITORY) AND + ((SIBR_GITLIBRARY_BRANCH STREQUAL args_GIT_TAG) OR + (SIBR_GITLIBRARY_TAG STREQUAL args_GIT_TAG) OR + (SIBR_GITLIBRARY_COMMIT_HASH STREQUAL args_GIT_TAG))) + message(STATUS "Library ${args_TARGET} already available, skipping.") + set(SIBR_GITLIBRARY_DECLARED ON) + else() + message(STATUS "Adding library ${args_TARGET} from git...") + endif() + endif() + + FetchContent_Declare(${args_TARGET} + GIT_REPOSITORY ${args_GIT_REPOSITORY} + GIT_TAG ${args_GIT_TAG} + GIT_SHALLOW ON + SOURCE_DIR ${CMAKE_SOURCE_DIR}/extlibs/${args_ROOT_DIR}/${args_SOURCE_DIR} + SUBBUILD_DIR ${CMAKE_SOURCE_DIR}/extlibs/${args_ROOT_DIR}/subbuild + BINARY_DIR ${CMAKE_SOURCE_DIR}/extlibs/${args_ROOT_DIR}/build + ) + FetchContent_GetProperties(${args_TARGET}) + string(TOLOWER "" lcTargetName) + + if((NOT SIBR_GITLIBRARY_DECLARED) AND (NOT ${lcTargetName}_POPULATED)) + message(STATUS "Populating library ${args_TARGET}...") + FetchContent_Populate(${args_TARGET} QUIET + GIT_REPOSITORY ${args_GIT_REPOSITORY} + GIT_TAG ${args_GIT_TAG} + SOURCE_DIR ${CMAKE_SOURCE_DIR}/extlibs/${args_ROOT_DIR}/${args_SOURCE_DIR} + SUBBUILD_DIR ${CMAKE_SOURCE_DIR}/extlibs/${args_ROOT_DIR}/subbuild + BINARY_DIR ${CMAKE_SOURCE_DIR}/extlibs/${args_ROOT_DIR}/build + ) + endif() + + add_subdirectory(${CMAKE_SOURCE_DIR}/extlibs/${args_ROOT_DIR}/${args_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/extlibs/${args_ROOT_DIR}/build) + + get_target_property(type ${args_TARGET} TYPE) + if(NOT (type STREQUAL "INTERFACE_LIBRARY")) + set_target_properties(${args_TARGET} PROPERTIES FOLDER "extlibs") + endif() + + list(APPEND ${args_TARGET}_INCLUDE_DIRS ${EXTLIBS_PACKAGE_FOLDER}/${args_ROOT_DIR}) + list(APPEND ${args_TARGET}_INCLUDE_DIRS ${EXTLIBS_PACKAGE_FOLDER}/${args_ROOT_DIR}/${args_SOURCE_DIR}) + + foreach(args_INCLUDE_DIR ${args_INCLUDE_DIRS}) + list(APPEND ${args_TARGET}_INCLUDE_DIRS ${EXTLIBS_PACKAGE_FOLDER}/${args_ROOT_DIR}/${args_SOURCE_DIR}/${args_INCLUDE_DIR}) + endforeach() + + include_directories(${${args_TARGET}_INCLUDE_DIRS}) + else() + message(FATAL "Error on sibr_gitlibrary for target ${args_TARGET}: missing git tag or git url.") + endif() +endfunction() \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/CMakeLists.txt b/submodules/gaussian-splatting/SIBR_viewers/src/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..eab58728e0e9f0c3311e845bf11ed3d56bf9ea32 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/CMakeLists.txt @@ -0,0 +1,176 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +################################################################################ +# This CMakeLists.txt manages which projects should be built and add their # +# dependencies. # +################################################################################ +set(SIBR_FOLDER "core") +set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER "") + +option(BUILD_SIBR "Build core libs of SIBR (sibr_system, sibr_graphics, sibr_view, sibr_assets, ...)" ON) + +#https://stackoverflow.com/questions/7787823/cmake-how-to-get-the-name-of-all-subdirectories-of-a-directory +MACRO(SUBDIRLIST result curdir) + FILE(GLOB children RELATIVE ${curdir} ${curdir}/*) + SET(dirlist "") + foreach(child ${children}) + IF(IS_DIRECTORY ${curdir}/${child}) + LIST(APPEND dirlist ${child}) + ENDIF() + endforeach() + SET(${result} ${dirlist}) +ENDMACRO() + +set(SIBR_PROJECTS_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}/projects") +SUBDIRLIST(SUBDIRS ${SIBR_PROJECTS_FOLDER}) + +list(APPEND PROJECT_SUBFOLDERS "apps" "preprocess" "renderer" "scripts" "library") + +# Moving ulr to the top of the list +list(PREPEND SUBDIRS "dataset_tools" "ulr" "basic") +list(REMOVE_DUPLICATES SUBDIRS) + +## DEPS ## +include(include_once) + +message(STATUS "\n\n****************** Handling core dependencies ******************") + +include_once(dependencies) ## Map/bind 3rdParty/external dependencies packages to cmake + +message(STATUS "****************************************************************\n\n") + +foreach(subdir ${SUBDIRS}) + set(${subdir}_ROOT_DIR "${SIBR_PROJECTS_FOLDER}/${subdir}") + set(PROJECT_NAME "BUILD_IBR_${subdir}") + string(TOUPPER ${PROJECT_NAME} PROJECT_NAME) + if(${${PROJECT_NAME}}) + foreach(PROJECT_SUBFOLDER ${PROJECT_SUBFOLDERS}) + if(EXISTS "${${subdir}_ROOT_DIR}/${PROJECT_SUBFOLDER}/cmake/Modules") + list(APPEND CMAKE_MODULE_PATH ${${subdir}_ROOT_DIR}/${PROJECT_SUBFOLDER}/cmake/Modules) + endif() + + if(EXISTS "${${subdir}_ROOT_DIR}/${PROJECT_SUBFOLDER}/cmake/dependencies.cmake") + message(STATUS "********* Handling ${subdir} ${PROJECT_SUBFOLDER} dependencies *********") + include_once("${${subdir}_ROOT_DIR}/${PROJECT_SUBFOLDER}/cmake/dependencies.cmake") + + message(STATUS "****************************************************************\n\n") + endif() + endforeach() + endif() +endforeach() + +Win3rdPartyGlobalCacheAction() + +include_directories(.) + +if (BUILD_SIBR) + add_subdirectory(core/system) + add_subdirectory(core/graphics) + add_subdirectory(core/renderer) + add_subdirectory(core/raycaster) + add_subdirectory(core/view) + add_subdirectory(core/scene) + add_subdirectory(core/assets) + add_subdirectory(core/imgproc) + add_subdirectory(core/video) +endif() + +set(PROJECTS_ON_AT_FIRST_BUILD "basic" "gaussianviewer" "remote") + +foreach(subdir ${SUBDIRS}) + message(STATUS "Adding ${subdir} project") + set(PROJECT_NAME "BUILD_IBR_${subdir}") + string(TOUPPER ${PROJECT_NAME} PROJECT_NAME) + + if(NOT (DEFINED ${PROJECT_NAME})) + foreach(PROJECT_SUBFOLDER ${PROJECT_SUBFOLDERS}) + if(EXISTS "${${subdir}_ROOT_DIR}/${PROJECT_SUBFOLDER}/CMakeLists.txt") + if(subdir IN_LIST PROJECTS_ON_AT_FIRST_BUILD) + option(${PROJECT_NAME} "Build project \"${subdir}\"" ON) + else() + option(${PROJECT_NAME} "Build project \"${subdir}\"" OFF) + endif() + break() + endif() + endforeach() + endif() + + message(STATUS "${PROJECT_NAME} is ${${PROJECT_NAME}}") + + if(${${PROJECT_NAME}}) + if(EXISTS "${${subdir}_ROOT_DIR}/CMakeLists.txt") + add_subdirectory("${${subdir}_ROOT_DIR}") + else() + foreach(PROJECT_SUBFOLDER ${PROJECT_SUBFOLDERS}) + if(EXISTS "${${subdir}_ROOT_DIR}/${PROJECT_SUBFOLDER}/CMakeLists.txt") + add_subdirectory("${${subdir}_ROOT_DIR}/${PROJECT_SUBFOLDER}") + endif() + endforeach() + endif() + + if(EXISTS "${${subdir}_ROOT_DIR}/documentation/" AND BUILD_DOCUMENTATION) + unset(PROJECT_PAGE) + unset(PROJECT_LINK) + unset(PROJECT_DESCRIPTION) + unset(PROJECT_TYPE) + include("${${subdir}_ROOT_DIR}/documentation/${subdir}_doc.cmake" OPTIONAL) + + if(NOT DEFINED PROJECT_PAGE) + set(PROJECT_PAGE "${subdir}Page") + endif() + + if(NOT DEFINED PROJECT_TYPE) + set(PROJECT_TYPE "OTHERS") + endif() + + set(PROJECT_SUBPAGE_REF " - @subpage ${PROJECT_PAGE}") + set(PROJECT_REF_REF " - @ref ${PROJECT_PAGE}") + + if(DEFINED PROJECT_LINK) + string(APPEND PROJECT_SUBPAGE_REF " (${PROJECT_LINK})") + string(APPEND PROJECT_REF_REF " (${PROJECT_LINK})") + endif() + + if(DEFINED PROJECT_DESCRIPTION) + string(APPEND PROJECT_SUBPAGE_REF ": ${PROJECT_DESCRIPTION}") + string(APPEND PROJECT_REF_REF " (${PROJECT_DESCRIPTION})") + endif() + + string(APPEND SIBR_PROJECTS_${PROJECT_TYPE}_SUBPAGE_REF_LOCAL "${PROJECT_SUBPAGE_REF}\n") + string(APPEND SIBR_PROJECTS_${PROJECT_TYPE}_REF_REF_LOCAL "${PROJECT_REF_REF}\n") + + if(EXISTS "${${subdir}_ROOT_DIR}/documentation/img") + set(DOXY_APP_SPECIFIC_IMG_PATH_LOCAL "${DOXY_APP_SPECIFIC_IMG_PATH_LOCAL} ${${subdir}_ROOT_DIR}/documentation/img") + endif() + + if(EXISTS "${${subdir}_ROOT_DIR}/LICENSE.md") + set(DOXY_DOC_EXCLUDE_PATTERNS_DIRS_LOCAL "${DOXY_DOC_EXCLUDE_PATTERNS_DIRS_LOCAL} ${${subdir}_ROOT_DIR}/LICENSE.md") + endif() + endif() + else() + set(DOXY_DOC_EXCLUDE_PATTERNS_DIRS_LOCAL "${DOXY_DOC_EXCLUDE_PATTERNS_DIRS_LOCAL} ${${subdir}_ROOT_DIR}") + endif() +endforeach() + +set(SIBR_PROJECTS_SAMPLES_SUBPAGE_REF "${SIBR_PROJECTS_SAMPLES_SUBPAGE_REF_LOCAL}" PARENT_SCOPE) +set(SIBR_PROJECTS_OURS_SUBPAGE_REF "${SIBR_PROJECTS_OURS_SUBPAGE_REF_LOCAL}" PARENT_SCOPE) +set(SIBR_PROJECTS_TOOLBOX_SUBPAGE_REF "${SIBR_PROJECTS_TOOLBOX_SUBPAGE_REF_LOCAL}" PARENT_SCOPE) +set(SIBR_PROJECTS_OTHERS_SUBPAGE_REF "${SIBR_PROJECTS_OTHERS_SUBPAGE_REF_LOCAL}" PARENT_SCOPE) +set(SIBR_PROJECTS_SAMPLES_REF_REF "${SIBR_PROJECTS_SAMPLES_REF_REF_LOCAL}" PARENT_SCOPE) +set(SIBR_PROJECTS_OURS_REF_REF "${SIBR_PROJECTS_OURS_REF_REF_LOCAL}" PARENT_SCOPE) +set(SIBR_PROJECTS_TOOLBOX_REF_REF "${SIBR_PROJECTS_TOOLBOX_REF_REF_LOCAL}" PARENT_SCOPE) +set(SIBR_PROJECTS_OTHERS_REF_REF "${SIBR_PROJECTS_OTHERS_REF_REF_LOCAL}" PARENT_SCOPE) +set(DOXY_APP_SPECIFIC_IMG_PATH "${DOXY_APP_SPECIFIC_IMG_PATH_LOCAL}" PARENT_SCOPE) +set(DOXY_DOC_EXCLUDE_PATTERNS_DIRS "${DOXY_DOC_EXCLUDE_PATTERNS_DIRS_LOCAL}" PARENT_SCOPE) + +if (BUILD_IBR_TFGL_INTEROP) + add_subdirectory(projects/tfgl_interop/renderer/custom_ops) +endif() diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/ActiveImageFile.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/ActiveImageFile.cpp new file mode 100644 index 0000000000000000000000000000000000000000..620bbbe278aa4f1c0e4590ea39ce8ca29ab3c6d1 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/ActiveImageFile.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +# include +# include +# include "core/assets/ActiveImageFile.hpp" + +namespace sibr +{ + bool ActiveImageFile::load( const std::string& filename, bool verbose ) + { + + std::fstream file(filename, std::ios::in); + if(_numImages == 0 ) + SIBR_WRG << "No Images Loaded while loading '"<> imageId; + _active[imageId] = true; + } + + if( verbose ) + SIBR_FLOG << "'"<< filename <<"' successfully loaded." << std::endl; + else + std::cerr<< "." ; + return true; + } + else { + for(int i=0; i < _numImages; i++) + _active[i]=true; + if( verbose ) + SIBR_WRG << "file not found: '"<& active( void ) const { return _active; } + + + private: + std::vector _active; ///< Flags denoting which images are active. + int _numImages = 0; ///< Number of images. + + }; + + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/CMakeLists.txt b/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..e68317caab93bc0366ce0a25702a764c05cb3d91 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/CMakeLists.txt @@ -0,0 +1,45 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +project(sibr_assets) + +file(GLOB SOURCES "*.cpp" "*.h" "*.hpp" ) +source_group("Source Files" FILES ${SOURCES}) + +file(GLOB SOURCES "*.cpp" "*.h" "*.hpp") + + +## Specify target rules +add_library(${PROJECT_NAME} SHARED ${SOURCES}) + +include_directories( + ${Boost_INCLUDE_DIRS} + ${xatlas_INCLUDE_DIRS} +) +target_link_libraries(${PROJECT_NAME} + ${Boost_LIBRARIES} + ${ASSIMP_LIBRARIES} + ${GLEW_LIBRARIES} + ${OPENGL_LIBRARIES} + ${OpenCV_LIBRARIES} + OpenMP::OpenMP_CXX + sibr_graphics + xatlas +) + +add_definitions(-DSIBR_ASSETS_EXPORTS -DBOOST_ALL_DYN_LINK) + +set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER ${SIBR_FOLDER}) + +## High level macro to install in an homogen way all our ibr targets +include(install_runtime) +ibr_install_target(${PROJECT_NAME} + INSTALL_PDB ## mean install also MSVC IDE *.pdb file (DEST according to target type) +) diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/CameraRecorder.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/CameraRecorder.cpp new file mode 100755 index 0000000000000000000000000000000000000000..b821210d7f7d216ef66e63e299edd76f0e56f191 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/CameraRecorder.cpp @@ -0,0 +1,515 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include +#include "core/assets/CameraRecorder.hpp" +#include "core/assets/InputCamera.hpp" +#include + +namespace sibr +{ + void CameraRecorder::use(Camera& cam) + { + if (_recording) { + _cameras.push_back(cam); + } + else if (_playing && _pos < _cameras.size() ) { + const float znear = cam.znear(); + const float zfar = cam.zfar(); + + if( !_playNoInterp ) { + //std::cout << _playing << std::endl; + // If we reach the last frame of the interpolation b/w two cameras, skip to next camera. + if (_interp > (1.0f - _speed)) + { + _interp = 0.0f; + _pos++; + } + // Interpolate between the two closest cameras. + const float k = std::min(std::max(_interp, 0.0f), 1.0f); + + sibr::Camera & camStart = _cameras[std::min(int(_pos), int(_cameras.size()) - 1)]; + sibr::Camera & camNext = _cameras[std::min(int(_pos) + 1, int(_cameras.size())-1)]; + + cam = sibr::Camera::interpolate(camStart, camNext, k); + + _interp += _speed; + } + else { + cam = _cameras[_pos]; + _pos++; + if (_pos == _cameras.size()) + _playNoInterp = false; + + } + + // Preserve the znear and zfar. + cam.znear(znear); + cam.zfar(zfar); + + if (_saving) { + std::ostringstream ssZeroPad; + ssZeroPad << std::setw(8) << std::setfill('0') << (_pos); + cam.setSavePath(_savingPath + "/" + ssZeroPad.str() + ".png"); + //std::cout << "Saving frame as: " << cam.savePath() << std::endl; + } + if (_savingVideo) { + cam.setDebugVideo(true); + } + if (_pos >= _cameras.size()) + { + stop(); + SIBR_LOG << "[CameraRecorder] - Playback Finished" << std::endl; + } + } + else { + //std::cout << _playing << std::endl; + cam.setSavePath(""); + cam.setDebugVideo(false); + } + } + + void CameraRecorder::playback(void) + { + stop(); + _playing = true; + SIBR_LOG << "[CameraRecorder] - Playing" << std::endl; + } + + void CameraRecorder::record(void) + { + stop(); + _recording = true; + SIBR_LOG << "[CameraRecorder] - Recording" << std::endl; + } + + void sibr::CameraRecorder::saving(std::string savePath) + { + _saving = true; + _savingPath = savePath; + SIBR_LOG << "[CameraRecorder] - Recording" << std::endl; + } + + void CameraRecorder::savingVideo(bool saveVideo) + { + _savingVideo = saveVideo; + } + + void sibr::CameraRecorder::stopSaving(void) + { + _saving = false; + _savingPath = ""; + } + + void CameraRecorder::stop(void) + { + _recording = _playing = false; + _pos = 0; + _interp = 0.0f; + } + + void CameraRecorder::reset(void) + { + stop(); + _cameras.clear(); + } + + bool CameraRecorder::load(const std::string& filename) + { + reset(); + + sibr::ByteStream stream; + + if (stream.load(filename) == false) + return false; + + int32 num = 0; + + std::cout << " CameraRecorder::load " << num << std::endl; + + stream >> num; + while (num > 0) + { + Camera cam; + stream >> cam; + _cameras.emplace_back(std::move(cam)); + --num; + } + SIBR_LOG << "[CameraRecorder] - Loaded from " << filename << std::endl; + return stream; + } + + void CameraRecorder::save(const std::string& filename) + { + sibr::ByteStream stream; + int32 num = (int32)_cameras.size(); + stream << num; + for (const Camera& cam : _cameras) + stream << cam; + + stream.saveToFile(filename); + SIBR_LOG << "[CameraRecorder] - Saved " << num << " cameras to " << filename << std::endl; + } + + bool CameraRecorder::safeLoad(const std::string & filename, int w, int h) + { + Path path = Path(filename); + + if (path.extension().string() == ".out") { + loadBundle(filename, w, h); + return true; + } else if (path.extension().string() == ".path") { + return load(filename); + } + SIBR_WRG << "Unable to load camera path" << std::endl; + return false; + } + + void CameraRecorder::loadBundle(const std::string & filePath, int w, int h) + { + const std::string bundlerFile = filePath; + SIBR_LOG << "Loading bundle path." << std::endl; + + // check bundler file + std::ifstream bundle_file(bundlerFile); + SIBR_ASSERT(bundle_file.is_open()); + + // read number of images + std::string line; + getline(bundle_file, line); // ignore first line - contains version + int numImages = 0; + bundle_file >> numImages; // read first value (number of images) + getline(bundle_file, line); // ignore the rest of the line + + std::vector cameras(numImages); + // Parse bundle.out file for camera calibration parameters + for (int i = 0; i < numImages; i++) { + + Matrix4f m; + bundle_file >> m(0) >> m(1) >> m(2) >> m(3) >> m(4); + bundle_file >> m(5) >> m(6) >> m(7) >> m(8) >> m(9); + bundle_file >> m(10) >> m(11) >> m(12) >> m(13) >> m(14); + + cameras[i] = InputCamera::Ptr(new InputCamera(i, w, h, m, true)); + + cameras[i]->znear(0.2f); cameras[i]->zfar(250.f); + + } + + for (const InputCamera::Ptr cam : cameras) + { + _cameras.push_back(*cam); + } + + } + + void CameraRecorder::loadColmap(const std::string &filePath, int w, int h) + { + SIBR_LOG << "Loading colmap path." << std::endl; + boost::filesystem::path colmapDir ( filePath ); + + SIBR_LOG << "DEBUG: colmap path dir " << colmapDir.parent_path().string() << std::endl; + + std::vector path = InputCamera::loadColmap(colmapDir.parent_path().string(), float(0.01), 1000, false ); + for (const InputCamera::Ptr cam : path) + { + _cameras.push_back(*cam); + } + } + + void CameraRecorder::loadLookat(const std::string &filePath, int w, int h) + { + SIBR_LOG << "Loading lookat path." << std::endl; + std::vector path = InputCamera::loadLookat(filePath, std::vector{Vector2u(w, h)}); + for (const InputCamera::Ptr cam : path) + { + _cameras.push_back(*cam); + } + } + + void CameraRecorder::saveAsBundle(const std::string & filePath, const int height, const int step) + { + + std::ofstream out(filePath.c_str(), std::ios::binary); + if (!out.good()) { + SIBR_LOG << "ERROR: cannot write to the file '" << filePath << "'" << std::endl; + return; + } + + if(_cameras.empty()) { + return; + } + + const int size = static_cast(_cameras.size() / step); + + out << "# Bundle file v0.3\n"; + out << size << " " << 0 << "\n"; + + for (int i = 0; i < _cameras.size(); i += step) { + + const sibr::Camera cam = _cameras[i]; + sibr::Quaternionf q = cam.rotation(); + sibr::Matrix3f m1 = q.toRotationMatrix(); + sibr::Vector3f pos = -m1.transpose() * cam.position(); + + float m[15]; + m[0] = 0.5f*height / tan(cam.fovy() / 2.f); m[1] = 0.0f; m[2] = 0.0f; + m[3] = m1(0, 0), m[4] = m1(1, 0), m[5] = m1(2, 0); + m[6] = m1(0, 1), m[7] = m1(1, 1), m[8] = m1(2, 1); + m[9] = m1(0, 2), m[10] = m1(1, 2), m[11] = m1(2, 2); + m[12] = pos.x(), m[13] = pos.y(), m[14] = pos.z(); + + out << m[0] << " " << m[1] << " " << m[2] << std::endl; + out << m[3] << " " << m[4] << " " << m[5] << std::endl; + out << m[6] << " " << m[7] << " " << m[8] << std::endl; + out << m[9] << " " << m[10] << " " << m[11] << std::endl; + out << m[12] << " " << m[13] << " " << m[14] << std::endl; + } + out << std::endl; + out.close(); + + SIBR_LOG << "[CameraRecorder] - Saved " << _cameras.size() << " cameras to " << filePath << " (using fovy " <<_cameras[0].fovy() << ")." << std::endl; + + } + + void CameraRecorder::saveAsColmap(const std::string& filePath, const int height, const int width) + { + + std::string basepath = parentDirectory(filePath); + std::cout << basepath << std::endl; + std::string images_filepath = basepath + "/images.txt"; + std::string cameras_filepath = basepath + "/cameras.txt"; + + std::ofstream out_images(images_filepath.c_str(), std::ios::binary); + std::ofstream out_cameras(cameras_filepath.c_str(), std::ios::binary); + + if (!out_images.good()) { + SIBR_LOG << "ERROR: cannot write to the file '" << filePath << "'" << std::endl; + return; + } + if (!out_cameras.good()) { + SIBR_LOG << "ERROR: cannot write to the file '" << filePath << "'" << std::endl; + return; + } + + if (_cameras.empty()) { + return; + } + + const int size = static_cast(_cameras.size()); + + sibr::Matrix3f converter; + converter << 1, 0, 0, + 0, -1, 0, + 0, 0, -1; + + + + out_images << "# Image list with two lines of data per image:" << std::endl; + out_images << "# IMAGE_ID, QW, QX, QY, QZ, TX, TY, TZ, CAMERA_ID, NAME" << std::endl; + out_images << "# POINTS2D[] as (X, Y, POINT3D_ID)" << std::endl; + for (int i = 0; i < _cameras.size(); i++) { + sibr::Matrix3f tmp = _cameras[i].rotation().toRotationMatrix() * converter; + sibr::Matrix3f Qinv = tmp.transpose(); + sibr::Quaternionf q = quatFromMatrix(Qinv); + sibr::Vector3f t = converter * _cameras[i].rotation().toRotationMatrix().transpose() * (-_cameras[i].position()); + + + out_images << i << " " << -_cameras[i].rotation().x() << " " << -_cameras[i].rotation().w() << " " << -_cameras[i].rotation().z() << " " << _cameras[i].rotation().y() << " " << + _cameras[i].view()(0, 3) << " " << -_cameras[i].view()(1, 3) << " " << -_cameras[i].view()(2, 3) << " " << i << " " << "00000000.png" << std::endl << std::endl; + + float focal = 0.5f * height / tan(_cameras[i].fovy() / 2.f); + //float focal = 1.0f / (tan(0.5f * cam.fovy()) * 2.0f / float(height)); + out_cameras << i << " " << "PINHOLE" << " " << width << " " << height << " " << focal << " " << focal << " " << width / 2.0 << " " << height / 2.0 << std::endl; + } + + out_images << std::endl; + out_images.close(); + out_cameras << std::endl; + out_cameras.close(); + SIBR_LOG << "[CameraRecorder] - Saved " << _cameras.size() << " cameras to " << filePath << " (using fovy " << _cameras[0].fovy() << ")." << std::endl; + + } + + + void CameraRecorder::saveAsFRIBRBundle(const std::string & dirPath, const int width, const int height) + { + const std::string bundlepath = dirPath + "/path.rd.out"; + const std::string listpath = dirPath + "/list.txt"; + const std::string imagesDir = dirPath + "/visualize/"; + sibr::makeDirectory(dirPath); + sibr::makeDirectory(imagesDir); + std::ofstream out(bundlepath); + std::ofstream outList(listpath); + if (out.good() && outList.good()) { + const int size = static_cast(_cameras.size() / 1); + out << "# Bundle file v0.3\n"; + out << size << " " << 0 << "\n"; + sibr::Matrix3f converter; + converter << 1, 0, 0, + 0, -1, 0, + 0, 0, -1; + sibr::Matrix3f from_cv; + from_cv << 1, 0, 0, + 0, -1, 0, + 0, 0, -1; + for (int i = 0; i < _cameras.size(); ++i) { + + const sibr::Camera cam = _cameras[i]; + + sibr::Matrix3f orientation = cam.rotation().toRotationMatrix(); + sibr::Vector3f position = cam.position(); + sibr::Matrix3f rotation_cv = converter.transpose() * orientation.transpose() * converter; + sibr::Matrix3f rotation_bundler = from_cv * rotation_cv; + sibr::Vector3f position_cv = converter.transpose() * position; + sibr::Vector3f translation_cv = -(rotation_cv * position_cv); + sibr::Vector3f pos = from_cv * translation_cv; + + sibr::Matrix3f m1 = rotation_bundler.transpose(); + float m[15]; + m[0] = 0.5f*height / tan(cam.fovy() / 2.f); m[1] = 0.0f; m[2] = 0.0f; + m[3] = m1(0, 0), m[4] = m1(1, 0), m[5] = m1(2, 0); + m[6] = m1(0, 1), m[7] = m1(1, 1), m[8] = m1(2, 1); + m[9] = m1(0, 2), m[10] = m1(1, 2), m[11] = m1(2, 2); + m[12] = pos.x(), m[13] = pos.y(), m[14] = pos.z(); + out << m[0] << " " << m[1] << " " << m[2] << std::endl; + out << m[3] << " " << m[4] << " " << m[5] << std::endl; + out << m[6] << " " << m[7] << " " << m[8] << std::endl; + out << m[9] << " " << m[10] << " " << m[11] << std::endl; + out << m[12] << " " << m[13] << " " << m[14] << std::endl; + + const std::string imageName = sibr::intToString<8>(i) + ".jpg"; + outList << "visualize/" + imageName << " 0 " << m[0] << std::endl; + + cv::Mat3b dummy(height, width); + cv::imwrite(imagesDir + imageName, dummy); + } + out << std::endl; + out.close(); + outList.close(); + + SIBR_LOG << "[CameraRecorder] - Saved " << _cameras.size() << " cameras to " << dirPath << "." << std::endl; + } + } + + void CameraRecorder::saveAsLookAt(const std::string & filePath) const + { + InputCamera::saveAsLookat(_cameras, filePath); + } + + // offline path rendering + bool CameraRecorder::loadPath(const std::string& pathFileName, int w, int h) { + _savingPath = parentDirectory(pathFileName); + if (!fileExists(pathFileName)) { + SIBR_WRG << "Camera path " << pathFileName << " doesnt exist. " << std::endl; + return false; + } + _ow = w, _oh = h; + if (boost::filesystem::extension(pathFileName) == ".out") + loadBundle(pathFileName, w, h); + else if (boost::filesystem::extension(pathFileName) == ".lookat") + loadLookat(pathFileName, w, h); + else if (boost::filesystem::extension(pathFileName) == ".txt") + loadColmap(pathFileName, w, h); + else + load(pathFileName); + return true; + } + + void CameraRecorder::recordOfflinePath(const std::string& outPathDir, ViewBase::Ptr view, const std::string& prefix) { + sibr::ImageRGBA32F::Ptr outImage; + outImage.reset(new ImageRGBA32F(_ow, _oh)); + std::string outpathd = outPathDir; + + sibr::RenderTargetRGBA32F::Ptr outFrame; + outFrame.reset(new RenderTargetRGBA32F(_ow, _oh)); + std::string outFileName; + + boost::filesystem::path dstFolder; + + outpathd = outPathDir; + + if (outPathDir == "pathOutput" && _savingPath != "") { // default to path parent, saved by loadPath + outpathd = _savingPath + "/" + "pathOutput"; + dstFolder = outpathd; + if (!directoryExists(outpathd) && !boost::filesystem::create_directories(dstFolder)) + SIBR_ERR << "Error creating directory " << dstFolder << std::endl; + } + + if( prefix != "" ) + dstFolder = outpathd = outpathd + "/" + prefix; + else + dstFolder = outpathd ; + + if (!directoryExists(outpathd) && !boost::filesystem::create_directories(dstFolder)) + SIBR_ERR << "Error creating directory " << dstFolder << std::endl; + + std::cout << "Rendering path with " << _cameras.size() << " cameras to " << outpathd << std::endl; + + for (int i = 0; i < _cameras.size(); ++i) { + outFrame->clear(); + std::ostringstream ssZeroPad; + ssZeroPad << std::setw(8) << std::setfill('0') << i; + outFileName = outpathd + "/" + ssZeroPad.str() + ".png"; + std::cout << outFileName << " " << std::endl; + view->onRenderIBR(*outFrame, _cameras[i]); + outFrame->readBack(*outImage); + outImage->save(outFileName, false); + } + std::cout << std::endl; + + std::cout << "Done rendering path. " << std::endl; + + } + + void CameraRecorder::saveImage(const std::string& outPathDir, const Camera& cam, int w, int h) { + sibr::ImageRGBA32F::Ptr outImage; + _ow = w, _oh = h; + outImage.reset(new ImageRGBA32F(_ow, _oh)); + std::string outpathd = outPathDir; + + sibr::RenderTargetRGBA32F::Ptr outFrame; + outFrame.reset(new RenderTargetRGBA32F(_ow, _oh)); + std::string outFileName; + + boost::filesystem::path dstFolder; + + outpathd = outPathDir; + + if (outPathDir == "") { // default to path parent, saved by loadPath + outpathd = _dsPath + "/" + "pathOutput"; + dstFolder = outpathd; + if (!directoryExists(outpathd) && !boost::filesystem::create_directories(dstFolder)) + SIBR_ERR << "Error creating directory " << dstFolder << std::endl; + } + + dstFolder = outpathd; + + if (!directoryExists(outpathd) && !boost::filesystem::create_directories(dstFolder)) + SIBR_ERR << "Error creating directory " << dstFolder << std::endl; + + std::cout << "Saving current camera to " << outpathd << std::endl; + + outFrame->clear(); + std::ostringstream ssZeroPad; + static int i = 0; + ssZeroPad << std::setw(8) << std::setfill('0') << i++; + outFileName = outpathd + "/" + ssZeroPad.str() + ".png"; + std::cout << outFileName << " " << std::endl; + _view->onRenderIBR(*outFrame, cam); + outFrame->readBack(*outImage); + outImage->save(outFileName, false); + std::cout << std::endl; + std::cout << "Done saving image. " << std::endl; + } + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/CameraRecorder.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/CameraRecorder.hpp new file mode 100755 index 0000000000000000000000000000000000000000..44dd414495ce45eeca7b82845926c023846a8bcf --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/CameraRecorder.hpp @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include +# include "core/assets/Config.hpp" +# include "core/graphics/Camera.hpp" +# include "core/view/ViewBase.hpp" + + +# define SIBR_CAMERARECORDER_DEFAULTFILE "camera-record.bytes" + +namespace sibr +{ + /** This class handles the recording and replay of a stream of cameras. + \ingroup sibr_assets + */ + class SIBR_ASSETS_EXPORT CameraRecorder + { + public: + + /** + Default constructor. + */ + CameraRecorder(void) : + _pos(0), _recording(false), _playing(false), _saving(false), _savingPath(""), _savingVideo(false), _savingVideoPath(""), _speed(1.0f), _interp(0.0f), _playNoInterp(false) { + //load(); + } + /** + Default destructor. + */ + ~CameraRecorder( void ) { + } + + /** + This method supports two modes: if the recorder is currently recording, + the camera argument will be saved into the recording; else if the recorder + is playing, the camera argument will be set to the current replaid camera. + \param cam A reference to the camera to record/update. + */ + void use( Camera& cam ); + + /** + Start playing the recorded camera stream from the beginning, at a rate of one step for each "use" call. + */ + void playback( void ); + + /** + Start recording a new camera stream, at a rate of one camera saved for each "use" call. + */ + void record( void ); + + /** + Start asking the renderer to save the frames, at a rate of one image saved for each "use" call. + */ + void saving(std::string savePath); + + /** + Toggle the save flag for video frames when replaying. + \param saveVideo the new flag status + */ + void savingVideo(bool saveVideo); + + /** + Stop saving. + */ + void stopSaving(void); + + /** + Stop playing/recording. + */ + void stop( void ); + + /** + Clear the current recording. + */ + void reset( void ); + + /** + Set value of play no interpolation + */ + void playNoInterpolation( bool val ) { _playNoInterp = val; } + + /** + Load a recorded camera stream from a given file. + \param filename Optional path to the file to load from. By default will try to + load SIBR_CAMERARECORDER_DEFAULTFILE from the current directory. + \return a boolean denoting the loading success/failure. + */ + bool load( const std::string& filename=SIBR_CAMERARECORDER_DEFAULTFILE ); + + /** + Save the current recording stream to a given file. + \param filename Optional path to the file to write to. By default will try to + write to SIBR_CAMERARECORDER_DEFAULTFILE in the current directory. + */ + void save( const std::string& filename=SIBR_CAMERARECORDER_DEFAULTFILE ); + + /** Load recorded path based on file extension. + *\param filename the file to load + *\param w resoltuion width + *\param h resolution height + *\return a success boolean + *\note w and h are needed when loading a Bundle. + */ + bool safeLoad(const std::string& filename, int w = 1920, int h = 1080); + + /** + Load a recording stream saved as a bundle file (useful for path from FRIBR). + \param filePath Path to the bundle file to write to. + \param w the image width to use for Fov computation + \param h the image height + */ + void loadBundle(const std::string & filePath, int w = 1920, int h = 1080); + + /** + *Load a camera path generated by the camera editor / bledner plugin + *\param filePath Path to the .lookat file. + *\param w Width of the cameras to create. + *\param h Height of the cameras to create. + */ + void loadLookat(const std::string &filePath, int w = 1920, int h = 1080); + + /** + *Load a camera path generated by colmap requires filename images.txt for now TODO GD; fix this + *\param filePath Path to the images.txt file; assumes that a cameras.txt is "next to" it; + *\param w Width of the cameras to create. + *\param h Height of the cameras to create. + */ + void loadColmap(const std::string &filePath, int w = 1920, int h = 1080); + + + /** + Save the current recording stream as a bundle file. + \param filePath Path to the bundle file to write to. + \param height the height in pixels of the camera. Used to compute focal length in mm as expected by bundle. + \param step set to a value greater than 1 to save every "step" camera in the recording stream. + */ + void saveAsBundle(const std::string & filePath, const int height, const int step = 1); + void saveAsColmap(const std::string& filePath, const int height, const int width); + + /** + Save the current recording stream as a bundle file and a series of empty images for FRIBR compatibility. + \param dirPath Path to the directory to export to. + \param width the width in pixels of the camera. + \param height the height in pixels of the camera. + */ + void saveAsFRIBRBundle(const std::string & dirPath, const int width, const int height); + + /** + Save the current recording stream as a lookat file. + \param filePath Path to the lookat file to write to. + */ + void saveAsLookAt(const std::string& filePath) const; + + /** + \return a boolean denoting if the recorder is currently playing. + */ + bool isPlaying() const { return _playing; } + + /** + \return a boolean denoting if the recorder is currently recording. + */ + bool isRecording() const { return _recording; } + + /** + \return a boolean denoting if the recorder is currently asking frames to be saved. + */ + bool isSaving() const { return _saving; } + + /** + \return A reference to the current stream of recorded cameras. + */ + std::vector& cams() { return _cameras; } + + /** + Updates the cameras from a vector, usefull to play already loaded path. + */ + void cams(std::vector& cams) { _cameras = cams; } + + + /** + Load a path, based on file extension name. Cameras loaded into _cameras + */ + bool loadPath(const std::string& pathFileName, int w, int h); + + /** + Play path for offline rendering using abstract View interface + */ + void recordOfflinePath(const std::string& outPathDir, ViewBase::Ptr view, const std::string& prefix); + + /** + Save an image + */ + void setViewPath(ViewBase::Ptr view, const std::string& dataset_path) { _view = view; _dsPath = dataset_path; }; + + void saveImage(const std::string& outPathDir, const Camera& cam, int w, int h); + + /** + * \return the interpolation speed + */ + float & speed() { return _speed; } + + private: + std::string _dsPath; // path to dataset + ViewBase::Ptr _view; // view to save images + uint _pos; ///< Current camera ID for replay. + std::vector _cameras; ///< List of recorded cameras. + bool _recording; ///< Are we currently recording. + bool _playing; ///< Are we currently playing. + bool _saving; ///< Are we saving the path as images. + std::string _savingPath; ///< Destination base path for saved images. + bool _savingVideo; ///< Are we saving the path as video. + std::string _savingVideoPath; ///< Destination base path for saved video. + float _speed; ///< Playback speed. + float _interp; ///< Current interpoaltion factor. + bool _playNoInterp; ///< Just play the cameras, make sure focal is preserved + int _ow, _oh; ///< offline output path resolution + }; + + ///// DEFINITIONS ///// + + + +} // namespace sibr + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/Config.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/Config.hpp new file mode 100644 index 0000000000000000000000000000000000000000..3386bc132505fb74fc7d335ba8c175f795ae5812 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/Config.hpp @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include "core/graphics/Config.hpp" +# include + + +#ifdef SIBR_OS_WINDOWS +//// Export Macro (used for creating DLLs) //// +# ifdef SIBR_STATIC_DEFINE +# define SIBR_EXPORT +# define SIBR_NO_EXPORT +# else +# ifndef SIBR_ASSETS_EXPORT +# ifdef SIBR_ASSETS_EXPORTS + /* We are building this library */ +# define SIBR_ASSETS_EXPORT __declspec(dllexport) +# else + /* We are using this library */ +# define SIBR_ASSETS_EXPORT __declspec(dllimport) +# endif +# endif +# ifndef SIBR_NO_EXPORT +# define SIBR_NO_EXPORT +# endif +# endif +# else +# define SIBR_ASSETS_EXPORT +# endif + +namespace sibr +{ + /** + * Utility that converts an integer id to a string using + * the "most used" format. + * \param id the id to convert (fi 7) + * \return the corresponding string (fi "0000007") + * \ingroup sibr_assets + */ + inline std::string imageIdToString( int id ) { + std::ostringstream oss; + oss << std::setfill('0') << std::setw(8) << id; + return oss.str(); + } + + /** Generate a string representation of an integer, padded with zeros. + * \param id the integer + * \return the padded string + * \note The template int value determines the padding count. + * \ingroup sibr_assets + * */ + template std::string intToString(int id) { + std::ostringstream oss; + oss << std::setfill('0') << std::setw(N) << id; + return oss.str(); + } + + /** + * Get the default path and filename used for the proxy + * mesh. + * \param datasetPath the base path + * \return the mesh path + * \ingroup sibr_assets + */ + inline std::string getProxyFilename( const std::string& datasetPath ) { + return datasetPath + "/pmvs/models/pmvs_recon.ply"; + } + + /** + * Loading status for streaming. + * \todo Rename the following status into: NotLoaded, CPULoading, CPUReady, GPUReady, Failure. + * \ingroup sibr_assets + */ + namespace LoadingStatus + { + enum Enum + { + NotLoaded = 0, + InProgress, + CPUReady, + Successful, + Failure, + + Count + }; + } // namespace LoadingStatus + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/IFileLoader.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/IFileLoader.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9d24dc248526f58b2ec7486a589f36502ba0f05c --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/IFileLoader.hpp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include "core/assets/Config.hpp" + +namespace sibr +{ + /** General file loading interface. + \ingroup sibr_assets + */ + class SIBR_ASSETS_EXPORT IFileLoader + { + public: + + /** Destructor. */ + virtual ~IFileLoader( void ) { } + + /** Load the file content from disk. + \param filename path to the file + \param verbose display information + \return a boolean denoting success + */ + virtual bool load( const std::string& filename, bool verbose = true ) = 0; + }; + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/ImageListFile.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/ImageListFile.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c354d7557147dac2f5c69a8a143e1380afc0f49b --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/ImageListFile.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +# include +# include +# include "core/assets/ImageListFile.hpp" + +namespace sibr +{ + bool ImageListFile::load( const std::string& filename, bool verbose ) + { + + std::fstream file(filename, std::ios::in); + + _infos.clear(); + if (file) + { + while (file.eof() == false) + { + Infos i; + file >> i.filename >> i.width >> i.height; + if (i.filename.size()) + _infos.emplace_back(std::move(i)); + } + + // store basename + boost::filesystem::path path(filename); + _basename = path.parent_path().string(); + + if( verbose ) + SIBR_FLOG << "'"<< filename <<"' successfully loaded." << std::endl; + + return true; + } + else + SIBR_WRG << "file not found: '"<& infos( void ) const { return _infos; } + + /** Image absename. + *\return the basename + **/ + const std::string& basename( void ) const { return _basename; } + + /** Load images. + \return the loaded images + */ + template + std::vector loadImages( void ) const; + + /** Load images, applying an active images file filter. + \param ac the active list file + \return the loaded images + \note Non-active images are present but empty. + */ + template + std::vector loadImages( const ActiveImageFile& ac) const; + + + private: + std::vector _infos; ///< Image infos. + std::string _basename; ///< Root name. + + }; + + ///// DEFINITIONS ///// + + + template + std::vector ImageListFile::loadImages( const ActiveImageFile& ac ) const { + std::vector out; + + SIBR_LOG << "[ImageListFile] loading images"; + out.resize(_infos.size()); + if (_infos.empty() == false) + { + #pragma omp parallel for + for (int i = 0; i < _infos.size(); ++i) + if( ac.active()[i] ) + out[i].load(_basename + "/" + _infos.at(i).filename, false); + } + else + SIBR_WRG << "cannot load images (ImageListFile is empty. Did you use ImageListFile::load(...) before ?"; + + std::cout << std::endl; + return out; + } + + template + std::vector ImageListFile::loadImages( void ) const { + std::vector out; + + std::cerr << "[ImageListFile] loading images"; + out.resize(_infos.size()); + if (_infos.empty() == false) + { + #pragma omp parallel for + for (int i = 0; i < _infos.size(); ++i) + out[i].load(_basename + "/" + _infos.at(i).filename, false); + } + else + SIBR_WRG << "cannot load images (ImageListFile is empty. Did you use ImageListFile::load(...) before ?"; + + return out; + } + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/InputCamera.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/InputCamera.cpp new file mode 100755 index 0000000000000000000000000000000000000000..97f07547f0de68a6688658078bed0a754e6126e6 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/InputCamera.cpp @@ -0,0 +1,1577 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "core/assets/ActiveImageFile.hpp" +#include "core/assets/InputCamera.hpp" +#include +#include +#include "core/system/String.hpp" +#include "picojson/picojson.hpp" + + +// Colmap binary stuff +#include "colmapheader.h" +typedef uint32_t image_t; +typedef uint32_t camera_t; +typedef uint64_t point3D_t; +typedef uint32_t point2D_t; + +#define SIBR_INPUTCAMERA_BINARYFILE_VERSION 10 +#define IBRVIEW_TOPVIEW_SAVEVERSION "version002" +#define FOCAL_X_UNDEFINED -1 + +namespace sibr +{ + InputCamera::InputCamera(float f, float k1, float k2, int w, int h, int id) : + _focal(f), _k1(k1), _k2(k2), _w(w), _h(h), _id(id), _active(true), _name(""), _focalx(FOCAL_X_UNDEFINED) + { + // Update fov and aspect ratio. + float fov = 2.0f * atan(0.5f * h / f); + float aspect = float(w) / float(h); + + Camera::aspect(aspect); + Camera::fovy(fov); + + _id = id; + } + + InputCamera::InputCamera(float fy, float fx, float k1, float k2, int w, int h, int id) : + _focal(fy), _k1(k1), _k2(k2), _w(w), _h(h), _id(id), _active(true), _name(""), _focalx(fx) + { + // Update fov and aspect ratio. + float fovY = 2.0f * atan(0.5f * h / fy); + float fovX = 2.0f * atan(0.5f * w / fx); + + Camera::aspect(tan(fovX / 2) / tan(fovY / 2)); + Camera::fovy(fovY); + + _id = id; + } + + + InputCamera::InputCamera(int id, int w, int h, sibr::Matrix4f m, bool active) : + _active(active) + { + Vector3f t; + float r[9]; + + for (int i = 0; i < 9; i++) r[i] = m(3 + i); + for (int i = 0; i < 3; i++) t[i] = m(12 + i); + + _w = w; + _h = h; + + _focal = m(0); + _focalx = FOCAL_X_UNDEFINED; + _k1 = m(1); + _k2 = m(2); + + float fov = 2.0f * atan(0.5f * h / m(0)); + float aspect = float(w) / float(h); + + sibr::Matrix3f matRotation; + matRotation << + r[0], r[1], r[2], + r[3], r[4], r[5], + r[6], r[7], r[8] + ; + + Camera::aspect(aspect); + Camera::fovy(fov); + + // http://www.cs.cornell.edu/~snavely/bundler/bundler-v0.4-manual.html#S6 + // Do pos = -R' * t + const sibr::Matrix3f orientation = matRotation.transpose(); + sibr::Vector3f position = -orientation * t; + Camera::position(position); + Camera::rotation(Quaternionf(orientation)); + + + Camera::principalPoint({ 0.5f, 0.5f }); + + + _id = id; + _name = ""; + } + + + + InputCamera::InputCamera(int id, int w, int h, sibr::Vector3f& position, sibr::Matrix3f& orientation, float focal, float k1, float k2, bool active) : + _active(active) + { + + + _w = w; + _h = h; + + _focal = focal; + _focalx = FOCAL_X_UNDEFINED; + _k1 = k1; + _k2 = k2; + + float fov = 2.0f * atan(0.5f * h / _focal); + float aspect = float(w) / float(h); + + + + Camera::aspect(aspect); + Camera::fovy(fov); + + // http://www.cs.cornell.edu/~snavely/bundler/bundler-v0.4-manual.html#S6 + // Do pos = -R' * t + + Camera::position(position); + Camera::rotation(Quaternionf(orientation)); + + _id = id; + _name = ""; + } + + InputCamera::InputCamera(const Camera& c, int w, int h) : Camera(c) { + _focal = 1.0f / (tan(0.5f * fovy()) * 2.0f / float(h)); + _focalx = FOCAL_X_UNDEFINED; + _k1 = _k2 = 0; + _w = w; + _h = h; + _id = 0; + _name = ""; + _active = true; + aspect(float(_w) / float(_h)); + } + + // ------------------------------------------------------------------------ + + void InputCamera::size(uint w, uint h) { _w = w; _h = h; } + uint InputCamera::w(void) const { return _w; } + uint InputCamera::h(void) const { return _h; } + bool InputCamera::isActive(void) const { return _active; } + + /* compatibility for preprocess (depth) */ + + + Vector3f InputCamera::projectScreen(const Vector3f& pt) const { + Vector3f proj_pt = project(pt); + Vector3f screen_pt((proj_pt[0] + 1.f) * _w / 2.0f, (1.f - proj_pt[1]) * _h / 2.0f, proj_pt[2] * 0.5f + 0.5f); + + return screen_pt; + } + + float InputCamera::focal() const { return _focal; }; + float InputCamera::focalx() const { return _focalx; }; + float InputCamera::k1() const { return _k1; }; + float InputCamera::k2() const { return _k2; }; + + InputCamera InputCamera::resizedH(int h) const { + + int w = int(_aspect * h); + + float sibr_focal = h * _focal / _h; + float k1 = _k1; + float k2 = _k2; + int id = _id; + + sibr::Matrix4f m; + + sibr::InputCamera cam(sibr_focal, k1, k2, w, h, id); + + cam.rotation(rotation()); + cam.position(position()); + + cam.znear(znear()); + cam.zfar(zfar()); + cam.name(name()); + + return cam; + } + + InputCamera InputCamera::resizedW(int w) const { + + int h = int(float(w) / _aspect); + + float sibr_focal = h * _focal / _h; + float k1 = _k1; + float k2 = _k2; + int id = _id; + + sibr::Matrix4f m; + + sibr::InputCamera cam(sibr_focal, k1, k2, w, h, id); + + cam.rotation(rotation()); + cam.position(position()); + + cam.znear(znear()); + cam.zfar(zfar()); + cam.name(name()); + + return cam; + } + + + + std::vector InputCamera::load(const std::string& datasetPath, float zNear, float zFar, const std::string& bundleName, const std::string& listName) + { + const std::string bundlerFile = datasetPath + "/cameras/" + bundleName; + const std::string listFile = datasetPath + "/images/" + listName; + const std::string clipFile = datasetPath + "/clipping_planes.txt"; + + // Loading clipping planes if they are available. + SIBR_LOG << "Loading clipping planes from " << clipFile << std::endl; + + struct Z { + Z() {} + Z(float f, float n) : far(f), near(n) {} + float far; + float near; + }; + std::vector nearsFars; + + { // Load znear & zfar for unprojecting depth samples + + float z; + std::ifstream zfile(clipFile); + // During preprocessing clipping planes are not yet defined + // the preprocess utility "depth" defines this + // SIBR_ASSERT(zfile.is_open()); + if (zfile.is_open()) { + int num_z_values = 0; + while (zfile >> z) { + if (num_z_values % 2 == 0) { + nearsFars.push_back(Z()); + nearsFars[nearsFars.size() - 1].near = z; + } + else { + nearsFars[nearsFars.size() - 1].far = z; + } + ++num_z_values; + } + + if (num_z_values > 0 && num_z_values % 2 != 0) { + nearsFars.resize(nearsFars.size() - 1); + } + + if (nearsFars.size() == 0) { + SIBR_WRG << " Could not extract at leat 2 clipping planes from '" << clipFile << "' ." << std::endl; + } + } + else { + SIBR_WRG << "Cannot open '" << clipFile << "' (not clipping plane loaded)." << std::endl; + } + + } + + // Load cameras and images infos. + SIBR_LOG << "Loading input cameras." << std::endl; + auto cameras = InputCamera::loadBundle(bundlerFile, zNear, zFar, listFile); + + if (!nearsFars.empty()) { + for (int cid = 0; cid < cameras.size(); ++cid) { + const int zid = std::min(cid, int(nearsFars.size()) - 1); + cameras[cid]->znear(nearsFars[zid].near); + cameras[cid]->zfar(nearsFars[zid].far); + } + } + + // Load active images + ActiveImageFile activeImageFile; + activeImageFile.setNumImages((int)cameras.size()); + // load active image file and set (in)active + if (activeImageFile.load(datasetPath + "/active_images.txt", false)) { + for (int i = 0; i < (int)cameras.size(); i++) { + if (!activeImageFile.active()[i]) + cameras[i]->setActive(false); + } + } + + // Load excluded images + ActiveImageFile excludeImageFile; + excludeImageFile.setNumImages((int)cameras.size()); + // load exclude image file and set *in*active + if (excludeImageFile.load(datasetPath + "/exclude_images.txt", false)) { + for (int i = 0; i < (int)cameras.size(); i++) { + // Attn (GD): invert the meaning of active for exclude: + // only file numbers explicitly in exclude_images are set + // to active, and these are the only ones we set to *inactive* + // should really create a separate class or have a flag "invert" + if (excludeImageFile.active()[i]) + cameras[i]->setActive(false); + } + } + return cameras; + } + + std::vector InputCamera::loadNVM(const std::string& nvmPath, float zNear, float zFar, std::vector wh) + { + std::ifstream in(nvmPath); + std::vector cameras; + + if (in.is_open()) + { + int rotation_parameter_num = 4; + bool format_r9t = false; + std::string token; + if (in.peek() == 'N') + { + in >> token; //file header + if (strstr(token.c_str(), "R9T")) + { + rotation_parameter_num = 9; //rotation as 3x3 matrix + format_r9t = true; + } + } + + int ncam = 0, npoint = 0, nproj = 0; + // read # of cameras + in >> ncam; if (ncam <= 1) return std::vector(); + + //read the camera parameters + + std::function matrix = [](const double q[9]) + { + + Eigen::Matrix3f m; + double qq = sqrt(q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]); + double qw, qx, qy, qz; + if (qq > 0) + { + qw = q[0] / qq; + qx = q[1] / qq; + qy = q[2] / qq; + qz = q[3] / qq; + } + else + { + qw = 1; + qx = qy = qz = 0; + } + m(0, 0) = float(qw * qw + qx * qx - qz * qz - qy * qy); + m(0, 1) = float(2 * qx * qy - 2 * qz * qw); + m(0, 2) = float(2 * qy * qw + 2 * qz * qx); + m(1, 0) = float(2 * qx * qy + 2 * qw * qz); + m(1, 1) = float(qy * qy + qw * qw - qz * qz - qx * qx); + m(1, 2) = float(2 * qz * qy - 2 * qx * qw); + m(2, 0) = float(2 * qx * qz - 2 * qy * qw); + m(2, 1) = float(2 * qy * qz + 2 * qw * qx); + m(2, 2) = float(qz * qz + qw * qw - qy * qy - qx * qx); + + return m; + }; + + for (int i = 0; i < ncam; ++i) + { + double f, q[9], c[3], d[2]; + in >> token >> f; + for (int j = 0; j < rotation_parameter_num; ++j) in >> q[j]; + in >> c[0] >> c[1] >> c[2] >> d[0] >> d[1]; + + std::string image_path = sibr::parentDirectory(nvmPath) + "/" + token; + sibr::Vector2i resolution = sibr::IImage::imageResolution(image_path); + + if (resolution.x() < 0 || resolution.y() < 0) + { + std::cerr << "Could not get resolution for input image: " << image_path << std::endl; + return std::vector(); + } + + int wIm = 1, hIm = 1; + if (ncam == wh.size()) { + wIm = wh[i].x(); + hIm = wh[i].y(); + } + else { + wIm = resolution.x(); + hIm = resolution.y(); + } + + //camera_data[i].SetFocalLength(f); + cameras.emplace_back(new InputCamera((float)f, (float)d[0], (float)d[1], wIm, hIm, i)); + + float fov = 2.0f * atan(0.5f * hIm / (float)f); + float aspect = float(wIm) / float(hIm); + cameras[i]->aspect(aspect); + cameras[i]->fovy(fov); + + //translation + Vector3f posCam((float)c[0], (float)c[1], (float)c[2]); + + if (format_r9t) + { + + std::cout << " WARNING THIS PART OF THE CODE WAS NEVER TESTED. IT IS SUPPOSED NOT TO WORK PROPERLY" << std::endl; + Eigen::Matrix3f matRotation; + matRotation << + float(q[0]), float(q[1]), float(q[2]), + float(q[3]), float(q[4]), float(q[5]), + float(q[6]), float(q[7]), float(q[8]) + ; + matRotation.transposeInPlace(); + + + cameras[i]->position(posCam); + cameras[i]->rotation(Quaternionf(matRotation)); + + } + else + { + + Eigen::Matrix3f converter; + converter << + 1, 0, 0, + 0, -1, 0, + 0, 0, -1; + //older format for compability + Quaternionf quat((float)q[0], (float)q[1], (float)q[2], (float)q[3]); + Eigen::Matrix3f matRotation = converter.transpose() * quat.toRotationMatrix(); + matRotation.transposeInPlace(); + + cameras[i]->position(posCam); + cameras[i]->rotation(Quaternionf(matRotation)); + + } + //camera_data[i].SetNormalizedMeasurementDistortion(d[0]); + cameras[i]->name(token); + } + std::cout << ncam << " cameras; " << npoint << " 3D points; " << nproj << " projections\n"; + } + else { + SIBR_WRG << "Cannot open '" << nvmPath << std::endl; + } + + return cameras; + } + + std::vector InputCamera::loadLookat(const std::string& lookatPath, const std::vector& wh, float znear, float zfar) + { + + std::ifstream in(lookatPath); + std::vector cameras; + + if (in.is_open()) + { + int i = 0; + for (std::string line; safeGetline(in, line); i++) + { + int w = 1024, h = 768; + if (wh.size() > 0) { + int whI = std::min(i, (int)wh.size() - 1); + w = wh[whI].x(); + h = wh[whI].y(); + } + else { + std::cout << "Warning default image size of 1024*768 is supposed for camera" << std::endl; + } + + bool use_fovx = false; + std::string camName = line.substr(0, line.find(" ")); + size_t originPos = line.find("-D origin=") + 10; + size_t targetPos = line.find("-D target=") + 10; + size_t upPos = line.find("-D up=") + 6; + size_t fovPos = line.find("-D fovy=") + 8; + int delta_fov = 9; + if (fovPos < 8) { + std::cout << "Warning: Fovy not found, backing to Fovx mode" << std::endl; + fovPos = line.find("-D fov=") + 7; + use_fovx = true; + delta_fov = 8; + } + size_t clipPos = line.find("-D clip=") + 8; + size_t aspectPos = line.find("-D aspect=") + 10; + size_t endPos = line.size(); + + std::string originStr = line.substr(originPos, targetPos - originPos - 11); + std::string targetStr = line.substr(targetPos, upPos - targetPos - 7); + std::string upStr = line.substr(upPos, fovPos - upPos - delta_fov); + std::string fovStr = line.substr(fovPos, clipPos - fovPos - 9); + std::string clipStr = line.substr(clipPos, endPos - clipPos); + + std::vector vecVal; + boost::split(vecVal, originStr, [](char c) {return c == ','; }); + Vector3f Eye(std::strtof(vecVal[0].c_str(), 0), std::strtof(vecVal[1].c_str(), 0), std::strtof(vecVal[2].c_str(), 0)); + boost::split(vecVal, targetStr, [](char c) {return c == ','; }); + Vector3f At(std::strtof(vecVal[0].c_str(), 0), std::strtof(vecVal[1].c_str(), 0), std::strtof(vecVal[2].c_str(), 0)); + + boost::split(vecVal, upStr, [](char c) {return c == ','; }); + Vector3f Up(std::strtof(vecVal[0].c_str(), 0), std::strtof(vecVal[1].c_str(), 0), std::strtof(vecVal[2].c_str(), 0)); + + float fov = std::strtof(fovStr.c_str(), 0); + + boost::split(vecVal, clipStr, [](char c) {return c == ','; }); + Vector2f clip(std::strtof(vecVal[0].c_str(), 0), std::strtof(vecVal[1].c_str(), 0)); + + Vector3f zAxis((Eye - At).normalized()); + Vector3f xAxis((Up.cross(zAxis)).normalized()); + Vector3f yAxis(zAxis.cross(xAxis)); + + Vector3f transl(-Eye.dot(xAxis), -Eye.dot(yAxis), -Eye.dot(zAxis)); + + Eigen::Matrix3f rotation; + rotation << xAxis, yAxis, zAxis; + rotation.transposeInPlace(); + + Eigen::Matrix4f mLook; + mLook.setZero(); + mLook.block<3, 3>(0, 0) = rotation; + mLook.block<3, 1>(0, 3) = transl; + mLook(3, 3) = 1; + + float fovRad = fov * float(M_PI) / 180; + float sibr_focal = 0.5f * h / tan(fovRad / 2.0f); //Lookat file contain the vertical field of view now + if (use_fovx) { + sibr_focal = 0.5f * w / tan(fovRad / 2.0f); //Lookat file contain the vertical field of view now + } + + Eigen::Matrix4f r(mLook); + /*float m[15] = { + sibr_focal,0,0, + r(0,0),r(0,1),r(0,2), + r(1,0),r(1,1),r(1,2), + r(2,0),r(2,1),r(2,2), + r(0,3),r(1,3),r(2,3) + }; + */ + Eigen::Matrix4f m; + m(0) = sibr_focal; m(1) = 0; m(2) = 0; + m(3) = r(0, 0); m(4) = r(0, 1); m(5) = r(0, 2); + m(6) = r(1, 0); m(7) = r(1, 1); m(8) = r(1, 2); + m(9) = r(2, 0); m(10) = r(2, 1); m(11) = r(2, 2); + m(12) = r(0, 3); m(13) = r(1, 3); m(14) = r(2, 3); + + + bool isActive = true; + + cameras.emplace_back(new InputCamera((int)cameras.size(), w, h, m, isActive)); + + if (znear > 0) { + cameras[i]->znear(znear); + } + else { + cameras[i]->znear(clip.x()); + } + if (zfar > 0) { + cameras[i]->zfar(zfar); + } + else { + cameras[i]->zfar(clip.y()); + } + cameras[i]->name(camName); + } + + } + else { + SIBR_WRG << "Cannot open '" << lookatPath << std::endl; + } + + return cameras; + + } + + std::string InputCamera::lookatString() const { + std::string infos = std::string(" -D origin=") + + std::to_string(position()[0]) + + std::string(",") + + std::to_string(position()[1]) + + std::string(",") + + std::to_string(position()[2]) + + std::string(" -D target=") + + std::to_string(position()[0] + + dir()[0]) + + std::string(",") + + std::to_string(position()[1] + + dir()[1]) + + std::string(",") + + std::to_string(position()[2] + + dir()[2]) + + std::string(" -D up=") + + std::to_string(up()[0]) + + std::string(",") + + std::to_string(up()[1]) + + std::string(",") + + std::to_string(up()[2]) + + std::string(" -D fovy=") + + std::to_string(180 * fovy() / M_PI) + + std::string(" -D clip=") + + std::to_string(znear()) + + std::string(",") + + std::to_string(zfar()) + + std::string("\n"); + return infos; + } + + void InputCamera::saveAsLookat(const std::vector& cams, const std::string& fileName) { + + std::ofstream fileRender(fileName, std::ios::out | std::ios::trunc); + for (const auto& cam : cams) { + + fileRender << cam->name() << cam->lookatString(); + } + + fileRender.close(); + } + + void InputCamera::saveImageSizes(const std::vector& cams, const std::string& fileName) { + + std::ofstream fileRender(fileName, std::ios::out | std::ios::trunc); + for (const auto& cam : cams) { + + fileRender << cam->w() << "x" << cam->h() << "\n"; + } + + fileRender.close(); + } + + + + + std::vector InputCamera::loadColmap(const std::string& colmapSparsePath, const float zNear, const float zFar, const int fovXfovYFlag) + { + const std::string camerasListing = colmapSparsePath + "/cameras.txt"; + const std::string imagesListing = colmapSparsePath + "/images.txt"; + + const std::string camerasListing2 = colmapSparsePath + "/cameras.txt2"; + const std::string imagesListing2 = colmapSparsePath + "/images.txt2"; + + std::ifstream camerasFile(camerasListing); + std::ifstream imagesFile(imagesListing); + std::ofstream camerasFile2(camerasListing2); + std::ofstream imagesFile2(imagesListing2); + if (!camerasFile.is_open()) { + SIBR_ERR << "Unable to load camera colmap file" << std::endl; + } + if (!imagesFile.is_open()) { + SIBR_WRG << "Unable to load images colmap file" << std::endl; + } + + std::vector cameras; + + std::string line; + + struct CameraParametersColmap { + size_t id; + size_t width; + size_t height; + float fx; + float fy; + float dx; + float dy; + }; + + std::map cameraParameters; + + std::map> camidtokens; + + while (safeGetline(camerasFile, line)) { + if (line.empty() || line[0] == '#') { + continue; + } + + std::vector tokens = sibr::split(line, ' '); + if (tokens.size() < 8) { + SIBR_WRG << "Unknown line." << std::endl; + continue; + } + if (tokens[1] != "PINHOLE" && tokens[1] != "OPENCV") { + SIBR_WRG << "Unknown camera type." << std::endl; + continue; + } + + CameraParametersColmap params; + params.id = std::stol(tokens[0]); + params.width = std::stol(tokens[2]); + params.height = std::stol(tokens[3]); + params.fx = std::stof(tokens[4]); + params.fy = std::stof(tokens[5]); + params.dx = std::stof(tokens[6]); + params.dy = std::stof(tokens[7]); + + cameraParameters[params.id] = params; + + camidtokens[params.id] = tokens; + } + + // Now load the individual images and their extrinsic parameters + sibr::Matrix3f converter; + converter << 1, 0, 0, + 0, -1, 0, + 0, 0, -1; + + int camid = 0; + int valid = 0; + while (safeGetline(imagesFile, line)) { + if (line.empty() || line[0] == '#') { + continue; + } + std::vector tokens = sibr::split(line, ' '); + if (tokens.size() < 10) { + SIBR_WRG << "Unknown line." << std::endl; + continue; + } + + uint cId = std::stoi(tokens[0]) - 1; + float qw = std::stof(tokens[1]); + float qx = std::stof(tokens[2]); + float qy = std::stof(tokens[3]); + float qz = std::stof(tokens[4]); + float tx = std::stof(tokens[5]); + float ty = std::stof(tokens[6]); + float tz = std::stof(tokens[7]); + size_t id = std::stol(tokens[8]); + + std::string imageName = tokens[9]; + + if (cameraParameters.find(id) == cameraParameters.end()) + { + SIBR_ERR << "Could not find intrinsics for image: " + << tokens[9] << std::endl; + } + const CameraParametersColmap& camParams = cameraParameters[id]; + + const sibr::Quaternionf quat(qw, qx, qy, qz); + const sibr::Matrix3f orientation = quat.toRotationMatrix().transpose() * converter; + sibr::Vector3f translation(tx, ty, tz); + + sibr::Vector3f position = -(orientation * converter * translation); + + sibr::InputCamera::Ptr camera; + if (fovXfovYFlag) { + camera = std::make_shared(InputCamera(camParams.fy, camParams.fx, 0.0f, 0.0f, int(camParams.width), int(camParams.height), int(cId))); + } + else { + camera = std::make_shared(InputCamera(camParams.fy, 0.0f, 0.0f, int(camParams.width), int(camParams.height), int(cId))); + } + + camera->name(imageName); + camera->position(position); + camera->rotation(sibr::Quaternionf(orientation)); + camera->znear(zNear); + camera->zfar(zFar); + + if (camera->position().x() < 0) + { + camerasFile2 << ++valid; + for (int i = 1; i < camidtokens[id].size(); i++) + camerasFile2 << " " << camidtokens[id][i]; + camerasFile2 << "\n\n"; + + imagesFile2<< valid; + for (int i = 1; i < tokens.size() - 1; i++) + imagesFile2 << " " << tokens[i]; + imagesFile2 << " " << valid << std::endl; + imagesFile2 << "\n\n"; + } + + cameras.push_back(camera); + + ++camid; + // Skip the observations. + safeGetline(imagesFile, line); + } + + + return cameras; + } + + std::vector InputCamera::loadBundle(const std::string& bundlerPath, float zNear, float zFar, const std::string& listImagePath, bool path) + { + SIBR_LOG << "Loading input cameras." << std::endl; + + // check bundler file + std::ifstream bundle_file(bundlerPath); + if (!bundle_file.is_open()) { + SIBR_ERR << "Unable to load bundle file at path \"" << bundlerPath << "\"." << std::endl; + return {}; + } + + const std::string listImages = listImagePath.empty() ? (bundlerPath + "/../list_images.txt") : listImagePath; + std::ifstream list_images(listImages); + if (!list_images.is_open()) { + SIBR_ERR << "Unable to load list_images file at path \"" << listImages << "\"." << std::endl; + return {}; + } + + // read number of images + std::string line; + getline(bundle_file, line); // ignore first line - contains version + int numImages = 0; + bundle_file >> numImages; // read first value (number of images) + getline(bundle_file, line); // ignore the rest of the line + + // Read all filenames + struct ImgInfos + { + std::string name; + int id; + int w, h; + }; + std::vector imgInfos; + { + ImgInfos infos; + while (true) + { + list_images >> infos.name; + if (infos.name.empty()) break; + list_images >> infos.w >> infos.h; + infos.name.erase(infos.name.find_last_of("."), std::string::npos); + infos.id = atoi(infos.name.c_str()); + imgInfos.push_back(infos); + infos.name.clear(); + } + } + + ImgInfos infoPrevImage; + bool shortListImages = false; + // check if list images has the same number of cameras as path, else assume we read the dataset list_images.txt + if (path && imgInfos.size() != numImages) + shortListImages = true; + + + + + std::vector cameras(numImages); + // Parse bundle.out file for camera calibration parameters + for (int i = 0, infosId = 0; i < numImages; i++) { + + ImgInfos infos; + std::string camName; + + if (!shortListImages) { + infoPrevImage = infos = imgInfos[infosId]; + camName = infos.name; + if (infosId > imgInfos.size()) + break; + } + else { + // hack; use info of last available image, but (always) change name + if( i < imgInfos.size()) + infoPrevImage = infos = imgInfos[infosId]; + else + infos = infoPrevImage; + + std::stringstream ss; + ss << std::setw(10) << std::setfill('0') << i; + std::string s = ss.str(); + camName = std::string("path_camera") + s; + } + + Matrix4f m; // bundler params + + bundle_file >> m(0) >> m(1) >> m(2) >> m(3) >> m(4); + bundle_file >> m(5) >> m(6) >> m(7) >> m(8) >> m(9); + bundle_file >> m(10) >> m(11) >> m(12) >> m(13) >> m(14); + + cameras[infosId] = InputCamera::Ptr(new InputCamera(infosId, infos.w, infos.h, m, true)); + cameras[infosId]->name(camName); + cameras[infosId]->znear(zNear); cameras[infosId]->zfar(zFar); + + ++infosId; + } + + return cameras; + } + + std::vector InputCamera::loadBundleFRIBR(const std::string& bundlerPath, float zNear, float zFar, const std::string& listImagePath) + { + SIBR_LOG << "Loading input cameras." << std::endl; + + // check bundler file + std::ifstream bundle_file(bundlerPath); + if (!bundle_file.is_open()) { + SIBR_ERR << "Unable to load bundle file at path \"" << bundlerPath << "\"." << std::endl; + return {}; + } + + + // read number of images + std::string line; + getline(bundle_file, line); // ignore first line - contains version + int numImages = 0; + bundle_file >> numImages; // read first value (number of images) + getline(bundle_file, line); // ignore the rest of the line + + std::vector cameras(numImages); + + Eigen::Matrix3f to_cv, converter; + to_cv << 1.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, + 0.0f, 0.0f, -1.0f; + converter << + 1, 0, 0, + 0, -1, 0, + 0, 0, -1; + // Parse bundle.out file for camera calibration parameters + for (int i = 0; i < numImages; i++) { + + float f, k1, k2; + bundle_file >> f >> k1 >> k2; + + float r00, r01, r02; + float r10, r11, r12; + float r20, r21, r22; + bundle_file >> r00 >> r01 >> r02 + >> r10 >> r11 >> r12 + >> r20 >> r21 >> r22; + + Eigen::Matrix3f rotation; + rotation(0, 0) = r00; + rotation(0, 1) = r01; + rotation(0, 2) = r02; + rotation(1, 0) = r10; + rotation(1, 1) = r11; + rotation(1, 2) = r12; + rotation(2, 0) = r20; + rotation(2, 1) = r21; + rotation(2, 2) = r22; + + sibr::Matrix3f orientation = (to_cv * rotation).transpose(); + + float tx, ty, tz; + bundle_file >> tx >> ty >> tz; + sibr::Vector3f position = -orientation * (to_cv * Eigen::Vector3f(tx, ty, tz)); + + std::stringstream pad_stream; + pad_stream << std::setfill('0') << std::setw(10) << i - 2 << ".png"; + std::string image_path = sibr::parentDirectory(bundlerPath) + "/" + listImagePath + pad_stream.str(); + + sibr::Vector2u resolution(2, 2); + sibr::ImageRGB temp; + if (!temp.load(image_path)) { + + pad_stream.str(""); + pad_stream << std::setfill('0') << std::setw(8) << i << ".jpg"; + image_path = sibr::parentDirectory(bundlerPath) + "/" + listImagePath + pad_stream.str(); + temp.load(image_path); + } + resolution = temp.size(); + + if (resolution.x() < 0 || resolution.y() < 0) + { + std::cerr << "Could not get resolution for calibrated camera: " << image_path << std::endl; + return {}; + } + + float dx = resolution.x() * 0.5f; + float dy = resolution.y() * 0.5f; + + orientation = /*converter.transpose() **/ orientation * converter; + position = /*converter.transpose() **/ position; + + cameras[i] = InputCamera::Ptr(new InputCamera(i, resolution.x(), resolution.y(), position, orientation, f, k1, k2, true)); + cameras[i]->name(pad_stream.str()); + cameras[i]->znear(zNear); cameras[i]->zfar(zFar); + + } + + return cameras; + } + + std::vector InputCamera::loadMeshroom(const std::string& meshroomSFMPath, const float zNear, const float zFar) + { + + std::string file_path = meshroomSFMPath + "/cameras.sfm"; + + std::ifstream json_file(file_path, std::ios::in); + + if (!json_file) + { + std::cerr << "file loading failed: " << file_path << std::endl; + return std::vector(); + } + + std::vector cameras; + + picojson::value v; + picojson::set_last_error(std::string()); + std::string err = picojson::parse(v, json_file); + if (!err.empty()) { + picojson::set_last_error(err); + json_file.setstate(std::ios::failbit); + } + + picojson::array& views = v.get("views").get(); + picojson::array& intrinsincs = v.get("intrinsics").get(); + picojson::array& poses = v.get("poses").get(); + + int numCameras = int(poses.size()); + //meras.resize(numCameras); + + sibr::Matrix3f converter; + converter << 1.0f, 0, 0, + 0, -1, 0, + 0, 0, -1; + + size_t pose_idx, view_idx, intrinsic_idx; + std::vector splitS; + + + for (size_t i = 0; i < numCameras; ++i) + { + + Matrix4f m; + //std::vector splitS; + + pose_idx = i; + std::string pose_id = poses[pose_idx].get("poseId").get(); + + for (size_t j = 0; j < views.size(); j++) { + if (pose_id.compare(views[j].get("poseId").get()) == 0) { + view_idx = j; + break; + } + } + + std::string intrinsics_id = views[view_idx].get("intrinsicId").get(); + + for (size_t k = 0; k < intrinsincs.size(); k++) { + if (intrinsics_id.compare(intrinsincs[k].get("intrinsicId").get()) == 0) { + intrinsic_idx = k; + break; + } + } + + m(0) = std::stof(intrinsincs[intrinsic_idx].get("pxFocalLength").get()); + float dx = std::stof(intrinsincs[intrinsic_idx].get("principalPoint").get()[0].get()); + float dy = std::stof(intrinsincs[intrinsic_idx].get("principalPoint").get()[1].get()); + + //std::stof(intrinsincs[intrinsic_idx].get("distortionParams").get()[0].get()); + m(1) = dx; + //std::stof(intrinsincs[intrinsic_idx].get("distortionParams").get()[1].get()); + m(2) = dy; + + std::string camName = pose_id + ".exr"; + int width = std::stoi(views[view_idx].get("width").get()); + int height = std::stoi(views[view_idx].get("height").get()); + + uint camId = uint(i); + + picojson::array& center = poses[pose_idx].get("pose").get("transform").get("center").get(); + picojson::array& rotation = poses[pose_idx].get("pose").get("transform").get("rotation").get(); + + std::vector rows; + Eigen::Vector3f row; + Eigen::Vector3f position(std::stof(center[0].get()), std::stof(center[1].get()), std::stof(center[2].get())); + Eigen::Matrix3f orientation; + + for (int ii = 0; ii < 3; ++ii) { + for (int jj = 0; jj < 3; ++jj) + row(jj) = std::stof(rotation[jj + ii * 3].get()); + rows.push_back(row); + } + + orientation.row(0) = rows[0]; + orientation.row(1) = rows[1]; + orientation.row(2) = rows[2]; + orientation = orientation * converter; + + for (int ii = 0; ii < 9; ii++) { + m(3 + ii) = orientation(ii); + } + + const sibr::Vector3f finTrans = -orientation.transpose() * position; + for (int ii = 0; ii < 3; ii++) { + m(12 + ii) = finTrans[ii]; + } + + sibr::InputCamera::Ptr cam = std::make_shared(camId, width, height, m, true); + cam->name(camName); + cam->znear(zNear); + cam->zfar(zFar); + cameras.push_back(cam); + + } + return cameras; + } + + Vector3f InputCamera::unprojectImgSpaceInvertY(const sibr::Vector2i& pixelPos, const float& depth) const + { + sibr::Vector2f pos2dGL(2.0f * ((pixelPos.cast() + sibr::Vector2f(0.5, 0.5)).cwiseQuotient(sibr::Vector2f(w(), h()))) - sibr::Vector2f(1, 1)); //to [-1,1] + pos2dGL.y() = -pos2dGL.y(); + return unproject(sibr::Vector3f(pos2dGL.x(), pos2dGL.y(), depth)); + } + + Vector3f InputCamera::projectImgSpaceInvertY(const Vector3f& point3d) const + { + sibr::Vector3f pos2dGL = project(point3d); + pos2dGL.y() = -pos2dGL.y(); + sibr::Vector2f pos2dImg = (0.5f * (pos2dGL.xy() + sibr::Vector2f(1, 1))).cwiseProduct(sibr::Vector2f(w(), h())); + return sibr::Vector3f(pos2dImg.x(), pos2dImg.y(), pos2dGL.z()); + } + + bool InputCamera::loadFromBinary(const std::string& filename) + { + ByteStream bytes; + + if (bytes.load(filename)) + { + uint8 version; + float focal; + float k1; + float k2; + uint16 w; + uint16 h; + Vector3f pos; + Quaternionf rot; + float fov; + float aspect; + float znear; + float zfar; + + bytes + >> version; + + if (version != SIBR_INPUTCAMERA_BINARYFILE_VERSION) + { + // Maybe the file format has been updated, or your binary file is not about InputCamera... + SIBR_ERR << "incorrect file format (version number does not correspond)." << std::endl; + + return false; + } + + bytes + >> focal >> k1 >> k2 >> w >> h + >> pos.x() >> pos.y() >> pos.z() + >> rot.w() >> rot.x() >> rot.y() >> rot.z() + >> fov >> aspect >> znear >> zfar + ; + + _focal = focal; + _k1 = k1; + _k2 = k2; + _w = (uint)w; + _h = (uint)h; + Camera::position(pos); + Camera::rotation(rot); + Camera::fovy(fov); + Camera::aspect(aspect); + Camera::znear(znear); + Camera::zfar(zfar); + + return true; + } + else + { + SIBR_WRG << "cannot open file '" << filename << "'." << std::endl; + } + return false; + } + + void InputCamera::saveToBinary(const std::string& filename) const + { + ByteStream bytes; + + uint8 version = SIBR_INPUTCAMERA_BINARYFILE_VERSION; + float focal = _focal; + float k1 = _k1; + float k2 = _k2; + uint16 w = (uint16)_w; + uint16 h = (uint16)_h; + Vector3f pos = position(); + Quaternionf rot = rotation(); + float fov = _fov; + float aspect = _aspect; + float znear = _znear; + float zfar = _zfar; + + bytes + << version + << focal << k1 << k2 << w << h + << pos.x() << pos.y() << pos.z() + << rot.w() << rot.x() << rot.y() << rot.z() + << fov << aspect << znear << zfar + ; + + bytes.saveToFile(filename); + } + + void InputCamera::readFromFile(std::istream& infile) + { + std::string version; + infile >> version; + if (version != IBRVIEW_TOPVIEW_SAVEVERSION) + { + SIBR_WRG << "Sorry but your TopView camera configuration " + "is too old (we added new features since!)" << std::endl; + return; + } + + Vector3f v; + infile >> v.x() >> v.y() >> v.z(); + Quaternionf q; + infile >> q.x() >> q.y() >> q.z() >> q.w(); + set(v, q); + } + + void InputCamera::writeToFile(std::ostream& outfile) const + { + outfile << IBRVIEW_TOPVIEW_SAVEVERSION "\n"; + Vector3f v = transform().position(); + Quaternionf q = transform().rotation(); + outfile << " " << v.x() << " " << v.y() << " " << v.z() << " "; + outfile << q.x() << " " << q.y() << " " << q.z() << " " << q.w(); + } + + std::string InputCamera::toBundleString(bool negativeZ, bool recomputeFocal) const { + + std::stringstream ss; + ss << std::setprecision(16); + float focal; + if( recomputeFocal ) + focal = 0.5f * h() / tan(fovy() / 2.0f); // We cannot set the focal but we need to compute it + else + focal = _focal; + + Eigen::Matrix3f r = transform().rotation().toRotationMatrix(); + sibr::Vector3f t = -transform().rotation().toRotationMatrix().transpose() * position(); + + ss << focal << " " << k1() << " " << k2() << "\n"; // The focal is set to zero in the loading module we use fov=2.0f * atan( 0.5f*h / focal) here + if (!negativeZ) { + ss << r(0) << " " << r(1) << " " << r(2) << "\n"; + ss << r(3) << " " << r(4) << " " << r(5) << "\n"; + ss << r(6) << " " << r(7) << " " << r(8) << "\n"; + ss << t(0) << " " << t(1) << " " << t(2) << "\n"; + } + else { + ss << r(0) << " " << -r(2) << " " << r(1) << "\n"; + ss << r(3) << " " << -r(5) << " " << r(4) << "\n"; + ss << r(6) << " " << -r(8) << " " << r(7) << "\n"; + ss << t(0) << " " << t(1) << " " << t(2) << "\n"; + } + + return ss.str(); + } + + std::vector InputCamera::getImageCorners() const + { + return { {0,0}, {_w - 1, 0}, {_w - 1,_h - 1}, {0, _h - 1} }; + } + + void InputCamera::saveAsBundle(const std::vector& cams, const std::string& fileName, bool negativeZ, const bool exportImages, bool oldFocal) { + + std::ofstream outputBundleCam; + outputBundleCam.open(fileName); + outputBundleCam << "# Bundle file v0.3" << std::endl; + outputBundleCam << cams.size() << " " << 0 << std::endl; + + for (int c = 0; c < cams.size(); c++) { + auto& camIm = cams[c]; + outputBundleCam << camIm->toBundleString(negativeZ, oldFocal); + } + + outputBundleCam.close(); + + // Export the images list and empty images (useful for fribr). + if (exportImages) { + std::ofstream outList; + const std::string listpath = fileName + "/../list_images.txt"; + const std::string imagesDir = fileName + "/../visualize/"; + sibr::makeDirectory(imagesDir); + + outList.open(listpath); + if (outList.good()) { + for (int i = 0; i < cams.size(); ++i) { + const sibr::InputCamera::Ptr cam = cams[i]; + const std::string imageName = cam->name().empty() ? sibr::intToString<8>(i) + ".jpg" : cam->name(); + outList << "visualize/" << imageName << " " << cam->w() << " " << cam->h() << std::endl; + cv::Mat3b dummy(cam->h(), cam->w()); + cv::imwrite(imagesDir + imageName, dummy); + } + outList.close(); + } + else { + SIBR_WRG << "Unable to export images list to path \"" << listpath << "\"." << std::endl; + } + } + } + + void InputCamera::saveAsLookat(const std::vector& cams, const std::string& fileName) + { + + std::ofstream file(fileName, std::ios::out | std::ios::trunc); + if (!file.is_open()) { + SIBR_WRG << "Unable to save to file at path " << fileName << std::endl; + return; + } + // Get the padding count. + const int len = int(std::floor(std::log10(cams.size()))) + 1; + for (size_t cid = 0; cid < cams.size(); ++cid) { + const auto& cam = cams[cid]; + std::string id = std::to_string(cid); + const std::string pad = std::string(len - id.size(), '0'); + + const sibr::Vector3f& pos = cam.position(); + const sibr::Vector3f& up = cam.up(); + const sibr::Vector3f tgt = cam.position() + cam.dir(); + + + file << "Cam" << pad << id; + file << " -D origin=" << pos[0] << "," << pos[1] << "," << pos[2]; + file << " -D target=" << tgt[0] << "," << tgt[1] << "," << tgt[2]; + file << " -D up=" << up[0] << "," << up[1] << "," << up[2]; + file << " -D fovy=" << cam.fovy(); + file << " -D clip=" << cam.znear() << "," << cam.zfar(); + file << "\n"; + } + + file.close(); + } + + std::vector InputCamera::loadColmapBin(const std::string& colmapSparsePath, const float zNear, const float zFar, const int fovXfovYFlag) + { + const std::string camerasListing = colmapSparsePath + "/cameras.bin"; + const std::string imagesListing = colmapSparsePath + "/images.bin"; + + + std::ifstream camerasFile(camerasListing, std::ios::binary); + std::ifstream imagesFile(imagesListing, std::ios::binary); + + if (!camerasFile.is_open()) { + SIBR_ERR << "Unable to load camera colmap file" << camerasListing << std::endl; + } + if (!imagesFile.is_open()) { + SIBR_WRG << "Unable to load images colmap file" << imagesListing << std::endl; + } + + std::vector cameras; + + std::string line; + + struct CameraParametersColmap { + size_t id; + size_t width; + size_t height; + float fx; + float fy; + float dx; + float dy; + }; + + std::map cameraParameters; + const size_t num_cameras = ReadBinaryLittleEndian(&camerasFile); + + for (size_t i = 0; i < num_cameras ; ++i) { + + CameraParametersColmap params; + + params.id = ReadBinaryLittleEndian(&camerasFile); + int model_id = ReadBinaryLittleEndian(&camerasFile); + params.width = ReadBinaryLittleEndian(&camerasFile); + params.height = ReadBinaryLittleEndian(&camerasFile); + std::vector Params(4); + + ReadBinaryLittleEndian(&camerasFile, &Params); + params.fx = float(Params[0]); + params.fy = float(Params[1]); + params.dx = float(Params[2]); + params.dy = float(Params[3]); + cameraParameters[params.id] = params; + } + + // Now load the individual images and their extrinsic parameters + sibr::Matrix3f converter; + converter << 1, 0, 0, + 0, -1, 0, + 0, 0, -1; + + const size_t num_reg_images = ReadBinaryLittleEndian(&imagesFile); + for (size_t i = 0; i < num_reg_images; ++i) { + + uint cId = ReadBinaryLittleEndian(&imagesFile); + float qw = float(ReadBinaryLittleEndian(&imagesFile)); + float qx = float(ReadBinaryLittleEndian(&imagesFile)) ; + float qy = float(ReadBinaryLittleEndian(&imagesFile)) ; + float qz = float(ReadBinaryLittleEndian(&imagesFile)) ; + float tx = float(ReadBinaryLittleEndian(&imagesFile)); + float ty = float(ReadBinaryLittleEndian(&imagesFile)); + float tz = float(ReadBinaryLittleEndian(&imagesFile)); + size_t id = ReadBinaryLittleEndian(&imagesFile) ; + + + if (cameraParameters.find(id) == cameraParameters.end()) + { + /* code multi camera broken + SIBR_ERR << "Could not find intrinsics for image: " + << id << std::endl; + */ + id = 1; + } + const CameraParametersColmap& camParams = cameraParameters[id]; + + + const sibr::Quaternionf quat(qw, qx, qy, qz); + const sibr::Matrix3f orientation = quat.toRotationMatrix().transpose() * converter; + sibr::Vector3f translation(tx, ty, tz); + + sibr::Vector3f position = -(orientation * converter * translation); + + sibr::InputCamera::Ptr camera; + if (fovXfovYFlag) { + camera = std::make_shared(InputCamera(camParams.fy, camParams.fx, 0.0f, 0.0f, int(camParams.width), int(camParams.height), int(cId))); + } + else { + camera = std::make_shared(InputCamera(camParams.fy, 0.0f, 0.0f, int(camParams.width), int(camParams.height), int(cId))); + } + std::string image_name; + char name_char; + do { + imagesFile.read(&name_char, 1); + if (name_char != '\0') { + image_name += name_char; + } + } while (name_char != '\0'); + + camera->name(image_name); + camera->position(position); + camera->rotation(sibr::Quaternionf(orientation)); + camera->znear(zNear); + camera->zfar(zFar); + cameras.push_back(camera); + + + // ignore the 2d points + const size_t num_points2D = ReadBinaryLittleEndian(&imagesFile); + + for (size_t j = 0; j < num_points2D; ++j) { + const double x = ReadBinaryLittleEndian(&imagesFile); + const double y = ReadBinaryLittleEndian(&imagesFile); + point3D_t id = ReadBinaryLittleEndian(&imagesFile); + } + } + return cameras; + } + + std::vector InputCamera::loadJSON(const std::string& jsonPath, const float zNear, const float zFar) + { + std::ifstream json_file(jsonPath, std::ios::in); + + if (!json_file) + { + std::cerr << "file loading failed: " << jsonPath << std::endl; + return std::vector(); + } + + std::vector cameras; + + picojson::value v; + picojson::set_last_error(std::string()); + std::string err = picojson::parse(v, json_file); + if (!err.empty()) { + picojson::set_last_error(err); + json_file.setstate(std::ios::failbit); + } + + picojson::array& frames = v.get(); + + for (size_t i = 0; i < frames.size(); ++i) + { + int id = frames[i].get("id").get(); + std::string imgname = frames[i].get("img_name").get(); + int width = frames[i].get("width").get(); + int height = frames[i].get("height").get(); + float fy = frames[i].get("fy").get(); + float fx = frames[i].get("fx").get(); + + sibr::InputCamera::Ptr camera = std::make_shared(InputCamera(fy, fx, 0.0f, 0.0f, width, height, id)); + + picojson::array& pos = frames[i].get("position").get(); + sibr::Vector3f position(pos[0].get(), pos[1].get(), pos[2].get()); + + //position.x() = 0; + //position.y() = 0; + //position.z() = 1; + + picojson::array& rot = frames[i].get("rotation").get(); + sibr::Matrix3f orientation; + for (int i = 0; i < 3; i++) + { + picojson::array& row = rot[i].get(); + for (int j = 0; j < 3; j++) + { + orientation(i, j) = row[j].get(); + } + } + orientation.col(1) = -orientation.col(1); + orientation.col(2) = -orientation.col(2); + //orientation = sibr::Matrix3f::Identity(); + + camera->name(imgname); + camera->position(position); + camera->rotation(sibr::Quaternionf(orientation)); + camera->znear(zNear); + camera->zfar(zFar); + cameras.push_back(camera); + } + return cameras; + } + + std::vector InputCamera::loadTransform(const std::string& transformPath, int w, int h, std::string extension, const float zNear, const float zFar, const int offset, const int fovXfovYFlag) + { + std::ifstream json_file(transformPath, std::ios::in); + + if (!json_file) + { + std::cerr << "file loading failed: " << transformPath << std::endl; + return std::vector(); + } + + std::vector cameras; + + picojson::value v; + picojson::set_last_error(std::string()); + std::string err = picojson::parse(v, json_file); + if (!err.empty()) { + picojson::set_last_error(err); + json_file.setstate(std::ios::failbit); + } + + float fovx = v.get("camera_angle_x").get(); + picojson::array& frames = v.get("frames").get(); + + for (int i = 0; i < frames.size(); i++) + { + std::string imgname = frames[i].get("file_path").get() + "." + extension; + + auto mat = frames[i].get("transform_matrix").get(); + + Eigen::Matrix4f matrix; + for (int i = 0; i < 4; i++) + { + auto row = mat[i].get(); + for (int j = 0; j < 4; j++) + { + matrix(i, j) = row[j].get(); + } + } + + Eigen::Matrix3f R = matrix.block<3, 3>(0, 0); + Eigen::Vector3f T(matrix(0, 3), matrix(1, 3), matrix(2, 3)); + + float focalx = 0.5f * w / tan(fovx / 2.0f); + float focaly = (((float)h)/w) * focalx; + + sibr::InputCamera::Ptr camera; + if (fovXfovYFlag) { + camera = std::make_shared(InputCamera(focaly, focalx, 0.0f, 0.0f, int(w), int(h), i + offset)); + } + else { + camera = std::make_shared(InputCamera(focalx, 0.0f, 0.0f, int(w), int(h), i + offset)); + } + + camera->name(imgname); + camera->position(T); + camera->rotation(sibr::Quaternionf(R)); + camera->znear(zNear); + camera->zfar(zFar); + cameras.push_back(camera); + } + return cameras; + } + + +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/InputCamera.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/InputCamera.hpp new file mode 100644 index 0000000000000000000000000000000000000000..66dfdb804bb6bd4e3221aa2dcb7ed6e80b2298b6 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/InputCamera.hpp @@ -0,0 +1,333 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include "core/graphics/Config.hpp" +#include "core/graphics/Camera.hpp" +#include "core/assets/Config.hpp" + +namespace sibr +{ + /** Input camera parameters. Inherits all basic camera functionality from Camera + * and adds functions for depth samples from multi-view stereo. + * + * \sa Camera, NovelCamera + * \ingroup sibr_assets + */ + class SIBR_ASSETS_EXPORT InputCamera : public Camera + { + public: + typedef std::shared_ptr Ptr; + + /** Near/far plane representation. */ + struct Z { + + /** Constructor. */ + Z() {} + + /** Constructor. + * \warning Ordering of the values is swapped. + * \param f far plane + * \param n near plane + */ + Z(float f, float n) : far(f), near(n) {} + + float far = 0.0f; ///< Far plane. + float near = 0.0f; ///< Near plane. + }; + + /** Default constructor. */ + InputCamera() : + _focal(0.f), _k1(0.f), _k2(0.f), _w(0), _h(0), _id(0), _active(true) + { } + + /** Partial constructor + * \param f focal length in mm + * \param k1 first distortion parameter + * \param k2 second distortion parameter + * \param w width of input image + * \param h height of input image + * \param id ID of input image + */ + InputCamera(float f, float k1, float k2, int w, int h, int id); + InputCamera(float fy, float fx, float k1, float k2, int w, int h, int id); + + /** Constructor, initialize the input camera. + * \param id ID of input image + * \param w width of input image + * \param h height of input image + * \param position camera position + * \param rotation camera rotation + * \param focal focal length in mm + * \param k1 first distortion parameter + * \param k2 second distortion parameter + * \param active input image active or not + */ + InputCamera(int id, int w, int h, sibr::Vector3f & position, sibr::Matrix3f & rotation, float focal, float k1, float k2, bool active); + + /** Constructor, initialize the input camera. + * \param id ID of input image + * \param w width of input image + * \param h height of input image + * \param m camera parameters resad from Bundler output file + * \param active input image active or not + * \param fovFromFocal: if true, compute fov from focal else use "standard sibr" convention + * \sa Bundler: http://phototour.cs.washington.edu/bundler/ + * \deprecated Avoid using this legacy constructor. + */ + InputCamera(int id, int w, int h, sibr::Matrix4f m, bool active); + + /** Constructor from a basic Camera. + * \param c camera + * \param w image width + * \param h image height + */ + InputCamera(const Camera& c, int w, int h); + + /** Copy constructor. */ + InputCamera(const InputCamera&) = default; + + /** Move constructor. */ + InputCamera(InputCamera&&) = default; + + /** Copy operator. */ + InputCamera& operator =(const InputCamera&) = default; + + /** Move operator. */ + InputCamera& operator =(InputCamera&&) = default; + + /** Input image width + * \return width of input image + */ + uint w(void) const; + + /** Input image height + * \return height of input image + */ + uint h(void) const; + + /** Check if the input camera active or inactive, + * camera is completely ignored if set to inactive. + * \return true if active, false otherwise + */ + bool isActive(void) const; + + /** Set camera active status + *\param active if true, camera is in use + */ + void setActive(bool active) { _active = active ; } + + /** \return the image name */ + inline const std::string& name(void) const { return _name; } + + /** Set camera name + * \param s the new name + */ + inline void name( const std::string& s ) { _name = s; } + + /** Update image dimensions. Calls \a update() after changing image width and height + * \param w image width + * \param h image height + */ + void size( uint w, uint h ); + + /** \return the camera id */ + uint id() const { return _id; } + + /** Project a world space point into screen space. + *\param pt 3d world point + *\return screen space position and depth, in (0,w)x(0,h)x(0,1) + */ + Vector3f projectScreen( const Vector3f& pt ) const; + + /** \return the focal length */ + float focal() const; + + /** \return the focal length x */ + float focalx() const; + + /** set the focal length ; to be used with caution; focal is usually inferred from the fov*/ + void setFocal(float focal) { _focal = focal; } + + /** \return the k1 distorsion parameter */ + float k1() const; + + /** \return the k2 distorsion parameter */ + float k2() const; + + /** Back-project pixel coordinates and depth. + * \param pixelPos pixel coordinates p[0],p[1] in [0,w-1]x[0,h-1] + * \param depth d in [-1,1] + * \returns 3D world point + */ + Vector3f unprojectImgSpaceInvertY( const sibr::Vector2i & pixelPos, const float & depth ) const; + + /** Project 3D point using perspective projection. + * \param point3d 3D point + * \returns pixel coordinates in [0,w-1]x[0,h-1] and depth d in [-1,1] + */ + Vector3f projectImgSpaceInvertY( const Vector3f& point3d ) const; + + /** Load from internal binary representation. + * \param filename file path + * \return success boolean + */ + bool loadFromBinary( const std::string& filename ); + + /** Save to disk using internal binary representation. + * \param filename file path + */ + void saveToBinary( const std::string& filename ) const; + + /** Save a file in the IBR TopView format. + * \param outfile the destination file + */ + void writeToFile(std::ostream& outfile) const; + + /** Load a file in the IBR TopView format. + * \param infile the input file + */ + void readFromFile(std::istream& infile); + + /** Conver to Bundle string. + * \param negativeZ should the Z axis be flipped + * \recomputeFocal recompute the focal or just set + * \return a string that can be used to create a bundle file from this camera + */ + std::string toBundleString(bool negativeZ = false, bool recomputeFocal = true) const; + + + /** \return A vector of four Vector2i corresponding to the pixels at the camera corners + */ + std::vector getImageCorners() const; + + /** Return a new camera resized to the specified height + */ + sibr::InputCamera resizedH(int h) const; + /** Return a new camera resized to the specified height + */ + sibr::InputCamera resizedW(int w) const; + + /** Return the lookat string of the camera + */ + std::string lookatString() const; + /** save a vector of cameras as lookat + */ + static void saveAsLookat(const std::vector & cams, const std::string & fileName); + /** save a vector of cameras sizes to a file to be read by mitsuba rendering script + */ + static void saveImageSizes(const std::vector & cams, const std::string & fileName); + + + /** Save a vector of cameras as a bundle file. + *\param cams the cameras + * \param fileName output bundle file path + * \param negativeZ should the Z axis be flipped + * \param exportImages should empty images with the proper dimensions be saved in a visualize subdirectory + * \param oldFocal: recompute focal, else assign that of camera TODO: fix this + */ + static void saveAsBundle(const std::vector & cams, const std::string & fileName, bool negativeZ = false, bool exportImages = false, bool recomputeFocal=true); + + /** Save a vector of cameras as a lookat file. + *\param cams the cameras + * \param fileName output lookat file path + */ + static void saveAsLookat(const std::vector & cams, const std::string & fileName); + + /** Load cameras from a bundler file. + *\param datasetPath path to the root of the dataset, should contain bundle.out, list_images.txt and optionally clipping_planes.txt + * \param zNear default near-plane value to use if the clipping_planes.txt file doesn't exist + * \param zFar default far-plane value to use if the clipping_planes.txt file doesn't exist + * \param bundleName name of the bundle file + * \param listName name of the list images file + * \returns the loaded cameras + */ + static std::vector load( const std::string& datasetPath, float zNear = 0.01f, float zFar = 1000.0f, const std::string & bundleName = "bundle.out", const std::string & listName = "list_images.txt"); + + /** Load cameras from a NVM file. + *\param nvmPath path to the NVM file + * \param zNear default near-plane value to use + * \param zFar default far-plane value to use. + * \param wh will contain the sizes of each camera image + * \returns the loaded cameras + */ + static std::vector loadNVM(const std::string& nvmPath, float zNear = 0.01f, float zFar = 1000.0f, std::vector wh = std::vector()); + + /** Load cameras from a .lookat file generated by our Blender plugin. + * \param lookatPath path to the lookAt file + * \param wh indicative size of each camera image + * \param zNear default near-plane value to use + * \param zFar default far-plane value to use. + * \returns the loaded cameras + */ + static std::vector loadLookat(const std::string& lookatPath, const std::vector& wh= std::vector(),float zNear= -1, float zFar= -1); + + static std::vector InputCamera::loadTransform(const std::string& transformPath, int w, int h, std::string extension, const float zNear = 0.01f, const float zFar = 1000.0f, const int offset = 0, const int fovXfovYFlag = 0); + + /** Load cameras from a Colmap txt file. + * \param colmapSparsePath path to the Colmap sparse directory, should contains cameras.txt and images.txt + * \param zNear default near-plane value to use + * \param zFar default far-plane value to use. + * \param fovXfovYFlag should we use two dimensional fov. + * \returns the loaded cameras + * \note the camera frame is internally transformed to be consistent with fribr and RC. + */ + static std::vector loadColmap(const std::string& colmapSparsePath, const float zNear = 0.01f, const float zFar = 1000.0f, const int fovXfovYFlag = 0); + + static std::vector loadColmapBin(const std::string& colmapSparsePath, const float zNear = 0.01f, const float zFar = 1000.0f, const int fovXfovYFlag = 0); + + static std::vector loadJSON(const std::string& jsonPath, const float zNear = 0.01f, const float zFar = 1000.0f); + + /** Load cameras from a bundle file. + * \param bundlerPath path to the bundle file. + * \param zNear default near-plane value to use + * \param zFar default far-plane value to use. + * \param listImagePath path to the list_images.txt file. Will default to a file in the same directory as the bundle.out file. + * \param path: if this is a path, then you can load more images that those defined in the list_images file of the datset; TODO: possibly should require a list_images.txt for the path + * \returns the loaded cameras + */ + static std::vector loadBundle(const std::string& bundlerPath, float zNear = 0.01f, float zFar = 1000.0f, const std::string & listImagePath = "", bool path = false); + + /** Load cameras from a bundle file. + * \param bundlerPath path to the bundle file. + * \param zNear default near-plane value to use + * \param zFar default far-plane value to use. + * \param listImagePath path to the list_images.txt file. Will default to a file in the same directory as the bundle.out file. + * \returns the loaded cameras + */ + static std::vector loadBundleFRIBR(const std::string& bundlerPath, float zNear = 0.01f, float zFar = 1000.0f, const std::string & listImagePath = ""); + + /** Load cameras from a Meshrrom SFM cameras.sfm txt file. + * \param meshroomSFMPath path to the Meshroom StructureFromMotion/{dd63cea98bda0e3b53ec76f17b0753b3e4dde589}/ directory, should contains cameras.sfm + * \param zNear default near-plane value to use + * \param zFar default far-plane value to use. + * \returns the loaded cameras + * \note the camera frame is internally transformed to be consistent with fribr and RC. + */ + static std::vector loadMeshroom(const std::string& meshroomSFMPath, const float zNear = 0.01f, const float zFar = 1000.0f); + + uint _id; ///< Input camera id + + protected: + + float _focal; ///< focal length + float _focalx; ///< focal length x, if there is one (colmap typically; -1 by default use with caution) + float _k1; ///< K1 bundler distorsion parameter + float _k2; ///< K2 bundler dist parameter + uint _w; ///< Image width + uint _h; ///< Image height + std::string _name; ///< Input image name + bool _active; ///< is the camera currently in use. + }; + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/Resources.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/Resources.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7b43e90f4fa9f0670a5c960fa6f71287b9c8a082 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/Resources.cpp @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include +#include +#include +#include +#include "core/assets/Resources.hpp" + +/// \todo TODO: If you care about security (did someone want to hack/use your app +/// to hide a virus/retrieve informations from this compiled code), comment +/// the following line and resolve warnings by finding new safe-functions. +#pragma warning(disable:4996) // affect this .cpp only + +namespace sibr +{ + + Resources* Resources::_instance = NULL; + + Resources* Resources::Instance() + { + if (_instance == 0) + _instance = new Resources; + return _instance; + } + + Resources::Resources() + { + _rscPaths.push_back(sibr::getInstallDirectory()); + std::ifstream rscFile(sibr::getInstallDirectory() + "/ibr_resources.ini"); + + if(rscFile.good()) + { + for(std::string line; safeGetline(rscFile, line); ) + { + _rscPaths.push_back(line); + } + } + else { + std::ifstream rscFile2(sibr::getInstallDirectory() + "/bin/ibr_resources.ini"); + for(std::string line; safeGetline(rscFile2, line); ) + _rscPaths.push_back(line); + } + + /// \todo WIP: used in prevision to load plugins (TODO: test under linux) + std::ifstream pathFile(sibr::getInstallDirectory() + "/ibr_paths.ini"); + if(pathFile.good()) + { + for(std::string line; safeGetline(pathFile, line); ) + { + std::string name = line.substr(0, line.find("=")); + std::string value = line.substr(line.find("=")+1, line.length()); + char* curEnv = getenv(name.c_str()); + std::string currentEnv; + if(curEnv!=NULL) + currentEnv = std::string(curEnv); +#ifdef SIBR_OS_WINDOWS + std::replace(value.begin(), value.end(), '/', '\\'); // linux to windows path + char delimiter = ';'; +#else + std::replace(value.begin(), value.end(), '\\', '/'); // windows to linux path + char delimiter = ':'; +#endif + std::stringstream ss; + ss << delimiter; + if(!currentEnv.empty()) + if (currentEnv.at(currentEnv.length()-1) != delimiter) + currentEnv.append(ss.str()); + + line = name + "=" + currentEnv + value; + putenv(const_cast(line.c_str())); + + std::cout<<"[Resources] env: "< +#include + +namespace sibr +{ + + /** Singleton used to store a list of plausible path to look for (based on the ibr_resources.ini) + \ingroup sibr_assets + */ + class SIBR_ASSETS_EXPORT Resources + { + public: + /// Our singleton + static Resources* Instance(); + + protected: + /// Constructor. + Resources(); + + /// Destructor + virtual ~Resources(); + + public: + /** Look for the filename into plausible resource paths. + * \param filename file name + * \param success was the file found in the registered locations + * \return the full file path + */ + std::string getResourceFilePathName(std::string const & filename, bool & success); + + /** Look for the filename into plausible resource paths. + * \param filename file name + * \return the full file path + */ + std::string getResourceFilePathName(std::string const & filename); + + protected: + std::vector _rscPaths; ///< List of directories to check into. + static Resources * _instance; ///< Singleton. + }; + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/UVUnwrapper.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/UVUnwrapper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..500b5725024e571e45d65af6c55ca561892b744a --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/UVUnwrapper.cpp @@ -0,0 +1,276 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "UVUnwrapper.hpp" +#include +#include +#include "xatlas.h" + +int printCallback(const char * format, ...) { + va_list args; + va_start(args, format); + std::cout << "\r"; + const int res = vprintf(format, args); + va_end(args); + return res; +} + +bool progressCallback(xatlas::ProgressCategory category, int progress, void *userData){ + std::cout << "\r\t" << xatlas::StringForEnum(category) << "[" << std::flush; + for (int i = 0; i < 10; i++) + std::cout << (progress / ((i + 1) * 10) ? "*" : " "); + std::cout << "] " << progress << "%" << std::flush; + if(progress == 100) { + std::cout << std::endl; + } + return true; +} + +void setPixel(uint8_t *dest, int destWidth, int x, int y, const sibr::Vector3ub & color){ + uint8_t *pixel = &dest[x * 3 + y * (destWidth * 3)]; + pixel[0] = color[0]; + pixel[1] = color[1]; + pixel[2] = color[2]; +} + +// https://github.com/miloyip/line/blob/master/line_bresenham.c +// License: public domain. +static void rasterizeLine(uint8_t *dest, int destWidth, const int *p1, const int *p2, const sibr::Vector3ub & color) +{ + const int dx = abs(p2[0] - p1[0]), sx = p1[0] < p2[0] ? 1 : -1; + const int dy = abs(p2[1] - p1[1]), sy = p1[1] < p2[1] ? 1 : -1; + int err = (dx > dy ? dx : -dy) / 2; + int current[2]; + current[0] = p1[0]; + current[1] = p1[1]; + while(setPixel(dest, destWidth, current[0], current[1], color), current[0] != p2[0] || current[1] != p2[1]){ + const int e2 = err; + if (e2 > -dx) { err -= dy; current[0] += sx; } + if (e2 < dy) { err += dx; current[1] += sy; } + } +} + +/* +https://github.com/ssloy/tinyrenderer/wiki/Lesson-2:-Triangle-rasterization-and-back-face-culling +Copyright Dmitry V. Sokolov + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ +void rasterizeTriangle(uint8_t *dest, int destWidth, const int *t0, const int *t1, const int *t2, const sibr::Vector3ub & color) +{ + if (t0[1] > t1[1]) std::swap(t0, t1); + if (t0[1] > t2[1]) std::swap(t0, t2); + if (t1[1] > t2[1]) std::swap(t1, t2); + const int total_height = t2[1] - t0[1]; + for (int i = 0; i < total_height; i++) { + const bool second_half = i > t1[1] - t0[1] || t1[1] == t0[1]; + const int segment_height = second_half ? t2[1] - t1[1] : t1[1] - t0[1]; + const float alpha = (float)i / total_height; + const float beta = (float)(i - (second_half ? t1[1] - t0[1] : 0)) / float(segment_height); + int A[2], B[2]; + for (int j = 0; j < 2; j++) { + A[j] = int(t0[j] + (t2[j] - t0[j]) * alpha); + B[j] = int(second_half ? t1[j] + (t2[j] - t1[j]) * beta : t0[j] + (t1[j] - t0[j]) * beta); + } + if (A[0] > B[0]) std::swap(A, B); + for (int j = A[0]; j <= B[0]; j++) { + setPixel(dest, destWidth, j, t0[1] + i, color); + } + } +} + +using namespace sibr; + +UVUnwrapper::UVUnwrapper(const sibr::Mesh& mesh, unsigned int res) : _mesh(mesh) { + _size = res; + // Create empty atlas. + xatlas::SetPrint(printCallback, false); + _atlas = xatlas::Create(); + xatlas::SetProgressCallback(_atlas, progressCallback, nullptr); + + // Add the mesh to the atlas. + SIBR_LOG << "[UVMapper] Adding one mesh with " << mesh.vertices().size() << " vertices and " << mesh.triangles().size() << " triangles." << std::endl; + // For now consider everything as one mesh. Splitting in components *might* help. + xatlas::MeshDecl meshDecl; + meshDecl.vertexCount = uint32_t(mesh.vertices().size()); + meshDecl.vertexPositionData = mesh.vertexArray(); + meshDecl.vertexPositionStride = sizeof(sibr::Vector3f); + if (mesh.hasNormals()) { + meshDecl.vertexNormalData = mesh.normalArray(); + meshDecl.vertexNormalStride = sizeof(sibr::Vector3f); + } + // UV can be used as a hint. + if (mesh.hasTexCoords()) { + meshDecl.vertexUvData = mesh.texCoordArray(); + meshDecl.vertexUvStride = sizeof(sibr::Vector2f); + } + meshDecl.indexCount = uint32_t(mesh.triangles().size() * 3); + meshDecl.indexData = mesh.triangleArray(); + meshDecl.indexFormat = xatlas::IndexFormat::UInt32; + const xatlas::AddMeshError error = xatlas::AddMesh(_atlas, meshDecl, 1); + if (error != xatlas::AddMeshError::Success) { + xatlas::Destroy(_atlas); + SIBR_ERR << "\r[UVMapper] Error adding mesh: " << xatlas::StringForEnum(error) << std::endl; + } + // Not necessary. Only called here so geometry totals are printed after the AddMesh progress indicator + xatlas::AddMeshJoin(_atlas); +} + + +sibr::Mesh::Ptr UVUnwrapper::unwrap() { + + // Generate atlas. + SIBR_LOG << "[UVMapper] Generating atlas.." << std::endl; + + xatlas::ChartOptions chartOptions = xatlas::ChartOptions(); + xatlas::PackOptions packOptions = xatlas::PackOptions(); + packOptions.bruteForce = false; + packOptions.resolution = uint32_t(_size); + Timer timer; + timer.tic(); + xatlas::Generate(_atlas, chartOptions, packOptions); + + SIBR_LOG << "[UVMapper] Generation took: " << timer.deltaTimeFromLastTic() << "s." << std::endl; + SIBR_LOG << "[UVMapper] Output resolution: " << _atlas->width << "x" << _atlas->height << std::endl; + SIBR_LOG << "[UVMapper] Generated " << _atlas->chartCount << " charts, " << _atlas->atlasCount << " atlases." << std::endl; + for (uint32_t i = 0; i < _atlas->atlasCount; i++) { + SIBR_LOG << "[UVMapper] \tAtlas " << i << ": utilisation: " << _atlas->utilization[i] * 100.0f << "%" << std::endl; + } + + + uint32_t totalVertices = 0; + uint32_t totalFaces = 0; + for (uint32_t i = 0; i < _atlas->meshCount; i++) { + const xatlas::Mesh& xmesh = _atlas->meshes[i]; + totalVertices += xmesh.vertexCount; + totalFaces += xmesh.indexCount / 3; + } + SIBR_LOG << "[UVMapper] Output geometry data: " << totalVertices << " vertices, " << totalFaces << " triangles." << std::endl; + // Write meshes. + uint32_t firstVertex = 0; + std::vector positions; + std::vector normals; + std::vector texcoords; + std::vector colors; + std::vector triangles; + + // We could preallocate and paraellize if needed. + for (uint32_t i = 0; i < _atlas->meshCount; i++) { + const xatlas::Mesh& xmesh = _atlas->meshes[i]; + for (uint32_t v = 0; v < xmesh.vertexCount; v++) { + const xatlas::Vertex& vertex = xmesh.vertexArray[v]; + const sibr::Vector3f& pos = _mesh.vertices()[vertex.xref]; + positions.emplace_back(pos); + if (_mesh.hasNormals()) { + const sibr::Vector3f& n = _mesh.normals()[vertex.xref]; + normals.emplace_back(n); + } + if (_mesh.hasColors()) { + const sibr::Vector3f& c = _mesh.colors()[vertex.xref]; + colors.emplace_back(c); + } + + _mapping.emplace_back(vertex.xref); + texcoords.emplace_back(vertex.uv[0] / float(_atlas->width), vertex.uv[1] / float(_atlas->height)); + } + for (uint32_t f = 0; f < xmesh.indexCount; f += 3) { + const uint32_t i0 = firstVertex + xmesh.indexArray[f + 0]; + const uint32_t i1 = firstVertex + xmesh.indexArray[f + 1]; + const uint32_t i2 = firstVertex + xmesh.indexArray[f + 2]; + triangles.emplace_back(i0, i1, i2); + } + firstVertex += xmesh.vertexCount; + } + Mesh::Ptr finalMesh(new Mesh(false)); + finalMesh->vertices(positions); + finalMesh->normals(normals); + finalMesh->texCoords(texcoords); + finalMesh->colors(colors); + finalMesh->triangles(triangles); + + SIBR_LOG << "[UVMapper] Done." << std::endl; + return finalMesh; +} + +const std::vector& UVUnwrapper::mapping() const +{ + return _mapping; +} + + +std::vector UVUnwrapper::atlasVisualization() const { + if(!_atlas || _atlas->width <= 0 || _atlas->height <= 0) { + SIBR_WRG << "[UVMapper] Atlas has not been created/processed." << std::endl; + return {}; + } + + SIBR_LOG << "[UVMapper] Rasterizing result maps..." << std::endl; + + // Rasterize unwrapped meshes. + // \todo port to SIBR image API. + std::vector outputChartsImage; + const uint32_t imageDataSize = _atlas->width * _atlas->height * 3; + outputChartsImage.resize(_atlas->atlasCount * imageDataSize); + for (uint32_t i = 0; i < _atlas->meshCount; i++) { + const xatlas::Mesh &xmesh = _atlas->meshes[i]; + const sibr::Vector3ub white = { 255, 255, 255 }; + // Rasterize mesh charts. + for (uint32_t j = 0; j < xmesh.chartCount; j++) { + const xatlas::Chart *chart = &xmesh.chartArray[j]; + const sibr::Vector3ub color = sibr::randomColor(); + for (uint32_t k = 0; k < chart->faceCount; k++) { + int verts[3][2]; + for (int l = 0; l < 3; l++) { + const xatlas::Vertex &v = xmesh.vertexArray[xmesh.indexArray[chart->faceArray[k] * 3 + l]]; + verts[l][0] = int(v.uv[0]); + verts[l][1] = int(v.uv[1]); + } + uint8_t *imageData = &outputChartsImage[chart->atlasIndex * imageDataSize]; + rasterizeTriangle(imageData, _atlas->width, verts[0], verts[1], verts[2], color); + rasterizeLine(imageData, _atlas->width, verts[0], verts[1], white); + rasterizeLine(imageData, _atlas->width, verts[1], verts[2], white); + rasterizeLine(imageData, _atlas->width, verts[2], verts[0], white); + } + } + } + + // Convert raw vectors to images. + std::vector views(_atlas->meshCount); + for (uint32_t i = 0; i < _atlas->meshCount; i++) { + views[i].reset(new ImageRGB(_atlas->width, _atlas->height)); + uint8_t *imageData = &outputChartsImage[i * imageDataSize]; +#pragma omp parallel for + for(int y = 0; y < int(_atlas->height); ++y) { + for(int x = 0; x < int(_atlas->width); ++x) { + const size_t baseId = (y * _atlas->width + x)*3; + for(int j = 0; j < 3; ++j) { + views[i](x, y)[j] = imageData[baseId + j]; + } + } + } + views[i]->flipH(); + } + return views; +} + +UVUnwrapper::~UVUnwrapper() { + xatlas::Destroy(_atlas); +} + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/UVUnwrapper.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/UVUnwrapper.hpp new file mode 100644 index 0000000000000000000000000000000000000000..760724b84b776c633940fe82bf6a42d0053555f1 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/UVUnwrapper.hpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include +#include + +namespace xatlas { + struct Atlas; +} + +namespace sibr +{ + /** Unwraps a mesh onto a plane, generating texture coordinates for each vertex. + * Internaly relies on xatlas for unwrapping. + \ingroup sibr_assets + */ + class SIBR_ASSETS_EXPORT UVUnwrapper { + public: + + /** Constructor. + *\param mesh the mesh to unwrap, if UVs are already present they will be used as a guide + *\param res the target texture width, will determine UV accuracy + */ + UVUnwrapper(const sibr::Mesh& mesh, unsigned int res); + + /** Unwrap the mesh, return a copy with UV coordinates. Note that some vertices might be duplicated if they are assigned different UVs in two faces. + * \return the unwrapped mesh + */ + sibr::Mesh::Ptr unwrap(); + + /** For each vertex of the unwrapped mesh, the mapping give the index of the corresponding vertex in the input mesh. + * \return a reference to the mapping vector + */ + const std::vector & mapping() const; + + /** Generate debug visualization by rasterizing the meshes in texture space. + * \return a set of images, one per atlas + */ + std::vector atlasVisualization() const; + + /// Destructor. + ~UVUnwrapper(); + + private: + + const sibr::Mesh& _mesh; ///< Unwrapped mesh. + unsigned int _size; ///< Width of the atlas, detemrine the accuracy of the estimated UVs. + xatlas::Atlas* _atlas; ///< Atlas object. + std::vector _mapping; ///< Mapping from the new vertices to the old (some might be duplicated with different UV values). + + }; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/colmapheader.h b/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/colmapheader.h new file mode 100644 index 0000000000000000000000000000000000000000..4917e56fe0ba6111ca2ba53ae0ca7f988995e600 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/colmapheader.h @@ -0,0 +1,196 @@ +// Copyright (c) 2022, ETH Zurich and UNC Chapel Hill. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of +// its contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de) + +#ifndef COLMAP_SRC_UTIL_ENDIAN_H_ +#define COLMAP_SRC_UTIL_ENDIAN_H_ + +#include +#include +#include + +//namespace colmap { + +// Reverse the order of each byte. +template +T ReverseBytes(const T& data); + +// Check the order in which bytes are stored in computer memory. +bool IsLittleEndian(); +bool IsBigEndian(); + +// Convert data between endianness and the native format. Note that, for float +// and double types, these functions are only valid if the format is IEEE-754. +// This is the case for pretty much most processors. +template +T LittleEndianToNative(const T x); +template +T BigEndianToNative(const T x); +template +T NativeToLittleEndian(const T x); +template +T NativeToBigEndian(const T x); + +// Read data in little endian format for cross-platform support. +template +T ReadBinaryLittleEndian(std::istream* stream); +template +void ReadBinaryLittleEndian(std::istream* stream, std::vector* data); + +// Write data in little endian format for cross-platform support. +template +void WriteBinaryLittleEndian(std::ostream* stream, const T& data); +template +void WriteBinaryLittleEndian(std::ostream* stream, const std::vector& data); + +//////////////////////////////////////////////////////////////////////////////// +// Implementation +//////////////////////////////////////////////////////////////////////////////// + +template +T ReverseBytes(const T& data) { + T data_reversed = data; + std::reverse(reinterpret_cast(&data_reversed), + reinterpret_cast(&data_reversed) + sizeof(T)); + return data_reversed; +} + +inline bool IsLittleEndian() { +#ifdef BOOST_BIG_ENDIAN + return false; +#else + return true; +#endif +} + +inline bool IsBigEndian() { +#ifdef BOOST_BIG_ENDIAN + return true; +#else + return false; +#endif +} + +template +T LittleEndianToNative(const T x) { + if (IsLittleEndian()) { + return x; + } else { + return ReverseBytes(x); + } +} + +template +T BigEndianToNative(const T x) { + if (IsBigEndian()) { + return x; + } else { + return ReverseBytes(x); + } +} + +template +T NativeToLittleEndian(const T x) { + if (IsLittleEndian()) { + return x; + } else { + return ReverseBytes(x); + } +} + +template +T NativeToBigEndian(const T x) { + if (IsBigEndian()) { + return x; + } else { + return ReverseBytes(x); + } +} + +template +T ReadBinaryLittleEndian(std::istream* stream) { + T data_little_endian; + stream->read(reinterpret_cast(&data_little_endian), sizeof(T)); + return LittleEndianToNative(data_little_endian); +} + +template +void ReadBinaryLittleEndian(std::istream* stream, std::vector* data) { + for (size_t i = 0; i < data->size(); ++i) { + (*data)[i] = ReadBinaryLittleEndian(stream); + } +} + +template +void WriteBinaryLittleEndian(std::ostream* stream, const T& data) { + const T data_little_endian = NativeToLittleEndian(data); + stream->write(reinterpret_cast(&data_little_endian), sizeof(T)); +} + +template +void WriteBinaryLittleEndian(std::ostream* stream, const std::vector& data) { + for (const auto& elem : data) { + WriteBinaryLittleEndian(stream, elem); + } +} + +//} // namespace colmap + +#include +#include +#include +#include + +bool IsNotWhiteSpace(const int character) { + return character != ' ' && character != '\n' && character != '\r' && + character != '\t'; +} + +bool StringStartsWith(const std::string& str, const std::string& prefix) { + return !prefix.empty() && prefix.size() <= str.size() && + str.substr(0, prefix.size()) == prefix; +} + +void StringLeftTrim(std::string* str) { + str->erase(str->begin(), + std::find_if(str->begin(), str->end(), IsNotWhiteSpace)); +} + +void StringRightTrim(std::string* str) { + str->erase(std::find_if(str->rbegin(), str->rend(), IsNotWhiteSpace).base(), + str->end()); +} + +void StringTrim(std::string* str) { + StringLeftTrim(str); + StringRightTrim(str); +} + +#endif // COLMAP_SRC_UTIL_ENDIAN_H_ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/sibr_assets.dox b/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/sibr_assets.dox new file mode 100644 index 0000000000000000000000000000000000000000..7c5f30fc03dde87d34e03cbe960d6102d6d2244b --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/assets/sibr_assets.dox @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +/*! + \defgroup sibr_assets sibr_assets + + \brief Assets and files utilities. + +*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/CMakeLists.txt b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..870fa1a8cf74cce5afcd93c4ba2188a3c1131bd1 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/CMakeLists.txt @@ -0,0 +1,71 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +project(sibr_graphics) + +file(GLOB SOURCES "*.cpp" "*.h" "*.hpp") +source_group("Source Files" FILES ${SOURCES}) + +file(GLOB RESOURCES "resources/*.ini") +source_group("Resources Files" FILES ${RESOURCES}) + +## Specify target rules +add_library(${PROJECT_NAME} SHARED ${SOURCES}) + +include_directories( + ${Boost_INCLUDE_DIRS} + ${imgui_INCLUDE_DIRS} +) +if(WIN32) +target_link_libraries(${PROJECT_NAME} + ${Boost_LIBRARIES} + ${ASSIMP_LIBRARIES} + ${GLEW_LIBRARIES} + ${OPENGL_LIBRARIES} + ${OpenCV_LIBRARIES} + OpenMP::OpenMP_CXX + imgui + glfw3 + sibr_system +) +else() +target_link_libraries(${PROJECT_NAME} + ${Boost_LIBRARIES} + ${ASSIMP_LIBRARIES} + ${GLEW_LIBRARIES} + ${OPENGL_LIBRARIES} + ${OpenCV_LIBRARIES} + OpenMP::OpenMP_CXX + imgui + ${GLFW_LIBRARY} + sibr_system +) +endif() + +if (NOT WIN32) + target_link_libraries(${PROJECT_NAME} + #GLEW + rt m dl X11 pthread Xrandr Xinerama Xxf86vm Xcursor + # X11 Xi Xrandr Xxf86vm Xinerama Xcursor dl rt m pthread + ) +endif() + +add_definitions(-DSIBR_GRAPHICS_EXPORTS -DIMGUI_EXPORTS -DBOOST_ALL_DYN_LINK) + +set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER ${SIBR_FOLDER}) + + +## High level macro to install in an homogen way all our ibr targets +include(install_runtime) +ibr_install_target(${PROJECT_NAME} + INSTALL_PDB ## mean install also MSVC IDE *.pdb file (DEST according to target type) + RESOURCES ${RESOURCES} + RSC_FOLDER "core" +) diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Camera.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Camera.cpp new file mode 100644 index 0000000000000000000000000000000000000000..15a9c95d2078b77df29f7350ff8103bd097f2550 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Camera.cpp @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "core/graphics/Camera.hpp" + +namespace sibr +{ + + ByteStream& operator << (ByteStream& stream, const Camera& c ) + { + Camera::Transform3f t = c.transform(); + float fovy = c.fovy(); + float aspect = c.aspect(); + float znear = c.znear(); + float zfar = c.zfar(); + return stream + << t << fovy << aspect << znear << zfar; + } + + ByteStream& operator >> (ByteStream& stream, Camera& c ) + { + Camera::Transform3f t; + float fovy = 0.f; + float aspect = 0.f; + float znear = 0.f; + float zfar = 0.f; + stream + >> t >> fovy >> aspect >> znear >> zfar; + c.transform(t); + c.fovy(fovy); + c.aspect(aspect); + c.znear(znear); + c.zfar(zfar); + return stream; + } + + void Camera::perspective( float fovRad, float ratio, float znear, float zfar ) + { + _fov = fovRad; + _aspect = ratio; + _znear = znear; + _zfar = zfar; + _dirtyViewProj = true; + } + + Vector3f Camera::project( const Vector3f& p3d ) const + { + Vector4f p4d; + p4d[0] = p3d[0]; p4d[1] = p3d[1]; p4d[2] = p3d[2]; p4d[3] = 1.0; + Vector4f p3d_t = viewproj() * p4d; + p3d_t = p3d_t / p3d_t[3]; + //p3d_t[2] = p3d_t[2]*0.5f + 0.5f; // [-1;1] to [0;1] // not used + return Vector3f(p3d_t[0], p3d_t[1], p3d_t[2]); // so return [-1;1] + + //p3d_t[2] = p3d_t[2]*0.5f + 0.5f; // [-1;1] to [0;1] // not used + //return Vector3f(p3d_t[0], p3d_t[1], p3d_t[2]); // so return [-1;1] + } + + Vector3f Camera::unproject( const Vector3f& p3d ) const + { + Vector4f p4d; + p4d[0] = p3d[0]; p4d[1] = p3d[1]; p4d[2] = p3d[2]; p4d[3] = 1.0; + //p4d[2] = p4d[2]*2.f - 1.f; // [0;1] to [-1;1] // not used + Vector4f p3d_t = invViewproj() * p4d;//;viewproj().inverse() * p4d; + return Vector3f(p3d_t[0],p3d_t[1],p3d_t[2])/p3d_t[3]; + } + + bool Camera::frustumTest(const Vector3f& position3d, const Vector2f& pixel2d) const + { + return (pixel2d.cwiseAbs().array() < (1.0f-1e-5f) ).all() && (dir().dot(position3d - position()) > 0); + } + + bool Camera::frustumTest(const Vector3f& position3d) const + { + return frustumTest(position3d, project(position3d).xy()); + } + + void Camera::forceUpdateViewProj( void ) const + { + _matViewProj = sibr::Matrix4f(proj()*view()); + //_matViewProj = proj()*view(); + _invMatViewProj = _matViewProj.inverse(); + _dirtyViewProj = false; + } + + Vector3f Camera::dir( void ) const + { + return quatRotateVec(rotation(), Vector3f( 0.f, 0.f,-1.f)); + } + + Vector3f Camera::up( void ) const + { + return quatRotateVec(rotation(), Vector3f( 0.f, 1.f, 0.f)); + } + + Vector3f Camera::right( void ) const + { + return quatRotateVec(rotation(), Vector3f( 1.f, 0.f, 0.f)); + } + + Matrix4f Camera::proj( void ) const + { + //std::cout << "FOV: " << _fov << "Aspect" << _aspect << "ZNEAR" << _znear << "ZFAR" << _zfar << std::endl << std::flush; + if (ortho()) + return sibr::orthographic(_right, _top, _znear, _zfar); + else + return sibr::perspective(_fov, _aspect, _znear, _zfar, _p); + } + + /*static*/ Camera Camera::interpolate( const Camera& from, const Camera& to, float dist01 ) + { + dist01 = std::max(0.f, std::min(1.f, dist01)); + Transform3f t = Transform3f::interpolate(from._transform, to._transform, dist01); + Camera out = from; + out._transform = t; + out.fovy(dist01*from.fovy() + (1.0f-dist01)*to.fovy()); + out.aspect(dist01*from.aspect() + (1.0f-dist01)*to.aspect()); + out.zfar(dist01*from.zfar() + (1.0f-dist01)*to.zfar()); + out.znear(dist01*from.znear() + (1.0f-dist01)*to.znear()); + if (from.ortho()) { + out.orthoRight(dist01*from.orthoRight() + (1.0f-dist01)*to.orthoRight()); + out.orthoTop(dist01*from.orthoTop() + (1.0f-dist01)*to.orthoTop()); + } + return out; + } + + void Camera::setStereoCam(bool isLeft, float focal, float iod) + { + _matViewProj = sibr::perspectiveStereo(_fov, _aspect, _znear, _zfar, focal, iod, isLeft)*view(); + _invMatViewProj = _matViewProj.inverse(); + } + + void Camera::setOrthoCam(float right, float top) + { + _matViewProj = sibr::orthographic(right,top,_znear,_zfar)*view(); + _invMatViewProj = _matViewProj.inverse(); + _dirtyViewProj = false; + _isOrtho = true; + _right = right; + _top = top; + } + + void Camera::transform( const Transform3f& t ) + { + _transform = t; + _dirtyViewProj = true; + } + +} // namespace sibr \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Camera.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Camera.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d4e470e0c2f2500dc98a287d9614ca3dbf31584a --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Camera.hpp @@ -0,0 +1,426 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include "core/graphics/Config.hpp" +# include "core/system/Transform3.hpp" + + +namespace sibr +{ + /** Represent a basic camera. + \note In practice, InputCamera is used most of the time + * \ingroup sibr_graphics + */ + class SIBR_GRAPHICS_EXPORT Camera + { + public: + SIBR_CLASS_PTR(Camera); + typedef Transform3 Transform3f; + + public: + + /// Default constructor. + Camera( void ): + _matViewProj(Matrix4f::Identity()), _invMatViewProj(Matrix4f::Identity()), + _dirtyViewProj(true), _savePath(""), _debugVideoFrames(false), + _fov(70.f/180.0f*float(M_PI)), _aspect(1.f), _znear(0.01f), _zfar(1000.f), _right(1.0f), _top(1.0f), _isOrtho(false), _p(0.5f, 0.5f) { } + + /** Set the camera pose. + \param translation the camera translation + \param rotation the camera rotation + */ + void set( const Vector3f& translation, const Quaternionf& rotation ); + + /** Set the camera pose based on two points and a up vector. + \param eye the camera position + \param center the camera target point + \param up the camera up vector + */ + void setLookAt( const Vector3f& eye, const Vector3f& center, const Vector3f& up ); + + /** Translate the camera. + \param v the translation + */ + void translate( const Vector3f& v ); + + /** Translate the camera with respect to a reference frame. + \param v the translation + \param ref the reference frame + */ + void translate( const Vector3f& v, const Transform3f& ref ); + + /** Set the camera position. + \param v the new position + */ + void position( const Vector3f& v ); + + /** \return the camer position. */ + const Vector3f& position( void ) const; + + /** Rotate the camera. + \param rotation the quaternion rotation to apply + */ + void rotate( const Quaternionf& rotation ); + + /** Rotate the camera. + \param v the euler angles to apply + */ + void rotate( const Vector3f& v ); + + /** Rotate the camera with respect to a reference frame. + \param v the rotation euler angles + \param ref the reference frame + */ + void rotate( const Vector3f& v, const Transform3f& ref ); + + /** Set the camera rotation. + \param v the new rotation euler angles + */ + void rotation( const Vector3f& v ); + + /** Set the camera rotation. + \param q the new rotation + */ + void rotation( const Quaternionf& q ); + + /** \return the camera rotation. */ + const Quaternionf& rotation( void ) const; + + /** Set the camera transform. + \param t the new transform + */ + void transform( const Transform3f& t ); + + /** \return the camera transform. */ + const Transform3f& transform( void ) const; + + ///////////////////////////////////////////////////////////////// + ///// ==================== Projection ==================== ///// + ///////////////////////////////////////////////////////////////// + + /** Set the vertical field of view (in radians). + \param value the new value + */ + void fovy( float value ); + + /** \return the vertical field of view (in radians). */ + float fovy( void ) const; + + /** Set the aspect ratio. + \param value the new value + */ + void aspect( float value ); + + /** \return the aspect ratio. */ + float aspect( void ) const; + + /** Set the near plane. + \param value the new value + */ + void znear( float value ); + + /** \return the near plane distance */ + float znear( void ) const; + + /** Set the far plane. + \param value the new value + */ + void zfar( float value ); + + /** \return the far plane distance */ + float zfar( void ) const; + + /** Set the right frustum extent. + \param value the new value + */ + void orthoRight( float value ); + + /** \return the right frustum distance */ + float orthoRight( void ) const; + + /** Set the top frustum extent. + \param value the new value + */ + void orthoTop( float value ); + + /** \return the top frustum distance */ + float orthoTop( void ) const; + + /** \return true if the camera is orthographic. */ + bool ortho(void) const; + + /** \return the camera direction vector. */ + Vector3f dir( void ) const; + + /** \return the camera up vector. */ + Vector3f up( void ) const; + + /** \return the camera right vector. */ + Vector3f right( void ) const; + + /** Project 3D point using perspective projection. + * \param point3d 3D point + * \return pixel coordinates in [-1,1] and depth in [-1,1] + */ + Vector3f project( const Vector3f& point3d ) const; + + /** Back-project pixel coordinates and depth. + * \param pixel2d pixel coordinates p[0],p[1] in [-1,1] and depth p[2] in [-1,1] + * \return 3D point + */ + Vector3f unproject( const Vector3f& pixel2d ) const; + + /** Update the projection parameters of the camera. + \param fovRad the vertical field ov view in radians + \param ratio the aspect ratio + \param znear the near plane distance + \param zfar the far plane distance + */ + void perspective( float fovRad, float ratio, float znear, float zfar ); + + /** Check if a point falls inside the camera frustum. + \param position3d the point location in 3D + \return true if the point falls inside + */ + bool frustumTest(const Vector3f& position3d) const; + + /** Check if a point falls inside the camera frustum. Use this version if you already have the projected point. + \param position3d the point location in 3D + \param pixel2d the projection location of the point in image space ([-1,1]) + \return true if the point falls inside + */ + bool frustumTest(const Vector3f& position3d, const Vector2f& pixel2d) const; + + /** \return the camera model matrix (for camera stub rendering for instance). */ + Matrix4f model( void ) const { return _transform.matrix(); } + + /** \return the camera view matrix. */ + Matrix4f view( void ) const { return _transform.invMatrix(); } + + /** \return the camera projection matrix. */ + virtual Matrix4f proj( void ) const; + + /** \return the camera view-proj matrix (cached). */ + const Matrix4f& viewproj( void ) const; + + /** \return the camera inverse view-proj matrix (cached). */ + const Matrix4f& invViewproj( void ) const; + + /** Set the camera principal point. + \param p the principal point, expressed in [0,1] + */ + void principalPoint(const sibr::Vector2f & p); + + /** Interpolate between two cameras. + \param from start camera + \param to end camera + \param dist01 the interpolation factor + \return a camera with interpolated parameters + */ + static Camera interpolate( const Camera& from, const Camera& to, float dist01 ); + + /** Set stereo camera projection parameters. + \param isLeft is the camera for the left eye (else right) + \param focal the focal distance + \param iod the inter ocular distance + */ + void setStereoCam(bool isLeft, float focal, float iod); + + /** Set orthographic camera projection parameters. + \param right the right frustum extent + \param top the top frustum extent + */ + void setOrthoCam(float right, float top); + + /** \return true if the rendering generated with the camera be saved. */ + bool needSave() const { return _savePath!=""; } + + /**\return true if the rendering generated with the camera be saved as a frame. */ + bool needVideoSave() const { return _debugVideoFrames; } + + /** \return the save destination path for renderings */ + std::string savePath() const { return _savePath; } + + /** Set the save destination path for renderings. + \param savePath the new path + */ + void setSavePath(std::string savePath) { _savePath = savePath; } + + /** Toggle video saving. + \todo Cleanup naming. + \param debug if true, saving frames + */ + void setDebugVideo(const bool debug) { _debugVideoFrames = debug; } + + protected: + + /** Trigger a viewproj matrix udpate. */ + void forceUpdateViewProj( void ) const; + + std::string _savePath; ///< Save destination path when reocrding images. + bool _debugVideoFrames; ///< Is video saving enabled or not. \todo Cleanup. + mutable Matrix4f _matViewProj; ///< View projection matrix. + mutable Matrix4f _invMatViewProj; ///< Inverse projection matrix. + mutable bool _dirtyViewProj; ///< Does the camera matrix need an update. + + Transform3f _transform; ///< The camera pose. + float _fov; ///< The vertical field of view (radians) + float _aspect; ///< Aspect ratio. + float _znear; ///< Near plane. + float _zfar; ///< Far plane. + float _right; ///< Frustum half width. + float _top; ///< Frustum half height. + sibr::Vector2f _p = {0.5f, 0.5}; ///< Principal point. + bool _isOrtho; ///< Is the camera orthographic. + }; + + /** Write a camera to a byte stream. + \param stream the stream to write to + \param c the camera + \return the stream (for chaining). + */ + SIBR_GRAPHICS_EXPORT ByteStream& operator << (ByteStream& stream, const Camera& c ); + + /** Read a camera from a byte stream. + \param stream the stream to read from + \param c the camera + \return the stream (for chaining). + */ + SIBR_GRAPHICS_EXPORT ByteStream& operator >> (ByteStream& stream, Camera& c ); + + ///// DEFINITIONS ///// + + ///////////////////////////////////////////////////////////////// + inline const Transform3f& Camera::transform( void ) const { + return _transform; + } + + inline void Camera::set( const Vector3f& translation, const Quaternionf& rotation ) { + _dirtyViewProj = true; _transform.set(translation, rotation); + } + + inline void Camera::setLookAt( const Vector3f& eye, const Vector3f& at, const Vector3f& up ) { + const Vector3f zAxis( (eye - at).normalized() ); + const Vector3f xAxis( (up.normalized().cross(zAxis)).normalized() ); + const Vector3f yAxis( zAxis.cross(xAxis).normalized() ); + + Eigen::Matrix3f rotation; + rotation << xAxis, yAxis, zAxis; + Quaternionf q(rotation); + + _transform.set(eye,q); + forceUpdateViewProj(); + } + + inline void Camera::translate( const Vector3f& v ) { + _dirtyViewProj = true; _transform.translate(v); + } + inline void Camera::translate( const Vector3f& v, const Transform3f& ref ) { + _dirtyViewProj = true; _transform.translate(v, ref); + } + inline void Camera::position( const Vector3f& v ) { + _dirtyViewProj = true; _transform.position(v); + } + inline const Vector3f& Camera::position( void ) const { + return _transform.position(); + } + + inline void Camera::rotate( const Quaternionf& rotation ) { + _dirtyViewProj = true; _transform.rotate(rotation); + } + inline void Camera::rotate( const Vector3f& v ) { + _dirtyViewProj = true; _transform.rotate(v); + } + inline void Camera::rotate( const Vector3f& v, const Transform3f& ref ) { + _dirtyViewProj = true; _transform.rotate(v, ref); + } + + inline void Camera::rotation( const Vector3f& v ) { + _dirtyViewProj = true; _transform.rotation(v); + } + inline void Camera::rotation( const Quaternionf& q ) { + _dirtyViewProj = true; _transform.rotation(q); + } + + inline const Quaternionf& Camera::rotation( void ) const { + return _transform.rotation(); + } + + ///////////////////////////////////////////////////////////////// + + inline void Camera::fovy( float value ) { + _fov = value; _dirtyViewProj = true; + } + inline float Camera::fovy( void ) const { + return _fov; + } + + inline void Camera::aspect( float value ) { + _aspect = value; _dirtyViewProj = true; + } + inline float Camera::aspect( void ) const { + return _aspect; + } + + inline void Camera::znear( float value ) { + _znear = value; _dirtyViewProj = true; + } + inline float Camera::znear( void ) const { + return _znear; + } + + inline void Camera::zfar( float value ) { + _zfar = value; _dirtyViewProj = true; + } + inline float Camera::zfar( void ) const { + return _zfar; + } + + inline void Camera::principalPoint(const sibr::Vector2f & p) { + _p = p; _dirtyViewProj = true; + } + + inline void Camera::orthoRight( float value ) { + _right = value; _dirtyViewProj = true; + } + inline float Camera::orthoRight( void ) const { + return _right; + } + + inline void Camera::orthoTop( float value ) { + _top = value; _dirtyViewProj = true; + } + inline float Camera::orthoTop( void ) const { + return _top; + } + inline bool Camera::ortho(void) const { + return _isOrtho; + } + + + inline const Matrix4f& Camera::viewproj( void ) const { + if (_dirtyViewProj) + forceUpdateViewProj(); + + return _matViewProj; + } + + inline const Matrix4f& Camera::invViewproj( void ) const { + if (_dirtyViewProj) + forceUpdateViewProj(); + + return _invMatViewProj; + } + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Config.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Config.hpp new file mode 100644 index 0000000000000000000000000000000000000000..254eb97bbbe47f6688775bea214a2184e28d6a34 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Config.hpp @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include "core/system/Config.hpp" +# include "core/system/Utils.hpp" + +//#define GLEW_STATIC +#include + +# include + +# define GLFW_INCLUDE_GLU +# include + + +// (used by Image) +# pragma warning(push, 0) +# include +# include +# include +# pragma warning(pop) + + + +# ifdef SIBR_OS_WINDOWS +//// Export Macro (used for creating DLLs) //// +# ifdef SIBR_STATIC_DEFINE +# define SIBR_EXPORT +# define SIBR_NO_EXPORT +# else +# ifndef SIBR_GRAPHICS_EXPORT +# ifdef SIBR_GRAPHICS_EXPORTS + /* We are building this library */ +# define SIBR_GRAPHICS_EXPORT __declspec(dllexport) +# else + /* We are using this library */ +# define SIBR_GRAPHICS_EXPORT __declspec(dllimport) +# endif +# endif +# ifndef SIBR_NO_EXPORT +# define SIBR_NO_EXPORT +# endif +# endif +# else +# define SIBR_GRAPHICS_EXPORT +# endif + + +/** Macro to check OpenGL error and throw \p std::runtime_error if found */ +# undef CHECK_GL_ERROR +# define CHECK_GL_ERROR { \ + GLenum err = glGetError(); \ + if (err) { \ + std::string errorStr = "Unknown"; \ + switch (err) { \ + case GL_INVALID_ENUM: \ + errorStr = "GL_INVALID_ENUM"; \ + break; \ + case GL_INVALID_VALUE: \ + errorStr = "GL_INVALID_VALUE"; \ + break; \ + case GL_INVALID_OPERATION: \ + errorStr = "GL_INVALID_OPERATION"; \ + break; \ + case GL_STACK_OVERFLOW: \ + errorStr = "GL_STACK_OVERFLOW"; \ + break; \ + case GL_STACK_UNDERFLOW: \ + errorStr = "GL_STACK_UNDERFLOW"; \ + break; \ + case GL_OUT_OF_MEMORY: \ + errorStr = "GL_OUT_OF_MEMORY"; \ + break; \ + case GL_INVALID_FRAMEBUFFER_OPERATION: \ + errorStr = "GL_INVALID_FRAMEBUFFER_OPERATION"; \ + break; \ + default: \ + break; \ + } \ + SIBR_ERR << "OpenGL error 0x0" << std::hex << err << std::dec << " (" << int(err) << ") " << errorStr << " at " << __FILE__ << ":" << __LINE__ << std::endl; \ + } \ +} + +#define SIBR_GLSL(version, shader) "#version " #version "\n" #shader + + +namespace sibr +{ + /** Clamp a value. + \param value value to clamp + \param min min value + \param max max value + \return min(max(value, min), max) + \ingroup sibr_graphics + */ + template + inline T clamp( T value, T min, T max ) { + return std::max(min, std::min(max, value)); + } + +} // namespace sibr + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Frustum.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Frustum.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6f79daae64065f52bd730048f8755efc02934ffe --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Frustum.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +// Partially based on: +// http://www.lighthouse3d.com/tutorials/view-frustum-culling + +#include "core/graphics/Camera.hpp" +#include "core/graphics/Frustum.hpp" + +namespace sibr +{ + Frustum::Frustum(const Camera& cam) + { + float ratio = cam.aspect(); + float angle = cam.fovy(); + float nearD = cam.znear(); + float farD = cam.zfar(); + + // compute width and height of the near and far plane sections + float tang = (float)tan(SIBR_DEGTORAD(angle) * 0.5); + float nh = nearD * tang; + float nw = nh * ratio; + float fh = farD * tang; + float fw = fh * ratio; + + Vector3f nc, fc, X, Y, Z; + const Vector3f& p = cam.position(); + + // compute the Z axis of camera + // this axis points in the opposite direction from + // the looking direction + Z = -cam.dir(); + + // X axis of camera with given "up" vector and Z axis + X = cam.up().cross(Z); + X.normalize(); + + // the real "up" vector is the cross product of Z and X + Y = cam.up(); + + // compute the centers of the near and far planes + nc = p - Z * nearD; + fc = p - Z * farD; + + _planes[NEARP].buildFrom( -Z, nc ); + _planes[FARP].buildFrom( Z, fc ); + + Vector3f aux, normal; + + aux = (nc + Y*nh) - p; + aux.normalize(); + normal = aux.cross(X); + _planes[TOP].buildFrom( normal, nc + Y*nh ); + + aux = (nc - Y*nh) - p; + aux.normalize(); + normal = X.cross(aux); + _planes[BOTTOM].buildFrom( normal, nc - Y*nh ); + + aux = (nc - X*nw) - p; + aux.normalize(); + normal = aux.cross(Y); + _planes[LEFT].buildFrom( normal, nc - X*nw ); + + aux = (nc + X*nw) - p; + aux.normalize(); + normal = Y.cross(aux); + _planes[RIGHT].buildFrom( normal, nc + X*nw ); + } + + Frustum::TestResult Frustum::testSphere(const Vector3f& p, float radius) + { + float distance; + TestResult result = INSIDE; + + for (int i = 0; i < 6; i++) { + distance = _planes[i].distanceWithPoint(p); + if (distance < -radius) + return OUTSIDE; + else if (distance < radius) + result = INTERSECT; + } + return result; + } + + float Frustum::Plane::distanceWithPoint(const Vector3f& p) + { + // dist = A*rx + B*ry + C*rz + D = n . r + D + return A*p.x() + B*p.y() + C*p.z() + D; + } + void Frustum::Plane::buildFrom(const Vector3f& normal, const Vector3f& point) + { + Vector3f n = normal; + n.normalize(); + A = n.x(); + B = n.y(); + C = n.z(); + D = -n.dot(point); + } + + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Frustum.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Frustum.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f30654cc344ec5a6fb1cd6a7552579fafbef2e9c --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Frustum.hpp @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include +# include "core/graphics/Config.hpp" +# include "core/system/Vector.hpp" + +namespace sibr +{ + class Camera; + + /** Represent a 3D frustum defined by 6 planes. + * \warning This class has not been strongly tested! + * \ingroup sibr_graphics + */ + class SIBR_GRAPHICS_EXPORT Frustum + { + public: + + /// Result of intersection test. + enum TestResult + { + OUTSIDE = 0, + INTERSECT, + INSIDE + }; + + /// Frustum plane representation. + struct Plane + { + float A; + float B; + float C; + float D; + + /** Get the distance from a point to the plane. + \param p 3D point + \return distance + */ + float distanceWithPoint(const Vector3f& p); + + /** Build a plane from a normal and a point. + \param normal the normal + \param point a point belonging to the plane + */ + void buildFrom(const Vector3f& normal, const Vector3f& point); + }; + + public: + + /** Construct the furstum associated to a camera. + \param cam the camera + */ + Frustum(const Camera& cam); + + /** Test if a sphere intersects the frustum or is contained in it. + \param sphere sphere center + \param radius sphere radis + \return if the sphere is inside, intersecting or outside the frustum + */ + TestResult testSphere(const Vector3f& sphere, float radius); + + private: + + /// Location of each plane. + enum + { + TOP = 0, + BOTTOM, + LEFT, + RIGHT, + NEARP, + FARP, + + COUNT + }; + + + std::array _planes; ///< Frustum planes. + + }; + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/GPUQuery.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/GPUQuery.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9ee4b1abc31bcaab9fff18af873e9462cb7c2718 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/GPUQuery.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "GPUQuery.hpp" + +using namespace sibr; + +GPUQuery::GPUQuery(GLenum type, size_t count) : _count(count), _type(type){ + if(count < 2) { + SIBR_WRG << "Using a buffer of size >= 2 is recommended to avoid synchronization problems." << std::endl; + } + _ids.resize(count); + glGenQueries(GLsizei(_ids.size()), &_ids[0]); + _current = _count - 1; + // Dummy initial query. + for (int i = 0; i < _count; ++i) + { + begin(); + end(); + } +} + +void GPUQuery::begin() { + if(_observing) { + SIBR_WRG << "Query already started..." << std::endl; + return; + } + _current = (_current + 1) % _count; + glBeginQuery(_type, _ids[_current]); + _observing = true; +} + +void GPUQuery::end() { + if (!_observing) { + SIBR_WRG << "Query not running..." << std::endl; + return; + } + glEndQuery(_type); + _observing = false; +} + +uint64 GPUQuery::value() { + if (_observing) { + SIBR_WRG << "Query still running, ending it first..." << std::endl; + end(); + } + // We want the ID of the previous frame, taking into account that we have incremented the counter once more when ending it. So minus 1. + // Except if you have only one query, in which case we query this one, but it will stall the GPU. + const size_t previous = (_current - 1) % _count; + GLuint64 data = 0; + glGetQueryObjectui64v(_ids[previous], GL_QUERY_RESULT, &data); + //CHECK_GL_ERROR; + return data; +} \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/GPUQuery.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/GPUQuery.hpp new file mode 100644 index 0000000000000000000000000000000000000000..11f00b024657b2ec8bfeae1584ebcdab86f16ff8 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/GPUQuery.hpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once +#include +#include + +namespace sibr { + + /** + * Provide a buffered wrapper around an OpenGL query object, avoiding manual synchronization. + * See section 4.2 of the OpenGL 4.6 specification for more details on the types of queries available + * (time elapsed, number of primitives, number of fragment writes...). + * + * For example, to get the processing time of a mesh draw call, you can use the following. + * In renderer initialisation: + * GPUQuery query(GL_TIME_ELAPSED); + * In the rendering loop: + * query.begin(); + * mesh.draw(); + * query.end(); + * In your GUI loop: + * const uint64 time = query.value(); + * //... display it. + * + * \warning Because the query is using buffering to avoid stalling when querying the value, + * you SHOULD NOT use the same query object for multiple timings in the same frame. + * It should also be use for multiple consecutive frames ; because of buffering again, + * the first time value() is queried, it might be erroneous. + * + * \note If you want to create a query inline (for a one shot measurement), set the buffer + * count to 1, and know that it will introduce a stall when querying the value. + * \ingroup sibr_graphics + */ + class SIBR_GRAPHICS_EXPORT GPUQuery + { + SIBR_CLASS_PTR(GPUQuery); + + public: + + /** Create a query of a given type. + \param type the OpenGL enum type + \param count number of buffered internal queries (ideally >= 2). + */ + GPUQuery(GLenum type, size_t count = 2); + + /** Start measuring. */ + void begin(); + + /** Stop measuring. */ + void end(); + + /** Obtain the raw value (time in nanoseconds, number of primitives,...) for the query before last. + This allows for buffering from one frame to the next and avoid stalls (except if count is set to 1). + \return the query value. + */ + uint64 value(); + + private: + + std::vector _ids; ///< Internal queries IDs. + const size_t _count; ///< Number of queries. + GLenum _type; ///< Type of query. + size_t _current = 0; ///< Current internla query used. + bool _observing = false; ///< Are we currently measuring. + }; + +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/GUI.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/GUI.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5b4b2fa032b786b7fc29c8d3c3ad71038f3b3586 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/GUI.cpp @@ -0,0 +1,436 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#include "core/graphics/Window.hpp" +#include "core/graphics/GUI.hpp" +#include "core/graphics/Mesh.hpp" + +// We extend ImGui functionality so we need the internal definitions. +#define IMGUI_DEFINE_MATH_OPERATORS +#include + +namespace sibr +{ + + bool showImGuiWindow(const std::string& windowTitle, const IRenderTarget& rt, ImGuiWindowFlags flags, Viewport & viewport, bool invalidTexture, bool updateLayout, int handle ) + { + bool isWindowFocused = false; + // If we are asked to, we need to update the viewport at launch. + if (updateLayout) { + ImGui::SetNextWindowPos(ImVec2(viewport.finalLeft(), viewport.finalTop())); + ImGui::SetNextWindowSize(ImVec2(0, 0)); + ImGui::SetNextWindowContentSize(ImVec2(viewport.finalWidth(), viewport.finalHeight())); + } + + if (::ImGui::Begin(windowTitle.c_str(), NULL, flags)) + { + // Get the current cursor position (where your window is) + ImVec2 pos = /*ImGui::GetItemRectMin() + */::ImGui::GetCursorScreenPos(); + Vector2f offset, size; + Vector2i availRegionSize(::ImGui::GetContentRegionAvail().x, ::ImGui::GetContentRegionAvail().y); + + fitImageToDisplayRegion(viewport.finalSize(), availRegionSize, offset, size); + + size = size.cwiseMax( sibr::Vector2f( 1.0f,1.0f) ); + + + pos.x += offset.x(); + pos.y += offset.y(); + + + ImGui::SetCursorPos(ImVec2(offset.x(), ImGui::GetTitleBarHeight()+offset.y())); + ImGui::InvisibleButton((windowTitle + "--TEXTURE-INVISIBLE_BUTTON").c_str(), ImVec2(size.x(), size.y())); + if (!invalidTexture) { + ::ImGui::GetWindowDrawList()->AddImage((void*)(intptr_t)(rt.handle(handle)), + pos, ImVec2(pos.x + size.x(), pos.y + size.y()), + ImVec2(0, 1), ImVec2(1, 0)); + } + + isWindowFocused = ImGui::IsWindowFocused(); + + viewport = Viewport(pos.x, pos.y, pos.x+size.x(), pos.y+size.y()); + + // Hand back the inputs to sibr. + if (ImGui::IsItemHovered()) { + ImGui::CaptureKeyboardFromApp(false); + ImGui::CaptureMouseFromApp(false); + } + } + ::ImGui::End(); + + return isWindowFocused; + } + + Mesh::Ptr generateMeshForText(const std::string & text, unsigned int & separationIndex){ + // Technically we don't care if we already are in the middle of a ImGui frame. + // as long as we clear the draw list. ImGui will detect the empty draw lists and cull them. + ImGui::PushID(1234567809); + ImGui::SetNextWindowPos(ImVec2(0,0)); + ImGui::Begin(text.c_str(), nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoInputs); + ImGui::SetWindowFontScale(ImGui::GetIO().FontGlobalScale); + + ImGui::Text(text.c_str()); + // Get back the draw list. + ImDrawList * drawlist = ImGui::GetWindowDrawList(); + const int vertCount = drawlist->VtxBuffer.Size; + const int indexCount = drawlist->IdxBuffer.Size; + // We generate one mesh from the draw list. + std::vector vertices(vertCount); + std::vector uvs(vertCount); + std::vector colors(vertCount); + std::vector faces(indexCount / 3); + + sibr::Vector3f centroid(0.0f, 0.0f, 0.0f); + for (int k = 0; k < vertCount; ++k) { + const auto & vtx = drawlist->VtxBuffer[k]; + vertices[k][0] = (vtx.pos.x)*2.0f; + vertices[k][1] = -vtx.pos.y*2.0f; + uvs[k][0] = vtx.uv.x; uvs[k][1] = vtx.uv.y; + ImVec4 col = ImGui::ColorConvertU32ToFloat4(vtx.col); + colors[k][0] = col.x; colors[k][1] = col.y; + colors[k][2] = col.z; vertices[k][2] = col.w; + centroid += vertices[k]; + } + for (int k = 0; k < indexCount; k += 3) { + faces[k / 3][0] = (unsigned int)drawlist->IdxBuffer[k]; + faces[k / 3][1] = (unsigned int)drawlist->IdxBuffer[k + 1]; + faces[k / 3][2] = (unsigned int)drawlist->IdxBuffer[k + 2]; + } + // Center the mesh? + centroid /= float(vertices.size()); + for (int k = 0; k < vertices.size(); ++k) { + vertices[k] -= centroid; + } + Mesh::Ptr mesh = std::make_shared(); + mesh->vertices(vertices); + mesh->colors(colors); + mesh->texCoords(uvs); + mesh->triangles(faces); + // Store the separation idnex between the background and the text foreground. + separationIndex = drawlist->CmdBuffer[0].ElemCount; + + // Finish the window, then clear the draw list. + ImGui::End(); + ImGui::PopID(); + drawlist->Clear(); + return mesh; + } + + + void fitImageToDisplayRegion(const Vector2f & imgSize, const Vector2i & regionSize, Vector2f& offset, Vector2f& size) + { + + Vector2f ratios = imgSize.cwiseQuotient(regionSize.cast()); + if (ratios.x() < ratios.y()) + { + float aspect = imgSize.x() / imgSize.y(); + size.y() = float(regionSize.y()); + size.x() = size.y() * aspect; + } + else + { + float aspect = imgSize.y() / imgSize.x(); + size.x() = float(regionSize.x()); + size.y() = size.x() * aspect; + } + offset = regionSize.cast() / 2 - size / 2; + } + + + + sibr::Vector2f ZoomData::topLeft() const { return center - diagonal; } + sibr::Vector2f ZoomData::bottomRight() const { return center + diagonal; } + + sibr::Vector2f ZoomData::uvFromBoxPos(const sibr::Vector2f& pos) const + { + return topLeft() + 2.0f*diagonal.cwiseProduct(pos); + } + + ZoomData ZoomData::scaled(const sibr::Vector2f& size) const + { + ZoomData out; + out.center = center.cwiseProduct(size); + out.diagonal = diagonal.cwiseProduct(size); + return out; + } + + void ZoomInterraction::updateZoom(const sibr::Vector2f& canvasSize) + { + const auto & d = callBackData; + if (d.ctrlPressed) { + return; + } + + sibr::Vector2f posF = zoomData.uvFromBoxPos(d.positionRatio); + + if (d.isHoovered && d.isClickedRight && !zoomData.underMofidication) { + zoomData.underMofidication = true; + zoomData.tmpTopLeft = posF; + zoomData.firstClickPixel = d.mousePos; + } + if (d.isHoovered && zoomData.underMofidication) { + zoomData.tmpBottonRight = posF; + zoomData.secondClickPixel = d.mousePos; + } + + if (zoomData.underMofidication) { + ImGui::GetWindowDrawList()->AddRect( + ImVec2(zoomData.firstClickPixel[0], zoomData.firstClickPixel[1]), + ImVec2(zoomData.secondClickPixel[0], zoomData.secondClickPixel[1]), + IM_COL32(255, 0, 0, 255), 0, 0, 2 + ); + } + + if (d.isReleasedRight && zoomData.underMofidication) { + zoomData.underMofidication = false; + if ((zoomData.tmpBottonRight - zoomData.tmpTopLeft).cwiseProduct(canvasSize).cwiseAbs().minCoeff() > 10) { + zoomData.center = 0.5f*(zoomData.tmpBottonRight + zoomData.tmpTopLeft); + zoomData.diagonal = 0.5f*(zoomData.tmpBottonRight - zoomData.tmpTopLeft).cwiseAbs(); + auto scaledBox = zoomData.scaled(canvasSize); + float target_ratio = canvasSize[0] / canvasSize[1]; + float current_ratio = scaledBox.diagonal[0] / scaledBox.diagonal[1]; + if (current_ratio > target_ratio) { + scaledBox.diagonal.y() = scaledBox.diagonal.x() / target_ratio; + } else { + scaledBox.diagonal.x() = scaledBox.diagonal.y() * target_ratio; + } + zoomData.diagonal = scaledBox.diagonal.cwiseQuotient(canvasSize); + } + } + + if (d.isHoovered && d.scroll != 0) { + zoomData.diagonal = zoomData.diagonal.cwiseProduct(pow(1.15f, -d.scroll)*sibr::Vector2f(1, 1)); + } + + + + zoomData.diagonal = zoomData.diagonal.cwiseMin(sibr::Vector2f(0.5, 0.5)); + using Box = Eigen::AlignedBox2f; + using Corner = Box::CornerType; + + Box target(sibr::Vector2f(0, 0), sibr::Vector2f(1, 1)); + Box current(zoomData.topLeft(), zoomData.bottomRight()); + + if (!target.contains(current)) { + Box inside = current; + inside.clamp(target); + for (int c = 0; c < 4; ++c) { + Corner cType = (Corner)c; + if ( (current.corner(cType)-inside.corner(cType)).isZero() ) { + Corner opposite = (Corner)(3 - c); + zoomData.center += (inside.corner(opposite) - current.corner(opposite)); + break; + } + } + } + + } + + + void SegmentSelection::update(const CallBackData & callback, const sibr::Vector2i & size, const ZoomData & zoom) + { + sibr::Vector2i pos = zoom.scaled(size.cast()).uvFromBoxPos(callback.positionRatio).cast(); + + if (callback.isHoovered && callback.isClickedRight && callback.ctrlPressed && (!first || valid)) { + firstPosScreen = callback.mousePos.cast(); + firstPosIm = pos.cast(); + secondPosScreen = firstPosScreen; + first = true; + } else if (callback.isHoovered && first) { + secondPosScreen = callback.mousePos.cast(); + secondPosIm = pos.cast(); + + if (callback.isClickedRight) { + first = false; + valid = true; + computeRasterizedLine(); + } + } + } + + void SegmentSelection::computeRasterizedLine() + { + if (!valid) { + return; + } + + sibr::Vector2i diff = secondPosIm - firstPosIm; + int l = diff.cwiseAbs().maxCoeff(); + rasterizedLine.resize(l + 1); + for (int i = 0; i <= l; ++i) { + rasterizedLine[i] = (firstPosIm.cast() + (i / (float)l)*diff.cast()).cast(); + } + } + + void DisplayImageGui( + GLuint texture, + const sibr::Vector2i & displaySize, + const sibr::Vector2f& uv0, + const sibr::Vector2f& uv1 + ) { + ImGui::Image((void*)(intptr_t)(texture), ImVec2(float(displaySize[0]), float(displaySize[1])), ImVec2(uv0[0], uv0[1]), ImVec2(uv1[0], uv1[1])); + } + + void ImageWithCallback( + GLuint texture, + const sibr::Vector2i & displaySize, + CallBackData & callbackDataOut, + const sibr::Vector2f & uv0, + const sibr::Vector2f & uv1 + ) { + CallBackData & data = callbackDataOut; + + data.itemPos = toSIBR(ImGui::GetCursorScreenPos()); + DisplayImageGui(texture, displaySize, uv0, uv1); + + data.itemSize = toSIBR(ImGui::GetItemRectSize()); + data.isHoovered = ImGui::IsItemHovered(); + data.isClickedLeft = ImGui::IsMouseClicked(0); + data.isReleasedLeft = ImGui::IsMouseReleased(0); + data.isClickedRight = ImGui::IsItemClicked(1); + data.isReleasedRight = ImGui::IsMouseReleased(1); + data.ctrlPressed = ImGui::GetIO().KeyCtrl; + data.scroll = ImGui::GetIO().MouseWheel; + + if (data.isHoovered) { + data.mousePos = toSIBR(ImGui::GetIO().MousePos); + data.positionRatio = (data.mousePos - data.itemPos).cwiseQuotient(data.itemSize); + } + } + + void ImageWithZoom(GLuint texture, const sibr::Vector2i & displaySize, ZoomInterraction & zoom) + { + ImageWithCallback(texture, displaySize, zoom.callBackData, zoom.zoomData.topLeft(), zoom.zoomData.bottomRight()); + zoom.updateZoom(displaySize.template cast()); + } + +} // namespace sibr + + +namespace ImGui { + + const float GetTitleBarHeight() { return GetTextLineHeight() + GetStyle().FramePadding.y * 2.0f; } + + void PushScaledItemWidth(float item_width) + { + ImGui::PushItemWidth(ImGui::GetIO().FontGlobalScale * item_width); + } + + bool TabButton(const char * label, bool highlight, const ImVec2 & size) + { + if (highlight) { + ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(0, 0.8f, 0.8f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(0, 0.6f, 0.6f)); + } + bool b = ImGui::Button(label, size); + if (highlight) { + ImGui::PopStyleColor(2); + } + return b; + } + + void PlotMultiLines(const char* label, std::vector values, int values_count, const std::vector& colors, float scale_min, float scale_max, ImVec2 graph_size) { + // Note: code extracted from ImGui and udpated to display multiple lines on the same graph. + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + // Force the plot type. + ImGuiPlotType plot_type = ImGuiPlotType_Lines; + const ImVec2 label_size = CalcTextSize(label, NULL, true); + if (graph_size.x == 0.0f) + graph_size.x = CalcItemWidth(); + if (graph_size.y == 0.0f) + graph_size.y = label_size.y + (style.FramePadding.y * 2); + + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(graph_size.x, graph_size.y)); + const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding); + const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0)); + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, 0, &frame_bb)) + return; + const bool hovered = ItemHoverable(inner_bb, 0); + + // Determine scale from values if not specified + if (scale_min == FLT_MAX || scale_max == FLT_MAX) + { + float v_min = FLT_MAX; + float v_max = -FLT_MAX; + for (int j = 0; j < values.size(); ++j) { + for (int i = 0; i < values_count; i++) + { + const float v = values[j][i]; + v_min = ImMin(v_min, v); + v_max = ImMax(v_max, v); + } + } + if (scale_min == FLT_MAX) + scale_min = v_min; + if (scale_max == FLT_MAX) + scale_max = v_max; + } + + RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding); + int values_offset = 0; + + if (values_count > 0) + { + int res_w = ImMin((int)graph_size.x, values_count) + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0); + int item_count = values_count + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0); + + // No tooltip for now. + + const float t_step = 1.0f / (float)res_w; + const float inv_scale = (scale_min == scale_max) ? 0.0f : (1.0f / (scale_max - scale_min)); + + for (int vid = 0; vid < values.size(); ++vid) { + float v0 = values[vid][(0 + values_offset) % values_count]; + float t0 = 0.0f; + ImVec2 tp0 = ImVec2(t0, 1.0f - ImSaturate((v0 - scale_min) * inv_scale)); // Point in the normalized space of our target rectangle + float histogram_zero_line_t = (scale_min * scale_max < 0.0f) ? (-scale_min * inv_scale) : (scale_min < 0.0f ? 0.0f : 1.0f); // Where does the zero line stands + + const ImU32 col_base = GetColorU32(colors[vid >= colors.size() ? 0 : vid]); + const ImU32 col_hovered = col_base; + + for (int n = 0; n < res_w; n++) + { + const float t1 = t0 + t_step; + const int v1_idx = (int)(t0 * item_count + 0.5f); + IM_ASSERT(v1_idx >= 0 && v1_idx < values_count); + const float v1 = values[vid][(v1_idx + values_offset + 1) % values_count]; + const ImVec2 tp1 = ImVec2(t1, 1.0f - ImSaturate((v1 - scale_min) * inv_scale)); + + // NB: Draw calls are merged together by the DrawList system. Still, we should render our batch are lower level to save a bit of CPU. + ImVec2 pos0 = ImLerp(inner_bb.Min, inner_bb.Max, tp0); + ImVec2 pos1 = ImLerp(inner_bb.Min, inner_bb.Max, (plot_type == ImGuiPlotType_Lines) ? tp1 : ImVec2(tp1.x, histogram_zero_line_t)); + if (plot_type == ImGuiPlotType_Lines) + { + window->DrawList->AddLine(pos0, pos1, col_base); + } + else if (plot_type == ImGuiPlotType_Histogram) + { + if (pos1.x >= pos0.x + 2.0f) + pos1.x -= 1.0f; + window->DrawList->AddRectFilled(pos0, pos1, col_base); + } + + t0 = t1; + tp0 = tp1; + } + } + } + } + +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/GUI.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/GUI.hpp new file mode 100644 index 0000000000000000000000000000000000000000..171fb3957a9ad091b28df187912b281478c9cd02 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/GUI.hpp @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include "core/graphics/Config.hpp" +# include "core/system/Vector.hpp" +# include "core/graphics/Image.hpp" +# include "core/graphics/RenderTarget.hpp" +# include "core/graphics/Window.hpp" + +#include + +namespace sibr +{ + + /** Show the content of a rendertarget in an ImGui window. + \param windowTitle the window name (unique) + \param rt the rendrtarget to display + \param flags ImGui flags + \param viewport will contain the window extent on screen + \param invalidTexture ignore the RT + \param updateLayout force update the camera location on screen + \param handle the texture index to display from the input RT + \return true if window is focused (useful for managing interactions). + \ingroup sibr_graphics + */ + SIBR_GRAPHICS_EXPORT bool showImGuiWindow(const std::string& windowTitle, const IRenderTarget& rt, ImGuiWindowFlags flags, Viewport & viewport, bool invalidTexture, bool updateLayout, int handle = 0); + + /** + Helper that compute the location and extent to display an image in a given region without cropping or distorting it + \param imgSize the image size + \param regionSize the region size + \param offset will containg the top-left corner location + \param size will contain the size to use + \ingroup sibr_graphics + */ + SIBR_GRAPHICS_EXPORT void fitImageToDisplayRegion(const Vector2f & imgSize, const Vector2i & regionSize, Vector2f& offset, Vector2f& size); + + /** Generate a mesh for a given label, using ImGui internally. This will generate a mesh that contain both the background and foreground geometry packed together sequentially. + \param text the text to generate the label of + \param separationIndex will contain the location of the first triangle of the foreground mesh + \return the mesh containing first the background triangles then the foreground triangles + \ingroup sibr_graphics + */ + SIBR_GRAPHICS_EXPORT Mesh::Ptr generateMeshForText(const std::string & text, unsigned int & separationIndex); + +} // namespace sibr + +namespace ImGui { + + /** \return the height of the title bar (for layout) + \ingroup sibr_graphics + */ + SIBR_GRAPHICS_EXPORT const float GetTitleBarHeight(); + + /** + * Push a width for item which is HiDPI aware. + * \param item_width The with to push, in regular pixels. + * \ingroup sibr_graphics + */ + SIBR_GRAPHICS_EXPORT void PushScaledItemWidth(float item_width); + + /** Helper to create a tab button item. + \param label the button text + \param highlight should the button be highlit + \param size the size of the button (0,0 will autosize). + \return true if the tab is active + * \ingroup sibr_graphics + */ + SIBR_GRAPHICS_EXPORT bool TabButton(const char* label, bool highlight, const ImVec2& size = ImVec2(0, 0)); + + /** Plot multiple curves on a graph. All curves should have the same number of samples. + Only lines are supported, code is based on internal ImGui implementation for one curve. + \param label the graph ImGui label + \param values a list of pointers to list of values + \param values_count number of samples in each list + \param colors one or mulitple colors to use for each curve + \param scale_min the value corresponding to the bottom of the graph + \param scale_max the value corresponding to the top of the graph + \param graph_size size of the graph widget + */ + SIBR_GRAPHICS_EXPORT void PlotMultiLines(const char* label, std::vector values, int values_count, const std::vector& colors, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0.0f, 0.0f)); +} + +namespace sibr { + + /** Display an image using ImGui::image, with additional options. + \param texture the ID of the texture to display + \param displaySize the target size + \param uv0 bottom-left corner of the image to display + \param uv1 top-right corner of the image to display + */ + SIBR_GRAPHICS_EXPORT void DisplayImageGui( + GLuint texture, + const sibr::Vector2i & displaySize, + const sibr::Vector2f& uv0 = { 0, 0 }, + const sibr::Vector2f& uv1 = { 1, 1 } + ); + + /** Store user interaction information to be returned when displaying an image. */ + struct SIBR_GRAPHICS_EXPORT CallBackData { + sibr::Vector2f positionRatio; ///< Position ratio. + sibr::Vector2f itemPos, itemSize, mousePos; ///< Mouse information. + float scroll = 0.0f; ///< Scroll amount. + bool isHoovered = false, isClickedRight = false, isClickedLeft = false, + isReleasedRight = false, isReleasedLeft = false, ctrlPressed = false; ///< Is the image currently: hovered, right-clicked pressed, left-click pressed , right-click released, left-click released, is the ctrl key pressed. + }; + + /** Display an image using ImGui::image with support for returning interaction information (did the user click the image, etc.). + \param texture the ID of the texture to display + \param displaySize the target size + \param callbackDataOut will contain interaction information for the current frame + \param uv0 bottom-left corner of the image to display + \param uv1 top-right corner of the image to display + */ + SIBR_GRAPHICS_EXPORT void ImageWithCallback( + GLuint texture, + const sibr::Vector2i & displaySize, + CallBackData & callbackDataOut, + const sibr::Vector2f& uv0 = { 0, 0 }, + const sibr::Vector2f& uv1 = { 1, 1 } + ); + + /** Store additional user zoom information to be returned when displaying an image. */ + struct SIBR_GRAPHICS_EXPORT ZoomData { + + /** \return the zoomed region top left corner in image space. */ + sibr::Vector2f topLeft() const; + + /** \return the zoomed region bottom right corner in image space. */ + sibr::Vector2f bottomRight() const; + + /** Convert pixel coordinates in UV, taking the zoom into account. + \param pos the pixel position + \return the corresponding UVs + */ + sibr::Vector2f uvFromBoxPos(const sibr::Vector2f& pos) const; + + /** Rescale zoom data using a reference region size. + \param size the region size + \return the resized data + */ + ZoomData scaled(const sibr::Vector2f& size) const; + + sibr::Vector2f center = sibr::Vector2f(0.5f, 0.5f), diagonal = sibr::Vector2f(0.5f, 0.5f), + tmpTopLeft, tmpBottonRight, firstClickPixel, secondClickPixel; ///< Zoomed region corners and location. + bool underMofidication = false; ///< Is the user currently zooming. + }; + + /** Store user interaction and zooming information to be returned when displaying an image. */ + struct SIBR_GRAPHICS_EXPORT ZoomInterraction { + /** Update zoom information. + \param canvasSize size ot the displayed region of the image + */ + void updateZoom(const sibr::Vector2f& canvasSize); + + CallBackData callBackData; ///< Interaction data. + ZoomData zoomData; ///< Zoom data. + }; + + /** Display an image using ImGui::image with support for returning user zoom information. + \param texture the ID of the texture to display + \param displaySize the target size + \param zoom will contain zoom information for the current frame + */ + SIBR_GRAPHICS_EXPORT void ImageWithZoom( + GLuint texture, + const sibr::Vector2i & displaySize, + ZoomInterraction & zoom + ); + + /** Represent a segment defined by the user by clicking on screen. */ + struct SIBR_GRAPHICS_EXPORT SegmentSelection { + + /** Update based on user interaction data. + \param callback user interaction data + \param size the region size + \param zoom optional zoom interaction data + */ + void update(const CallBackData& callback, const sibr::Vector2i& size, const ZoomData& zoom = {}); + + /** Generate a rasterized line as a list of pixels.*/ + void computeRasterizedLine(); + + sibr::Vector2i firstPosScreen, secondPosScreen, firstPosIm, secondPosIm; ///< Segment endpoints in image and screen space. + std::vector rasterizedLine; ///< List of pixel covered by the rasterized line. + bool first = false, valid = false; ///< Current interactions state. + }; +} + +/** Convert an ImGui vector to a sibr vector. +\param v the vector to convert +\return the corresponding sibr vector. +*/ +template sibr::Vector toSIBR(const ImVec2 & v) { + return sibr::Vector(v.x, v.y); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Image.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Image.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a411418e33dfdc91afdb495190476f41a27fa886 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Image.cpp @@ -0,0 +1,398 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#include "core/graphics/Image.hpp" +#include + +namespace sibr +{ + namespace opencv + { + + + float imageTypeCVRange(int cvDepth) + { + // keep in mind + //enum { CV_8U=0, CV_8S=1, CV_16U=2, CV_16S=3, CV_32S=4, CV_32F=5, CV_64F=6 }; + static float ranges[] = { + imageTypeRange(), + imageTypeRange(), + imageTypeRange(), + imageTypeRange(), + imageTypeRange(), + imageTypeRange(), + imageTypeRange() + }; + return ranges[cvDepth]; + } + + void convertBGR2RGB(cv::Mat& img) + { + switch (img.channels()) + { + case 3: + cv::cvtColor(img, img, cv::COLOR_BGR2RGB); + break; + case 4: + cv::cvtColor(img, img, cv::COLOR_BGRA2RGBA); + break; + default: + break; + } + } + + void convertRGB2BGR(cv::Mat& img) + { + switch (img.channels()) + { + case 3: + cv::cvtColor(img, img, cv::COLOR_RGB2BGR); + break; + case 4: + cv::cvtColor(img, img, cv::COLOR_RGBA2BGRA); + break; + default: + break; + } + } + + } // namespace opencv + + sibr::ImageRGBA convertL32FtoRGBA(const sibr::ImageL32F & imgF) + { + sibr::ImageRGBA out(imgF.w(), imgF.h()); + for (uint y = 0; y < out.h(); ++y) { + for (uint x = 0; x < out.w(); ++x) { + unsigned char const * p = reinterpret_cast(&imgF(x, y).x()); + for (std::size_t i = 0; i != sizeof(float); ++i) { + out(x, y)[i] = p[i]; + } + } + } + return out; + } + + sibr::ImageL32F convertRGBAtoL32F(const sibr::ImageRGBA & imgRGBA) + { + sibr::ImageL32F out(imgRGBA.w(), imgRGBA.h()); +#pragma omp parallel for + for (int y = 0; y < int(out.h()); ++y) { + for (uint x = 0; x < out.w(); ++x) { + unsigned char * p = reinterpret_cast(&out(x, y).x()); + for (std::size_t i = 0; i != sizeof(float); ++i) { + p[i] = imgRGBA(x, y)[i]; + } + } + } + return out; + } + + sibr::ImageRGBA convertRGB32FtoRGBA(const sibr::ImageRGB32F & imgF) + { + sibr::ImageRGBA out(3*imgF.w(), imgF.h()); +#pragma omp parallel for + for (int y = 0; y < int(imgF.h()); ++y) { + for (uint x = 0; x < imgF.w(); ++x) { + for (int k = 0; k < 3; k++) { + unsigned char const * p = reinterpret_cast(&imgF(x, y)[k]); + for (std::size_t i = 0; i != sizeof(float); ++i) { + out(k*imgF.w() + x, y)[i] = p[i]; + } + } + } + } + return out; + } + + sibr::ImageRGB32F convertRGBAtoRGB32F(const sibr::ImageRGBA& imgRGBA) + { + sibr::ImageRGB32F out(imgRGBA.w() / 3, imgRGBA.h()); +#pragma omp parallel for + for (int y = 0; y < int(out.h()); ++y) { + for (uint x = 0; x < out.w(); ++x) { + for (int k = 0; k < 3; k++) { + unsigned char* p = reinterpret_cast(&out(x, y)[k]); + for (std::size_t i = 0; i != sizeof(float); ++i) { + p[i] = imgRGBA(k * out.w() + x, y)[i]; + } + } + } + } + return out; + } + + sibr::ImageRGBA convertNormalMapToSphericalHalf(const sibr::ImageRGB32F & imgF) + { + uint phi_uint; + uint theta_uint; + unsigned char * phi_ptr = reinterpret_cast(&phi_uint); + unsigned char * theta_ptr = reinterpret_cast(&theta_uint); + + ImageRGBA out(imgF.w(),imgF.h()); + + for (uint i = 0; i < out.h(); ++i) { + for (uint j = 0; j < out.w(); ++j) { + const double phi = std::acos((double)imgF(j, i)[2]); + const double theta = std::atan2((double)imgF(j, i)[1], (double)imgF(j, i)[0]); + phi_uint = (uint)((phi / M_PI) * (1 << 16)); + theta_uint = (uint)((0.5*(theta / M_PI + 1.0)) * (1 << 16)); + + unsigned char * out_ptr = reinterpret_cast(&out(j, i)[0]); + out_ptr[0] = phi_ptr[0]; + out_ptr[1] = phi_ptr[1]; + out_ptr[2] = theta_ptr[0]; + out_ptr[3] = theta_ptr[1]; + } + } + + return out; + } + + sibr::ImageRGB32F convertSphericalHalfToNormalMap(const sibr::ImageRGBA & imgRGBA) + { + uint phi_uint; + uint theta_uint; + unsigned char * phi_ptr = reinterpret_cast(&phi_uint); + unsigned char * theta_ptr = reinterpret_cast(&theta_uint); + + ImageRGB32F out(imgRGBA.w(), imgRGBA.h()); + + for (uint i = 0; i < out.h(); ++i) { + for (uint j = 0; j < out.w(); ++j) { + unsigned char const * out_ptr = reinterpret_cast(&imgRGBA(j, i)[0]); + phi_ptr[0] = out_ptr[0]; + phi_ptr[1] = out_ptr[1]; + theta_ptr[2] = out_ptr[0]; + theta_ptr[3] = out_ptr[1]; + + float theta = ((float)phi_uint*2.0f / (1 << 16) - 1.0f)*float(M_PI); + float phi = ((float)theta_uint /(1 << 16))*float(M_PI); + float sin_t = std::sin(theta); + float cos_t = std::cos(theta); + float sin_p = std::sin(phi); + float cos_p = std::cos(phi); + out(j, i) = sibr::Vector3f(sin_t*cos_p, sin_t*sin_p, cos_t); + } + } + + return out; + } + + Image coloredClass(const Image::Ptr imClass) { + + const int color_list[25][3] = { + {255, 179, 0},{128, 62, 117},{166, 189, 215} ,{193, 0, 32},{0,128,255},{0, 125, 52}, + {246, 118, 142},{0, 83, 138},{255, 122, 92} ,{0, 255, 0},{255, 142, 0},{179, 40, 81}, + {244, 200, 0},{127, 24, 13},{147, 170, 0} ,{89, 51, 21},{241, 58, 19},{35, 44, 22}, + {83, 55, 122},{255,0,128},{128,255,0} ,{128,0,255},{206, 162, 98},{128,128,128},{255,255,255} + }; + + std::vector colors(256); + for (int i = 0; i < 255; i++) { + colors[i] = Vector3ub(color_list[i % 25][0], color_list[i % 25][1], color_list[i % 25][2]); + } + colors[255] = Vector3ub(0, 0, 0); + Image imClassColor(imClass->w(), imClass->h()); + + for (unsigned int i = 0; i < imClass->w(); i++) { + for (unsigned int j = 0; j < imClass->h(); j++) { + imClassColor(i, j) = colors[imClass(i, j).x() % 256]; + } + } + return imClassColor; + } + + Image coloredClass(const Image::Ptr imClass) { + + const int color_list[25][3] = { + { 255, 179, 0 },{ 128, 62, 117 },{ 166, 189, 215 } ,{ 193, 0, 32 },{ 0,128,255 },{ 0, 125, 52 }, + { 246, 118, 142 },{ 0, 83, 138 },{ 255, 122, 92 } ,{ 0, 255, 0 },{ 255, 142, 0 },{ 179, 40, 81 }, + { 244, 200, 0 },{ 127, 24, 13 },{ 147, 170, 0 } ,{ 89, 51, 21 },{ 241, 58, 19 },{ 35, 44, 22 }, + { 83, 55, 122 },{ 255,0,128 },{ 128,255,0 } ,{ 128,0,255 },{ 206, 162, 98 },{ 128,128,128 },{ 255,255,255 } + }; + + std::vector colors(256); + for (int i = 0; i < 255; i++) { + colors[i] = Vector3ub(color_list[i % 25][0], color_list[i % 25][1], color_list[i % 25][2]); + } + colors[255] = Vector3ub(0, 0, 0); + Image imClassColor(imClass->w(), imClass->h()); + + for (unsigned int j = 0; j < imClass->h(); j++) { + for (unsigned int i = 0; i < imClass->w(); i++) { + + Vector3ub color; + if (imClass(i, j).x() < 0) + color = colors[255]; + else + color = colors[imClass(i, j).x() % 256]; + + imClassColor(i, j) = color; + } + } + return imClassColor; + } + + void showFloat(const Image & im, bool logScale, double min, double max) { + Image imIntensity(im.w(), im.h()); + Image imColor(im.w(), im.h()); + + if (min == -DBL_MAX && max == DBL_MAX) { + cv::minMaxLoc(im.toOpenCV(), &min, &max); + } + else if (min == -DBL_MAX) { + double drop; + cv::minMaxLoc(im.toOpenCV(), &min, &drop); + } + else if (max == DBL_MAX) { + double drop; + cv::minMaxLoc(im.toOpenCV(), &drop, &max); + } + + if (logScale) { + min = log(min); + max = log(max); + } + + for (unsigned int j = 0; j < im.h(); j++) { + for (unsigned int i = 0; i < im.w(); i++) { + if (logScale) + imIntensity(i, j).x() = static_cast(std::max(0.0, std::min((log(im(i, j).x()) - min) * 255 / (max - min), 255.0))); + else + imIntensity(i, j).x() = static_cast(std::max(0.0, std::min((im(i, j).x() - min) * 255 / (max - min), 255.0))); + } + } + cv::Mat colorMat; + cv::applyColorMap(imIntensity.toOpenCV(), colorMat, cv::COLORMAP_PARULA); + imColor.fromOpenCVBGR(colorMat); + show(imColor); + } + + cv::Mat duplicate3(cv::Mat c) { + cv::Mat out; + cv::Mat in[] = { c, c, c }; + cv::merge(in, 3, out); + return out; + } + + // Adopted from http://www.64lines.com/jpeg-width-height. Gets the JPEG size from the file stream passed + // to the function, file reference: http://www.obrador.com/essentialjpeg/headerinfo.htm + sibr::Vector2i IImage::get_jpeg_size(std::ifstream& file) + { + // Check for valid JPG + if (file.get() != 0xFF || file.get() != 0xD8) + return Eigen::Vector2i(-1, -1); + file.get(); file.get(); // Skip the rest of JPG identifier. + + std::streampos block_length = static_cast(file.get() * 256 + file.get() - 2); + for (;;) + { + // Skip the first block since it doesn't contain the resolution + file.seekg(file.tellg() + block_length); + + // Check if we are at the start of another block + if (!file.good() || file.get() != 0xFF) + break; + + // If the block is not the "Start of frame", skip to the next block + if (file.get() != 0xC0) + { + block_length = static_cast(file.get() * 256 + file.get() - 2); + continue; + } + + // Found the appropriate block. Extract the dimensions. + for (int i = 0; i < 3; ++i) file.get(); + + int height = file.get() * 256 + file.get(); + int width = file.get() * 256 + file.get(); + return sibr::Vector2i(width, height); + } + return sibr::Vector2i(-1, -1); + } + + // Adopted from http://stackoverflow.com/questions/22638755/image-dimensions-without-loading + // kudos to Lukas (http://stackoverflow.com/users/643315/lukas). + sibr::Vector2i IImage::imageResolution(const std::string& file_path) + { + enum ValidFormats { + PNG = 0, + BMP, + TGA, + JPG, + JPEG, + VALID_COUNT + }; + + std::string valid_extensions[] = { + "png", + "bmp", + "tga", + "jpg", + "jpeg" + }; + + std::string extension = sibr::to_lower(sibr::getExtension(file_path)); + + int extension_id = 0; + while (extension_id < VALID_COUNT && + extension != valid_extensions[extension_id]) + extension_id++; + + if (extension_id == VALID_COUNT) + return Eigen::Vector2i(-1, -1); + + std::ifstream file(file_path, std::ios::binary); + if (!file.good()) + return Eigen::Vector2i(-1, -1); + + uint32_t temp = 0; + int32_t width = -1; + int32_t height = -1; + switch (extension_id) + { + case PNG: + file.seekg(16); + file.read(reinterpret_cast(&width), 4); + file.read(reinterpret_cast(&height), 4); + width = sibr::ByteStream::ntohl(width); + height = sibr::ByteStream::ntohl(height); + break; + case BMP: + file.seekg(14); + file.read(reinterpret_cast(&temp), 4); + if (temp == 40) // Windows Format + { + file.read(reinterpret_cast(&width), 4); + file.read(reinterpret_cast(&height), 4); + } + else if (temp == 20) // MAC Format + { + file.read(reinterpret_cast(&width), 2); + file.read(reinterpret_cast(&height), 2); + } + break; + case TGA: + file.seekg(12); + file.read(reinterpret_cast(&width), 2); + file.read(reinterpret_cast(&height), 2); + break; + case JPG: + case JPEG: + return get_jpeg_size(file); + break; + } + return sibr::Vector2i(width, height); + } + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Image.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Image.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0016514f2718efb612a30bab8c01ac1ed2c97477 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Image.hpp @@ -0,0 +1,1312 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include "core/graphics/Config.hpp" +# include "core/system/Vector.hpp" +# include "core/system/ByteStream.hpp" + +# pragma warning(push, 0) +# include +# include +# include +# include +# pragma warning(pop) + +#include +#include + +namespace cv +{ + /** Extend OpenCV support for Eigen types. + \ingroup sibr_graphics + */ + /*template + class DataType > + { + public: + typedef Eigen::Matrix value_type; ///< Vector type. + typedef Eigen::Matrix::work_type, cn, 1, Eigen::DontAlign> work_type; ///< Wrapper type. + typedef T_Type channel_type; ///< Component type. + typedef value_type vec_type; ///< Vector type. + enum { generic_type = 0, depth = DataDepth::value, channels = cn, fmt = ((channels - 1) << 8) + DataDepth::fmt, type = CV_MAKETYPE(depth, channels) }; + };*/ +} + +namespace sibr +{ + + /** + * \addtogroup sibr_graphics + * @{ + */ + + namespace opencv + { + /** \return the OpenCV type corresponding to a C type. */ + template + SIBR_GRAPHICS_EXPORT int imageType(void);// { return -1; } // default, unknown + /** \return the OpenCV type corresponding to a C type. */ + template <> SIBR_GRAPHICS_EXPORT inline int imageType< uint8 >(void) { return CV_8U; } + /** \return the OpenCV type corresponding to a C type. */ + template <> SIBR_GRAPHICS_EXPORT inline int imageType< int8 >(void) { return CV_8S; } + /** \return the OpenCV type corresponding to a C type. */ + template <> SIBR_GRAPHICS_EXPORT inline int imageType< uint16>(void) { return CV_16U; } + /** \return the OpenCV type corresponding to a C type. */ + template <> SIBR_GRAPHICS_EXPORT inline int imageType< int16 >(void) { return CV_16S; } + /** \return the OpenCV type corresponding to a C type. */ + template <> SIBR_GRAPHICS_EXPORT inline int imageType< int32 >(void) { return CV_32S; } + /** \return the OpenCV type corresponding to a C type. */ + template <> SIBR_GRAPHICS_EXPORT inline int imageType< float >(void) { return CV_32F; } + /** \return the OpenCV type corresponding to a C type. */ + template <> SIBR_GRAPHICS_EXPORT inline int imageType< double>(void) { return CV_64F; } + + /** \return the size of the range of values a type can take when used in OpenCV. */ + template + inline float imageTypeRange(void) { + return (float)std::numeric_limits::max();//-std::numeric_limits::min(); + } + /** \return the size of the range of values a type can take when used in OpenCV. */ + template <> SIBR_GRAPHICS_EXPORT inline float imageTypeRange< float >(void) { return 1.f; } + /** \return the size of the range of values a type can take when used in OpenCV. */ + template <> SIBR_GRAPHICS_EXPORT inline float imageTypeRange< double>(void) { return 1.f; } + + /** Get the size of the range of values an OpenCV type can take. + \param cvDepth the OpenCV type depth + \return the size of the range + */ + SIBR_GRAPHICS_EXPORT float imageTypeCVRange(int cvDepth); + + /** Convert a BGR cv::Mat into a RGB cv::Mat, in-place. + \param dst the matrix to convert + */ + SIBR_GRAPHICS_EXPORT void convertBGR2RGB(cv::Mat& dst); + + /** Convert a BGR cv::Mat into a RGB cv::Mat, in-place. + \param dst the matrix to convert + */ + SIBR_GRAPHICS_EXPORT void convertRGB2BGR(cv::Mat& dst); + } + + typedef Vector4f ColorRGBA; + + /** @} */ + + /** + * Interface virtual class for all the templated image classes. + * Contains all functions not making reference to the internal type or numComp in their signature/return type + * \sa Image + * \ingroup sibr_graphics + */ + class SIBR_GRAPHICS_EXPORT IImage { + public: + SIBR_CLASS_PTR(IImage); + + /** Load an image from the disk (png, jpeg, exr, etc., see OpenCV cv::imread documentation for more details). + \param filename the path to the file + \param verbose display additional informations + \param warning_if_not_found log if the file doesn't exist, even if verbose is set to false + \return a success flag + */ + virtual bool load(const std::string& filename, bool verbose = true, bool warning_if_not_found = true) = 0; + + /** Load an image from the disk (stored as a raw binary blob). + \param filename the path to the file + \param verbose display additional informations + \return a success flag + */ + virtual bool loadByteStream(const std::string& filename, bool verbose = true) = 0; + + /** Save an image to the disk (png, jpeg, see OpenCV cv::imwrite documentation for more details). + \param filename the path to the file + \param verbose display additional informations + \warning HDR images will be converted to LDR, \sa saveHDR . + \warning Some image formats can't be stored in some file formats. + */ + virtual void save(const std::string& filename, bool verbose = true) const = 0; + + /** Save an image to the disk (as a raw binary blob). + \param filename the path to the file + \param verbose display additional informations + */ + virtual void saveByteStream(const std::string& filename, bool verbose = true) const = 0; + + /** Save an HDR image to the disk (exr, hdr, see OpenCV cv::imwrite documentation for more details). + \param filename the path to the file + \param verbose display additional informations + */ + virtual void saveHDR(const std::string& filename, bool verbose = true) const = 0; + + /** \return the image width. */ + virtual uint w(void) const = 0; + + /** \return the image height. */ + virtual uint h(void) const = 0; + + /** \return the image size. */ + virtual sibr::Vector2u size(void) const = 0; + + /** Check if a pixel (x,y) is inside the image boundaries. + \param xy the pixel coordinates + \return true if 0<=x + class ImagePtr; + + /** + * This class is used to store images. Internally, a cv::Mat + * is used. The template parameter define a fixed size/format that + * will be used to convert automatically the image format when + * you load or copy from another image. + * \warning We disallow copy as we would have to do a costly in-depth copy of the underlying cv::Mat. + * If you store images in a vector attribute of a class, you might have to SIBR_DISALLOW_COPY of your class. + * \note OpenCV uses generally BGR channels (e.g. after loading an image file). + * However the internal cv::Mat of this class stores + * RGB channels. You can get RGB cv::Mat with toOpenCV() or use + * toOpenCVBGR(). (Most of OpenCV's features works with RGB too but + * not imshow, imwrite, imread.) + * \ingroup sibr_graphics + */ + template + class Image : public IImage { + public: + typedef T_Type Type; + typedef ImagePtr Ptr; + + typedef Eigen::Matrix Pixel; + enum { e_NumComp = T_NumComp }; + + public: + + /// Default constructor. + Image(void); + + /** Constructor. + \param width image width + \param height image height + \warning The image content will be undefined. + */ + Image(uint width, uint height); + + /** Constructor. + \param width image width + \param height image height + \param init default value to use for all components of all pixels + */ + Image(uint width, uint height, const T_Type& init); + + /** Constructor. + \param width image width + \param height image height + \param init default value to use for all pixels + */ + Image(uint width, uint height, const Pixel& init); + + /** Move constructor. + \param other image to move, don't use after move + */ + Image(Image&& other); + + /** Move operator. + \param other image to move, don't use after move + */ + Image& operator=(Image&& other) noexcept; + + Image& fill(Pixel const& value); + + /** + \copydoc IImage::load + */ + bool load(const std::string& filename, bool verbose = true, bool warning_if_not_found = true); + + /** + \copydoc IImage::loadByteStream + */ + bool loadByteStream(const std::string& filename, bool verbose = true); + + /** + \copydoc IImage::save + */ + void save(const std::string& filename, bool verbose = true) const; + + /** + \copydoc IImage::saveByteStream + */ + void saveByteStream(const std::string& filename, bool verbose = true) const; + + /** + \copydoc IImage::saveHDR + */ + void saveHDR(const std::string& filename, bool verbose = true) const; + + /** Pixel accessor. + \param x x coordinate + \param y y coordinate + \return a reference to the pixel value. + */ + const Pixel& operator()(uint x, uint y) const; + + /** Pixel accessor. + \param x x coordinate + \param y y coordinate + \return a reference to the pixel value. + */ + Pixel& operator()(uint x, uint y); + + /** Pixel accessor. + \param xy pixel coordinates + \return a reference to the pixel value. + */ + const Pixel& operator()(const sibr::Vector2i & xy) const; + + /** Pixel accessor. + \param xy pixel coordinates + \return a reference to the pixel value. + */ + Pixel& operator()(const sibr::Vector2i & xy); + + /** Pixel accessor. + \param xy pixel coordinates + \return a reference to the pixel value. + */ + const Pixel& operator()(const ::sibr::Vector2f & xy) const; + + /** Pixel accessor. + \param xy pixel coordinates + \return a reference to the pixel value. + */ + Pixel& operator()(const ::sibr::Vector2f & xy); + + /** \copydoc IImage::pixelStr */ + virtual std::string pixelStr(const ::sibr::Vector2i & xy) const; + + /** \return a pointer to the raw image data. */ + const void* data(void) const; + + /** \return a pointer to the raw image data. */ + void* data(void); + + + /** Convert a pixel value to a 4 components float vector (in 0,1). + \param x x coordinate + \param y y coordinate + \return the normalized expanded value + */ + ColorRGBA color(uint x, uint y) const; + + /** Set a pixel value from 4 components float vector (in 0,1). + \param x x coordinate + \param y y coordinate + \param c the new value + */ + void color(uint x, uint y, const ColorRGBA& c); + + /** Helper to convert a 4 components float vector (in 0,1) to the proper pixel format. + \param rgba the value to convert + \return the converted value + */ + static Pixel color(const ColorRGBA& rgba); + + /** Generate a resized version of the current image. + \param width the target width + \param height the target height + \param cv_interpolation_method the up/down scaling method + \return the resized image + */ + Image resized(int width, int height, int cv_interpolation_method = cv::INTER_LINEAR) const; + + /** Generate a resized version of the current image so that the maximum + dimension (either width or height) is now equal to maxlen. Preserve the original ratio. + Example: src is 2048x1024, resizedMax(1024) -> dst is 1024x512 + \param maxlen the target maximum dimension value + \return the resized image + */ + Image resizedMax(int maxlen) const; + + /** \return a deep copy of the image. */ + Image clone(void) const; + + /** \return a pointer to a deep copy of the image. */ + ImagePtr clonePtr(void) const; + + /** \return the image width. */ + uint w(void) const; + + /** \return the image height. */ + uint h(void) const; + + /** \return the image size. */ + sibr::Vector2u size(void) const; + + /** Check if a pixel (x,y) is inside the image boundaries. + \param x x coordinate + \param y y coordinate + \return true if 0<=x + bool isInRange(T x, T y) const { return (x >= 0 && y >= 0 && x < (T)w() && y < (T)h()); } + + /** Check if a pixel (x,y) is inside the image boundaries. + \param x x coordinate + \param y y coordinate + \return true if 0<=x + bool inRange(T x, T y) const { return isInRange(x, y); } + + /** Check if a pixel (x,y) is inside the image boundaries. + \param xy the pixel coordinates + \return true if 0<=x= 0 && xy.y() >= 0 && xy.x() < (int)w() && xy.y() < (int)h()); } + + /** Check if a pixel (x,y) is inside the image boundaries. + \param xy the pixel coordinates + \return true if 0<=x= 0 && xy.y() >= 0 && xy.x() < (float)w() && xy.y() < (float)h()); } + + /** \copydoc IImage::numComp */ + uint numComp(void) const; + + /** \copydoc IImage::sizeOfComp */ + uint sizeOfComp(void) const; + + /** \copydoc IImage::flipH */ + void flipH(void); + + /** \copydoc IImage::flipV */ + void flipV(void); + + /** \copydoc IImage::opencvType */ + int opencvType(void) const { return CV_MAKETYPE(opencv::imageType(), T_NumComp); } + + /** \copydoc IImage::toOpenCV */ + const cv::Mat& toOpenCV(void) const { return _pixels; } + + /** \copydoc IImage::toOpenCVnonConst */ + cv::Mat& toOpenCVnonConst(void) { return _pixels; } + + /** \copydoc IImage::toOpenCVBGR */ + cv::Mat toOpenCVBGR(void) const; + + /** \copydoc IImage::fromOpenCV */ + void fromOpenCV(const cv::Mat& img); + + /** \copydoc IImage::fromOpenCVBGR */ + void fromOpenCVBGR(const cv::Mat& img); + + /** Find the component-wise minimum and maximum values contained in the image. + \param minImage will contain the minimum value + \param maxImage will contain the maximum value + */ + void findMinMax(Pixel& minImage, Pixel& maxImage); + + /** Rescale an image content in a defined range. + \param minValue the lower value of the range + \param maxValue the upper value of the range + */ + void remap(const Pixel& minValue, const Pixel& maxValue); + + /** Cast into another image type. + \return the converted image + */ + template T_Image cast() const { + T_Image b; + b.fromOpenCV(toOpenCV()); + return b; + } + + /** Fetch bilinear interpolated value from floating point pixel coordinates. + \param pixel query position in [0,w[x[0,h[ + \return the interpolated value + */ + Pixel bilinear(const sibr::Vector2f & pixel) const; + + /** Fetch bicubic interpolated value from floating point pixel coordinates. + \param pixelPosition query position in [0,w[x[0,h[ + \return the interpolated value + */ + Pixel bicubic(const sibr::Vector2f & pixelPosition) const; + + /** Disallow copy constructor. + \param other image to copy + */ + Image( const Image& other) = delete; + + /** Disallow copy operator. + \param other image to copy + */ + Image& operator =(const Image& other) = delete; + + protected: + + /** Helper for bicubic interpolation. + \param t blend factor + \param colors colors at the four corners + \return interpolated value + */ + static Eigen::Matrix monoCubic(float t, const Eigen::Matrix& colors); + + cv::Mat _pixels; ///< Pixels stored in RGB format + }; + + /** Provides a wrapper around a pointer to an image. + \ingroup sibr_graphics + */ + template + class ImagePtr { + public: + + using ImageType = Image; ///< Underlying image type. + + std::shared_ptr> imPtr; ///< Pointer type. + + /// Default constructor. + ImagePtr() { imPtr = std::shared_ptr>(); }; + + /** Constructor from a raw pointer. + \param imgPtr the raw pointer to wrap + */ + ImagePtr(Image* imgPtr) { imPtr = std::shared_ptr>(imgPtr); }; + + /** Constructor from a shared pointer. + \param imgPtr the shared pointer to wrap + */ + ImagePtr(const std::shared_ptr>& imgPtr) {imPtr = std::shared_ptr>(imgPtr); }; + + /** Generate a pointer by cloning an image. + \param img the image to clone + \return the pointer + */ + static ImagePtr fromImg(const ImageType & img) { return ImagePtr(std::make_shared>(img.clone())); }; + + /** Set a new pointee. + \param ptr the new image pointer + */ + void reset(ImageType * ptr) { imPtr.reset(ptr); }; + + /** \return the image */ + Image* get() { return imPtr.get(); }; + + /** Pixel accessor. + \param x x coordinate + \param y y coordinate + \return a reference to the pixel value. + */ + const typename Image::Pixel& operator()(uint x, uint y) const; + + /** Pixel accessor. + \param x x coordinate + \param y y coordinate + \return a reference to the pixel value. + */ + typename Image::Pixel& operator()(uint x, uint y); + + /** Pixel accessor. + \param xy pixel coordinates + \return a reference to the pixel value. + */ + const typename Image::Pixel& operator()(const sibr::Vector2i & xy) const; + + /** Pixel accessor. + \param xy pixel coordinates + \return a reference to the pixel value. + */ + typename Image::Pixel& operator()(const sibr::Vector2i & xy); + + /** \return the dereferenced image */ + Image& operator * () { return imPtr.operator*(); }; + + /** \return the dereferenced image */ + const Image& operator * () const { return imPtr.operator*(); }; + + /** \return raw pointer to the image */ + Image* operator -> () { return imPtr.operator->(); }; + + /** \return raw pointer to the image */ + const Image* operator -> () const { return imPtr.operator->(); }; + + /** Assign a shared ptr. + \param imgShPtr the shared pointer + \return a reference to the updated pointer + */ + std::shared_ptr> & operator = (std::shared_ptr> & imgShPtr) { imPtr = imgShPtr; return &imPtr; }; + + /** \return true if the image pointer is initialized. */ + operator bool() { return imPtr.get() != nullptr; }; + + /** \return true if the image pointer is initialized. */ + operator bool() const { return imPtr.get() != nullptr; }; + + }; + + /** + * \addtogroup sibr_graphics + * @{ + */ + + /// Standard image types + typedef Image ImageRGB; + typedef Image ImageRGBA; + typedef Image ImageL8; + typedef Image ImageUV8; + typedef Image ImageRGB16; + typedef Image ImageL16; + typedef Image ImageRGB32F; + typedef Image ImageFloat3; + typedef Image ImageRGBA32F; + typedef Image ImageFloat4; + typedef Image ImageL32F; + typedef Image ImageFloat1; + typedef Image ImageFloat2; + typedef Image ImageUV32F; + typedef Image ImageBool1; + typedef Image ImageDouble1; + typedef Image ImageDouble2; + typedef Image ImageDouble3; + typedef Image ImageDouble4; + typedef Image ImageInt1; + typedef Image ImageInt2; + typedef Image ImageInt3; + typedef Image ImageInt4; + + + /** Convert an integer ID map to a colored image using a different random color for each ID. Note that 255 is black. + \param imClass the ID map + \return a color coded map + */ + SIBR_GRAPHICS_EXPORT Image coloredClass(const Image::Ptr imClass); + + /** Convert an integer ID map to a colored image using a different random color for each ID. Note that 255 is black. + \param imClass the ID map + \return a color coded map + */ + SIBR_GRAPHICS_EXPORT Image coloredClass(const Image::Ptr imClass); + + /** Display a 32F image in a debug window, using the Parula colormap after normalizing the values. + \param im the float image to display + \param logScale display log(img) + \param min optional lower bound for the normalization + \param max optional upper bound for the normalization + */ + SIBR_GRAPHICS_EXPORT void showFloat(const Image & im, bool logScale = false, double min = -DBL_MAX, double max = DBL_MAX); + + /** Convert a L32F into a RGBA image while preserving bit-level representation. + Useful to save float maps as PNG, and benefit from PNG compression on disk. + \param imgF the image to convert + \return the packed RGBA image + */ + SIBR_GRAPHICS_EXPORT sibr::ImageRGBA convertL32FtoRGBA(const sibr::ImageL32F & imgF); + + /** Convert a RGBA into a L32F image while preserving bit-level representation. + Useful to decode float maps stored as as PNG. + \param imgRGBA the image to convert + \return the unpacked float image + */ + SIBR_GRAPHICS_EXPORT sibr::ImageL32F convertRGBAtoL32F(const sibr::ImageRGBA & imgRGBA); + + /** Convert a RGB32F into a RGBA image (3 times wider) while preserving bit-level representation. + Useful to save float maps as PNG, and benefit from PNG compression on disk. + \param imgF the image to convert + \return the packed RGBA image + */ + SIBR_GRAPHICS_EXPORT sibr::ImageRGBA convertRGB32FtoRGBA(const sibr::ImageRGB32F & imgF); + + /** Convert a RGBA into a RGB32F image while preserving bit-level representation. + Useful to decode float maps stored as as PNG. + \param imgRGBA the image to convert + \return the unpacked float image + */ + SIBR_GRAPHICS_EXPORT sibr::ImageRGB32F convertRGBAtoRGB32F(const sibr::ImageRGBA & imgRGBA); + + /** Convert a RGB32 normal map into a UV16 map storing theta and phi as half floats, packed into a RGBA8. + \param imgF the XYZ normal map + \return the packed theta,phi normal map + */ + SIBR_GRAPHICS_EXPORT sibr::ImageRGBA convertNormalMapToSphericalHalf(const sibr::ImageRGB32F & imgF); + + /** Convert a RGBA map, packing theta and phi as half floats, into a RGB32 normal map. + \param imgF packed theta,phi normal map + \return the XYZ normal map + */ + SIBR_GRAPHICS_EXPORT sibr::ImageRGB32F convertSphericalHalfToNormalMap(const sibr::ImageRGBA & imgF); + + /** Create a three channels cv::Mat by repeating a single channel cv::Mat. + \param c the input cv::Mat + \return a three channels cv::Mat + */ + SIBR_GRAPHICS_EXPORT cv::Mat duplicate3(cv::Mat c); + + /** Display an image into a popup OpenCV window. + \param img the image to display + \param windowTitle the window title + \param closeWindow close the window after key presses + */ + template + static void show(const Image & img, const std::string& windowTitle = "sibr::show()", bool closeWindow = true) { + cv::namedWindow(windowTitle, cv::WINDOW_AUTOSIZE | cv::WINDOW_KEEPRATIO | cv::WINDOW_GUI_EXPANDED); + // Note: CV_GUI_EXPANDED does only work with Qt + + cv::imshow(windowTitle, img.toOpenCVBGR()); + cv::waitKey(0); + if (closeWindow) { + cv::destroyWindow(windowTitle); + } + } + + /*** @} */ + + // ----- DEFINITIONS ------------- + + template + Image::Image(void) : + _pixels(0, 0, opencvType()) { } + + template + Image::Image(uint width, uint height) : + _pixels(height, width, opencvType()) { } + + template + Image::Image(uint width, uint height, const T_Type& init) : + _pixels(height, width, opencvType(), init) { } + + template + Image::Image(uint width, uint height, const Pixel& init) + { + cv::Scalar scal(0); + for (int i = 0; i < T_NumComp; i++) + scal(i) = init(i); + + _pixels = cv::Mat(height, width, opencvType(), scal); + + } + + template + Image::Image(Image&& other) { + operator =(std::move(other)); + } + + template + Image& Image::operator=(Image&& other) noexcept { + _pixels = std::move(other._pixels); + return *this; + } + + template + Image& Image::fill(Pixel const& value) { + std::fill(_pixels.begin(), _pixels.end(), value); + return *this; + } + + template + const void* Image::data(void) const { + SIBR_ASSERT(_pixels.isContinuous() == true); // if not true, you don't want to use this function + return _pixels.ptr(); + } + + template + void* Image::data(void) { + SIBR_ASSERT(_pixels.isContinuous() == true); // if not true, you don't want to use this function + return _pixels.ptr(); + } + + template + cv::Mat Image::toOpenCVBGR(void) const { + cv::Mat out = toOpenCV().clone(); + opencv::convertRGB2BGR(out); + return out; + } + + template + void Image::fromOpenCVBGR(const cv::Mat& imgSrc) { + cv::Mat img = imgSrc.clone(); + opencv::convertBGR2RGB(img); + fromOpenCV(img); + } + + template + void Image::fromOpenCV(const cv::Mat& imgSrc) { + cv::Mat img = imgSrc.clone(); + + if (img.depth() != opencv::imageType()) + { + img.convertTo(img, opencv::imageType(), + opencv::imageTypeRange() / opencv::imageTypeCVRange(img.depth())); + } + + cv::Vec p; + if (img.channels() != T_NumComp) + { + _pixels = cv::Mat(img.rows, img.cols, opencvType()); + for (int y = 0; y < img.rows; ++y) + { + for (int x = 0; x < img.cols; ++x) + { + const T_Type* ptr = img.ptr(y, x); + assert(ptr != nullptr); + uint i; + for (i = 0; i < (uint)img.channels() && i < T_NumComp; ++i) + p[i] = ptr[i]; + for (; i < T_NumComp && i < 3; ++i) + p[i] = p[0]; + for (; i < T_NumComp && i < 4; ++i) + p[i] = static_cast(opencv::imageTypeRange()); + + _pixels.at>(y, x) = p; + } + } + } + else + _pixels = img; + } + + template + Image Image::clone(void) const { + Image img; + img._pixels = _pixels.clone(); + return img; + } + + template + ImagePtr Image::clonePtr(void) const { + ImagePtr img(new Image()); + img->_pixels = _pixels.clone(); + return img; + } + + template + bool Image::load(const std::string& filename, bool verbose, bool warning_if_not_found) { + if (verbose) + SIBR_LOG << "Loading image file '" << filename << "'." << std::endl; + else + std::cerr << "."; + cv::Mat img = cv::imread(filename, cv::IMREAD_UNCHANGED | cv::IMREAD_ANYDEPTH | cv::IMREAD_ANYCOLOR); + if (img.data == nullptr) + { + operator =(Image()); // reset mat + + if (warning_if_not_found) { + SIBR_WRG << "Image file not found '" << filename << "'." << std::endl; + } + + return false; + } + opencv::convertBGR2RGB(img); + fromOpenCV(img); + return true; + } + + template + bool Image::loadByteStream(const std::string& filename, bool verbose) { + if (verbose) + SIBR_LOG << "Loading image file '" << filename << "'." << std::endl; + else + std::cerr << "."; + + + cv::Vec p; + + sibr::ByteStream bs; + if (!bs.load(filename)) + SIBR_WRG << "Image file not found '" << filename << "'." << std::endl; + + int wIm; + int hIm; + bs >> wIm >> hIm; + + _pixels = cv::Mat(hIm, wIm, opencvType()); + for (int y = 0; y < hIm; ++y) + { + for (int x = 0; x < wIm; ++x) + { + uint i; + for (i = 0; i < T_NumComp; ++i) + bs >> p[i]; + + _pixels.at>(y, x) = p; + } + } + + return true; + } + + template + void Image::save(const std::string& filename, bool verbose) const { + { // Create the output dir if doesn't exists + boost::filesystem::path outdir = boost::filesystem::path(filename).parent_path(); + if (outdir.empty() == false) + boost::filesystem::create_directories(outdir); + } + + // Important Note: + // If you have a problem when saving an image (e.g. black image) then + // check the targeted image file format manages correctly the T_Type and + // T_NumpComp you provide. + // OpenCV doesn't seem to check always for such incompatibility (and just + // save empty pixels) + + if (verbose) + SIBR_LOG << "Saving image file '" << filename << "'." << std::endl; + + cv::Mat img; + if (T_NumComp == 1) { + cv::cvtColor(toOpenCVBGR(), img, cv::COLOR_GRAY2BGR); + } /// \todo TODO: support for 2 channels images. + else { + // For 3 and 4 channels, leave the image untouched. + img = toOpenCVBGR(); + } + + cv::Mat finalImage; + if (T_NumComp == 4) { + cv::Mat4b imageF_8UC4; + double scale = 255.0 / (double)opencv::imageTypeRange(); + img.convertTo(imageF_8UC4, CV_8UC4, scale); + finalImage = imageF_8UC4; + } + else { + cv::Mat3b imageF_8UC3; + double scale = 255.0 / (double)opencv::imageTypeRange(); + img.convertTo(imageF_8UC3, CV_8UC3, scale); + finalImage = imageF_8UC3; + } + + if (img.cols > 0 && img.rows > 0) + { + if (cv::imwrite(filename, finalImage) == false) + SIBR_ERR << "unknown error while saving image '" << filename << "'" + << " (do the targeted file format manages correctly the bpc ?)" << std::endl; + } + else + SIBR_WRG << "failed to save (image is empty)" << std::endl; + } + + template + void Image::saveHDR(const std::string& filename, bool verbose) const { + { // Create the output dir if doesn't exists + boost::filesystem::path outdir = boost::filesystem::path(filename).parent_path(); + if (outdir.empty() == false) + boost::filesystem::create_directories(outdir); + } + + if (verbose) + SIBR_LOG << "Saving image file '" << filename << "'." << std::endl; + + cv::Mat img; + if (T_NumComp == 1) { + cv::cvtColor(toOpenCVBGR(), img, cv::COLOR_GRAY2BGR); + } /// \todo TODO: support for 2 channels images. + else { + // For 3 and 4 channels, leave the image untouched. + img = toOpenCVBGR(); + } + + cv::Mat finalImage; + if (T_NumComp == 4) { + cv::Mat4f imageF_32FC4; + double scale = 1.0 / (double)opencv::imageTypeRange(); + img.convertTo(imageF_32FC4, CV_32FC4, scale); + finalImage = imageF_32FC4; + } + else { + cv::Mat3f imageF_32FC3; + double scale = 1.0 / (double)opencv::imageTypeRange(); + img.convertTo(imageF_32FC3, CV_32FC3, scale); + finalImage = imageF_32FC3; + } + + if (img.cols > 0 && img.rows > 0) + { + if (cv::imwrite(filename, finalImage) == false) + SIBR_ERR << "unknown error while saving image '" << filename << "'" + << " (do the targeted file format manages correctly the bpc ?)" << std::endl; + } + else + SIBR_WRG << "failed to save (image is empty)" << std::endl; + } + + template + void Image::saveByteStream(const std::string& filename, bool verbose) const { + { // Create the output dir if doesn't exists + boost::filesystem::path outdir = boost::filesystem::path(filename).parent_path(); + if (outdir.empty() == false) + boost::filesystem::create_directories(outdir); + } + if (verbose) + SIBR_LOG << "Saving image file '" << filename << "'." << std::endl; + + sibr::ByteStream bs; + + int wIm = w(); + int hIm = h(); + + if (wIm > 0 && hIm > 0) { + bs << wIm << hIm; + for (int j = 0; j < hIm; j++) { + for (int i = 0; i < wIm; i++) { + for (int k = 0; k < T_NumComp; k++) { + bs << _pixels.at>(j, i)[k]; + } + } + } + bs.saveToFile(filename); + } + else + SIBR_WRG << "failed to save (image is empty)" << std::endl; + } + + template + inline const typename Image::Pixel& Image::operator()(uint x, uint y) const { +#ifndef NDEBUG + if (!(x < w() && y < h())) { + std::cout << " access (" << x << " , " << y << ") while size is " << w() << " x " << h() << std::endl; +} +#endif + SIBR_ASSERT(x < w() && y < h()); + return _pixels.at::Pixel>(y, x); + } + + template + inline const typename Image::Pixel & ImagePtr::operator()(uint x, uint y) const + { + return (*imPtr)(x, y); + } + + template + inline typename Image::Pixel& Image::operator()(uint x, uint y) { +#ifndef NDEBUG + if (!(x < w() && y < h())) { + std::cout << " access (" << x << " , " << y << ") while size is " << w() << " x " << h() << std::endl; + } +#endif + SIBR_ASSERT(x < w() && y < h()); + return _pixels.at::Pixel>(y, x); + } + + template + inline typename Image::Pixel & ImagePtr::operator()(uint x, uint y) + { + return (*imPtr)(x, y); + } + + + template + inline const typename Image::Pixel& Image::operator()(const sibr::Vector2i & xy) const { + return operator()(xy[0], xy[1]); + } + template + inline const typename Image::Pixel & ImagePtr::operator()(const sibr::Vector2i & xy) const + { + return (*imPtr)(xy[0], xy[1]); + } + + template + inline typename Image::Pixel& Image::operator()(const sibr::Vector2i & xy) { + return operator()(xy[0], xy[1]); + } + template + inline typename Image::Pixel & ImagePtr::operator()(const sibr::Vector2i & xy) + { + return (*imPtr)(xy[0], xy[1]); + } + + template + inline typename Image::Pixel& Image::operator()(const sibr::Vector2f & xy) { + return operator()((int)xy[0], (int)xy[1]); + } + template + inline const typename Image::Pixel& Image::operator() (const sibr::Vector2f & xy) const { + return operator()((int)xy[0], (int)xy[1]); + } + + template + ColorRGBA Image::color(uint x, uint y) const { + SIBR_ASSERT(x < w() && y < h()); + float scale = 1.f / opencv::imageTypeRange(); + cv::Vec v = _pixels.at>(y, x); + + return ColorRGBA(v.val[0] * scale, v.val[1] * scale, v.val[2] * scale, + (T_NumComp > 3) ? v.val[3] * scale : 1.f); + } + template + void Image::color(uint x, uint y, const ColorRGBA& rgba) { + SIBR_ASSERT(x < w() && y < h()); + float scale = opencv::imageTypeRange(); + cv::Vec v;//(p.data(), T_NumComp); + for (uint i = 0; i < T_NumComp; ++i) v[i] = T_Type(rgba[i] * scale); + _pixels.at>(y, x) = v; + } + + template + Image Image::resized(int width, int height, int cv_interpolation_method) const + { + if (width == w() && height == h()) + return clone(); + Image dst; + cv::resize(toOpenCV(), dst._pixels, cv::Size(width, height), 0, 0, cv_interpolation_method); + return dst; + } + + template + Image Image::resizedMax(int maxlen) const + { + float newWidth = (w() >= h()) ? maxlen : maxlen * ((float)w() / (float)h()); + float newHeight = (h() >= w()) ? maxlen : maxlen * ((float)h() / (float)w()); + + return resized((int)newWidth, (int)newHeight); + } + + template + typename Image::Pixel Image::color(const ColorRGBA& rgba) { + float scale = opencv::imageTypeRange(); + Pixel v;//(p.data(), T_NumComp); + for (uint i = 0; i < T_NumComp; ++i) v[i] = T_Type(rgba[i] * scale); + return v; + } + + template + std::string Image::pixelStr(const ::sibr::Vector2i & xy) const { + if (isInRange(xy)) { + std::stringstream ss; +// ss << "( " << operator()(xy).cast, int, T_Type>::type>().transpose() << " )"; +std::cerr << "PIXEL STR PB" << std::endl; +exit(1); + return ss.str(); + } + return ""; + } + + template + uint Image::w(void) const { + return _pixels.cols; + } + + template + uint Image::h(void) const { + return _pixels.rows; + } + + template + sibr::Vector2u Image::size(void) const { + return sibr::Vector2u(w(), h()); + } + + template + uint Image::numComp(void) const { + return T_NumComp; + } + + template + uint Image::sizeOfComp(void) const { + return sizeof(T_Type)*T_NumComp; + } + + template + void Image::flipH(void) { + cv::flip(_pixels, _pixels, 0 /*!=0 means horizontal*/); + } + template + void Image::flipV(void) { + cv::flip(_pixels, _pixels, 1 /*!=1 means vertical*/); + } + + template + void Image::findMinMax(Pixel& minImage, Pixel& maxImage) { + for (uint c = 0; c < T_NumComp; ++c) { + minImage[c] = T_Type(opencv::imageTypeRange()); + maxImage[c] = T_Type(-opencv::imageTypeRange()); + } + + Pixel p; + for (uint y = 0; y < h(); ++y) { + for (uint x = 0; x < w(); ++x) { + Pixel v = operator()(x, y); + for (uint c = 0; c < T_NumComp; ++c) { + minImage[c] = std::min(v[c], minImage[c]); + maxImage[c] = std::max(v[c], maxImage[c]); + } + } + } + } + + template + void Image::remap(const Pixel& minVal, const Pixel& maxVal) { + Pixel minImage; + Pixel maxImage; + findMinMax(minImage, maxImage); + + Pixel p; + for (uint y = 0; y < h(); ++y) { + for (uint x = 0; x < w(); ++x) { + Pixel v = operator()(x, y); + for (uint i = 0; i < T_NumComp; ++i) + p[i] = minVal[i] + ((maxVal[i] - minVal[i])*(v[i] - minImage[i])) / (maxImage[i] - minImage[i]); + operator()(x, y) = p; + } + } + } + + template + Eigen::Matrix Image::bilinear(const sibr::Vector2f & queryPosition) const + { + if (w() < 2 || h() < 2) { + return Eigen::Matrix(); + } + + const sibr::Vector2i cornerPixel = sibr::Vector2f((queryPosition - 0.5f*sibr::Vector2f(1, 1)).unaryExpr([](float f) { return std::floor(f); })).template cast(); + + const sibr::Vector2f ts = queryPosition - (cornerPixel.cast() + 0.5f*sibr::Vector2f(1, 1)); + + const sibr::Vector2i topLeft(0, 0), bottomRight(w() - 1, h() - 1); + + const sibr::Vector2i mm = sibr::clamp(cornerPixel + sibr::Vector2i(0, 0), topLeft, bottomRight); + const sibr::Vector2i pm = sibr::clamp(cornerPixel + sibr::Vector2i(1, 0), topLeft, bottomRight); + const sibr::Vector2i mp = sibr::clamp(cornerPixel + sibr::Vector2i(0, 1), topLeft, bottomRight); + const sibr::Vector2i pp = sibr::clamp(cornerPixel + sibr::Vector2i(1, 1), topLeft, bottomRight); + return ( + operator()(mm).template cast() * (1.0f - ts[0]) * (1.0f - ts[1]) + + operator()(pm).template cast() * ts[0] * (1.0f - ts[1]) + + operator()(mp).template cast() * (1.0f - ts[0]) * ts[1] + + operator()(pp).template cast() * ts[0] * ts[1] + ).template cast(); + } + + template + Eigen::Matrix Image::monoCubic(float t, const Eigen::Matrix & colors) + { + static const Eigen::Matrix M = 0.5f* (Eigen::Matrix() << + 0, 2, 0, 0, + -1, 0, 1, 0, + 2, -5, 4, -1, + -1, 3, -3, 1 + ).finished().transpose(); + + return colors * (M*Eigen::Matrix(1, t, t*t, t*t*t)); + } + + template + Eigen::Matrix Image::bicubic(const sibr::Vector2f & queryPosition) const + { + static const std::vector > offsets = { + { { -1,-1 },{ 0,-1 } ,{ 1,-1 },{ 2,-1 } }, + { { -1,0 },{ 0,0 } ,{ 1,0 },{ 2,0 } }, + { { -1,1 },{ 0,1 } ,{ 1,1 },{ 2,1 } }, + { { -1,2 },{ 0,2 } ,{ 1,2 },{ 2,2 } } + }; + + typedef Eigen::Matrix ColorStack; + + if (w() < 4 || h() < 4) { + return Vector(); + } + + const sibr::Vector2i cornerPixel = (queryPosition - 0.5f*sibr::Vector2f(1, 1)).unaryExpr([](float f) { return std::floor(f); }).template cast(); + const sibr::Vector2f ts = queryPosition - (cornerPixel.cast() + 0.5f*sibr::Vector2f(1, 1)); + + ColorStack colorsGrid[4]; + const sibr::Vector2i topLeft(0, 0), bottomRight(w() - 1, h() - 1); + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) { + const sibr::Vector2i pixelPosition = cornerPixel + offsets[i][j]; + colorsGrid[i].col(j) = operator()(sibr::clamp(pixelPosition, topLeft, bottomRight)).template cast(); + } + } + + ColorStack bs; + for (int i = 0; i < 4; ++i) { + bs.col(i) = monoCubic(ts[0], colorsGrid[i]); + } + + Vector resultFloat = monoCubic(ts[1], bs); + return (resultFloat.unaryExpr([](float f) { return sibr::clamp(f, 0.0f, sibr::opencv::imageTypeRange()); })).template cast(); + } + + template + inline Vector fromOpenCV(const cv::Vec & vec) { + Vector out; + for (int i = 0; i < N; ++i) { + out[i] = static_cast(vec[i]); + } + return out; + } + + template + inline cv::Vec toOpenCV(const Vector & vec) { + cv::Vec out; + for (int i = 0; i < N; ++i) { + out[i] = static_cast(vec[i]); + } + return out; + } + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Input.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Input.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ffbdacdcfc62731933f894e4cf0b4aba37e2519d --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Input.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#include "core/graphics/Input.hpp" + +namespace sibr +{ + + /*static*/ Input& Input::global( void ) + { + /// \todo TODO: add warning if no windows have been created + static Input instance; + instance._empty = false; + return instance; + } + + /*static*/ void Input::poll( void ) + { + sibr::Input::global().swapStates(); + glfwPollEvents(); + } + + Input Input::subInput(const sibr::Input & global, const sibr::Viewport & viewport, const bool mouseOutsideDisablesKeyboard) + { + Input sub = global; + sub._mousePrevPos -= sibr::Vector2i(viewport.finalLeft(), viewport.finalTop()); + sub._mousePos -= sibr::Vector2i(viewport.finalLeft(), viewport.finalTop()); + + if (!global.isInsideViewport(viewport)) { + sub._mouseButton = MouseButton(); + sub._mouseScroll = 0; + + if (mouseOutsideDisablesKeyboard) { + sub._keyboard = Keyboard(); + } + return sub; + } + + return sub; + } + + bool Input::isInsideViewport(const sibr::Viewport & viewport) const + { + Eigen::AlignedBox2i subBox; + subBox.extend(Vector2i(viewport.finalLeft(), viewport.finalTop())); + subBox.extend(Vector2i(viewport.finalRight(), viewport.finalBottom())); + + return subBox.contains(mousePosition()); + } + + KeyCombination::KeyCombination() : numKeys(0), isTrue(true) { } + KeyCombination::KeyCombination(int n, bool b) : numKeys(n), isTrue(b) { } + + KeyCombination::operator bool() const + { + return isTrue && ( numKeys == sibr::Input::global().key().getNumActivated() ); + } + + KeyCombination operator&& ( const KeyCombination & combA, const KeyCombination & combB) + { + return KeyCombination(combA.numKeys + combB.numKeys, combA.isTrue && combB.isTrue); + } + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Input.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Input.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d835badbbfefcc75c8f66088e5e9ddc366bcaa3f --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Input.hpp @@ -0,0 +1,443 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include + +//#define GLEW_STATIC +#include +# define GLFW_INCLUDE_GLU +# include + +# include "core/graphics/Config.hpp" +# include "core/system/Vector.hpp" +# include "core/graphics/Viewport.hpp" + +namespace sibr +{ + namespace Key + { + /** Key codes (based on GLFW codes). */ + enum Code + { + Unknown = 0 /*GLFW_KEY_UNKNOWN*/, + Space = GLFW_KEY_SPACE, + Apostrophe = GLFW_KEY_APOSTROPHE, + Comma = GLFW_KEY_COMMA, + Minus = GLFW_KEY_MINUS, + Period = GLFW_KEY_PERIOD, + Slash = GLFW_KEY_SLASH, + Num0 = GLFW_KEY_0, + Num1 = GLFW_KEY_1, + Num2 = GLFW_KEY_2, + Num3 = GLFW_KEY_3, + Num4 = GLFW_KEY_4, + Num5 = GLFW_KEY_5, + Num6 = GLFW_KEY_6, + Num7 = GLFW_KEY_7, + Num8 = GLFW_KEY_8, + Num9 = GLFW_KEY_9, + Semicolon = GLFW_KEY_SEMICOLON, + Equal = GLFW_KEY_EQUAL, + A = GLFW_KEY_A, + B = GLFW_KEY_B, + C = GLFW_KEY_C, + D = GLFW_KEY_D, + E = GLFW_KEY_E, + F = GLFW_KEY_F, + G = GLFW_KEY_G, + H = GLFW_KEY_H, + I = GLFW_KEY_I, + J = GLFW_KEY_J, + K = GLFW_KEY_K, + L = GLFW_KEY_L, + M = GLFW_KEY_M, + N = GLFW_KEY_N, + O = GLFW_KEY_O, + P = GLFW_KEY_P, + Q = GLFW_KEY_Q, + R = GLFW_KEY_R, + S = GLFW_KEY_S, + T = GLFW_KEY_T, + U = GLFW_KEY_U, + V = GLFW_KEY_V, + W = GLFW_KEY_W, + X = GLFW_KEY_X, + Y = GLFW_KEY_Y, + Z = GLFW_KEY_Z, + LeftBracket = GLFW_KEY_LEFT_BRACKET, + Backslash = GLFW_KEY_BACKSLASH, + RightBracket = GLFW_KEY_RIGHT_BRACKET, + GraveAccent = GLFW_KEY_GRAVE_ACCENT, + World1 = GLFW_KEY_WORLD_1, + World2 = GLFW_KEY_WORLD_2, + Escape = GLFW_KEY_ESCAPE, + Enter = GLFW_KEY_ENTER, + Tab = GLFW_KEY_TAB, + Backspace = GLFW_KEY_BACKSPACE, + Insert = GLFW_KEY_INSERT, + Delete = GLFW_KEY_DELETE, + Right = GLFW_KEY_RIGHT, + Left = GLFW_KEY_LEFT, + Down = GLFW_KEY_DOWN, + Up = GLFW_KEY_UP, + Page_up = GLFW_KEY_PAGE_UP, + Page_down = GLFW_KEY_PAGE_DOWN, + Home = GLFW_KEY_HOME, + End = GLFW_KEY_END, + CapsLock = GLFW_KEY_CAPS_LOCK, + ScrollLock = GLFW_KEY_SCROLL_LOCK, + NumLock = GLFW_KEY_NUM_LOCK, + PrintScreen = GLFW_KEY_PRINT_SCREEN, + Pause = GLFW_KEY_PAUSE, + F1 = GLFW_KEY_F1, + F2 = GLFW_KEY_F2, + F3 = GLFW_KEY_F3, + F4 = GLFW_KEY_F4, + F5 = GLFW_KEY_F5, + F6 = GLFW_KEY_F6, + F7 = GLFW_KEY_F7, + F8 = GLFW_KEY_F8, + F9 = GLFW_KEY_F9, + F10 = GLFW_KEY_F10, + F11 = GLFW_KEY_F11, + F12 = GLFW_KEY_F12, + F13 = GLFW_KEY_F13, + F14 = GLFW_KEY_F14, + F15 = GLFW_KEY_F15, + F16 = GLFW_KEY_F16, + F17 = GLFW_KEY_F17, + F18 = GLFW_KEY_F18, + F19 = GLFW_KEY_F19, + F20 = GLFW_KEY_F20, + F21 = GLFW_KEY_F21, + F22 = GLFW_KEY_F22, + F23 = GLFW_KEY_F23, + F24 = GLFW_KEY_F24, + F25 = GLFW_KEY_F25, + KPNum0 = GLFW_KEY_KP_0, + KPNum1 = GLFW_KEY_KP_1, + KPNum2 = GLFW_KEY_KP_2, + KPNum3 = GLFW_KEY_KP_3, + KPNum4 = GLFW_KEY_KP_4, + KPNum5 = GLFW_KEY_KP_5, + KPNum6 = GLFW_KEY_KP_6, + KPNum7 = GLFW_KEY_KP_7, + KPNum8 = GLFW_KEY_KP_8, + KPNum9 = GLFW_KEY_KP_9, + KPDecimal = GLFW_KEY_KP_DECIMAL, + KPDivide = GLFW_KEY_KP_DIVIDE, + KPMultiply = GLFW_KEY_KP_MULTIPLY, + KPSubtract = GLFW_KEY_KP_SUBTRACT, + KPAdd = GLFW_KEY_KP_ADD, + KPEnter = GLFW_KEY_KP_ENTER, + KPEqual = GLFW_KEY_KP_EQUAL, + LeftShift = GLFW_KEY_LEFT_SHIFT, + LeftControl = GLFW_KEY_LEFT_CONTROL, + LeftAlt = GLFW_KEY_LEFT_ALT, + LeftSuper = GLFW_KEY_LEFT_SUPER, + RightShift = GLFW_KEY_RIGHT_SHIFT, + RightControl = GLFW_KEY_RIGHT_CONTROL, + RightAlt = GLFW_KEY_RIGHT_ALT, + RightSuper = GLFW_KEY_RIGHT_SUPER, + Menu = GLFW_KEY_MENU, + + count // this one is a 'tricks' to automatically get the number + // of elements in this enum (just type sibr::Key::count). + }; + } // namespace Key + + namespace Mouse + { + /** Mouse button codes (based on GLFW codes). */ + enum Code + { + Button1 = GLFW_MOUSE_BUTTON_1, + Button2 = GLFW_MOUSE_BUTTON_2, + Button3 = GLFW_MOUSE_BUTTON_3, + Button4 = GLFW_MOUSE_BUTTON_4, + Button5 = GLFW_MOUSE_BUTTON_5, + Button6 = GLFW_MOUSE_BUTTON_6, + Button7 = GLFW_MOUSE_BUTTON_7, + Button8 = GLFW_MOUSE_BUTTON_8, + Last = GLFW_MOUSE_BUTTON_LAST, + + Left = GLFW_MOUSE_BUTTON_LEFT, + Middle = GLFW_MOUSE_BUTTON_MIDDLE, + Right = GLFW_MOUSE_BUTTON_RIGHT, + + Unknown, + count + }; + } // namespace Mouse + + /** Helper keeping track of the number of keys currently pressed. */ + struct SIBR_GRAPHICS_EXPORT KeyCombination + { + /// Default constructor. + KeyCombination(); + + /** Constructor. + \param n number of keys pressed + \param b are they active or not + */ + KeyCombination(int n, bool b); + + /** \return true if they are numKeys pressed keys and their combination is active. */ + operator bool() const; + + int numKeys; ///< Number of pressed keys. + bool isTrue; ///< Activations status. + }; + + /** Merge two set of pressed keys. + \param combA first set + \param combB second set + \return the union set + */ + KeyCombination SIBR_GRAPHICS_EXPORT operator&&( const KeyCombination & combA, const KeyCombination & combB); + + /** Keep track of the pressed/active/released state of a set of keys/buttons. + \sa Key::Code, Mouse::Code + */ + template + class InputState + { + public: + + /** Is an item currently active. + \param code the item code (key or mouse) + \return true if the item is active at this frame + */ + bool isActivated( TEnum code ) const { + return _currentStates[(size_t)code]; + } + + /** Is an item released (lasts one frame). + \param code the item code (key or mouse) + \return true if the item is released at this frame + */ + bool isReleased( TEnum code ) const { + return _lastStates[(size_t)code] \ + && !_currentStates[(size_t)code]; + } + + /** Is an item pressed at this frame (lasts one frame). + \sa isActivated + \param code the item code (key or mouse) + \return true if the item is pressed at this frame + */ + bool isPressed( TEnum code ) const { + return !_lastStates[(size_t)code] \ + && _currentStates[(size_t)code]; + } + + /** Is an item currently pressed and only this one (lasts one frame). + \sa isActivated + \param code the item code (key or mouse) + \return true if the item is the only one pressed + */ + KeyCombination isPressedOnly( TEnum code ) const { + return KeyCombination(1,isPressed(code)); + } + + /** Is an item currently active and only this one. + \param code the item code (key or mouse) + \return true if the item is the only one active + */ + KeyCombination isActivatedOnly( TEnum code ) const { + return KeyCombination(1,isActivated(code)); + } + + /** Declare an item as pressed at this frame. + \param code the item code (Key or Mouse). + */ + void press( TEnum code ) { + _currentStates[(size_t)code] = true; + } + + /** Declare an item as released at this frame. + \param code the item code (Key or Mouse). + */ + void release( TEnum code ) { + _currentStates[(size_t)code] = false; + _lastStates[(size_t)code] = true; + } + + /** Mute an item. + \param code the item code (Key or Mouse). + */ + void silent( TEnum code ) { + _currentStates[(size_t)code] = \ + _lastStates[(size_t)code] = false; + } + + /** Reset all items state. + */ + void clearStates( void ) { + std::fill(_currentStates.begin(), _currentStates.end(), false); + std::fill(_lastStates.begin(), _lastStates.end(), false); + } + + /** Update previous frame states with the current frame ones. */ + void swapStates( void ) { + _lastStates = _currentStates; + } + + /** \return the number of keys currently activated. */ + int getNumActivated( void ) const { + int n=0; + for(int i=0; i _currentStates; ///< Current frame state. + std::array _lastStates; ///< Last frame state. + }; + + /** Maintain the complete state of user interactions (mouse, keyboard) for a given view or window. + All coordinates are recaled with respect to the associated view. + To check if the B key is currently held: + input.key().isActivated(Key::B); + To check if the right mouse was just released: + input.mouseButton().isReleased(Mouse::Right); + + \ingroup sibr_graphics + */ + class SIBR_GRAPHICS_EXPORT Input + { + public: + typedef InputState Keyboard; + typedef InputState MouseButton; + + public: + + /** \return the global system input (all others are derived from this one) */ + static Input& global( void ); + + /** Generate a new Input object based on a parent one and a viewport. Events (clicks) happening outside + the viewport will be ignored, mouse coordinates will be recentered with respect to the viewport. + \param global the parent input + \param viewport the viewport to retrict the input to + \param mouseOutsideDisablesKeyboard if set to true, keyboard inputs are ignored when the mouse is outside the viewport + \return the new restricted input + */ + static Input subInput(const sibr::Input & global, const sibr::Viewport & viewport, const bool mouseOutsideDisablesKeyboard = true); + + /** Is the mouse inside a given viewport. + \param viewport the viewport to test against + \return true if the mouse is inside. + */ + bool isInsideViewport(const sibr::Viewport & viewport) const; + + /** Update internal state based on GLFW, call once per frame. */ + static void poll( void ); + + /** \return the keyboard state. */ + const Keyboard& key( void ) const { + return _keyboard; + } + + /** \return the keyboard state. */ + Keyboard& key( void ) { + return _keyboard; + } + + /** \return the mouse buttons state. */ + const MouseButton& mouseButton( void ) const { + return _mouseButton; + } + + /** \return the mouse buttons state. */ + MouseButton& mouseButton( void ) { + return _mouseButton; + } + + /** \return the current mouse position */ + const Vector2i& mousePosition( void ) const { + return _mousePos; + } + + /** Set the current mouse position. + \param mousePos the new position + */ + void mousePosition( Vector2i mousePos ) { + _mousePos = mousePos; + } + + /** \return the change in mouse position since last frame. */ + Vector2i mouseDeltaPosition( void ) const { + return _mousePrevPos-_mousePos; + } + + /** If any number key is pressed, return the lowest one. + \return the smallest pressed number, or -1 if none is pressed. + */ + int pressedNumber() const { + static const std::vector keys = { + Key::Num0, Key::Num1, Key::Num2, Key::Num3, Key::Num4, + Key::Num5, Key::Num6, Key::Num7, Key::Num8, Key::Num9 + }; + + for (int i = 0; i < 10; ++i){ + if (_keyboard.isPressed(keys[i]) ){ + return i; + } + } + return -1; + } + + /** Update last frame state with the current one. Call at the end of each frame. */ + void swapStates( void ) { + key().swapStates(); + mouseButton().swapStates(); + _mousePrevPos = _mousePos; + _mouseScroll = 0.0; + } + + /** \return the scroll amount along the vertical axis. */ + double mouseScroll( void ) const { + return _mouseScroll; + } + + /** Set the scroll amount. + \param v the scroll amount. + */ + void mouseScroll(double v) { + _mouseScroll = v; + } + + /** \return true if the input is associated to an empty view/window. */ + bool empty() const { + return _empty; + } + + private: + + Keyboard _keyboard; ///< Keyboard state. + MouseButton _mouseButton; ///< Mouse state. + + Vector2i _mousePos = {0, 0}; ///< Current mouse position. + Vector2i _mousePrevPos = { 0, 0 }; ///< Previous mouse position. + double _mouseScroll = 0.0; ///< Current scroll amount. + bool _empty = true; ///< Is the input associated to an empty view/window. + + }; + + ///// DEFINITIONS ///// + + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/MaterialMesh.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/MaterialMesh.cpp new file mode 100755 index 0000000000000000000000000000000000000000..c0d147d9de5df8dc2c072bcdee2cd0d713ed93e7 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/MaterialMesh.cpp @@ -0,0 +1,1746 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include +#include +#include +#include + +#include // C++ importer interface +#include // Output data structure +#include // Post processing flags +#include +#include + +#include "core/system/ByteStream.hpp" +#include "core/graphics/MaterialMesh.hpp" +#include "core/system/Transform3.hpp" +#include "boost/filesystem.hpp" +#include "core/system/XMLTree.h" +#include "core/system/Matrix.hpp" +#include +#include + +namespace sibr +{ + bool MaterialMesh::load(const std::string& filename) + { + + srand(static_cast (time(0))); + Assimp::Importer importer; + importer.SetPropertyBool(AI_CONFIG_PP_FD_REMOVE, true); + // cause Assimp to remove all degenerated faces as soon as they are detected + const aiScene* scene = importer.ReadFile(filename, + aiProcess_Triangulate | aiProcess_JoinIdenticalVertices | + aiProcess_FindDegenerates); + + if (!scene) + { + SIBR_WRG << "error: can't load mesh '" << filename + << "' (" << importer.GetErrorString() << ")." << std::endl; + return false; + } + + if (scene->mNumMeshes == 0) + { + SIBR_WRG << "error: the loaded model file ('" << filename + << "') contains zero or more than one mesh. Number of meshes : " << + scene->mNumMeshes << std::endl; + return false; + } + + auto convertVec = [](const aiVector3D& v) { + return Vector3f(v.x, v.y, v.z); }; + _triangles.clear(); + + uint offsetVertices = 0; + uint offsetFaces = 0; + uint matId = 0; // Material + std::map matName2Id; // Material + + _maxMeshId = size_t(int(scene->mNumMeshes) - 1); + + SIBR_LOG << "Mesh with " << scene->mNumMeshes << " elements." << std::endl; + for (uint meshId = 0; meshId < scene->mNumMeshes; ++meshId) { + const aiMesh* mesh = scene->mMeshes[meshId]; + + _vertices.resize(offsetVertices + mesh->mNumVertices); + _meshIds.resize(offsetVertices + mesh->mNumVertices); + for (uint i = 0; i < mesh->mNumVertices; ++i) { + _vertices[offsetVertices + i] = convertVec(mesh->mVertices[i]); + _meshIds[offsetVertices + i] = meshId; + } + + if (mesh->HasVertexColors(0) && mesh->mColors[0]) + { + _colors.resize(offsetVertices + mesh->mNumVertices); + for (uint i = 0; i < mesh->mNumVertices; ++i) + { + _colors[offsetVertices + i] = Vector3f( + mesh->mColors[0][i].r, + mesh->mColors[0][i].g, + mesh->mColors[0][i].b); + } + } + + if (mesh->HasVertexColors(0) && mesh->mColors[0]) + { + _colors.resize(offsetVertices + mesh->mNumVertices); + for (uint i = 0; i < mesh->mNumVertices; ++i) + { + _colors[offsetVertices + i] = Vector3f( + mesh->mColors[0][i].r, + mesh->mColors[0][i].g, + mesh->mColors[0][i].b); + } + } + + if (mesh->HasNormals()) + { + _normals.resize(offsetVertices + mesh->mNumVertices); + for (uint i = 0; i < mesh->mNumVertices; ++i) { + _normals[offsetVertices + i] = convertVec(mesh->mNormals[i]); + } + + } + + bool randomUV = true; + + if (mesh->HasTextureCoords(0)) + { + _texcoords.resize(offsetVertices + mesh->mNumVertices); + for (uint i = 0; i < mesh->mNumVertices; ++i) { + _texcoords[offsetVertices + i] = + convertVec(mesh->mTextureCoords[0][i]).xy(); + if (convertVec(mesh->mTextureCoords[0][i]).xy().x() != 0.f || + convertVec(mesh->mTextureCoords[0][i]).xy().y() != 0.f) + { + randomUV = false; + } + } + + } + + if (randomUV) { + SIBR_LOG << "using random UVs." << std::endl; + _texcoords.resize(offsetVertices + mesh->mNumVertices); + for (uint i = 0; i < mesh->mNumVertices; ++i) { + float u = static_cast(rand()) / static_cast(RAND_MAX); + float v = static_cast(rand()) / static_cast(RAND_MAX); + _texcoords[offsetVertices + i] = + Vector2f(u * 5.f, v * 5.f); + } + } + + + if (meshId == 0) { + SIBR_LOG << "Mesh contains: colors: " << mesh->HasVertexColors(0) + << ", normals: " << mesh->HasNormals() + << ", texcoords: " << mesh->HasTextureCoords(0) << std::endl; + } + + //----------------------------- FULL MATERIAL ------------------------ + uint currentMatId = matId; + aiString aiMatName; + + if (AI_SUCCESS != scene->mMaterials[mesh->mMaterialIndex]-> + Get(AI_MATKEY_NAME, aiMatName)) { + SIBR_LOG << "material not found " << mesh->mMaterialIndex + << std::endl; + } + + std::string matName = aiMatName.C_Str(); + + if (matName2Id.find(matName) == matName2Id.end()) { + + matName2Id[matName] = matId; + _matId2Name.push_back(matName); + + matId++; + } + else { + currentMatId = matName2Id[matName]; + } + + //-------------------------- END FULL MATERIAL --------------------- + + _triangles.reserve(offsetFaces + mesh->mNumFaces); + _matIds.reserve(offsetFaces + mesh->mNumFaces); //material + _matIdsVertices.resize(_vertices.size()); + for (uint i = 0; i < mesh->mNumFaces; ++i) + { + const aiFace* f = &mesh->mFaces[i]; + if (f->mNumIndices != 3) + SIBR_WRG << "Discarding a face (not a triangle, num indices: " + << f->mNumIndices << ")" << std::endl; + else + { + Vector3u tri = Vector3u(offsetVertices + f->mIndices[0], offsetVertices + f->mIndices[1], offsetVertices + f->mIndices[2]); + if (tri[0] < 0 || tri[0] >= _vertices.size() + || tri[1] < 0 || tri[1] >= _vertices.size() + || tri[2] < 0 || tri[2] >= _vertices.size()) + SIBR_WRG << "Face num [" << i << "] contains invalid vertex id(s)" << std::endl; + else { + _triangles.push_back(tri); + _matIds.push_back(currentMatId); //material + + } + + } + } + + offsetFaces = (uint)_triangles.size(); + offsetVertices = (uint)_vertices.size(); + + } + + SIBR_LOG << "Mesh '" << filename << " successfully loaded. " << scene->mNumMeshes << " meshes were loaded with a total of " + << " (" << _triangles.size() << ") faces and " + << " (" << _vertices.size() << ") vertices detected." << std::endl; + SIBR_LOG << "Init material part complete." << std::endl; + + _gl.dirtyBufferGL = true; + return true; + } + + sibr::Matrix4f parseTransform(const rapidxml::xml_node<>* nodeTrans) + { + sibr::Matrix4f objectToWorld = sibr::Matrix4f::Identity(); + if (nodeTrans) + { + // Helper functions + const auto getfValue = [&](rapidxml::xml_node<>* n, std::string const& name, float& value) { + if (n && n->first_attribute(name.c_str())) { + value = std::stof(n->first_attribute(name.c_str())->value()); + } + }; + const auto getVector = [&](rapidxml::xml_node<>* n, std::string const& name, sibr::Vector3f& vec) { + const auto isNonFloat = [](const char c) { + return c == ',' || c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '"' || c == 0; + }; + const auto eatNonFloat = [&](const char* str, int& i) { + while (isNonFloat(str[i])) ++i; + }; + const auto eatFloat = [&](const char* str, int& i) { + while (!isNonFloat(str[i])) ++i; + }; + if (n && n->first_attribute(name.c_str())) { + int index = 0; + const char* value = n->first_attribute(name.c_str())->value(); + for (int i = 0; i < vec.size(); ++i) { + eatNonFloat(value, index); + vec[i] = std::atof(value + index); + eatFloat(value, index); + } + } + }; + const auto getAxesValues = [&](rapidxml::xml_node<>* n, float& x, float& y, float& z) { + getfValue(n, "x", x); + getfValue(n, "y", y); + getfValue(n, "z", z); + }; + + // Loop through all the transform commands, + // and "accumulate" the transform matrices into "objectToWorld" + for (rapidxml::xml_node<>* node = nodeTrans->first_node(); node; node = node->next_sibling()) { + sibr::Matrix4f nodeMatrix = sibr::Matrix4f::Identity(); + const char* transformType = node->name(); + if (strcmp(transformType, "matrix") == 0) { + std::string matrixValue = node->first_attribute("value")->value(); + std::istringstream issMatrix(matrixValue); + std::vector split( + std::istream_iterator{issMatrix}, + std::istream_iterator()); + nodeMatrix << + std::stof(split[0]), std::stof(split[1]), std::stof(split[2]), std::stof(split[3]), + std::stof(split[4]), std::stof(split[5]), std::stof(split[6]), std::stof(split[7]), + std::stof(split[8]), std::stof(split[9]), std::stof(split[10]), std::stof(split[11]), + std::stof(split[12]), std::stof(split[13]), std::stof(split[14]), std::stof(split[15]); + } + else if (strcmp(transformType, "translate") == 0) { + getAxesValues(node, nodeMatrix(0, 3), nodeMatrix(1, 3), nodeMatrix(2, 3)); + } + else if (strcmp(transformType, "scale") == 0) { + float scale = 1.f; + getfValue(node, "value", scale); + getAxesValues(node, nodeMatrix(0, 0), nodeMatrix(1, 1), nodeMatrix(2, 2)); + nodeMatrix(0, 0) *= scale; + nodeMatrix(1, 1) *= scale; + nodeMatrix(2, 2) *= scale; + } + else if (strcmp(transformType, "rotate") == 0) { + float rotateX = 0.f, rotateY = 0.f, rotateZ = 0.f; + float angleDegrees = 0.f; + getAxesValues(node, rotateX, rotateY, rotateZ); + getfValue(node, "angle", angleDegrees); + float angleRadians = angleDegrees * (float)M_PI / 180.f; + sibr::Transform3 transform; + transform.rotate(Eigen::Quaternionf( + Eigen::AngleAxisf(angleRadians, + Eigen::Vector3f(rotateX, rotateY, rotateZ)))); + nodeMatrix = transform.matrix(); + } + else if (strcmp(transformType, "lookat") == 0) { + sibr::Vector3f eye{ 0, 0, 0 }, target{ 0, 0, 1 }, up{ 0, 1, 0 }; + getVector(node, "origin", eye); + getVector(node, "target", target); + getVector(node, "up", up); + // WTF why inverse the lookat??? + nodeMatrix = sibr::lookAt(eye, target, up).inverse(); + } + else { + throw std::runtime_error(std::string("Mitsuba xml parser: Unknown tranform type: ") + transformType); + } + objectToWorld = nodeMatrix * objectToWorld; + } + } + return objectToWorld; + } + + // Extracts Name from (can accept node == nullptr) + // + std::string parseMatID(const rapidxml::xml_node<>* node) + { + std::string res; + if (node) + { + const rapidxml::xml_attribute<>* id = node->first_attribute("id"); + res = id->value(); + } + return res; + } + + bool shouldFlipNormals(const rapidxml::xml_node<>* shape) + { + assert(shape != nullptr); + for (const rapidxml::xml_node<>* node = shape->first_node("boolean"); node; node = node->next_sibling("boolean")) + { + if (node->first_attribute("name")->value() == std::string("flipNormals")) + { + return node->first_attribute("value")->value() == std::string("true"); + } + } + return false; + } + + std::string parseFilename(const rapidxml::xml_node<>* shape) + { + assert(shape); + for (const rapidxml::xml_node<>* node = shape->first_node("string"); node; node = node->next_sibling("string")) + { + if (node->first_attribute("name")->value() == std::string("filename")) + { + return node->first_attribute("value")->value(); + } + } + return ""; + } + + bool MaterialMesh::loadMtsXML(const std::string& xmlFile, bool loadTextures) + { + srand(static_cast (time(0))); + bool allLoaded = true; + std::string pathFolder = boost::filesystem::path(xmlFile).parent_path() + .string(); + sibr::XMLTree doc(xmlFile); + std::map meshes; + + struct ShapeGroup { + struct Shape + { + std::string filename; + std::string matname; + sibr::Matrix4f toWorld = sibr::Matrix4f::Identity(); + Shape& operator=(Shape const&) = default; + bool flipNormals = false; + }; + std::vector shapes; + sibr::Matrix4f objectToWorld = sibr::Matrix4f::Identity(); + }; + + std::map idToShapegroups; + + rapidxml::xml_node<> *nodeScene = doc.first_node("scene"); + + // First parse all the shapegroups + for (rapidxml::xml_node<> *node = nodeScene->first_node("shape"); + node; node = node->next_sibling("shape")) + { + if (strcmp(node->first_attribute()->name(), "type") == 0 && + strcmp(node->first_attribute()->value(), "shapegroup") == 0) { + + //std::cout << "Found : " << node->first_attribute("id")->value() << std::endl; + + std::string id = node->first_attribute("id")->value(); + ShapeGroup shapeGroup; + for (rapidxml::xml_node<>* shapeNode = node->first_node("shape");shapeNode;shapeNode=shapeNode->next_sibling()) + { + ShapeGroup::Shape shape; + shape.filename = parseFilename(shapeNode); + shape.toWorld = parseTransform(shapeNode->first_node("transform")); + shape.matname = parseMatID(shapeNode->first_node("ref")); + shape.flipNormals = shouldFlipNormals(shapeNode); + shapeGroup.shapes.push_back(shape); + } + rapidxml::xml_node<>* tNode = node->first_node("transform"); + shapeGroup.objectToWorld = parseTransform(tNode); + idToShapegroups[id] = shapeGroup; + } + } + // Second: Create all the actual shapes + for (rapidxml::xml_node<> *node = nodeScene->first_node("shape"); + node; node = node->next_sibling("shape")) + { + for (rapidxml::xml_attribute<> *browserAttributes = node-> + first_attribute(); + browserAttributes; + browserAttributes = browserAttributes->next_attribute()) { + // Create the instances of the shapegroups + if (strcmp(browserAttributes->name(), "type") == 0 && + strcmp(browserAttributes->value(), "instance") == 0 + ) { + rapidxml::xml_node<>* nodeRef = node->first_node("ref"); + const std::string _id = nodeRef->first_attribute("id")->value(); + SIBR_LOG << "Instancing " << _id << std::endl; + if (idToShapegroups.find(_id) == idToShapegroups.end()) + { + SIBR_WRG << "Could not find shapegroup " << _id << "!!!" << std::endl; + continue; + } + const ShapeGroup& shapeGroup = idToShapegroups[_id]; + rapidxml::xml_node<>* nodeTrans = node->first_node("transform"); + // I am not 100% sure of the order of the matrices + sibr::Matrix4f objectToWorld = shapeGroup.objectToWorld * parseTransform(nodeTrans); + sibr::MaterialMesh instance; + for (const auto& shape : shapeGroup.shapes) + { + std::cout << shape.filename; + const std::string meshPath = pathFolder + "/" + shape.filename; + + if (meshes.find(meshPath) == meshes.end()) + { + meshes[meshPath] = MaterialMesh(); + meshes[meshPath].load(meshPath); + } + + sibr::MaterialMesh toWorldMesh = meshes[meshPath]; + + if (shape.flipNormals && toWorldMesh.hasNormals()) + { + const auto& refNormals = toWorldMesh.normals(); + sibr::Mesh::Normals normals(refNormals.size()); + for (int nid = 0; nid < refNormals.size(); ++nid) + { + normals[nid] = -refNormals[nid]; + } + toWorldMesh.normals(normals); + } + // Convert to world coordinates + sibr::Matrix4f matrix = shape.toWorld * objectToWorld; + { + sibr::MaterialMesh::Vertices vertices(toWorldMesh.vertices().size()); + for (int v = 0; v < toWorldMesh.vertices().size(); v++) { + sibr::Vector4f v4(toWorldMesh.vertices()[v].x(), + toWorldMesh.vertices()[v].y(), + toWorldMesh.vertices()[v].z(), 1.0); + vertices[v] = (matrix* v4).xyz(); + } + + toWorldMesh.vertices(vertices); + } + + // If the mesh has normals, we should transform them also. + if (toWorldMesh.hasNormals()) { + sibr::Mesh::Normals normals(toWorldMesh.normals().size()); + const sibr::Matrix3f normalTMatrix = matrix.block(0, 0, 3, 3).inverse().transpose(); + for (int v = 0; v < toWorldMesh.normals().size(); v++) { + const sibr::Vector3f& ln = toWorldMesh.normals()[v]; + normals[v] = (normalTMatrix * ln).xyz(); + } + toWorldMesh.normals(normals); + } + + if (!shape.matname.empty()) + { + toWorldMesh.matId2Name({ shape.matname }); + } + + instance.merge(toWorldMesh); + } + merge(instance); + } + // Create the "unique" shapes + else if (strcmp(browserAttributes->name(), "type") == 0 && + (strcmp(browserAttributes->value(), "obj") == 0 || + strcmp(browserAttributes->value(), "ply") == 0)) { + + rapidxml::xml_node<> *nodeRef = node->first_node("string"); + const std::string filename = nodeRef->first_attribute("value") + ->value(); + const std::string meshPath = pathFolder + "/" + filename; + // Search for any normal options: + rapidxml::xml_node<> *nodeOpt = node->first_node("boolean"); + bool flipNormals = false; + while (nodeOpt) { + const std::string name = nodeOpt->first_attribute("name")->value(); + const std::string value = nodeOpt->first_attribute("value")->value(); + if (name == "flipNormals" && value == "true") { + flipNormals = true; + } + nodeOpt = nodeOpt->next_sibling("boolean"); + } + + + if (meshes.find(filename) == meshes.end()) { + meshes[filename] = sibr::MaterialMesh(); + if (!meshes[filename].load(meshPath)) { + return false; + } + if (meshes[filename].matIds().empty()) + { + SIBR_WRG << "Material (" << filename << ") not present ..." << std::endl; + } + + } + + SIBR_LOG << "Adding one instance of: " << filename + << std::endl; + + rapidxml::xml_node<> *nodeRefMat = node->first_node("ref"); + if (nodeRefMat) { + const std::string matName = nodeRefMat + ->first_attribute("id")->value(); + + MatId2Name newmatIdtoName; + newmatIdtoName.push_back(matName); + meshes[filename].matId2Name(newmatIdtoName); + } + + rapidxml::xml_node<> *nodeTrans = node + ->first_node("transform"); + + sibr::Matrix4f objectToWorld = parseTransform(nodeTrans); + + sibr::MaterialMesh toWorldMesh = meshes[filename]; + + // Apply normals transformation if needed. + if (flipNormals && toWorldMesh.hasNormals()) { + const auto & refNormals = toWorldMesh.normals(); + sibr::Mesh::Normals normals(refNormals.size()); + for (int nid = 0; nid < refNormals.size(); nid++) { + normals[nid] = -refNormals[nid]; + } + toWorldMesh.normals(normals); + } + + if (nodeTrans) { + // Transform the vertices position + { + sibr::Mesh::Vertices vertices(toWorldMesh.vertices().size()); + for (int v = 0; v < toWorldMesh.vertices().size(); v++) { + sibr::Vector4f v4(toWorldMesh.vertices()[v].x(), + toWorldMesh.vertices()[v].y(), + toWorldMesh.vertices()[v].z(), 1.0); + vertices[v] = (objectToWorld*v4).xyz(); + + } + toWorldMesh.vertices(vertices); + } + + // Transform the normals too + if (toWorldMesh.hasNormals()) { + sibr::Mesh::Normals normals(toWorldMesh.normals().size()); + const sibr::Matrix3f normalTMatrix = objectToWorld.block(0, 0, 3, 3).inverse().transpose(); + for (int v = 0; v < toWorldMesh.normals().size(); v++) { + const sibr::Vector3f& ln = toWorldMesh.normals()[v]; + normals[v] = (normalTMatrix * ln); + } + toWorldMesh.normals(normals); + } + } + + merge(toWorldMesh); + } + } + } + + SIBR_LOG << "Loaded mesh: " << vertices().size() << " verts, " << meshIds().size() << " ids." << std::endl; + // Load all the materials + for (rapidxml::xml_node<> *node = nodeScene->first_node("bsdf"); + node; node = node->next_sibling("bsdf")) + { + //getting id + rapidxml::xml_attribute<> *attribute = node->first_attribute("id"); + if (attribute != nullptr) { + + std::string nameMat = attribute->value(); + + + // Check if a texture exists in our node with diffuse reflectance + // If none is found, explore each BRDF until found. + std::vector *> queue; + queue.push_back(node); + + bool breakBool = false; + + while (!queue.empty()) { + + + //Texture Case + for (rapidxml::xml_node<> *nodeTexture = + queue.front()->first_node("texture"); + nodeTexture; + nodeTexture = nodeTexture->next_sibling("texture")) { + + if (strcmp(nodeTexture->first_attribute("name")->value(), + "diffuseReflectance") == 0 || + strcmp(nodeTexture->first_attribute("name")->value(), + "reflectance") == 0 || + strcmp(nodeTexture->first_attribute("name")->value(), + "specularReflectance") == 0 + ) + { + //std::cout << "DiffuseReflectance Texture found" << std::endl; + rapidxml::xml_node<> *firstTexture = nodeTexture-> + first_node("texture"); + if (firstTexture == nullptr) { + firstTexture = nodeTexture; + } + for (rapidxml::xml_node<> *nodeString = firstTexture-> + first_node("string"); + nodeString; + nodeString = nodeString->next_sibling("string")) + { + std::string textureName = + nodeString->first_attribute("value")->value(); + sibr::ImageRGBA::Ptr texture(new sibr::ImageRGBA()); + // If we skip loading the textures, still set them as empty images. + if (!loadTextures || texture->load(pathFolder + "/" + textureName)) { + /*std::cout << "Diffuse " << pathFolder + "/" + + textureName << std::endl;*/ + _diffuseMaps[nameMat] = texture; + breakBool = true; + break; + } + else { + SIBR_ERR << "Diffuse layer for: " << + nameMat << " not found" << std::endl; + } + + } + if (breakBool) + break; + } + } + + + //Color case + + if (!breakBool) { + std::list colorsFormatList; + colorsFormatList.push_back("rgb"); + colorsFormatList.push_back("srgb"); + for (std::string colorsFormat : colorsFormatList) + for (rapidxml::xml_node<> *nodeTexture = + queue.front()->first_node(colorsFormat.c_str()); + nodeTexture; + nodeTexture = nodeTexture->next_sibling( + colorsFormat.c_str())) { + + if (strcmp(nodeTexture->first_attribute("name")->value(), + "diffuseReflectance") == 0 || + strcmp(nodeTexture->first_attribute("name")->value(), + "reflectance") == 0 || + strcmp(nodeTexture->first_attribute("name")->value(), + "specularReflectance") == 0 + ) + { + /*std::cout << "DiffuseReflectance Color found" + << std::endl;*/ + rapidxml::xml_node<> *firstTexture = nodeTexture-> + first_node(colorsFormat.c_str()); + if (firstTexture == nullptr) { + firstTexture = nodeTexture; + } + std::string colorString = + nodeTexture->first_attribute("value")->value(); + sibr::Vector3f colorMaterial; + float redComponent, greenComponent, blueComponent; +#ifdef SIBR_OS_WINDOWS + sscanf_s(colorString.c_str(), "%f, %f, %f", + &redComponent, &greenComponent, &blueComponent); +#else + sscanf(colorString.c_str(), "%f, %f, %f", + &redComponent, &greenComponent, &blueComponent); +#endif + const sibr::ImageRGBA::Pixel color( + static_cast(redComponent * 255), + static_cast(greenComponent * 255), + static_cast(blueComponent * 255), + 255); + sibr::ImageRGBA::Ptr texture(new sibr::ImageRGBA( + 1, 1, color)); + if (texture) { + /*std::cout << "Diffuse color : " << + redComponent << ", " << blueComponent << + ", " << greenComponent << ", " << std::endl;*/ + _diffuseMaps[nameMat] = texture; + _tagsCoveringMaps[nameMat] = nullptr; + + breakBool = true; + break; + } + else { + SIBR_ERR << "Diffuse layer for: " << nameMat + << " not found" << std::endl; + } + + if (breakBool) + break; + } + } + } + + queue.erase(queue.begin()); + + for (rapidxml::xml_node<> *node = queue.front()-> + first_node("bsdf"); + node; node = node->next_sibling("bsdf")) + { + queue.push_back(node); + } + + } + if (_diffuseMaps[nameMat].get() == nullptr) { + + float r = static_cast(rand()) / static_cast(RAND_MAX); + float g = static_cast(rand()) / static_cast(RAND_MAX); + float b = static_cast(rand()) / static_cast(RAND_MAX); + + const sibr::ImageRGBA::Pixel color( + static_cast(r * 255), + static_cast(g * 255), + static_cast(b * 255), + static_cast (255) + ); + sibr::ImageRGBA::Ptr texture(new sibr::ImageRGBA( + 1, 1, color)); + SIBR_WRG << "Warning: No color and no texture found for " << nameMat << ", " << + "material will be chosen randomly." << std::endl; + _diffuseMaps[nameMat] = texture; + + _tagsCoveringMaps[nameMat] = nullptr; + /*if (_hasTagsCoveringFile) { + _tagsCoveringMaps[nameMat] = _listCoveringImagesTags.at( + _tagsCoveringMaps.size() % _listCoveringImagesTags.size()); + }*/ + } + + + + } + } + + bool breakBool = false; + for (rapidxml::xml_node<> *node = nodeScene->first_node("bsdf"); + node; node = node->next_sibling("bsdf")) + { + if (node != nullptr && node->first_attribute("id") != nullptr) + { + std::string nameMat = node->first_attribute("id")->value(); + + bool breakBool = false; + for (rapidxml::xml_node<> *nodeTexture = node-> + first_node("texture"); + nodeTexture; nodeTexture = nodeTexture-> + next_sibling("texture")) { + + if (strcmp(nodeTexture->first_attribute("name")->value(), + "opacity") == 0 && + nodeTexture->first_attribute("type") && + strcmp(nodeTexture->first_attribute("type")->value(), + "scale") == 0) { + //std::cout << "Found opacity mask:" << nameMat << std::endl; + + for (rapidxml::xml_node<> *nodeString = nodeTexture-> + first_node("texture")->first_node("string"); + nodeString; nodeString = nodeString-> + next_sibling("string")) + { + std::string textureName = nodeString-> + first_attribute("value")->value(); + sibr::ImageRGB::Ptr texture(new sibr::ImageRGB()); + if (!loadTextures || texture->load(pathFolder + "/" + textureName)) { + _opacityMaps[nameMat] = texture; + breakBool = true; + break; + } + else { + SIBR_ERR << "Opacity layer for: " << + nameMat << " not found" << std::endl; + } + + + } + if (breakBool) + break; + } + + } + if (!breakBool) { + const sibr::ImageRGB::Pixel color(255, 255, 255); + sibr::ImageRGB::Ptr texture(new sibr::ImageRGB(1, 1, color)); + _opacityMaps[nameMat] = texture; + + } + } + } + + createSubMeshes(); + return true; + + } + + void MaterialMesh::loadCoveringTagsTexture( + const std::vector& listFilesTags) { + + for (const std::string filename : listFilesTags) { + + sibr::ImageRGB::Ptr textureTag(new sibr::ImageRGB()); + if (textureTag->load(filename)) { + _listCoveringImagesTags.push_back(textureTag); + } + else { + SIBR_ERR << "Diffuse layer for: " << + filename << " not found" << std::endl; + } + } + if (_listCoveringImagesTags.size() > 0) + _hasTagsCoveringFile = true; + + if (_hasTagsCoveringFile) { + unsigned int counter = 0; + for (auto it = matId2Name().begin(); it != matId2Name().end(); ++it) { + if (_tagsCoveringMaps.find(*it) != _tagsCoveringMaps.end()) { + _tagsCoveringMaps[*it] = _listCoveringImagesTags.at( + counter % _listCoveringImagesTags.size()); + counter++; + } + } + } + + } + + void MaterialMesh::fillColorsWithIndexMaterials(void) + { + sibr::Mesh::Colors colorsIdsMaterials(vertices().size()); + + sibr::Mesh::Colors randomsColors; + + srand(static_cast (time(0))); + for (std::string material : _matId2Name) { + float r = static_cast(rand()) / static_cast(RAND_MAX); + float g = static_cast(rand()) / static_cast(RAND_MAX); + float b = static_cast(rand()) / static_cast(RAND_MAX); + + randomsColors.push_back(sibr::Vector3f(r, g, b)); + } + + for (unsigned int i = 0; i < _matIds.size(); i++) + { + colorsIdsMaterials.at(_triangles.at(i)[0]) = randomsColors.at( + _matIds.at(i)); + colorsIdsMaterials.at(_triangles.at(i)[1]) = randomsColors.at + (_matIds.at(i)); + colorsIdsMaterials.at(_triangles.at(i)[2]) = randomsColors.at + (_matIds.at(i)); + } + + colors(colorsIdsMaterials); + } + + + void MaterialMesh::fillColorsWithMatIds() + { + sibr::Mesh::Colors colorsIdsMaterials(vertices().size()); + + for (unsigned int i = 0; i < _matIds.size(); i++) + { + const uint matId = uint(_matIds.at(i) + 1); + const sibr::Vector3u col = { uchar(matId & 0xff), uchar((matId >> 8) & 0xff) , uchar((matId >> 16) & 0xff) }; + const sibr::Vector3f finalCol = col.cast() / 255.0f; + colorsIdsMaterials.at(_triangles.at(i)[0]) = finalCol; + colorsIdsMaterials.at(_triangles.at(i)[1]) = finalCol; + colorsIdsMaterials.at(_triangles.at(i)[2]) = finalCol; + } + + colors(colorsIdsMaterials); + } + + Mesh MaterialMesh::generateSubMaterialMesh(int material) const + { + + sibr::Mesh::Vertices newVertices; + sibr::Mesh::Triangles newTriangles; + + sibr::Mesh::Colors newColors; + sibr::Mesh::Normals newNormals; + sibr::Mesh::UVs newTexCoords; + + std::map mapIdVert; + + int cmptValidVert = 0; + int cmptVert = 0; + + sibr::Mesh::Colors oldColors; + if (hasColors()) + oldColors = colors(); + + sibr::Mesh::Normals oldNormals; + if (hasNormals()) + oldNormals = normals(); + + sibr::Mesh::UVs oldTexCoords; + if (hasTexCoords()) + oldTexCoords = texCoords(); + + for (int i = 0; i < matIds().size(); i++) + { + if (matIds().at(i) == material) { + + uint v1, v2, v3; + v1 = triangles().at(i)[0]; + v2 = triangles().at(i)[1]; + v3 = triangles().at(i)[2]; + + auto search = mapIdVert.find(v1); + if (search == mapIdVert.end()) { + newVertices.push_back(vertices()[v1]); + if (hasColors()) { + newColors.push_back(oldColors[v1]); + } + if (hasNormals()) { + newNormals.push_back(oldNormals[v1]); + } + if (hasTexCoords()) { + newTexCoords.push_back(oldTexCoords[v1]); + } + mapIdVert[v1] = cmptValidVert; + cmptValidVert++; + } + + search = mapIdVert.find(v2); + if (search == mapIdVert.end()) { + newVertices.push_back(vertices()[v2]); + if (hasColors()) { + newColors.push_back(oldColors[v2]); + } + if (hasNormals()) { + newNormals.push_back(oldNormals[v2]); + } + if (hasTexCoords()) { + newTexCoords.push_back(oldTexCoords[v2]); + } + mapIdVert[v2] = cmptValidVert; + cmptValidVert++; + } + + search = mapIdVert.find(v3); + if (search == mapIdVert.end()) { + newVertices.push_back(vertices()[v3]); + if (hasColors()) { + newColors.push_back(oldColors[v3]); + } + if (hasNormals()) { + newNormals.push_back(oldNormals[v3]); + } + if (hasTexCoords()) { + newTexCoords.push_back(oldTexCoords[v3]); + } + mapIdVert[v3] = cmptValidVert; + cmptValidVert++; + } + newTriangles.push_back(sibr::Vector3u(mapIdVert[v1], mapIdVert[v2] + , mapIdVert[v3])); + + } + } + + Mesh newMesh; + newMesh.vertices(newVertices); + newMesh.triangles(newTriangles); + if (hasColors()) + newMesh.colors(newColors); + if (hasNormals()) + newMesh.normals(newNormals); + if (hasTexCoords()) + newMesh.texCoords(newTexCoords); + + return newMesh; + } + + void MaterialMesh::forceBufferGLUpdate(void) const + { + if (!_gl.bufferGL) { SIBR_ERR << "Tried to forceBufferGL on a non OpenGL Mesh" << std::endl; return; } + _gl.dirtyBufferGL = false; + _gl.bufferGL->build(*this); + } + + void MaterialMesh::freeBufferGLUpdate(void) const + { + _gl.dirtyBufferGL = false; + _gl.bufferGL->free(); + } + + void MaterialMesh::subdivideMesh2(float threshold) { + + auto areaHeronsFormula = [](sibr::Vector3f A, sibr::Vector3f B, + sibr::Vector3f C) -> float { + float a = distance(A, B); + float b = distance(B, C); + float c = distance(C, A); + return sqrtf((a + (b + c))*(c - (a - b))*(c + (a - b))* + (a + (b - c))) / 4.f; + }; + + bool mustChange = true; + while (mustChange) { + mustChange = false; + sibr::Mesh::Colors newColors(colors()); + sibr::Mesh::Normals newNormals(normals()); + sibr::Mesh::UVs newTexCoords(texCoords()); + sibr::Mesh::Vertices newVertices(vertices()); + sibr::MaterialMesh::MeshIds newMeshIds(meshIds()); + + sibr::Mesh::Triangles newTriangles; + sibr::MaterialMesh::MatIds newMatIds; + std::cout << triangles().size() << " triangles" << std::endl; + for (unsigned int i = 0; i < triangles().size(); i++) { + sibr::Vector3u t = triangles().at(i); + + int tMatId; + if (i < matIds().size()) + tMatId = matIds().at(i); + + sibr::Vector3f a = vertices().at(t.x()); + sibr::Vector3f b = vertices().at(t.y()); + sibr::Vector3f c = vertices().at(t.z()); + + if (areaHeronsFormula(a, b, c) >= (_averageArea*threshold)) { + mustChange = true; + + sibr::Vector3f aColor, bColor, cColor, aNormal, bNormal, cNormal; + sibr::Vector2f aTexCoords, bTexCoords, cTexCoords; + + sibr::Vector3f newColor, newNormal; + sibr::Vector2f newTexCoord; + sibr::Vector3f newVertex; + + if (hasColors()) { + newColor = (colors().at(t.x()) + colors().at(t.y()) + + colors().at(t.z())) / 3.f; + } + + if (hasNormals()) { + newNormal = (normals().at(t.x()) + normals().at(t.y()) + + normals().at(t.z())) / 3.f; + } + + if (hasTexCoords()) { + newTexCoord = (texCoords().at(t.x()) + texCoords().at(t.y()) + + texCoords().at(t.z())) / 3.f; + } + + + newVertex = (vertices().at(t.x()) + vertices().at(t.y()) + + vertices().at(t.z())) / 3.f; + + newVertices.push_back(newVertex); + + if (hasColors()) { + newColors.push_back(newColor); + } + + if (hasNormals()) { + newNormals.push_back(newNormal); + } + + if (hasTexCoords()) { + newTexCoords.push_back(newTexCoord); + } + + if (hasMeshIds()) { + // Pick the first referenced vertex as the provoking vertex. + newMeshIds.push_back(meshIds().at(t.x())); + } + + int newIndexVertex = static_cast (newVertices.size()) - 1; + newTriangles.push_back(sibr::Vector3u(t.x(), + t.y(), + newIndexVertex)); + newTriangles.push_back(sibr::Vector3u(t.y(), + t.z(), + newIndexVertex)); + newTriangles.push_back(sibr::Vector3u(t.z(), + t.x(), + newIndexVertex)); + if (i < matIds().size()) { + for (unsigned int n = 0; n < 3; ++n) + newMatIds.push_back(tMatId); + } + } + else { + newTriangles.push_back(t); + if (i < matIds().size()) + newMatIds.push_back(tMatId); + } + } + vertices(newVertices); + colors(newColors); + normals(newNormals); + texCoords(newTexCoords); + triangles(newTriangles); + matIds(newMatIds); + meshIds(newMeshIds); + } + } + + void MaterialMesh::subdivideMesh(float threshold) { + + bool mustChange = true; + while (mustChange) { + mustChange = false; + sibr::Mesh::Colors newColors(colors()); + sibr::Mesh::Normals newNormals(normals()); + sibr::Mesh::UVs newTexCoords(texCoords()); + sibr::Mesh::Vertices newVertices(vertices()); + sibr::MaterialMesh::MeshIds newMeshIds(meshIds()); + + sibr::Mesh::Triangles newTriangles; + sibr::MaterialMesh::MatIds newMatIds; + + + std::cout << triangles().size() << " triangles" << std::endl; + + for (unsigned int i = 0; i < triangles().size(); i++) { + sibr::Vector3u t = triangles().at(i); + + int tMatId; + if (i < matIds().size()) + tMatId = matIds().at(i); + + sibr::Vector3f a = vertices().at(t.x()); + sibr::Vector3f b = vertices().at(t.y()); + sibr::Vector3f c = vertices().at(t.z()); + + float localMaximum = 0.f; + int longestSide; + + float d = distance(a, b); + if (d > localMaximum) { + localMaximum = d; longestSide = 0; + } + d = distance(b, c); + if (d > localMaximum) { + localMaximum = d; longestSide = 1; + } + d = distance(c, a); + if (d > localMaximum) { + localMaximum = d; longestSide = 2; + } + + + if (localMaximum >= (_averageSize*threshold)) { + mustChange = true; + + sibr::Vector3f aColor, bColor, cColor, aNormal, bNormal, + cNormal; + sibr::Vector2f aTexCoords, bTexCoords, cTexCoords; + + sibr::Vector3f *v1Pos, *v2Pos, *v1Color, *v2Color, + *v1Normal, *v2Normal; + sibr::Vector2f *v1TexCoords, *v2TexCoords; + + sibr::Vector3f newColor, newNormal; + sibr::Vector2f newTexCoord; + sibr::Vector3f newVertex; + + if (hasColors()) { + aColor = colors().at(t.x()); + bColor = colors().at(t.y()); + cColor = colors().at(t.z()); + } + + if (hasNormals()) { + aNormal = normals().at(t.x()); + bNormal = normals().at(t.y()); + cNormal = normals().at(t.z()); + } + + if (hasTexCoords()) { + aTexCoords = texCoords().at(t.x()); + bTexCoords = texCoords().at(t.y()); + cTexCoords = texCoords().at(t.z()); + } + if (longestSide == 0) { + v1Pos = &a; v2Pos = &b; + v1Color = &aColor; v2Color = &bColor; + v1Normal = &aNormal; v2Normal = &bNormal; + v1TexCoords = &aTexCoords; v2TexCoords = &bTexCoords; + } + else if (longestSide == 1) { + v1Pos = &b; v2Pos = &c; + v1Color = &bColor; v2Color = &cColor; + v1Normal = &bNormal; v2Normal = &cNormal; + v1TexCoords = &bTexCoords; v2TexCoords = &cTexCoords; + } + else if (longestSide == 2) { + v1Pos = &c; v2Pos = &a; + v1Color = &cColor; v2Color = &aColor; + v1Normal = &cNormal; v2Normal = &aNormal; + v1TexCoords = &cTexCoords; v2TexCoords = &aTexCoords; + } + newVertex = sibr::Vector3f((v1Pos->x() + v2Pos->x()) / 2.f, + (v1Pos->y() + v2Pos->y()) / 2.f, + (v1Pos->z() + v2Pos->z()) / 2.f); + newColor = sibr::Vector3f((v1Color->x() + v2Color->x()) / 2.f, + (v1Color->y() + v2Color->y()) / 2.f, + (v1Color->z() + v2Color->z()) / 2.f); + newNormal = sibr::Vector3f((v1Normal->x() + v2Normal->x()) / 2.f, + (v1Normal->y() + v2Normal->y()) / 2.f, + (v1Normal->z() + v2Normal->z()) / 2.f); + newTexCoord = sibr::Vector2f((v1TexCoords->x() + + v2TexCoords->x()) / 2.f, + (v1TexCoords->y() + v2TexCoords->y()) / 2.f); + + newVertices.push_back(newVertex); + + if (hasColors()) { + newColors.push_back(newColor); + } + + if (hasNormals()) { + newNormals.push_back(newNormal); + } + + if (hasTexCoords()) { + newTexCoords.push_back(newTexCoord); + } + + if (hasMeshIds()) { + // Use the first referenced vertex as the provoking vertex. + newMeshIds.push_back(meshIds().at(t.x())); + } + + int newIndexVertex = static_cast (newVertices.size()) - 1; + if (i < matIds().size()) { + newMatIds.push_back(tMatId); + newMatIds.push_back(tMatId); + } + if (longestSide == 0) { + newTriangles.push_back(sibr::Vector3u(t.x(), + newIndexVertex, + t.z())); + newTriangles.push_back(sibr::Vector3u(newIndexVertex, + t.y(), + t.z())); + } + else if (longestSide == 1) { + newTriangles.push_back(sibr::Vector3u(t.x(), + t.y(), + newIndexVertex)); + newTriangles.push_back(sibr::Vector3u(t.x(), + newIndexVertex, + t.z())); + } + else if (longestSide == 2) { + newTriangles.push_back(sibr::Vector3u(t.x(), + t.y(), + newIndexVertex)); + newTriangles.push_back(sibr::Vector3u(newIndexVertex, + t.y(), + t.z())); + } + } + else { + newTriangles.push_back(t); + if (i < matIds().size()) + newMatIds.push_back(tMatId); + } + } + vertices(newVertices); + colors(newColors); + normals(newNormals); + texCoords(newTexCoords); + triangles(newTriangles); + matIds(newMatIds); + meshIds(newMeshIds); + } + // We can now subdivide the large triangles with sub-Triangles + } + + void MaterialMesh::ambientOcclusion(const MaterialMesh::AmbientOcclusion & ao) + { + if (!_aoInitialized) { + + _ambientOcclusion = ao; + colors(_aoFunction(*this, 64)); + createSubMeshes(); + float averageDistance = 0.f; + for (sibr::Vector3u t : triangles()) { + + float maximumDistance = 0.f; + + sibr::Vector3f a = vertices().at(t.x()); + sibr::Vector3f b = vertices().at(t.y()); + sibr::Vector3f c = vertices().at(t.z()); + + float d = distance(a, b); + if (d > maximumDistance) maximumDistance = d; + d = distance(b, c); + if (d > maximumDistance) maximumDistance = d; + d = distance(a, c); + if (d > maximumDistance) maximumDistance = d; + + averageDistance += maximumDistance; + } + + + const auto areaHeronsFormula = [](sibr::Vector3f A, sibr::Vector3f B, + sibr::Vector3f C) -> float { + float a = distance(A, B); + float b = distance(B, C); + float c = distance(C, A); + return sqrtf((a + (b + c))*(c - (a - b))*(c + (a - b))* + (a + (b - c))) / 4.f; + }; + + float averageArea = 0.f; + for (sibr::Vector3u t : triangles()) { + + averageArea += areaHeronsFormula(vertices().at(t.x()), + vertices().at(t.y()), + vertices().at(t.z())); + } + + + + averageDistance /= triangles().size(); + _averageSize = averageDistance; + averageArea /= triangles().size(); + _averageArea = averageArea; + std::cout << "Average distance SIZE = " << _averageSize << std::endl; + std::cout << "Average distance SIZE = " << _averageArea << std::endl; + _aoInitialized = true; + } + if (ao.AttenuationDistance != _ambientOcclusion.AttenuationDistance) { + _ambientOcclusion = ao; + colors(_aoFunction(*this, 64)); + createSubMeshes(); + } + if (ao.SubdivideThreshold < _ambientOcclusion.SubdivideThreshold) { + _ambientOcclusion = ao; + subdivideMesh(_ambientOcclusion.SubdivideThreshold); + colors(_aoFunction(*this, 64)); + createSubMeshes(); + } + _ambientOcclusion = ao; + } + + + void MaterialMesh::initAlbedoTextures(void) { + + //Creates textures for albedo + if (_albedoTexturesInitialized) { + return; + } + + _albedoTextures.resize(matId2Name().size()); + _idTextures.resize(matId2Name().size()); + _opacityTextures.resize(matId2Name().size()); + _idTexturesOpacity.resize(matId2Name().size()); + unsigned int i = 0; + for (auto it = matId2Name().begin(); + it != matId2Name().end(); + ++it) + { + sibr::ImageRGBA::Ptr texturePtr = diffuseMap(*it); + if (texturePtr) { + _albedoTextures[i] = std::shared_ptr( + new sibr::Texture2DRGBA(*texturePtr,SIBR_GPU_LINEAR_SAMPLING)); + _idTextures[i] = _albedoTextures[i]->handle(); + } + else { + _albedoTextures[i] = std::shared_ptr( + new sibr::Texture2DRGBA()); + _idTextures[i] = _albedoTextures[i]->handle(); + } + + sibr::ImageRGB::Ptr texturePtrOpacity = opacityMap(*it); + if (texturePtrOpacity && texturePtr) { + _opacityTextures[i] = std::shared_ptr( + new sibr::Texture2DRGB(*texturePtrOpacity,SIBR_GPU_LINEAR_SAMPLING)); + _idTexturesOpacity[i] = _opacityTextures[i]->handle(); + } + else { + _opacityTextures[i] = std::shared_ptr( + new sibr::Texture2DRGB()); + _idTexturesOpacity[i] = _opacityTextures[i]->handle(); + } + + if (_hasTagsCoveringFile && _tagsCoveringMaps[*it]) { + sibr::ImageRGB::Ptr texturePtrTag = tagsCoveringMap(*it); + _tagsCoveringTexture[*it] = std::shared_ptr( + new sibr::Texture2DRGB(*texturePtrTag,SIBR_GPU_LINEAR_SAMPLING)); + _idTagsCoveringTexture[*it] = _tagsCoveringTexture[*it]->handle(); + } + + _switchTags[*it] = false; + + i++; + } + if (_hasTagsFile) { + sibr::ImageRGB::Ptr texturePtr = _tagsMap; + _tagTexture = std::shared_ptr( + new sibr::Texture2DRGB(*texturePtr,SIBR_GPU_LINEAR_SAMPLING)); + _idTagTexture = _tagTexture->handle(); + } + + + _albedoTexturesInitialized = true; + } + + void MaterialMesh::renderAlbedo(bool depthTest, bool backFaceCulling, + RenderMode mode, bool frontFaceCulling, bool invertDepthTest, + bool specificMaterial, std::string nameOfSpecificMaterial + ) const + { + if (_subMeshes.empty()) { + return; + } + + unsigned int i = 0; + bool textureFound = false; + std::string texName; + for (auto it = matId2Name().begin(); it != matId2Name().end() && !textureFound; ++it) { + + if (_albedoTextures[i] != nullptr) { + + sibr::ImageRGB::Ptr coveringTagImage = tagsCoveringMap(*it); + if (_hasTagsCoveringFile && coveringTagImage + && tagsCoveringMaps().find(*it) != tagsCoveringMaps().end()) { + texName = *it; + textureFound = true; + } + } + i++; + } + + i = 0; + for (auto it = matId2Name().begin(); it != matId2Name().end(); ++it) + { + if (!specificMaterial || *it == nameOfSpecificMaterial) + if (_albedoTextures[i] != nullptr) { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, _idTextures[i]); + + sibr::ImageRGB::Ptr coveringTagImage = tagsCoveringMap(*it); + if (_hasTagsCoveringFile && coveringTagImage + && tagsCoveringMaps().find(*it) != tagsCoveringMaps().end()) { + glActiveTexture(GL_TEXTURE1); + if (_switchTags.find(*it) != _switchTags.end() && _switchTags.at(*it) + && _hasTagsFile && _tagTexture) + glBindTexture(GL_TEXTURE_2D, _idTagTexture); + else + glBindTexture(GL_TEXTURE_2D, _idTagsCoveringTexture.at(*it)); + } + else if (_hasTagsFile && _tagTexture != nullptr) { + + glActiveTexture(GL_TEXTURE1); + if (_switchTags.find(*it) != _switchTags.end() && _switchTags.at(*it) + && _idTagsCoveringTexture.size() > 0) + glBindTexture(GL_TEXTURE_2D, _idTagsCoveringTexture.at(texName)); + else + glBindTexture(GL_TEXTURE_2D, _idTagTexture); + } + + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, _idTexturesOpacity[i]); + _subMeshes[i].render(depthTest, backFaceCulling, mode, + frontFaceCulling, invertDepthTest); + } + i++; + } + + + } + + + void MaterialMesh::renderThreeSixty(bool depthTest, bool backFaceCulling, + RenderMode mode, bool frontFaceCulling, bool invertDepthTest) const + { + + Mesh::render(depthTest, backFaceCulling, mode, frontFaceCulling, + invertDepthTest, true); + } + + void MaterialMesh::render(bool depthTest, bool backFaceCulling, + RenderMode mode, bool frontFaceCulling, bool invertDepthTest, + bool tessellation, bool adjacency) const + { + if (_typeOfRender == RenderCategory::classic) + { + Mesh::render(depthTest, backFaceCulling, mode, frontFaceCulling, + invertDepthTest, adjacency); + } + else if (_typeOfRender == RenderCategory::diffuseMaterials) + { + renderAlbedo(depthTest, backFaceCulling, mode, frontFaceCulling, + invertDepthTest); + } + else if (_typeOfRender == RenderCategory::threesixtyMaterials || + _typeOfRender == RenderCategory::threesixtyDepth) + { + renderThreeSixty(depthTest, backFaceCulling, mode, frontFaceCulling, + invertDepthTest); + } + } + + void MaterialMesh::merge(const MaterialMesh& other) + { + + if (_vertices.empty()) + { + this->operator = (other); + return; + } + + const size_t oldVerticesCount = vertices().size(); + const bool thisHasIds = hasMeshIds(); + + sibr::Mesh::merge(other); + + uint matIdsOffset = static_cast (_matId2Name.size()); + MatIds matIds = other.matIds(); + MatId2Name matId2Name; + + unsigned int nbOfSimilarity = 0; + for (unsigned int i = 0; i < other.matId2Name().size(); ++i) { + bool foundSimilarity = false; + unsigned int indexSimilarMaterial = 0; + for (unsigned int j = 0; j < _matId2Name.size() + && !foundSimilarity; ++j) { + + if (other.matId2Name().at(i).compare(_matId2Name.at(j)) == 0) { + //We find a similar material present on the two meshes + //Now we modify all triangles ids corresponding to this + // material + foundSimilarity = true; + nbOfSimilarity++; + indexSimilarMaterial = j; + } + } + if (!foundSimilarity) { + //It's a new material. + //We have found a new material, We will merge it in our list + //of materials later + matId2Name.push_back(other.matId2Name().at(i)); + //We substract the number of similarity to avoid + //the "gap" about the materials index + for (unsigned int j = 0; j < other.matIds().size(); ++j) { + unsigned int id = other.matIds().at(j); + if (id == i) { + matIds[j] = id + matIdsOffset - nbOfSimilarity; + } + } + } + else { + for (unsigned int j = 0; j < other.matIds().size(); ++j) { + unsigned int id = other.matIds().at(j); + if (id == i) { + matIds[j] = indexSimilarMaterial; + } + } + } + } + + _matIds.insert(_matIds.end(), matIds.begin(), matIds.end()); + _matId2Name.insert(_matId2Name.end(), matId2Name.begin(), + matId2Name.end()); + _opacityMaps.insert(other.opacityMaps().begin(), + other.opacityMaps().end()); + _diffuseMaps.insert(other.diffuseMaps().begin(), + other.diffuseMaps().end()); + + // We have to shift all meshes ids. + const bool otherHasIds = other.hasMeshIds(); + if (thisHasIds && otherHasIds) { + // Shift all other IDs by _maxMeshId+1. + _maxMeshId += 1; + MaterialMesh::MeshIds oIds(other.meshIds()); + const int shift = int(_maxMeshId); + for (size_t vid = 0; vid < oIds.size(); ++vid) { + oIds[vid] = shift + oIds[vid]; + } + _meshIds.insert(_meshIds.end(), oIds.begin(), oIds.end()); + _maxMeshId += other._maxMeshId; + + + } + else if (thisHasIds) { + // In that case other has no IDs. + _maxMeshId += 1; + MaterialMesh::MeshIds newMeshIds(other.vertices().size(), int(_maxMeshId)); + _meshIds.insert(_meshIds.end(), newMeshIds.begin(), newMeshIds.end()); + + } + else if (otherHasIds) { + // in that case give a new ID to the current mesh and insert the other IDs. + _maxMeshId = other._maxMeshId + 1; + _meshIds = MaterialMesh::MeshIds(oldVerticesCount, int(_maxMeshId)); + _meshIds.insert(_meshIds.end(), other.meshIds().begin(), other.meshIds().end()); + + } + } + + void MaterialMesh::makeWhole(void) + { + sibr::Mesh::makeWhole(); + if (!hasMatIds()) { + _matIds = MatIds(triangles().size(), 0); + _matIdsVertices = MatIds(vertices().size(), 0); + _matId2Name.push_back("emptyMat"); + } + if (!hasMeshIds()) { + _meshIds = MatIds(vertices().size(), 0); + _maxMeshId = 0; + } + } + + void MaterialMesh::createSubMeshes(void) { + + _subMeshes.clear(); + + for (unsigned int i = 0; i < _matId2Name.size(); i++) + { + _subMeshes.push_back(generateSubMaterialMesh(i)); + } + } + + sibr::MaterialMesh::Ptr MaterialMesh::invertedFacesMesh2() const + { + const auto invertedFacesMesh = sibr::Mesh::invertedFacesMesh2(); + auto invertedFacesMaterialMesh = std::make_shared + (*invertedFacesMesh); + // If we have some mesh IDs, just clone them as-is, no need for doubling. + if (hasMeshIds()) { + invertedFacesMaterialMesh->meshIds(meshIds()); + } + + const int nVertices = (int)vertices().size(); + const int nTriangles = (int)triangles().size(); + + Mesh::Triangles Ntriangles(2 * nTriangles); + MaterialMesh::MatIds NmatIds(hasMatIds() ? (2 * nTriangles) : 0); + + int v_id = 0; + sibr::Vector3u shift(nVertices, nVertices, nVertices); + int t_id = 0; + for (const auto & t : triangles()) { + Ntriangles[t_id] = t; + Ntriangles[t_id + nTriangles] = t.yxz() + shift; + ++t_id; + } + invertedFacesMaterialMesh->triangles(Ntriangles); + + if (hasMatIds()) { + int m_id = 0; + for (const auto & m : matIds()) { + NmatIds[m_id] = m; + NmatIds[m_id + nTriangles] = m; + ++m_id; + } + } + + invertedFacesMaterialMesh->matIds(NmatIds); + invertedFacesMaterialMesh->matId2Name(_matId2Name); + invertedFacesMaterialMesh->opacityMaps(_opacityMaps); + invertedFacesMaterialMesh->diffuseMaps(_diffuseMaps); + + return invertedFacesMaterialMesh; + } + + void MaterialMesh::addEnvironmentMap(float* forcedCenterX, + float* forcedCenterY, + float* forcedCenterZ, + float* forcedRadius) + { + sibr::Vector3f center; + float radius; + getBoundingSphere(center, radius); + + if (forcedCenterX) center.x() = *forcedCenterX; + if (forcedCenterY) center.y() = *forcedCenterY; + if (forcedCenterZ) center.z() = *forcedCenterZ; + if (forcedRadius) radius = *forcedRadius; + + //std::vector partsOfSphere; + std::vector partsOfSphere = { PartOfSphere::BOTTOM, PartOfSphere::UP }; + //partsOfSphere.push_back("bottom"); + //partsOfSphere.push_back("up"); + + for (PartOfSphere part : partsOfSphere) { + std::shared_ptr pSphere = getEnvSphere(center, radius, + Vector3f(0.f, 1.f, 0.f), + Vector3f(1.f, 0.f, 0.f), + part + ); + + sibr::MaterialMesh sphere(*pSphere); + + MatId2Name materialNames; + MatIds materialIds; + + std::string matName; + if (part == PartOfSphere::BOTTOM) + matName = std::string("SibrSkyEmissivebottom"); + else + matName = std::string("SibrSkyEmissiveup"); + materialNames.push_back(matName); + + std::vector matIdsSphere; + for (unsigned int i = 0; i < sphere.triangles().size(); ++i) { + matIdsSphere.push_back(0); + } + sphere.matId2Name(materialNames); + sphere.matIds(matIdsSphere); + + const sibr::ImageRGBA::Pixel color(0, + 255, + 255, + 255); + sibr::ImageRGBA::Ptr textureDiffuse(new sibr::ImageRGBA(1, 1, color)); + _diffuseMaps[matName] = textureDiffuse; + + const sibr::ImageRGB::Pixel opacityAlpha(255, 255, 255); + sibr::ImageRGB::Ptr textureOpacity(new sibr::ImageRGB( + 1, 1, opacityAlpha)); + _opacityMaps[matName] = textureOpacity; + sphere.generateNormals(); + merge(sphere); + } + + } + + + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/MaterialMesh.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/MaterialMesh.hpp new file mode 100755 index 0000000000000000000000000000000000000000..c6d10161dcb2173ccddc848bf30ffc0f515a7434 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/MaterialMesh.hpp @@ -0,0 +1,690 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include +# include +# include + +# include "core/graphics/Config.hpp" +# include "core/system/Vector.hpp" +# include "core/graphics/Image.hpp" +# include "core/graphics/Mesh.hpp" +# include "core/graphics/MeshBufferGL.hpp" +# include "core/graphics/Texture.hpp" + +namespace sibr +{ + + + /** Store both CPU and GPU data for a geometric mesh. + Specifically designed for synthetic scenes with material information. + Provide many processing and display methods. + \ingroup sibr_graphics + */ + class SIBR_GRAPHICS_EXPORT MaterialMesh : public sibr::Mesh + { + public: + typedef std::vector MatIds; + typedef std::vector MeshIds; + typedef std::vector MatId2Name; + + typedef std::map OpacityMaps; + typedef std::map DiffuseMaps; + + typedef sibr::ImageRGB::Ptr TagsMap; + typedef std::map TagsCoveringMaps; + + typedef std::vector SubMeshes; + typedef std::vector AlbedoTextures; + + typedef std::map SwitchTagsProperty; + + SIBR_CLASS_PTR(MaterialMesh); + + /** Synthetic data rendering options. */ + enum class RenderCategory + { + classic, + diffuseMaterials, + threesixtyMaterials, + threesixtyDepth + }; + + /** Ambient occlusion options. */ + struct AmbientOcclusion { + bool AoIsActive = false; + float AttenuationDistance = 1.f; + float IlluminanceCoefficient = 1.f; + float SubdivideThreshold = 10.f; + }; + typedef struct AmbientOcclusion AmbientOcclusion; + + std::string vertexShaderAlbedo = + "#version 450 \n" + "layout(location = 0) in vec3 in_vertex; \n" + "layout(location = 1) in vec3 in_colors; \n" + "layout(location = 2) in vec2 in_uvCoords; \n" + "layout(location = 3) in vec3 in_normal; \n" + "layout(location = 4) in float in_ao; \n" + "//layout(location = 4) in float in_material; \n" + "layout (location = 2) out vec2 uvCoords; \n" + "//out float material; \n" + "layout (location = 3) out vec3 normal; \n" + "out float ao ; \n" + "out vec3 pos_vertex; \n" + "layout (location = 1) out vec3 colors; \n" + "uniform mat4 MVP; \n" + "uniform bool lightIsPresent; \n" + "uniform vec3 lightPos; \n" + "void main(void) { \n" + " normal = in_normal; \n" + " ao = in_ao; \n" + " uvCoords = in_uvCoords; \n" + " colors= in_colors; \n" + " pos_vertex= in_vertex; \n" + " //material= float(in_material); \n" + " gl_Position = MVP*vec4(in_vertex,1) ; \n" + "} \n"; + + std::string fragmentShaderAlbedo = + "#version 450 \n" + "layout(binding = 0) uniform sampler2D tex; \n" + "layout(binding = 2) uniform sampler2D opacity; \n" + "uniform int layer; \n" + "uniform bool AoIsActive; \n" + "uniform vec2 grid; \n" + "uniform float IlluminanceCoefficient; \n" + "uniform bool lightIsPresent; \n" + "uniform float scaleTags; \n" + "uniform float intensityLight; \n" + "uniform vec3 lightPos; \n" + "layout (location = 2) in vec2 uvCoords; \n" + "layout (location = 3) in vec3 normal ; \n" + "layout (location = 1) in vec3 colors; \n" + "out vec4 out_color; \n" + "void main(void) { \n" + " vec4 opacityColor; \n" + " vec3 colorsModified = colors;\n" + " float lighter_ao = colors.x * IlluminanceCoefficient; \n" + " if (lighter_ao > 1.f ) lighter_ao = 1.f;\n" + " colorsModified.x = lighter_ao;\n" + " colorsModified.y = lighter_ao;\n" + " colorsModified.z = lighter_ao;\n" + " opacityColor = texture(opacity,vec2(uvCoords.x,1.0-uvCoords.y));\n" + " if (opacityColor.x < 0.1f && opacityColor.y < 0.1f && opacityColor.z < 0.1f ) discard;\n" + " \n" + " out_color = texture(tex,vec2(uvCoords.x,1.0-uvCoords.y));\n" + //" if (out_color.a != 0.f ) discard; \n" + //" \n" + " if (AoIsActive ) { \n" + " out_color = out_color * vec4(colorsModified,1);\n}" + " out_color = vec4(out_color.x,out_color.y,out_color.z,out_color.a);\n" + "} \n"; + + + std::string fragmentShaderAlbedoTag = + "#version 450 \n" + "layout(binding = 0) uniform sampler2D tex; \n" + "layout(binding = 1) uniform sampler2D tags; \n" + "layout(binding = 2) uniform sampler2D opacity; \n" + "uniform int layer; \n" + "uniform float scaleTags; \n" + "uniform bool AoIsActive; \n" + "uniform vec2 grid; \n" + "uniform float IlluminanceCoefficient; \n" + "uniform bool lightIsPresent; \n" + "uniform float intensityLight; \n" + "uniform vec3 lightPos; \n" + "layout (location = 2) in vec2 uvCoords; \n" + "layout (location = 3) in vec3 normal ; \n" + "layout (location = 1) in vec3 colors; \n" + "out vec4 out_color; \n" + "in vec3 pos_vertex; \n" + "void main(void) { \n" + " vec4 opacityColor; \n" + " vec3 colorsModified = colors;\n" + " float lighter_ao = colors.x * IlluminanceCoefficient; \n" + " if (lighter_ao >= 1.f ) lighter_ao = 1.f;\n" + " colorsModified.x = lighter_ao;\n" + " colorsModified.y = lighter_ao;\n" + " colorsModified.z = lighter_ao;\n" + " opacityColor = texture(opacity,vec2(uvCoords.x,1.0-uvCoords.y));\n" + " if (opacityColor.x < 0.1f || opacityColor.y < 0.1f || opacityColor.z < 0.1f ) discard;\n" + " \n" + " \n" + " out_color = texture(tex,vec2(uvCoords.x,1.0-uvCoords.y));\n" + " if (out_color.a < 0.1f ) discard; \n" + //" \n" + " out_color = texture(tags,vec2((uvCoords.x)*scaleTags,(1.0-(uvCoords.y))*scaleTags));\n" + " \n" + " if (out_color.x == 1.f && out_color.y == 1.f && out_color.z == 1.f) \n" + " out_color = texture(tex,vec2(uvCoords.x,1.0-uvCoords.y));\n" + " \n" + " \n" + " float coeffLight = 1.f; \n" + " if( lightIsPresent) { \n" + " vec3 vertexToLight = normalize( lightPos - pos_vertex );\n" + " coeffLight = abs(intensityLight*dot( vertexToLight, normal )) ; \n" + //" coeffLight = max(0.0,powerLight* dot( vertexToLight, normal )) ; \n" + " coeffLight = 0.50+coeffLight/2.0 ; \n" + " \n" + " \n" + " \n" + " } \n" + " \n" + " if (AoIsActive ) { \n" + " out_color = out_color * vec4(colorsModified,1);\n}" + " out_color = out_color * vec4(coeffLight,coeffLight,coeffLight,1);\n" + " out_color = vec4(out_color.x,out_color.y,out_color.z,out_color.a);\n" + //" if (out_color.x < 0.01f && out_color.y < 0.01f && out_color.z < 0.01f) discard; \n" + "} \n"; + + public: + + /** Constructor. + \param withGraphics init associated OpenGL buffers object (requires an openGL context) + */ + MaterialMesh(bool withGraphics = true) : Mesh(withGraphics) { + } + + /** Constructor from a basic mesh. + \param mesh the mesh to copy + */ + MaterialMesh(sibr::Mesh& mesh) : Mesh(mesh) {} + + /** Set material IDs (per triangle) + \param matIds the new ids + */ + inline void matIds(const MatIds& matIds); + + /** \return a reference to the per-triangle material IDs. */ + inline const MatIds& matIds(void) const; + + /** \return a reference to the per-vertex material IDs. */ + inline const MatIds& matIdsVertices(void) const; + + /** \return true if each triangle has a material ID assigned. */ + inline bool hasMatIds(void) const; + + /** \return the mapping between IDs and material names. */ + inline const MatId2Name& matId2Name(void) const; + + /** Set the mapping between IDs and material names. + \param matId2Name the new mapping + */ + inline void matId2Name(const MatId2Name& matId2Name); + + /** Set the mesh ID of each vertex. + \param meshIds the new ids + */ + inline void meshIds(const MeshIds& meshIds); + + /** \return a reference to the per-vertex mesh IDs. */ + inline const MeshIds& meshIds(void) const; + + /** \return true if source mesh information is available for each vertex. */ + inline bool hasMeshIds(void) const; + + /** Query a material opacity map. + \param matName the material name + \return the opacity texture if it exist + */ + inline sibr::ImageRGB::Ptr opacityMap(const std::string& matName) const; + + /** Set all material opacity maps. + \param maps the new maps + */ + inline void opacityMaps(const OpacityMaps & maps); + + /** \return all opacity maps. */ + inline const OpacityMaps& opacityMaps(void) const; + + /// Set the switchTag + inline void switchTag(const SwitchTagsProperty& switchTag); + /// get the switchTag + inline const SwitchTagsProperty& switchTag(void) const; + + /// Return the pointer to oppacity texture if it exist + /** Query a material diffuse map. + \param matName the material name + \return the diffuse texture if it exist + */ + inline sibr::ImageRGBA::Ptr diffuseMap(const std::string& matName) const; + + /** Set all material diffuse maps. + \param maps the new maps + */ + inline void diffuseMaps(const DiffuseMaps & maps); + + /** \return all diffuse maps. */ + inline const DiffuseMaps& diffuseMaps(void) const; + + /** Indicate if the mesh has an associated tag file (for calibration). + \param hasOrNot the flag + */ + inline void hasTagsFile(bool hasOrNot); + + /** \return true if the mesh has an associated tag file. */ + inline const bool hasTagsFile(void) const; + + /** Set the tag map. + \param map the new map + */ + inline void tagsMap(const TagsMap & map); + + /** \return the current tag map. */ + inline const TagsMap& tagsMap(void) const; + + /** Indicate if the mesh has an associated covering tag file (for calibration). + \param hasOrNot the flag + */ + inline void hasTagsCoveringFile(bool hasOrNot); + + /** \return true if the mesh has an associated covering tag file. */ + inline const bool hasTagsCoveringFile(void) const; + + /** Set the covering tag map. + \param map the new map + */ + inline void tagsCoveringMaps(const TagsCoveringMaps & map); + + /** \return the current covering tag map. */ + inline const TagsCoveringMaps& tagsCoveringMaps(void) const; + /// Return the pointer to oppacity texture if it exist + inline sibr::ImageRGB::Ptr tagsCoveringMap(const std::string& matName) const; + + /** Set the sub meshes. + \param subMeshes a list of submeshes + */ + inline void subMeshes(const SubMeshes& subMeshes); + + /** \return the list of submeshes. */ + inline const SubMeshes& subMeshes(void) const; + + /** Set the synthetic rendering mode. + \param type the new mode + */ + inline void typeOfRender(const RenderCategory& type); + + /** \return the current synthetic rendering mode. */ + inline const RenderCategory& typeOfRender(void) const; + + /** Set the ambient occlusion options and compute AO values, storing them in the vertex colors. + \param ao the new options + */ + void ambientOcclusion(const AmbientOcclusion& ao); + + /** \return the current ambient occlusion options. */ + inline const AmbientOcclusion& ambientOcclusion(void); + + /** Set the function used to compute ambient occlusion at each vertex. + \param aoFunction the new function to use + */ + inline void aoFunction(std::function& aoFunction); + + /** Load a mesh from the disk. + \param filename the file path + \return a success flag + \note Supports OBJ and PLY for now. + */ + bool load(const std::string& filename); + + /** Load a scene from a set of mitsuba XML scene files (referencing multiple OBJs/PLYs). + It handles instances (duplicating the geometry and applying the per-instance transformation). + \param xmlFile the file path + \param loadTextures should the material textures be loaded + \return a success flag + */ + bool loadMtsXML(const std::string& xmlFile, bool loadTextures = true); + + /* + Load tags image files from a list of file paths. + \param listFilesTags a list of image paths + */ + void loadCoveringTagsTexture(const std::vector& listFilesTags); + + /** Attribute a random color at each vertex based on the material IDs of the faces it belongs to. */ + void fillColorsWithIndexMaterials(); + + /** Store the material ID of each vertex in its color attribute (R: bits 0-7, G: 8-15, B: 16-23). */ + void fillColorsWithMatIds(); + + /** Merge another mesh into this one. + \param other the mesh to merge + \sa makeWhole + */ + void merge(const MaterialMesh& other); + + /** Make the mesh whole, ie it will have default values for all components (texture, materials, colors, etc) + It is useful when merging two meshes. If the second one is missing some attributes, the merging will break the mesh state if it isn't made whole. + */ + void makeWhole(void); + + /** Split the mesh geometry in multiple submeshes based on each vertex material ID. */ + void createSubMeshes(void); + + /** \return a copy of the mesh with "doubled" faces (obtained by merging the current mesh with a copy with inverted faces. */ + sibr::MaterialMesh::Ptr invertedFacesMesh2() const; + + /** Force upload of data to the GPU. */ + void forceBufferGLUpdate(void) const; + + /** Delete GPU mesh data. */ + void freeBufferGLUpdate(void) const; + + /** Subdivide a mesh triangles until a triangle area threshold is reached. + \param threshold the maximum deviation from the average triangle area allowed + */ + void subdivideMesh2(float threshold); + + /** Subdivide a mesh triangles until an edge length threshold is reached. + \param threshold the maximum deviation from the average edge length allowed + */ + void subdivideMesh(float threshold); + + /** Add an environment sphere to the mesh, surrounding the existing geometry. + \param forcedCenterX optional sphere center x coordinate + \param forcedCenterY optional sphere center y coordinate + \param forcedCenterZ optional sphere center z coordinate + \param forcedRadius optional sphere radius + */ + void addEnvironmentMap(float* forcedCenterX = nullptr, + float* forcedCenterY = nullptr, + float* forcedCenterZ = nullptr, + float* forcedRadius = nullptr); + + /** Render the geometry using OpenGL. + \param depthTest should depth testing be performed + \param backFaceCulling should culling be performed + \param mode the primitives rendering mode + \param frontFaceCulling should the culling test be flipped + \param invertDepthTest should the depth test be flipped (GL_GREATER_THAN) + \param tessellation should the rendering call tesselation shaders + \param adjacency should we get adjacent triangles info in geometry shader + */ + void render( + bool depthTest = true, + bool backFaceCulling = true, + RenderMode mode = FillRenderMode, + bool frontFaceCulling = false, + bool invertDepthTest = false, + bool tessellation = false, + bool adjacency = false + ) const; + + /** Render the geometry with albedo and tag textures. + \param depthTest should depth testing be performed + \param backFaceCulling should culling be performed + \param mode the primitives rendering mode + \param frontFaceCulling should the culling test be flipped + \param invertDepthTest should the depth test be flipped (GL_GREATER_THAN) + \param specificMaterial should we use a specific material + \param nameOfSpecificMaterial name of the specific material + */ + void renderAlbedo( + bool depthTest = true, + bool backFaceCulling = true, + RenderMode mode = FillRenderMode, + bool frontFaceCulling = false, + bool invertDepthTest = false, + bool specificMaterial = false, + std::string nameOfSpecificMaterial = "" + ) const; + + /** Render the geometry for 360 environment maps. + \param depthTest should depth testing be performed + \param backFaceCulling should culling be performed + \param mode the primitives rendering mode + \param frontFaceCulling should the culling test be flipped + \param invertDepthTest should the depth test be flipped (GL_GREATER_THAN) + */ + void renderThreeSixty( + bool depthTest, + bool backFaceCulling, + RenderMode mode, + bool frontFaceCulling, + bool invertDepthTest + ) const; + + /** Upload the material textures to the GPU. */ + void initAlbedoTextures(void); + + /** Generate a mesh containing all triangles with a given material. + \param material the material ID + \return the submesh + */ + Mesh generateSubMaterialMesh(int material) const; + + private: + + + MatIds _matIds; ///< Per triangle material ID. + MatIds _matIdsVertices; ///< Per vertex material ID. + MatId2Name _matId2Name; ///< ID to name material mapping. + + MeshIds _meshIds; ///< Per-vertex submesh ID. + size_t _maxMeshId = 0; ///< Maximum submesh ID encounter. + + OpacityMaps _opacityMaps; ///< Material opacity images. + DiffuseMaps _diffuseMaps; ///< Material diffuse images. + + //std::vector _uniformColorMtlList; + TagsMap _tagsMap; ///< Material tag images. + TagsCoveringMaps _tagsCoveringMaps; ///< Material covering tag images. + std::vector uniformColorMtlList; ///< List of materials with a diffuse map. + + SubMeshes _subMeshes; ///< Submeshes, one per material, for rendering them separately. + RenderCategory _typeOfRender = RenderCategory::diffuseMaterials; ///< Synthetic rendering mode. + + bool _albedoTexturesInitialized = false; ///< Are the texture initialized. + std::vector _albedoTextures; ///< Albedo textures. + std::vector _idTextures; ///< Texture handles. + std::vector _opacityTextures;///< Opacity textures. + std::vector _idTexturesOpacity;///< Opacity texture handles. + + bool _hasTagsFile = false; ///< Is a tag file associated to the mesh. + sibr::Texture2DRGB::Ptr _tagTexture; ///< Tag texture. + GLuint _idTagTexture = 0; ///< Tag texture handle. + + bool _hasTagsCoveringFile = false; ///< Is a covering tag file associated to the mesh. + sibr::Texture2DRGB::Ptr _tagCoveringTexture;///< Convering tag texture. + GLuint _idTagCoveringTexture = 0; ///< Covering tag texture handle. + + std::vector _listCoveringImagesTags; + std::map _tagsCoveringTexture; + std::map _idTagsCoveringTexture; + + SwitchTagsProperty _switchTags; + + //AO attributes + float _currentThreshold; + AmbientOcclusion _ambientOcclusion; ///< AO options. + std::function _aoFunction; ///< AO generation function. + bool _aoInitialized = false; ///< Is AO data initialized. + float _averageSize = 0.0f; ///< Average maximum edge length. + float _averageArea = 0.0f; ///< Average triangle area. + + }; + + ///// DEFINITION ///// + + + + void MaterialMesh::matIds(const MatIds& matIds) { + _matIds = matIds; + } + const MaterialMesh::MatIds& MaterialMesh::matIds(void) const { + return _matIds; + } + bool MaterialMesh::hasMatIds(void) const { + return (_triangles.size() > 0 && _triangles.size() == _matIds.size()); + } + const MaterialMesh::MatIds& MaterialMesh::matIdsVertices(void) const { + return _matIdsVertices; + } + const MaterialMesh::MatId2Name& MaterialMesh::matId2Name(void) const { + return _matId2Name; + } + void MaterialMesh::matId2Name(const MatId2Name & matId2Name) + { + _matId2Name = matId2Name; + } + + void MaterialMesh::meshIds(const MeshIds& meshIds) { + _meshIds = meshIds; + } + const MaterialMesh::MeshIds& MaterialMesh::meshIds(void) const { + return _meshIds; + } + bool MaterialMesh::hasMeshIds(void) const { + return (!_meshIds.empty() && _meshIds.size() == _vertices.size()); + } + + // Opacity map function + ImageRGB::Ptr MaterialMesh::opacityMap(const std::string& matName) const + { + std::map, sibr::ImagePtr >::const_iterator el = _opacityMaps.find(matName); + if (el != _opacityMaps.end()) { + return el->second; + } + return nullptr; + } + const MaterialMesh::OpacityMaps& MaterialMesh::opacityMaps(void) const + { + return _opacityMaps; + } + + void MaterialMesh::hasTagsFile(bool hasOrNot) + { + _hasTagsFile = hasOrNot; + } + + const bool MaterialMesh::hasTagsFile(void) const + { + return _hasTagsFile; + } + + void MaterialMesh::hasTagsCoveringFile(bool hasOrNot) + { + _hasTagsCoveringFile = hasOrNot; + } + + const bool MaterialMesh::hasTagsCoveringFile(void) const + { + return _hasTagsCoveringFile; + } + + void MaterialMesh::opacityMaps(const OpacityMaps& maps) + { + _opacityMaps = maps; + } + + void MaterialMesh::tagsMap(const TagsMap & map) { + _tagsMap = map; + } + + const MaterialMesh::TagsMap& MaterialMesh::tagsMap(void) const { + return _tagsMap; + } + + void MaterialMesh::tagsCoveringMaps(const TagsCoveringMaps & map) { + _tagsCoveringMaps = map; + } + + const MaterialMesh::TagsCoveringMaps& MaterialMesh::tagsCoveringMaps(void) const { + return _tagsCoveringMaps; + } + + sibr::ImageRGB::Ptr MaterialMesh::tagsCoveringMap(const std::string& matName) const { + std::map, sibr::ImagePtr >::const_iterator el = _tagsCoveringMaps.find(matName); + + if (el != _tagsCoveringMaps.end()) { + return el->second; + } + else return nullptr; + } + + /// Set the switchTag + void MaterialMesh::switchTag(const SwitchTagsProperty& switchTag) { + _switchTags = switchTag; + } + /// get the switchTag + const MaterialMesh::SwitchTagsProperty& MaterialMesh::switchTag(void) const { + return _switchTags; + } + + ImageRGBA::Ptr MaterialMesh::diffuseMap(const std::string& matName) const + { + std::map, sibr::ImagePtr >::const_iterator el = _diffuseMaps.find(matName); + + if (el != _diffuseMaps.end()) { + return el->second; + } + else return nullptr; + } + + /*ImageRGB MaterialMesh::diffuseMap(const std::string& matName) + { + auto & el =_diffuseMaps.find(matName); + if (el != _diffuseMaps.end()) { + return el->second; + } + }*/ + + const MaterialMesh::DiffuseMaps& MaterialMesh::diffuseMaps(void) const + { + return _diffuseMaps; + } + + void MaterialMesh::diffuseMaps(const DiffuseMaps& maps) + { + _diffuseMaps = maps; + } + + const MaterialMesh::SubMeshes& MaterialMesh::subMeshes(void) const + { + return _subMeshes; + } + + + void MaterialMesh::subMeshes(const SubMeshes& subMeshes) + { + _subMeshes = subMeshes; + } + + const MaterialMesh::RenderCategory& MaterialMesh::typeOfRender(void) const { + return _typeOfRender; + } + + + inline const MaterialMesh::AmbientOcclusion & MaterialMesh::ambientOcclusion(void) + { + return _ambientOcclusion; + } + + inline void MaterialMesh::aoFunction(std::function& + aoFunction) + { + _aoFunction = aoFunction; + } + + void MaterialMesh::typeOfRender(const RenderCategory& type) { + _typeOfRender = type; + } + + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Mesh.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Mesh.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9411834938555af0013fb3738537bb4fe8a0d346 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Mesh.cpp @@ -0,0 +1,2423 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include +#include +#include +#include + +#include // C++ importer interface +#include // Output data structure +#include // Post processing flags +#include +#include + +#include "core/system/ByteStream.hpp" +#include "core/graphics/Mesh.hpp" + +#include "boost/filesystem.hpp" +#include "core/system/XMLTree.h" +#include "core/system/Matrix.hpp" +#include +#include +#include "core/assets/colmapheader.h" + +namespace sibr +{ + typedef uint32_t image_t; + typedef uint32_t camera_t; + typedef uint64_t point3D_t; + typedef uint32_t point2D_t; + + void ReadPoints3DBinary(const std::string& path, Mesh::Vertices& verts, Mesh::Colors& cols, int& numverts) { + std::ifstream file(path, std::ios::binary); + // CHECK(file.is_open()) << path; + + const size_t num_points3D = ReadBinaryLittleEndian(&file); + numverts = num_points3D; + std::cerr << "Num 3D pts " << num_points3D << std::endl; + for (size_t i = 0; i < num_points3D; ++i) { + //class Point3D point3D; + + const uint64_t point3D_id = ReadBinaryLittleEndian(&file); + // num_added_points3D_ = std::max(num_added_points3D_, point3D_id); + + // point3D.XYZ()(0) = ReadBinaryLittleEndian(&file); + // point3D.XYZ()(1) = ReadBinaryLittleEndian(&file); + // point3D.XYZ()(2) = ReadBinaryLittleEndian(&file); + // point3D.Color(0) = ReadBinaryLittleEndian(&file); + // point3D.Color(1) = ReadBinaryLittleEndian(&file); + // point3D.Color(2) = ReadBinaryLittleEndian(&file); + // point3D.SetError(ReadBinaryLittleEndian(&file)); + + double x = ReadBinaryLittleEndian(&file); + double y = ReadBinaryLittleEndian(&file); + double z = ReadBinaryLittleEndian(&file); + Vector3f vert(x,y,z); + + verts.push_back(vert); + + float r = float(ReadBinaryLittleEndian(&file))/255.f; + float g = float(ReadBinaryLittleEndian(&file))/255.f; + float b = float(ReadBinaryLittleEndian(&file))/255.f; + + Vector3f c(r, g, b); + + cols.push_back(c); + double err = ReadBinaryLittleEndian(&file); + + const size_t track_length = ReadBinaryLittleEndian(&file); + //std::cerr << "Track length " << track_length << std::endl; + // read and include + for (size_t j = 0; j < track_length; ++j) { + const image_t image_id = ReadBinaryLittleEndian(&file); + const point2D_t point2D_idx = ReadBinaryLittleEndian(&file); + //point3D.Track().AddElement(image_id, point2D_idx); + } + //point3D.Track().Compress(); + + //points3D_.emplace(point3D_id, point3D); + } + } + + void ReadPoints3DText(const std::string& path, Mesh::Vertices& verts, Mesh::Vertices& cols) { + // points3D_.clear(); + std::ifstream file(path); + // CHECK(file.is_open()) << path; + std::string line; + std::string item; + while (std::getline(file, line)) { + StringTrim(&line); + if (line.empty() || line[0] == '#') { + continue; + } + std::stringstream line_stream(line); + // ID + std::getline(line_stream, item, ' '); + const point3D_t point3D_id = std::stoll(item); + + // Make sure, that we can add new 3D points after reading 3D points + // without overwriting existing 3D points. + // num_added_points3D_ = std::max(num_added_points3D_, point3D_id); + + // XYZ + std::getline(line_stream, item, ' '); + std::cerr << "point3D.XYZ(0) = " << std::stold(item) << std::endl; + + std::getline(line_stream, item, ' '); + std::cerr << "point3D.XYZ(1) = " << std::stold(item) << std::endl; + + std::getline(line_stream, item, ' '); + std::cerr << "point3D.XYZ(2) = " << std::stold(item) << std::endl; + + // Color + std::getline(line_stream, item, ' '); + std::cerr << "point3D.Color(0) = " << static_cast(std::stoi(item)) << std::endl; + + std::getline(line_stream, item, ' '); + std::cerr << "point3D.Color(1) = " << static_cast(std::stoi(item)) << std::endl; + + std::getline(line_stream, item, ' '); + std::cerr << "point3D.Color(2) = " << static_cast(std::stoi(item)) << std::endl; + + // ERROR + std::getline(line_stream, item, ' '); + std::cerr << "point3D.SetError(" << std::stold(item) << std::endl; + + // TRACK + while (!line_stream.eof()) { + // TrackElement track_el; + + std::getline(line_stream, item, ' '); + StringTrim(&item); + if (item.empty()) { + break; + } + std::cerr << "track_el.image_id = " << std::stoul(item) << std::endl; + + std::getline(line_stream, item, ' '); + std::cerr << "track_el.point2D_idx = " << std::stoul(item) << std::endl; + // point3D.Track().AddElement(track_el); + } + // point3D.Track().Compress(); + // points3D_.emplace(point3D_id, point3D); + } + } + + Mesh::Mesh(bool withGraphics) : _meshPath("") { + if (withGraphics) { + _gl.bufferGL.reset(new MeshBufferGL); + } + else { + _gl.bufferGL = nullptr; + } + } + + bool Mesh::saveToObj(const std::string& filename) const + { + aiScene scene; + scene.mRootNode = new aiNode(); + + scene.mMaterials = new aiMaterial * [1]; + scene.mMaterials[0] = nullptr; + scene.mNumMaterials = 1; + + scene.mMaterials[0] = new aiMaterial(); + + scene.mMeshes = new aiMesh * [1]; + scene.mNumMeshes = 1; + + scene.mMeshes[0] = new aiMesh(); + scene.mMeshes[0]->mMaterialIndex = 0; + + scene.mRootNode->mMeshes = new unsigned int[1]; + scene.mRootNode->mMeshes[0] = 0; + scene.mRootNode->mNumMeshes = 1; + + auto pMesh = scene.mMeshes[0]; + + const auto& vVertices = _vertices; + + pMesh->mVertices = new aiVector3D[vVertices.size()]; + pMesh->mNumVertices = static_cast(vVertices.size()); + + if (hasNormals()) { + pMesh->mNormals = new aiVector3D[vVertices.size()]; + } + else { + pMesh->mNormals = nullptr; + } + + if (hasTexCoords()) { + pMesh->mTextureCoords[0] = new aiVector3D[vVertices.size()]; + pMesh->mNumUVComponents[0] = 2; + } + else { + pMesh->mTextureCoords[0] = nullptr; + pMesh->mNumUVComponents[0] = 0; + } + + int j = 0; + for (auto itr = vVertices.begin(); itr != vVertices.end(); ++itr) + { + pMesh->mVertices[itr - vVertices.begin()] = aiVector3D(vVertices[j].x(), vVertices[j].y(), vVertices[j].z()); + if (hasNormals()) + pMesh->mNormals[itr - vVertices.begin()] = aiVector3D(_normals[j].x(), _normals[j].y(), _normals[j].z()); + if (hasTexCoords()) + pMesh->mTextureCoords[0][itr - vVertices.begin()] = aiVector3D(_texcoords[j][0], _texcoords[j][1], 0); + j++; + } + + pMesh->mFaces = new aiFace[_triangles.size()]; + pMesh->mNumFaces = (unsigned int)(_triangles.size()); + + for (uint i = 0; i < _triangles.size(); ++i) + { + const Vector3u& tri = _triangles[i]; + aiFace& face = pMesh->mFaces[i]; + face.mIndices = new unsigned int[3]; + face.mNumIndices = 3; + + face.mIndices[0] = tri[0]; + face.mIndices[1] = tri[1]; + face.mIndices[2] = tri[2]; + } + Assimp::Exporter mAiExporter; + const aiScene* s = (const aiScene*)&(scene); + + SIBR_LOG << "Saving (via ASSIMP) " << filename << "'..." << std::endl; + mAiExporter.Export(s, "obj", filename); + + // mesh and scene destructors free memory + + + return true; + } + + + bool Mesh::saveToBinaryPLY(const std::string& filename, bool universal, const std::string& textureName) const + { + assert(_vertices.size()); + + SIBR_LOG << "Saving '" << filename << "'..." << std::endl; + + // Note that Assimp supports also export for some formats. However, + // when I tried with the current Assimp version (3.0) it failed to + // do a good export for .ply (using binary version). + // In addition, at this time there is no control/ExportProperties. + // Thus I just do it myself. + + std::ofstream file(filename.c_str(), std::ios::out | std::ios::trunc | std::ios::binary); + + if (file) + { + file << "ply" << std::endl; + file << "format binary_big_endian 1.0" << std::endl; + file << "comment Created by SIBR project" << std::endl; + if (hasTexCoords()) + { + file << "comment TextureFile " << textureName << std::endl; + } + file << "element vertex " << _vertices.size() << std::endl; + file << "property float x" << std::endl; + file << "property float y" << std::endl; + file << "property float z" << std::endl; + if (hasColors()) + { + if (universal) + { + file << "property uchar red" << std::endl; + file << "property uchar green" << std::endl; + file << "property uchar blue" << std::endl; + } + else + { + file << "property ushort red" << std::endl; + file << "property ushort green" << std::endl; + file << "property ushort blue" << std::endl; + } + + } + if (hasNormals()) + { + file << "property float nx" << std::endl; + file << "property float ny" << std::endl; + file << "property float nz" << std::endl; + } + if (hasTexCoords()) + { + file << "property float texture_u" << std::endl; + file << "property float texture_v" << std::endl; + } + + file << "element face " << _triangles.size() << std::endl; + file << "property list uchar uint vertex_indices" << std::endl; + file << "end_header" << std::endl; + + /// BINARY version ///// + ByteStream bytes; + + for (uint i = 0; i < _vertices.size(); ++i) + { + const Vector3f& v = _vertices[i]; + + bytes << float(v[0]) << float(v[1]) << float(v[2]); + + if (hasColors()) + { + const Vector3f& c = _colors[i]; + if (universal) + bytes + << uint8(c[0] * (UINT8_MAX - 1)) + << uint8(c[1] * (UINT8_MAX - 1)) + << uint8(c[2] * (UINT8_MAX - 1)); // ! converting colors explicitly + else + bytes + << uint16(c[0] * (UINT16_MAX - 1)) + << uint16(c[1] * (UINT16_MAX - 1)) + << uint16(c[2] * (UINT16_MAX - 1)); // ! converting colors explicitly + } + + if (hasNormals()) + { + const Vector3f& n = _normals[i]; + + bytes << float(n[0]) << float(n[1]) << float(n[2]); + } + + if (hasTexCoords()) + { + const Vector2f& uv = _texcoords[i]; + + bytes << float(uv[0]) << float(uv[1]); + } + } + + for (uint i = 0; i < _triangles.size(); ++i) + { + const Vector3u& tri = _triangles[i]; + + bytes << uint8(3); + for (uint j = 0; j < 3; ++j) + bytes << uint32(tri[j]); + } + + file.write(reinterpret_cast(bytes.buffer()), bytes.bufferSize()); + file.close(); + SIBR_LOG << "Saving '" << filename << "'... done" << std::endl; + return true; + } + SIBR_LOG << "error: cannot write to file '" << filename << "'." << std::endl; + return false; + + } + + bool Mesh::saveToASCIIPLY(const std::string& filename, bool universal, const std::string& textureName) const + { + assert(_vertices.size()); + + // Note that Assimp supports also export for some formats. However, + // when I tried with the current Assimp version (3.0) it failed to + // do a good export for .ply (using binary version). + // In addition, at this time there is no control/ExportProperties. + // Thus I just do it myself. + + std::ofstream file(filename.c_str(), std::ios::out | std::ios::trunc | std::ios::binary); + + if (file) + { + file << "ply" << std::endl; + file << "format ascii 1.0" << std::endl; + file << "comment Created by SIBR project" << std::endl; + if (hasTexCoords()) + { + file << "comment TextureFile " << textureName << std::endl; + } + file << "element vertex " << _vertices.size() << std::endl; + file << "property float x" << std::endl; + file << "property float y" << std::endl; + file << "property float z" << std::endl; + + if (hasColors()) + { + if (universal) + { + file << "property uchar red" << std::endl; + file << "property uchar green" << std::endl; + file << "property uchar blue" << std::endl; + } + else + { + file << "property ushort red" << std::endl; + file << "property ushort green" << std::endl; + file << "property ushort blue" << std::endl; + } + } + + if (hasNormals()) + { + file << "property float nx" << std::endl; + file << "property float ny" << std::endl; + file << "property float nz" << std::endl; + } + + if (hasTexCoords()) + { + file << "property float texture_u" << std::endl; + file << "property float texture_v" << std::endl; + } + + file << "element face " << _triangles.size() << std::endl; + file << "property list uchar uint vertex_indices" << std::endl; + file << "end_header" << std::endl; + + /////// ASCII version ///// + + for (uint i = 0; i < _vertices.size(); ++i) + { + const Vector3f& v = _vertices[i]; + + file << v[0] << " " << v[1] << " " << v[2] << " "; + + if (hasColors()) + { + const Vector3f& c = _colors[i]; + + if (universal) + { + file << int(c[0] * (UINT8_MAX - 1)) << " " + << int(c[1] * (UINT8_MAX - 1)) << " " + << int(c[2] * (UINT8_MAX - 1)) << " "; + } + else + { + file << int(c[0] * (UINT16_MAX - 1)) << " " + << int(c[1] * (UINT16_MAX - 1)) << " " + << int(c[2] * (UINT16_MAX - 1)) << " "; + } + } + + if (hasNormals()) + { + const Vector3f& n = _normals[i]; + + file << n[0] << " " << n[1] << " " << n[2] << " "; + } + + if (hasTexCoords()) + { + const Vector2f& uv = _texcoords[i]; + + file << uv[0] << " " << uv[1] << " "; + } + + file << std::endl; + } + + for (uint i = 0; i < _triangles.size(); ++i) + { + const Vector3u& tri = _triangles[i]; + + file << 3; + for (uint j = 0; j < 3; ++j) + file << " " << tri[j]; + file << std::endl; + } + + file.close(); + SIBR_LOG << "'" << filename << "' saved." << std::endl; + return true; + } + SIBR_LOG << "error: cannot write to file '" << filename << "'." << std::endl; + return false; + + } + bool Mesh::load(const std::string& filename, const std::string& dataset_path ) + { + // Does the file exists? + if (!sibr::fileExists(filename)) { + SIBR_LOG << "Error: can't load mesh '" << filename << "." << std::endl; + return false; + } + Assimp::Importer importer; + //importer.SetPropertyBool(AI_CONFIG_PP_FD_REMOVE, true); // cause Assimp to remove all degenerated faces as soon as they are detected + const aiScene* scene = importer.ReadFile(filename, aiProcess_Triangulate | aiProcess_JoinIdenticalVertices | aiProcess_FindDegenerates); + + if (!scene) + { + SIBR_LOG << "error: can't load mesh '" << filename + << "' (" << importer.GetErrorString() << ")." << std::endl; + return false; + } + + // check for texture + aiMaterial *material; + if( scene->mNumMaterials > 0 ) { + material = scene->mMaterials[0]; + aiString Path; + if(material->GetTexture(aiTextureType_DIFFUSE, 0, &Path, NULL, NULL, NULL, NULL, NULL) == AI_SUCCESS ) { + _textureImageFileName = Path.data; + std::cerr << "Texture name " << _textureImageFileName << std::endl; + } + + } + + if (scene->mNumMeshes == 0) + { + SIBR_LOG << "error: the loaded model file ('" << filename + << "') contains zero or more than one mesh. Number of meshes : " << scene->mNumMeshes << std::endl; + return false; + } + + auto convertVec = [](const aiVector3D& v) { return Vector3f(v.x, v.y, v.z); }; + _triangles.clear(); + + uint offsetVertices = 0; + uint offsetFaces = 0; + uint matId = 0; + std::map matName2Id; + Matrix3f converter; + converter << + 1, 0, 0, + 0, 1, 0, + 0, 0, 1; + + for (uint meshId = 0; meshId < scene->mNumMeshes; ++meshId) { + const aiMesh* mesh = scene->mMeshes[meshId]; + + _vertices.resize(offsetVertices + mesh->mNumVertices); + for (uint i = 0; i < mesh->mNumVertices; ++i) + _vertices[offsetVertices + i] = converter * convertVec(mesh->mVertices[i]); + + + if (mesh->HasVertexColors(0) && mesh->mColors[0]) + { + _colors.resize(offsetVertices + mesh->mNumVertices); + for (uint i = 0; i < mesh->mNumVertices; ++i) + { + _colors[offsetVertices + i] = Vector3f( + mesh->mColors[0][i].r, + mesh->mColors[0][i].g, + mesh->mColors[0][i].b); + } + } + + if (mesh->HasNormals()) + { + _normals.resize(offsetVertices + mesh->mNumVertices); + for (uint i = 0; i < mesh->mNumVertices; ++i) { + _normals[offsetVertices + i] = converter * convertVec(mesh->mNormals[i]); + } + + } + + if (mesh->HasTextureCoords(0)) + { + _texcoords.resize(offsetVertices + mesh->mNumVertices); + for (uint i = 0; i < mesh->mNumVertices; ++i) + _texcoords[offsetVertices + i] = convertVec(mesh->mTextureCoords[0][i]).xy(); + // TODO: make a clean function + std::string texFileName = dataset_path + "/capreal/" + _textureImageFileName; + if( !fileExists(texFileName)) + texFileName = parentDirectory(parentDirectory(dataset_path)) + "/capreal/" + _textureImageFileName; + if( !fileExists(texFileName)) + texFileName = parentDirectory(dataset_path) + "/capreal/" + _textureImageFileName; + + if (!mesh->HasVertexColors(0) && fileExists(texFileName)) { + // Sample the texture + sibr::ImageRGB texImg; + texImg.load(texFileName); + std::cout << "Computing vertex colors .."; + _colors.resize(offsetVertices + mesh->mNumVertices); + for (uint ci = 0; ci < mesh->mNumVertices; ++ci) + { + Vector2f uv = _texcoords[offsetVertices + ci]; + Vector3ub col = texImg((uv[0]*texImg.w()), uint((1-uv[1])*texImg.h())); + _colors[offsetVertices + ci] = Vector3f(float(col[0]) / 255.0, float(col[1]) / 255.0, float(col[2]) / 255.0); + } + SIBR_WRG << "Done." << std::endl; + } + } + if (meshId == 0) { + SIBR_LOG << "Mesh contains: colors: " << mesh->HasVertexColors(0) + << ", normals: " << mesh->HasNormals() + << ", texcoords: " << mesh->HasTextureCoords(0) << std::endl; + } + + _triangles.reserve(offsetFaces + mesh->mNumFaces); + for (uint i = 0; i < mesh->mNumFaces; ++i) + { + const aiFace* f = &mesh->mFaces[i]; + if (f->mNumIndices != 3) + SIBR_LOG << "warning: discarding a face (not a triangle, num indices: " + << f->mNumIndices << ")" << std::endl; + else + { + Vector3u tri = Vector3u(offsetVertices + f->mIndices[0], offsetVertices + f->mIndices[1], offsetVertices + f->mIndices[2]); + if (tri[0] < 0 || tri[0] >= _vertices.size() + || tri[1] < 0 || tri[1] >= _vertices.size() + || tri[2] < 0 || tri[2] >= _vertices.size()) + SIBR_WRG << "face num [" << i << "] contains invalid vertex id(s)" << std::endl; + else { + _triangles.push_back(tri); + } + + } + } + + offsetFaces = (uint)_triangles.size(); + offsetVertices = (uint)_vertices.size(); + + } + + _meshPath = filename; + + SIBR_LOG << "Mesh '" << filename << " successfully loaded. " << scene->mNumMeshes << " meshes were loaded with a total of " + << " (" << _triangles.size() << ") faces and " + << " (" << _vertices.size() << ") vertices detected. Init GL ..." << std::endl; + SIBR_LOG << "Init GL mesh complete " << std::endl; + + _gl.dirtyBufferGL = true; + return true; + } + + bool Mesh::loadSfM(const std::string& filename, const std::string& dataset_path ) + { + // Does the file exist? + + std::string fname = dataset_path + "points3D.bin"; + + std::cerr << "LOADSFM: Try to open " << fname << std::endl; + + if (!sibr::fileExists(fname)) { + SIBR_LOG << "Error: can't load mesh '" << fname << "." << std::endl; + return false; + } + Vertices verts; + Colors cols; + int numverts; + + ReadPoints3DBinary(fname, verts, cols, numverts); + _triangles.clear(); + + uint matId = 0; + + _vertices.resize(numverts); + + for (uint i = 0; i < numverts; ++i) + _vertices[i] = verts[i]; + + _colors.resize(numverts); + + for (uint i = 0; i < numverts; ++i) + _colors[i] = Vector3f( + cols[i].x(), cols[i].y(), cols[i].z()); + + _meshPath = dataset_path + "/points3D.bin"; + _renderingOptions.mode = PointRenderMode; + + SIBR_LOG << "SfM Mesh '" << filename << " successfully loaded. " << " (" << _vertices.size() << ") vertices detected. Init GL ..." << std::endl; + SIBR_LOG << "Init GL mesh complete " << std::endl; + + _gl.dirtyBufferGL = true; + return true; + } + + + bool sibr::Mesh::loadMtsXML(const std::string& xmlFile) + { + bool allLoaded = true; + std::string pathFolder = boost::filesystem::path(xmlFile).parent_path().string(); + sibr::XMLTree doc(xmlFile); + + std::map meshes; + std::map idToFilename; + + rapidxml::xml_node<>* nodeScene = doc.first_node("scene"); + + for (rapidxml::xml_node<>* node = nodeScene->first_node("shape"); + node; node = node->next_sibling("shape")) + { + if (strcmp(node->first_attribute()->name(), "type") == 0 && + strcmp(node->first_attribute()->value(), "shapegroup") == 0) { + + std::cout << "Found : " << node->first_attribute("id")->value() << std::endl; + + std::string id = node->first_attribute("id")->value(); + std::string filename = node->first_node("shape")->first_node("string")->first_attribute("value")->value(); + idToFilename[id] = filename; + } + } + + for (rapidxml::xml_node<>* node = nodeScene->first_node("shape"); + node; node = node->next_sibling("shape")) + { + + if (strcmp(node->first_attribute()->name(), "type") == 0 && + strcmp(node->first_attribute()->value(), "instance") == 0 + ) { + rapidxml::xml_node<>* nodeRef = node->first_node("ref"); + const std::string id = nodeRef->first_attribute("id")->value(); + const std::string filename = idToFilename[id]; + const std::string meshPath = pathFolder + "/" + filename; + + if (meshes.find(filename) == meshes.end()) { + meshes[filename] = sibr::Mesh(); + if (!meshes[filename].load(meshPath)) { + return false; + } + + } + + std::cout << "Adding one instance of : " << filename << std::endl; + + rapidxml::xml_node<>* nodeTrans = node->first_node("transform"); + if (nodeTrans) { + sibr::Mesh toWorldMesh = meshes[filename]; + rapidxml::xml_node<>* nodeM1 = nodeTrans->first_node("matrix"); + std::string matrix1 = nodeM1->first_attribute("value")->value(); + rapidxml::xml_node<>* nodeM2 = nodeM1->next_sibling("matrix"); + std::string matrix2 = nodeM2->first_attribute("value")->value(); + + + std::istringstream issM1(matrix1); + std::vector splitM1(std::istream_iterator{issM1}, + std::istream_iterator()); + sibr::Matrix4f m1; + m1 << + std::stof(splitM1[0]), std::stof(splitM1[1]), std::stof(splitM1[2]), std::stof(splitM1[3]), + std::stof(splitM1[4]), std::stof(splitM1[5]), std::stof(splitM1[6]), std::stof(splitM1[7]), + std::stof(splitM1[8]), std::stof(splitM1[9]), std::stof(splitM1[10]), std::stof(splitM1[11]), + std::stof(splitM1[12]), std::stof(splitM1[13]), std::stof(splitM1[14]), std::stof(splitM1[15]); + + std::istringstream issM2(matrix2); + std::vector splitM2(std::istream_iterator{issM2}, + std::istream_iterator()); + sibr::Matrix4f m2; + m2 << + std::stof(splitM2[0]), std::stof(splitM2[1]), std::stof(splitM2[2]), std::stof(splitM2[3]), + std::stof(splitM2[4]), std::stof(splitM2[5]), std::stof(splitM2[6]), std::stof(splitM2[7]), + std::stof(splitM2[8]), std::stof(splitM2[9]), std::stof(splitM2[10]), std::stof(splitM2[11]), + std::stof(splitM2[12]), std::stof(splitM2[13]), std::stof(splitM2[14]), std::stof(splitM2[15]); + + sibr::Mesh::Vertices vertices; + for (int v = 0; v < toWorldMesh.vertices().size(); v++) { + sibr::Vector4f v4(toWorldMesh.vertices()[v].x(), toWorldMesh.vertices()[v].y(), toWorldMesh.vertices()[v].z(), 1.0); + vertices.push_back((m2 * (m1 * v4)).xyz()); + + } + + toWorldMesh.vertices(vertices); + merge(toWorldMesh); + + } + else { + merge(meshes[filename]); + } + + + } + else if (strcmp(node->first_attribute()->name(), "type") == 0 && + strcmp(node->first_attribute()->value(), "obj") == 0 + ) { + rapidxml::xml_node<>* nodeRef = node->first_node("string"); + const std::string filename = nodeRef->first_attribute("value")->value(); + const std::string meshPath = pathFolder + "/" + filename; + + if (meshes.find(filename) == meshes.end()) { + meshes[filename] = sibr::Mesh(); + if (!meshes[filename].load(meshPath)) { + return false; + } + + } + + std::cout << "Adding one instance of : " << filename << std::endl; + + rapidxml::xml_node<>* nodeTrans = node->first_node("transform"); + if (nodeTrans) { + sibr::Mesh toWorldMesh = meshes[filename]; + rapidxml::xml_node<>* nodeM1 = nodeTrans->first_node("matrix"); + std::string matrix1 = nodeM1->first_attribute("value")->value(); + + + std::istringstream issM1(matrix1); + std::vector splitM1(std::istream_iterator{issM1}, + std::istream_iterator()); + sibr::Matrix4f m1; + m1 << + std::stof(splitM1[0]), std::stof(splitM1[1]), std::stof(splitM1[2]), std::stof(splitM1[3]), + std::stof(splitM1[4]), std::stof(splitM1[5]), std::stof(splitM1[6]), std::stof(splitM1[7]), + std::stof(splitM1[8]), std::stof(splitM1[9]), std::stof(splitM1[10]), std::stof(splitM1[11]), + std::stof(splitM1[12]), std::stof(splitM1[13]), std::stof(splitM1[14]), std::stof(splitM1[15]); + + + sibr::Mesh::Vertices vertices; + for (int v = 0; v < toWorldMesh.vertices().size(); v++) { + sibr::Vector4f v4(toWorldMesh.vertices()[v].x(), toWorldMesh.vertices()[v].y(), toWorldMesh.vertices()[v].z(), 1.0); + vertices.push_back((m1 * v4).xyz()); + + } + + toWorldMesh.vertices(vertices); + merge(toWorldMesh); + + } + else { + merge(meshes[filename]); + } + + + } + } + + return true; + + } + + void Mesh::save(const std::string& filename, bool universal, const std::string &textureName) const + { + if (vertices().empty()) + SIBR_ERR << "cannot save this mesh (no vertices found)" << std::endl; + // This function is a just a switch (so we can change format details + // internally). + + const std::string ext = sibr::getExtension(filename); + if (ext == "obj") { + saveToObj(filename); + } + else { + // If you encounter problem with the resulting mesh, you can switch + // to the ASCII version for easy reading + // Meshlab does not support uint16 colors, if you want to use the mesh in such + // program, set 'universal' = true + if (universal) { + saveToASCIIPLY(filename, true, textureName); + } + else { + saveToBinaryPLY(filename, false); + } + } + + } + + void Mesh::vertices(const std::vector& vertices) + { + _gl.dirtyBufferGL = true; + _vertices.clear(); + + // iterator for values + std::vector::const_iterator it = vertices.begin(); + + // + while (it != vertices.end()) + { + Vector3f vertex; + + for (int i = 0; i < 3; ++i, ++it) + vertex[i] = (*it); + + _vertices.push_back(vertex); + } + } + + void Mesh::triangles(const std::vector& triangles) + { + _gl.dirtyBufferGL = true; + _triangles.clear(); + + // iterator for values + std::vector::const_iterator it = triangles.begin(); + + // + while (it != triangles.end()) + { + Vector3u triangle; + + for (int i = 0; i < 3; ++i, ++it) + triangle[i] = (*it); + + _triangles.push_back(triangle); + } + } + + void Mesh::texCoords(const std::vector& texcoords) + { + _gl.dirtyBufferGL = true; + _texcoords.clear(); + + // iterator for values + std::vector::const_iterator it = texcoords.begin(); + + // + while (it != texcoords.end()) + { + Vector2f texcoord; + + for (int i = 0; i < 2; ++i, ++it) + texcoord[i] = (*it); + + _texcoords.push_back(texcoord); + } + } + + void Mesh::normals(const std::vector& normals) + { + _gl.dirtyBufferGL = true; + _normals.clear(); + + // iterator for values + std::vector::const_iterator it = normals.begin(); + + // + while (it != normals.end()) + { + Vector3f normal; + + for (int i = 0; i < 3; ++i, ++it) + normal[i] = (*it); + + _normals.push_back(normal); + } + } + + void Mesh::generateNormals(void) + { + + // will store a list of normals (of all triangles around each vertex) + std::vector> vertexNormals(_vertices.size()); + + auto normalizeNormal = [](const Vector3f& normal) -> Vector3f { + float len = normal.norm(); + if (len > std::numeric_limits::epsilon()) + return normal / len; + //else // may happen on tiny sharp edge, in this case points up + return Vector3f(0.f, 1.f, 0.f); + }; + + int i = 0; + for (const Vector3u& tri : _triangles) + { + i++; + if (tri[0] > _vertices.size() || tri[1] > _vertices.size() || + tri[2] > _vertices.size()) { + SIBR_ERR << "Incorrect indices (" << i << ") " << tri[0] << ":" << tri[1] << ":" << tri[2] << std::endl; + } + else { + Vector3f u = _vertices[tri[0]] - _vertices[tri[2]]; + Vector3f v = _vertices[tri[0]] - _vertices[tri[1]]; + Vector3f normal = normalizeNormal(u.cross(v)); + + vertexNormals[tri[0]].push_back(normal); + vertexNormals[tri[1]].push_back(normal); + vertexNormals[tri[2]].push_back(normal); + } + } + + _normals.resize(vertexNormals.size()); + for (uint i = 0; i < _normals.size(); ++i) + { + Vector3f n = std::accumulate(vertexNormals[i].begin(), vertexNormals[i].end(), Vector3f(0.f, 0.f, 0.f)); + n = (n / (float)vertexNormals.size()); + n = normalizeNormal(n); + _normals[i] = -n; + } + + _gl.dirtyBufferGL = true; + } + + void Mesh::generateSmoothNormals(int numIter) + { + SIBR_LOG << "Generate vertex normals..." << std::endl; + // will store a list of normals (of all triangles around each vertex) + std::vector> vertexNormals(_vertices.size()); + + auto normalizeNormal = [](const Vector3f& normal) -> Vector3f { + float len = normal.norm(); + if (len > std::numeric_limits::epsilon()) + return normal / len; + //else // may happen on tiny sharp edge, in this case points up + return Vector3f(0.f, 1.f, 0.f); + }; + + + for (int i = 0; i < _triangles.size(); i++) + { + const Vector3u& tri = _triangles[i]; + if (tri[0] > _vertices.size() || tri[1] > _vertices.size() || + tri[2] > _vertices.size()) { + SIBR_ERR << "Incorrect indices (" << i << ") " << tri[0] << ":" << tri[1] << ":" << tri[2] << std::endl; + } + else { + Vector3f u = _vertices[tri[1]] - _vertices[tri[0]]; + Vector3f v = _vertices[tri[2]] - _vertices[tri[0]]; + Vector3f normal = u.cross(v); + + vertexNormals[tri[0]].push_back(normal); + vertexNormals[tri[1]].push_back(normal); + vertexNormals[tri[2]].push_back(normal); + } + } + + _normals.resize(vertexNormals.size()); + //#pragma omp parallel for + for (int i = 0; i < _normals.size(); ++i) + { + Vector3f n = std::accumulate(vertexNormals[i].begin(), vertexNormals[i].end(), Vector3f(0.f, 0.f, 0.f)); + if (numIter == 0)//no iteration + n = normalizeNormal(n); + _normals[i] = n; + } + + //Here we computed normals based on surrounding triangles + + for (int it = 0; it < numIter; it++) { + + std::vector> vertexNormalsIter(_vertices.size()); + + for (int i = 0; i < _triangles.size(); i++) + { + const Vector3u& tri = _triangles[i]; + if (tri[0] > _vertices.size() || tri[1] > _vertices.size() || + tri[2] > _vertices.size()) { + SIBR_ERR << "Incorrect indices (" << i << ") " << tri[0] << ":" << tri[1] << ":" << tri[2] << std::endl; + } + else { + for (int tId = 0; tId < 3; tId++) { + Vector3f normal = _normals[tri[tId]]; + vertexNormalsIter[tri[(tId + 1) % 3]].push_back(normal); + vertexNormalsIter[tri[(tId + 2) % 3]].push_back(normal); + } + } + } + + float maxLength = 0.0f; + for (int i = 0; i < _normals.size(); ++i) + { + Vector3f n = std::accumulate(vertexNormalsIter[i].begin(), vertexNormalsIter[i].end(), Vector3f(0.f, 0.f, 0.f)); + if (it + 1 == numIter)//last iteration + n = normalizeNormal(n); + _normals[i] = n; + maxLength = std::max(maxLength, _normals[i].norm()); + } + + // To avoid float overflow after multiple iterations, we need to normalize. + // But we can't just normalize each normal separately because we want to + // preserve the relative triangle area weighting. + // So instead we just send everything in [0,1] each time apart from the last iteration. + if (maxLength > 0.0f && (it + 1 < numIter)) { + for (int i = 0; i < _normals.size(); ++i) + { + _normals[i] /= maxLength; + } + } + + } + + _gl.dirtyBufferGL = true; + } + + void Mesh::generateSmoothNormalsDisconnected(int numIter) + { + SIBR_LOG << "Generate vertex normals..." << std::endl; + // will store a list of normals (of all triangles around each vertex) + std::vector> vertexNormals(_vertices.size()); + + auto normalizeNormal = [](const Vector3f& normal) -> Vector3f { + float len = normal.norm(); + if (len > std::numeric_limits::epsilon()) + return normal / len; + //else // may happen on tiny sharp edge, in this case points up + return Vector3f(0.f, 1.f, 0.f); + }; + + std::vector> vertCopy; + for (int i = 0; i < _vertices.size(); ++i) + { + vertCopy.push_back(std::make_pair(_vertices[i], i)); + } + + std::sort(vertCopy.begin(), vertCopy.end()); + + for (int i = 0; i < 100; ++i) + { + std::cout << "\t " << vertCopy[i].first << std::endl; + } + + std::vector v2firstCopy(_vertices.size(), -1); + int dupCount = 0; + for (int i = 0; i < _vertices.size(); ++i) + { + if (i % 1000 == 0) + std::cout << "\t " << i << " of " << _vertices.size() << std::endl; + + int ii = i - 1; + if ((vertCopy[ii].first - vertCopy[i].first).norm() > 0.000001f) { + + v2firstCopy[vertCopy[i].second] = vertCopy[i].second; + continue; + } + else { + dupCount++; + v2firstCopy[vertCopy[i].second] = v2firstCopy[vertCopy[ii].second]; + } + + } + + std::cout << "Duplicates found :" << dupCount << std::endl; + + for (int i = 0; i < _triangles.size(); i++) + { + const Vector3u& tri = _triangles[i]; + if (tri[0] > _vertices.size() || tri[1] > _vertices.size() || + tri[2] > _vertices.size()) { + SIBR_ERR << "Incorrect indices (" << i << ") " << tri[0] << ":" << tri[1] << ":" << tri[2] << std::endl; + } + else { + Vector3f u = _vertices[tri[1]] - _vertices[tri[0]]; + Vector3f v = _vertices[tri[2]] - _vertices[tri[0]]; + Vector3f normal = u.cross(v); + + vertexNormals[tri[0]].push_back(normal); + vertexNormals[tri[1]].push_back(normal); + vertexNormals[tri[2]].push_back(normal); + } + } + + sibr::Mesh::Normals normalsCopy; + normalsCopy.resize(vertexNormals.size()); + //#pragma omp parallel for + for (int i = 0; i < normalsCopy.size(); ++i) + { + normalsCopy[i] = sibr::Vector3f(0, 0, 0); + } + for (int i = 0; i < normalsCopy.size(); ++i) + { + Vector3f n = std::accumulate(vertexNormals[i].begin(), vertexNormals[i].end(), Vector3f(0.f, 0.f, 0.f)); + normalsCopy[v2firstCopy[i]] += n; + } + + //Here we computed normals based on surrounding triangles + + for (int it = 0; it < numIter; it++) { + + std::vector> vertexNormalsIter(_vertices.size()); + + for (int i = 0; i < _triangles.size(); i++) + { + const Vector3u& tri = _triangles[i]; + if (tri[0] > _vertices.size() || tri[1] > _vertices.size() || + tri[2] > _vertices.size()) { + SIBR_ERR << "Incorrect indices (" << i << ") " << tri[0] << ":" << tri[1] << ":" << tri[2] << std::endl; + } + else { + for (int tId = 0; tId < 3; tId++) { + Vector3f normal = normalsCopy[v2firstCopy[tri[tId]]]; + vertexNormalsIter[tri[(tId + 1) % 3]].push_back(normal); + vertexNormalsIter[tri[(tId + 2) % 3]].push_back(normal); + } + } + } + + //#pragma omp parallel for + for (int i = 0; i < normalsCopy.size(); ++i) + { + normalsCopy[i] = sibr::Vector3f(0, 0, 0); + } + for (int i = 0; i < normalsCopy.size(); ++i) + { + Vector3f n = std::accumulate(vertexNormalsIter[i].begin(), vertexNormalsIter[i].end(), Vector3f(0.f, 0.f, 0.f)); + normalsCopy[v2firstCopy[i]] += n; + } + + } + + _normals.resize(normalsCopy.size()); + for (int i = 0; i < _normals.size(); ++i) + { + _normals[i] += normalizeNormal(normalsCopy[v2firstCopy[i]]); + } + + _gl.dirtyBufferGL = true; + } + + void Mesh::laplacianSmoothing(int numIter, bool updateNormals) { + + if (numIter < 1) { + return; + } + + /// Build neighbors information. + /// \todo TODO: we could also detect vertices on the edges of the mesh to preserve their positions. + std::vector> neighbors(_vertices.size()); + for (const sibr::Vector3u& tri : _triangles) { + neighbors[tri[0]].emplace(tri[1]); + neighbors[tri[0]].emplace(tri[2]); + neighbors[tri[1]].emplace(tri[0]); + neighbors[tri[1]].emplace(tri[2]); + neighbors[tri[2]].emplace(tri[1]); + neighbors[tri[2]].emplace(tri[0]); + } + + /// Smooth by averaging. + const size_t verticesSize = _vertices.size(); + + for (int it = 0; it < numIter; ++it) { + std::vector newVertices(verticesSize); + + for (size_t vid = 0; vid < verticesSize; ++vid) { + newVertices[vid] = sibr::Vector3f(0.0f, 0.0f, 0.f); + for (const auto& ovid : neighbors[vid]) { + newVertices[vid] += _vertices[ovid]; + } + newVertices[vid] /= float(neighbors[vid].size()); + } + + vertices(newVertices); + } + + if (updateNormals) { + generateNormals(); + } + } + + void Mesh::adaptativeTaubinSmoothing(int numIter, bool updateNormals) { + + if (numIter < 1) { + return; + } + + /// Build neighbors information. + /// \todo TODO: we could also detect vertices on the edges of the mesh to preserve their positions. + std::vector> neighbors(_vertices.size()); + std::map>> cotanW; + for (const sibr::Vector3u& tri : _triangles) { + neighbors[tri[0]].emplace(tri[1]); + neighbors[tri[0]].emplace(tri[2]); + neighbors[tri[1]].emplace(tri[0]); + neighbors[tri[1]].emplace(tri[2]); + neighbors[tri[2]].emplace(tri[1]); + neighbors[tri[2]].emplace(tri[0]); + + std::vector vs; + for (int i = 0; i < 3; i++) + vs.push_back(_vertices[tri[i]]); + + for (int i = 0; i < 3; i++) { + float angle = acos((vs[i] - vs[(i + 2) % 3]).normalized().dot((vs[(i + 1) % 3] - vs[(i + 2) % 3]).normalized())); + cotanW[tri[i]][tri[(i + 1) % 3]].emplace(1.0f / (tan(angle) + 0.00001f)); + cotanW[tri[(i + 1) % 3]][tri[i]].emplace(1.0f / (tan(angle) + 0.00001f)); + } + + } + + /// Smooth by averaging. + const size_t verticesSize = _vertices.size(); + + std::vector newColors(verticesSize); + for (int it = 0; it < numIter; ++it) { + std::vector newVertices(verticesSize); +#pragma omp parallel for + for (int vid = 0; vid < verticesSize; ++vid) { + sibr::Vector3f v = _vertices[vid]; + sibr::Vector3f dtV = sibr::Vector3f(0.0f, 0.0f, 0.f); + float totalW = 0; + + std::vector colorsLocal; + colorsLocal.push_back(_colors[vid]); + for (const auto& ovid : neighbors[vid]) { + float w = 0; + for (const auto& cot : cotanW[vid][ovid]) { + w += 0.5 * cot; + } + totalW += w; + dtV += w * _vertices[ovid]; + colorsLocal.push_back(_colors[ovid]); + } + + sibr::Vector3f meanColor; + for (const auto& c : colorsLocal) { + meanColor += c; + } + meanColor /= colorsLocal.size(); + sibr::Vector3f varColor; + for (const auto& c : colorsLocal) { + pow(c.x() - meanColor.x(), 2); + varColor += sibr::Vector3f(pow(c.x() - meanColor.x(), 2), pow(c.y() - meanColor.y(), 2), pow(c.z() - meanColor.z(), 2)); + } + varColor /= colorsLocal.size(); + + newColors[vid] = varColor; + + if (totalW > 0) { + dtV /= totalW; + dtV = dtV - v; + if (it % 2 == 0) { + newVertices[vid] = v + 0.25 * dtV; + } + else { + newVertices[vid] = v + 0.25 * dtV; + } + } + } + + vertices(newVertices); + } + + colors(newColors); + if (updateNormals) { + generateNormals(); + } + } + + + + Mesh Mesh::generateSubMesh(std::function func) const + { + + sibr::Mesh::Vertices newVertices; + sibr::Mesh::Triangles newTriangles; + + sibr::Mesh::Colors newColors; + sibr::Mesh::Normals newNormals; + sibr::Mesh::UVs newUVs; + + std::map mapIdVert; + + int cmptValidVert = 0; + int cmptVert = 0; + + sibr::Mesh::Colors oldColors; + if (hasColors()) + oldColors = colors(); + + sibr::Mesh::Normals oldNormals; + if (hasNormals()) + oldNormals = normals(); + + sibr::Mesh::UVs oldUVs; + if (hasTexCoords()) + oldUVs = texCoords(); + + for (int v = 0; v < vertices().size(); v++) { + + if (func(v)) { + + newVertices.push_back(vertices()[v]); + + if (hasColors()) + newColors.push_back(oldColors[cmptVert]); + if (hasNormals()) + newNormals.push_back(oldNormals[cmptVert]); + if (hasTexCoords()) + newUVs.push_back(oldUVs[cmptVert]); + + mapIdVert[cmptVert] = cmptValidVert; + cmptValidVert++; + + } + else { + mapIdVert[cmptVert] = -1; + } + + cmptVert++; + + } + + for (sibr::Vector3u t : triangles()) { + + if (mapIdVert[t.x()] != -1 && + mapIdVert[t.y()] != -1 && + mapIdVert[t.z()] != -1) { + sibr::Vector3u newt(mapIdVert[t.x()], mapIdVert[t.y()], mapIdVert[t.z()]); + newTriangles.push_back(newt); + } + } + + Mesh newMesh; + newMesh.vertices(newVertices); + newMesh.triangles(newTriangles); + if (hasColors()) + newMesh.colors(newColors); + if (hasNormals()) + newMesh.normals(newNormals); + if (hasTexCoords()) + newMesh.texCoords(newUVs); + + return newMesh; + } + + void Mesh::forceBufferGLUpdate(bool adjacency) const + { + if (!_gl.bufferGL) { SIBR_ERR << "Tried to forceBufferGL on a non OpenGL Mesh" << std::endl; return; } + _gl.dirtyBufferGL = false; + _gl.bufferGL->build(*this, adjacency); + } + + void Mesh::freeBufferGLUpdate(void) const + { + _gl.dirtyBufferGL = false; + _gl.bufferGL->free(); + } + + void Mesh::render(bool depthTest, bool backFaceCulling, RenderMode mode, bool frontFaceCulling, bool invertDepthTest, bool tessellation, bool adjacency) const + { + if (!_gl.bufferGL) { SIBR_ERR << "Tried to render a non OpenGL Mesh" << std::endl; return; } + + if(adjacency && _renderingOptions.adjacency != adjacency) + { + _renderingOptions.adjacency = adjacency; + _gl.dirtyBufferGL = true; + } + + _renderingOptions.depthTest = depthTest; + _renderingOptions.backFaceCulling = backFaceCulling; + _renderingOptions.mode = mode; + _renderingOptions.frontFaceCulling = frontFaceCulling; + _renderingOptions.invertDepthTest = invertDepthTest; + _renderingOptions.tessellation = tessellation; + + if (_gl.dirtyBufferGL) + forceBufferGLUpdate(adjacency); + + if (depthTest) + glEnable(GL_DEPTH_TEST); + else + glDisable(GL_DEPTH_TEST); + + if (backFaceCulling) + { + glEnable(GL_CULL_FACE); + if (!frontFaceCulling) + glCullFace(GL_BACK); + else + glCullFace(GL_FRONT); + } + else + glDisable(GL_CULL_FACE); + + if (invertDepthTest) { + glDepthFunc(GL_GEQUAL); + } + + switch (mode) + { + case sibr::Mesh::FillRenderMode: + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + break; + case sibr::Mesh::PointRenderMode: + glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); + break; + case sibr::Mesh::LineRenderMode: + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + break; + default: + break; + } + + if (_triangles.size() != 0) { + if (tessellation) { + _gl.bufferGL->drawTessellated(); + } + else { + _gl.bufferGL->draw(adjacency); + } + } + else if (_vertices.size() != 0) { + _gl.bufferGL->draw_points(); + } + + // Reset default state (Policy is 'restore default values') + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glDepthFunc(GL_LESS); + } + + void Mesh::renderSubMesh(unsigned int begin, unsigned int end, + bool depthTest, + bool backFaceCulling, + RenderMode mode, + bool frontFaceCulling, + bool invertDepthTest + ) const { + if (!_gl.bufferGL) { SIBR_ERR << "Tried to render a non OpenGL Mesh" << std::endl; return; } + if (_gl.dirtyBufferGL) + forceBufferGLUpdate(); + + if (depthTest) + glEnable(GL_DEPTH_TEST); + else + glDisable(GL_DEPTH_TEST); + + if (backFaceCulling) + { + glEnable(GL_CULL_FACE); + if (!frontFaceCulling) + glCullFace(GL_BACK); + else + glCullFace(GL_FRONT); + } + else + glDisable(GL_CULL_FACE); + + if (invertDepthTest) { + glDepthFunc(GL_GEQUAL); + } + + switch (mode) + { + case sibr::Mesh::FillRenderMode: + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + break; + case sibr::Mesh::PointRenderMode: + glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); + break; + case sibr::Mesh::LineRenderMode: + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + break; + default: + break; + } + + if (_triangles.size() != 0) { + _gl.bufferGL->draw(begin, end); + } + else if (_vertices.size() != 0) { + _gl.bufferGL->draw_points(begin, end); + } + + // Reset default state (Policy is 'restore default values') + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glDepthFunc(GL_LESS); + } + + + void Mesh::render_points(void) const + { + forceBufferGLUpdate(); + glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); + _gl.bufferGL->draw_points(); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } + + void Mesh::render_points(bool depthTest) const + { + if (depthTest) { + glEnable(GL_DEPTH_TEST); + } + else { + glDisable(GL_DEPTH_TEST); + } + + render_points(); + + glDisable(GL_DEPTH_TEST); + } + + void Mesh::render_lines(void) const + { + if (!_gl.bufferGL) { SIBR_ERR << "Tried to render a non OpenGL Mesh" << std::endl; return; } + if (_gl.dirtyBufferGL) + forceBufferGLUpdate(); + _gl.bufferGL->draw_lines(); + } + + Mesh::SubMesh Mesh::extractSubMesh(const std::vector& newVerticesIds, VERTEX_LIST_CHOICE v_choice) const + { + + int numOldVertices = (int)vertices().size(); + bool keep_from_list = (v_choice == VERTEX_LIST_CHOICE::KEEP); + std::vector willBeKept(numOldVertices, !keep_from_list); + for (int id : newVerticesIds) { + if (id >= 0 && id < numOldVertices) { + willBeKept[id] = keep_from_list; + } + } + + int numValidNewVertices = 0; + for (bool b : willBeKept) { + if (b) { + ++numValidNewVertices; + } + } + + std::vector oldToNewVertexId(numOldVertices, -1); + + sibr::Mesh::Vertices newVertices(numValidNewVertices); + sibr::Mesh::Triangles newTriangles; + + sibr::Mesh::Colors newColors; + sibr::Mesh::Normals newNormals; + sibr::Mesh::UVs newUVs; + + if (hasColors()) { + newColors.resize(numValidNewVertices); + } + if (hasNormals()) { + newNormals.resize(numValidNewVertices); + } + if (hasTexCoords()) { + newUVs.resize(numValidNewVertices); + } + + int new_vertex_id = 0; + for (int id = 0; id < numOldVertices; ++id) { + if (willBeKept[id]) { + newVertices[new_vertex_id] = vertices()[id]; + oldToNewVertexId[id] = new_vertex_id; + + if (hasColors()) { + newColors[new_vertex_id] = colors()[id]; + } + if (hasNormals()) { + newNormals[new_vertex_id] = normals()[id]; + } + if (hasTexCoords()) { + newUVs[new_vertex_id] = texCoords()[id]; + } + ++new_vertex_id; + } + } + + std::vector isInRemovedTriangle(numOldVertices, false); + for (const auto& t : triangles()) { + sibr::Vector3i newVerticesId = t.cast().unaryExpr([&oldToNewVertexId](int v_id) { return oldToNewVertexId[v_id]; }); + if (newVerticesId.unaryViewExpr([](int v_id) { return v_id >= 0 ? 1 : 0; }).all()) { + newTriangles.push_back(newVerticesId.cast()); + } + else { + for (int c = 0; c < 3; c++) { + isInRemovedTriangle[t[c]] = true; + } + } + } + + bool oldMeshHasGraphics = (_gl.bufferGL.get() != nullptr); + + Mesh::SubMesh subMesh; + subMesh.meshPtr = std::make_shared(oldMeshHasGraphics); + sibr::Mesh& mesh = *subMesh.meshPtr; + mesh.vertices(newVertices); + mesh.triangles(newTriangles); + if (hasColors()) { + mesh.colors(newColors); + } + if (hasNormals()) { + mesh.normals(newNormals); + } + if (hasTexCoords()) { + mesh.texCoords(newUVs); + } + + for (int id = 0; id < numOldVertices; ++id) { + if (isInRemovedTriangle[id]) { + subMesh.complementaryVertices.push_back(id); + } + } + + return subMesh; + } + + sibr::Mesh Mesh::invertedFacesMesh() const + { + sibr::Mesh invertedFacesMesh(_gl.bufferGL != nullptr); + invertedFacesMesh.vertices(vertices()); + if (hasColors()) { + invertedFacesMesh.colors(colors()); + } + if (hasNormals()) { + invertedFacesMesh.normals(normals()); + } + if (hasTexCoords()) { + invertedFacesMesh.texCoords(texCoords()); + } + + sibr::Mesh::Triangles invertedTriangles(triangles().size()); + for (int t_id = 0; t_id < (int)triangles().size(); ++t_id) { + invertedTriangles[t_id] = triangles()[t_id].yxz(); + } + invertedFacesMesh.triangles(invertedTriangles); + + return invertedFacesMesh; + } + + sibr::Mesh::Ptr Mesh::invertedFacesMesh2() const + { + auto invertedFacesMesh = std::make_shared(_gl.bufferGL != nullptr); + + int nVertices = (int)vertices().size(); + int nTriangles = (int)triangles().size(); + + Mesh::Vertices Nvertices(2 * nVertices); + Mesh::Triangles Ntriangles(2 * nTriangles); + Mesh::Colors Ncolors(hasColors() ? 2 * nVertices : 0); + Mesh::Normals Nnormals(hasNormals() ? 2 * nVertices : 0); + Mesh::UVs Nuvs(hasTexCoords() ? 2 * nVertices : 0); + + int v_id = 0; + for (const auto& v : vertices()) { + Nvertices[v_id] = v; + Nvertices[v_id + nVertices] = v; + + if (hasNormals()) { + Nnormals[v_id] = normals()[v_id]; + Nnormals[v_id + nVertices] = -normals()[v_id]; + } + + if (hasColors()) { + Ncolors[v_id] = colors()[v_id]; + Ncolors[v_id + nVertices] = colors()[v_id]; + } + + if (hasTexCoords()) { + Nuvs[v_id] = texCoords()[v_id]; + Nuvs[v_id + nVertices] = texCoords()[v_id]; + } + + ++v_id; + } + invertedFacesMesh->vertices(Nvertices); + + if (hasNormals()) { + invertedFacesMesh->normals(Nnormals); + } + if (hasColors()) { + invertedFacesMesh->colors(Ncolors); + } + if (hasTexCoords()) { + invertedFacesMesh->texCoords(Nuvs); + } + + sibr::Vector3u shift(nVertices, nVertices, nVertices); + int t_id = 0; + for (const auto& t : triangles()) { + Ntriangles[t_id] = t; + Ntriangles[t_id + nTriangles] = t.yxz() + shift; + ++t_id; + } + invertedFacesMesh->triangles(Ntriangles); + + return invertedFacesMesh; + } + + const std::string Mesh::getMeshFilePath(void) const + { + return _meshPath; + } + + void Mesh::getBoundingSphere(Vector3f& outCenter, float& outRadius, bool referencedOnly, bool usePCcenter) const + { + // Get the center of mass + + double totalArea = 0, currentArea; + double xCenter = 0, yCenter = 0, zCenter = 0; + + const Triangles& tri = _triangles; + const Vertices& vert = _vertices; + if (usePCcenter) { + sibr::Vector3d outCenterDbl; + for (const Vector3f& v : vert) + { + outCenterDbl += v.cast(); + } + + outCenter = (outCenterDbl / vert.size()).cast(); + } + else { + if (tri.size() == 0) { + SIBR_WRG << "No triangles found for evaluation of sphere center, result will be NaN"; + } + for (const Vector3u& t : tri) + { + float trix1 = vert[t[0]].x(); + float triy1 = vert[t[0]].y(); + float triz1 = vert[t[0]].z(); + + float trix2 = vert[t[1]].x(); + float triy2 = vert[t[1]].y(); + float triz2 = vert[t[1]].z(); + + float trix3 = vert[t[2]].x(); + float triy3 = vert[t[2]].y(); + float triz3 = vert[t[2]].z(); + + currentArea = ((vert[t[1]] - vert[t[0]]).cross(vert[t[2]] - vert[t[0]])).norm() / 2.0; + totalArea += currentArea; + + xCenter += ((trix1 + trix2 + trix3) / 3) * currentArea; + yCenter += ((triy1 + triy2 + triy3) / 3) * currentArea; + zCenter += ((triz1 + triz2 + triz3) / 3) * currentArea; + } + + outCenter = Vector3f(float(xCenter / totalArea), float(yCenter / totalArea), float(zCenter / totalArea)); + } + + + outRadius = 0.f; + if (referencedOnly) { + for (const Vector3u& t : tri) + { + outRadius = std::max(outRadius, distance(vert[t[0]], outCenter)); + outRadius = std::max(outRadius, distance(vert[t[1]], outCenter)); + outRadius = std::max(outRadius, distance(vert[t[2]], outCenter)); + } + } + else { + for (const Vector3f& v : vert) + outRadius = std::max(outRadius, distance(v, outCenter)); + } + } + + + Eigen::AlignedBox Mesh::getBoundingBox(void) const + { + Eigen::AlignedBox box; + for (const auto& vertex : _vertices) { + box.extend(vertex); + } + return box; + } + + sibr::Mesh::Ptr sibr::Mesh::getEnvSphere(sibr::Vector3f center, float radius, sibr::Vector3f zenith, sibr::Vector3f north, + PartOfSphere part) { + + sibr::Vector3f east = north.cross(zenith); + sibr::Mesh::Ptr envMesh(new sibr::Mesh()); + sibr::Mesh::Vertices vert; + sibr::Mesh::UVs uvs; + sibr::Mesh::Triangles tri; + + int highLimit = 0, lowLimit = 0; + switch (part) + { + case PartOfSphere::WHOLE: + highLimit = 90; + lowLimit = -90; + break; + case PartOfSphere::UP: + highLimit = 90; + lowLimit = 0; + break; + case PartOfSphere::BOTTOM: + highLimit = 0; + lowLimit = -90; + break; + } + + for (int lat = lowLimit; lat <= highLimit; lat++) { + for (int lgt = 0; lgt <= 360; lgt++) { + + sibr::Vector3f point = cos(0.5 * M_PI * lat / 90.0f) * (cos(2 * M_PI * lgt / 360.0f) * north + sin(2 * M_PI * lgt / 360.0f) * east) + + sin(0.5 * M_PI * lat / 90.0f) * zenith; + + vert.push_back(10.f * radius * point + center); + + uvs.push_back(sibr::Vector2f(lgt / 360.0f, 0.5 + lat / 180.0f)); + + } + } + + for (int lat = lowLimit; lat < highLimit; lat++) { + for (int lgt = 0; lgt < 360; lgt++) { + + int delta = 1; + int lgtShift = lgt + 361 * (lat - lowLimit); + tri.push_back(sibr::Vector3u(lgtShift, lgtShift + delta, lgtShift + 361 + delta)); + tri.push_back(sibr::Vector3u(lgtShift, lgtShift + 361 + delta, lgtShift + 361)); + } + } + envMesh->vertices(vert); + envMesh->texCoords(uvs); + envMesh->triangles(tri); + + return envMesh; + } + + sibr::Vector3f Mesh::centroid() const + { + sibr::Vector3d centroid(0, 0, 0); + for (auto& vertex : _vertices) { + centroid += vertex.cast(); + } + if (_vertices.size() > 0) { + centroid /= static_cast(_vertices.size()); + } + return centroid.cast(); + } + + std::stringstream Mesh::getOffStream(bool verbose) const + { + if (verbose) { + std::cout << "[sibr::Mesh::getOffStream()] ... " << std::flush; + } + + std::stringstream s; + s << "OFF \n \n" << vertices().size() << " " << triangles().size() << " 0 " << std::endl; + + for (const auto& v : vertices()) { + s << v.x() << " " << v.y() << " " << v.z() << std::endl; + } + + for (const auto& t : triangles()) { + s << "3 " << t.x() << " " << t.y() << " " << t.z() << std::endl; + } + + if (verbose) { + std::cout << " done " << std::endl; + } + + return s; + } + + void Mesh::fromOffStream(std::stringstream& stream, bool computeNormals) + { + int n_vert; + int n_faces; + int n_edges; + + std::string line; + safeGetline(stream, line); + safeGetline(stream, line); + std::istringstream iss(line); + + iss >> n_vert >> n_faces >> n_edges; + + _vertices.resize(n_vert); + for (int v = 0; v < n_vert; ++v) { + safeGetline(stream, line); + std::istringstream lineStream(line); + + lineStream >> _vertices[v][0] >> _vertices[v][1] >> _vertices[v][2]; + + } + + _triangles.resize(0); + _triangles.reserve(3 * n_faces); + int face_size; + for (int t = 0; t < n_faces; ++t) { + safeGetline(stream, line); + std::istringstream lineStream(line); + + lineStream >> face_size; + + if (face_size == 3) { + sibr::Vector3u t; + lineStream >> t[0] >> t[1] >> t[2]; + _triangles.push_back(t); + + } + else if (face_size == 4) { + sibr::Vector3u t1, t2; + lineStream >> t1[0] >> t1[1] >> t1[2] >> t2[2]; + t2[0] = t1[0]; + t2[1] = t1[2]; + _triangles.push_back(t1); + _triangles.push_back(t2); + } + } + + if (computeNormals) { + generateNormals(); + } + + if (_gl.bufferGL.get()) { + _gl.dirtyBufferGL = true; + } + } + + sibr::Mesh::Ptr Mesh::getTestCube(bool withGraphics) + { + std::vector vertices = { + { +1, +1, +1 }, { -1, +1, +1 }, { -1, -1, +1 }, + { +1, -1, +1 }, { +1, +1, -1 }, { -1, +1, -1 }, + { -1, -1, -1 }, { +1, -1, -1 } + }; + + std::vector indices = { + { 0, 1, 2 }, { 0, 2, 3 }, { 7, 4, 0 }, { 7, 0, 3 }, { 4, 5, 1 }, + { 4, 1, 0 }, { 5, 6, 2 }, { 5, 2, 1 }, { 3, 2, 6 }, { 3, 6, 7 }, + { 6, 5, 4 }, { 6, 4, 7 } + }; + + sibr::Mesh::Ptr mesh(new sibr::Mesh(withGraphics)); + mesh->vertices(vertices); + mesh->triangles(indices); + mesh->generateNormals(); + + return mesh; + } + + Mesh::Ptr Mesh::getSphereMesh(const Vector3f& center, float radius, bool withGraphics, int precision) { + const int nTheta = precision; + const int nPhi = precision; + const int nPoints = nTheta * nPhi; + std::vector vertices(nPoints), normals(nPoints); + + for (int t = 0; t < nTheta; ++t) { + double theta = (t / (double)(nTheta - 1)) * M_PI; + double cosT = std::cos(theta); + double sinT = std::sin(theta); + for (int p = 0; p < nPhi; ++p) { + double phi = 2.0 * (p / (double)(nPhi - 1) - 0.5) * M_PI; + double cosP = std::cos(phi), sinP = std::sin(phi); + normals[p + nPhi * t] = Vector3d(sinT * cosP, sinT * sinP, cosT).cast(); + vertices[p + nPhi * t] = center + radius * normals[p + nPhi * t]; + } + } + + std::vector indices(6 * (nTheta - 1) * nPhi); + int triangle_id = 0; + for (int t = 0; t < nTheta - 1; ++t) { + for (int p = 0; p < nPhi; ++p) { + int current_id = p + nPhi * t; + int offset_row = 1 - (p == nPhi - 1 ? nPhi : 0); + int next_in_row = current_id + offset_row; + int next_in_col = current_id + nPhi; + int next_next = next_in_col + offset_row; + indices[3 * triangle_id + 0] = current_id; + indices[3 * triangle_id + 1] = next_in_col; + indices[3 * triangle_id + 2] = next_in_row; + indices[3 * triangle_id + 3] = next_in_row; + indices[3 * triangle_id + 4] = next_in_col; + indices[3 * triangle_id + 5] = next_next; + triangle_id += 2; + } + } + + Mesh::Ptr sphereMesh = Mesh::Ptr(new Mesh(withGraphics)); + sphereMesh->vertices(vertices); + sphereMesh->normals(normals); + sphereMesh->triangles(indices); + + return sphereMesh; + } + + sibr::Mesh::Ptr Mesh::subDivide(float limitSize, size_t maxRecursion) const + { + struct Less { + bool operator()(const sibr::Vector3f& a, const sibr::Vector3f& b) const { + return a < b; + } + }; + + struct Edge { + sibr::Vector3f midPoint; + sibr::Vector3f midNormal; + std::vector triangles_ids; + float length; + int v_ids[2]; + }; + + struct Triangle { + Triangle() : edges_ids(std::vector(3, -1)), edges_flipped(std::vector(3, false)) {} + std::vector edges_ids; + std::vector edges_flipped; + }; + + auto subMeshPtr = std::make_shared(); + + std::map mapEdges; + std::vector edges; + std::vector tris(triangles().size()); + + int t_id = 0; + int e_id = 0; + for (const auto& t : triangles()) { + bool degenerate = false; + for (int k = 0; k < 3; ++k) { + int v0 = t[k]; + int v1 = t[(k + 1) % 3]; + // Skip degenerate faces. + if (v0 == v1) { + degenerate = true; + break; + } + const sibr::Vector3f midPoint = 0.5f * (vertices()[v0] + vertices()[v1]); + sibr::Vector3f midNormal(0.0f, 0.0f, 0.0f); + if (hasNormals()) { + midNormal = (0.5f * (normals()[v0] + normals()[v1])).normalized(); + } + + const float length = (vertices()[v0] - vertices()[v1]).norm(); + if (mapEdges.count(midPoint) == 0) { + mapEdges[midPoint] = e_id; + const Edge edge = { midPoint, midNormal, {t_id}, length, {v0,v1} }; + tris[t_id].edges_ids[k] = e_id; + edges.push_back(edge); + ++e_id; + } + else { + const int edge_id = mapEdges[midPoint]; + edges[edge_id].triangles_ids.push_back(t_id); + tris[t_id].edges_ids[k] = edge_id; + if (v0 != edges[edge_id].v_ids[0]) { + tris[t_id].edges_flipped[k] = true; + } + } + } + if (degenerate) { + continue; + } + ++t_id; + } + + const int nOldVertices = (int)vertices().size(); + sibr::Mesh::Vertices newVertices = vertices(); + sibr::Mesh::Normals newNormals = normals(); + + std::vector edge_to_divided_edges(edges.size(), -1); + + sibr::Mesh::Triangles newTriangles; + + bool dbg = false; + int num_divided_edges = 0; + for (const Triangle& t : tris) { + // Ignore undef triangles. + if (t.edges_ids[0] == -1 && t.edges_ids[1] == -1 && t.edges_ids[2] == -1) { + continue; + } + std::vector ks(3, -1); + std::vector non_ks(3, -1); + for (int k = 0; k < 3; ++k) { + const int e_id = t.edges_ids[k]; + if (edges[e_id].length > limitSize) { + if (ks[0] < 0) { + ks[0] = k; + } + else if (ks[1] < 0) { + ks[1] = k; + } + else { + ks[2] = k; + } + + if (edge_to_divided_edges[e_id] < 0) { + edge_to_divided_edges[e_id] = num_divided_edges; + newVertices.push_back(edges[e_id].midPoint); + newNormals.push_back(edges[e_id].midNormal); + ++num_divided_edges; + + } + + } + else { + if (non_ks[0] < 0) { + non_ks[0] = k; + } + } + } + + const sibr::Vector3i corners_ids = sibr::Vector3i(0, 1, 2).unaryViewExpr([&](int i) { + return edges[t.edges_ids[i]].v_ids[t.edges_flipped[i] ? 1 : 0]; + }); + const sibr::Vector3i midpoints_ids = sibr::Vector3i(0, 1, 2).unaryViewExpr([&](int i) { + return edge_to_divided_edges[t.edges_ids[i]] >= 0 ? nOldVertices + edge_to_divided_edges[t.edges_ids[i]] : -1; + }); + + if (ks[2] >= 0) { + newTriangles.push_back(sibr::Vector3u(corners_ids[0], midpoints_ids[0], midpoints_ids[2])); + newTriangles.push_back(sibr::Vector3u(corners_ids[1], midpoints_ids[1], midpoints_ids[0])); + newTriangles.push_back(sibr::Vector3u(corners_ids[2], midpoints_ids[2], midpoints_ids[1])); + newTriangles.push_back(midpoints_ids.cast()); + } + else if (ks[1] >= 0) { + const int candidate_edge_1_v_id_1 = corners_ids[non_ks[0]]; + const int candidate_edge_1_v_id_2 = midpoints_ids[(non_ks[0] + 1) % 3]; + const int candidate_edge_2_v_id_1 = corners_ids[(non_ks[0] + 1) % 3]; + const int candidate_edge_2_v_id_2 = midpoints_ids[(non_ks[0] + 2) % 3]; + const float candidate_edge_1_norm = (newVertices[candidate_edge_1_v_id_1] - newVertices[candidate_edge_1_v_id_2]).norm(); + const float candidate_edge_2_norm = (newVertices[candidate_edge_2_v_id_1] - newVertices[candidate_edge_2_v_id_2]).norm(); + if (candidate_edge_1_norm < candidate_edge_2_norm) { + newTriangles.push_back(sibr::Vector3u(candidate_edge_1_v_id_1, corners_ids[(non_ks[0] + 1) % 3], candidate_edge_1_v_id_2)); + newTriangles.push_back(sibr::Vector3u(candidate_edge_1_v_id_2, midpoints_ids[(non_ks[0] + 2) % 3], candidate_edge_1_v_id_1)); + } + else { + newTriangles.push_back(sibr::Vector3u(candidate_edge_2_v_id_1, candidate_edge_2_v_id_2, corners_ids[non_ks[0]])); + newTriangles.push_back(sibr::Vector3u(candidate_edge_2_v_id_1, midpoints_ids[(non_ks[0] + 1) % 3], candidate_edge_2_v_id_2)); + } + newTriangles.push_back(sibr::Vector3u(midpoints_ids[(non_ks[0] + 1) % 3], corners_ids[(non_ks[0] + 2) % 3], midpoints_ids[(non_ks[0] + 2) % 3])); + } + else if (ks[0] >= 0) { + newTriangles.push_back(sibr::Vector3u(midpoints_ids[ks[0]], corners_ids[(ks[0] + 1) % 3], corners_ids[(ks[0] + 2) % 3])); + newTriangles.push_back(sibr::Vector3u(midpoints_ids[ks[0]], corners_ids[(ks[0] + 2) % 3], corners_ids[ks[0]])); + } + else { + newTriangles.push_back(corners_ids.cast()); + } + } + std::cout << "." << std::flush; + + subMeshPtr->vertices(newVertices); + if (hasNormals()) { + subMeshPtr->normals(newNormals); + } + subMeshPtr->triangles(newTriangles); + if (num_divided_edges > 0 && maxRecursion > 0) { + return subMeshPtr->subDivide(limitSize, maxRecursion - 1); + } + + return subMeshPtr; + } + + float Mesh::meanEdgeSize() const + { + double sumSizes = 0; + for (const auto& t : triangles()) { + const auto& v1 = vertices()[t[0]]; + const auto& v2 = vertices()[t[1]]; + const auto& v3 = vertices()[t[2]]; + sumSizes += (double)((v1 - v2).norm() + (v2 - v3).norm() + (v3 - v1).norm()); + } + + return (float)(sumSizes / (3 * triangles().size())); + } + + Mesh::Ptr Mesh::clone() const + { + auto outMesh = std::make_shared(_gl.bufferGL != nullptr); + outMesh->vertices(vertices()); + outMesh->triangles(triangles()); + + if (hasNormals()) { + outMesh->normals(normals()); + } + + if (hasColors()) { + outMesh->colors(colors()); + } + + if (hasTexCoords()) { + outMesh->texCoords(texCoords()); + } + + return outMesh; + } + + void Mesh::merge(const Mesh& other) + { + bool withGraphics = (_gl.bufferGL != nullptr); + + if (_vertices.empty()) + { + this->operator = (other); + } + else + { + Vertices vertices; + Normals normals; + Colors colors; + UVs texcoords; + + const uint offset = static_cast(_vertices.size()); + Vector3u triOffset(offset, offset, offset); + Triangles triangles = other.triangles(); + + for (Vector3u& t : triangles) + t += triOffset; + + + if (hasNormals()) + _normals.insert(_normals.end(), other.normals().begin(), other.normals().end()); + + if (hasColors()) + _colors.insert(_colors.end(), other.colors().begin(), other.colors().end()); + + if (hasTexCoords()) + _texcoords.insert(_texcoords.end(), other.texCoords().begin(), other.texCoords().end()); + + + _vertices.insert(_vertices.end(), other.vertices().begin(), other.vertices().end()); + _triangles.insert(_triangles.end(), triangles.begin(), triangles.end()); + + } + + if (withGraphics) + _gl.bufferGL.reset(new MeshBufferGL); + } + + void sibr::Mesh::makeWhole(void) + { + if (!hasNormals()) + _normals = Normals(vertices().size()); + + if (!hasColors()) + _colors = Colors(vertices().size()); + + if (!hasTexCoords()) + _texcoords = UVs(vertices().size()); + + } + + void Mesh::eraseTriangles(const std::vector& faceIDList) + { + uint indexMax = 0; + for (uint i = 0; i < triangles().size(); ++i) + indexMax = std::max(indexMax, triangles()[i].maxCoeff()); + + std::vector faceToErase(triangles().size(), false); + for (uint faceID : faceIDList) + faceToErase[faceID] = true; + + + Mesh::Triangles newTris; + Mesh::Vertices newVerts; + std::vector indexRemap(indexMax + 1, -1); + + newTris.reserve(triangles().size()); + newVerts.reserve(vertices().size()); + + for (uint i = 0; i < triangles().size(); ++i) + { + if (faceToErase[i]) + continue; + + Vector3u t = triangles()[i]; + Vector3u newT; + for (uint j = 0; j < 3; ++j) + { + if (indexRemap[t[j]] == -1) + { + indexRemap[t[j]] = (int)newVerts.size(); + newVerts.push_back(vertices().at(t[j])); + } + newT[j] = (uint)indexRemap[t[j]]; + + } + + newTris.push_back(newT); + } + + if (hasColors()) + { + Mesh::Colors newColors(newVerts.size()); + for (uint i = 0; i < indexRemap.size(); ++i) + if (indexRemap[i] != -1) + newColors[indexRemap[i]] = colors().at(i); + colors(newColors); + } + + if (hasNormals()) + { + Mesh::Normals newNormals(newVerts.size()); + for (uint i = 0; i < indexRemap.size(); ++i) + if (indexRemap[i] != -1) + newNormals[indexRemap[i]] = normals().at(i); + normals(newNormals); + } + + + if (hasTexCoords()) + { + Mesh::UVs newUVs(newVerts.size()); + for (uint i = 0; i < indexRemap.size(); ++i) + if (indexRemap[i] != -1) + newUVs[indexRemap[i]] = texCoords().at(i); + texCoords(newUVs); + } + + triangles(newTris); + vertices(newVerts); + } + + std::vector > Mesh::removeDisconnectedComponents() + { + std::vector > allComponents; + + std::vector> v_triangles(vertices().size()); + int t_id = 0; + for (const auto& t : triangles()) { + for (int k = 0; k < 3; ++k) { + v_triangles[t[k]].push_back(t_id); + } + ++t_id; + } + + + std::vector wasVisited(vertices().size(), false); + int v_id = 0; + for (const auto& v : vertices()) { + + if (!wasVisited[v_id]) { + std::priority_queue next_ids; + next_ids.push(v_id); + wasVisited[v_id] = true; + + std::vector component; + + while (next_ids.size() > 0) { + int next_id = next_ids.top(); + next_ids.pop(); + component.push_back(next_id); + + for (int t : v_triangles[next_id]) { + for (int k = 0; k < 3; ++k) { + int other_v_id = triangles()[t][k]; + if (!wasVisited[other_v_id]) { + next_ids.push(other_v_id); + wasVisited[other_v_id] = true; + } + } + } + } + + allComponents.emplace_back(component); + } + ++v_id; + } + + return allComponents; + } + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Mesh.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Mesh.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4a06d50a2fab1db13ae94abd7368c4ee3de058c8 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Mesh.hpp @@ -0,0 +1,566 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include +# include +# include + +# include "core/graphics/Config.hpp" +# include "core/system/Vector.hpp" +# include "core/graphics/MeshBufferGL.hpp" +# include "core/graphics/Image.hpp" + +// Be sure to use STL objects from client's dll version by exporting this declaration (see warning C4251) +//template class SIBR_GRAPHICS_EXPORT std::vector; +//template class SIBR_GRAPHICS_EXPORT std::vector; + +namespace sibr +{ + /** Store both CPU and GPU data for a geometric mesh. + Provide many processing and display methods. + \ingroup sibr_graphics + */ + class SIBR_GRAPHICS_EXPORT Mesh + { + SIBR_CLASS_PTR(Mesh); + + public: + + typedef std::vector Vertices; + typedef std::vector Normals; + typedef std::vector Triangles; + typedef std::vector Colors; + typedef std::vector UVs; + + /** Mesh rendering mode. */ + enum RenderMode + { + PointRenderMode, + LineRenderMode, + FillRenderMode + }; + + /** Mesh rendering options. */ + struct RenderingOptions { + bool depthTest = true; ///< Should depth test be performed. + bool backFaceCulling = true; ///< Should back faces be culled. + RenderMode mode = FillRenderMode; ///< Rendering mode: points, lines, filled. + bool frontFaceCulling = false; ///< Cull fornt faces. + bool invertDepthTest = false; ///< Invert the depth test. + bool tessellation = false; ///< Is there a tessellation shader + bool adjacency = false; + }; + + + public: + + /** Constructor. + \param withGraphics init associated OpenGL buffers object (requires an openGL context) + */ + Mesh( bool withGraphics = true ); + + /** Set vertices. + \param vertices the new vertices + */ + inline void vertices(const Vertices& vertices); + + /** Set vertices from a vector of floats (linear). + \param vertices the new vertices + */ + void vertices( const std::vector& vertices ); + + /** \return a reference to the vertices. */ + inline const Vertices& vertices( void ) const; + + /** Update a specific vertex position + \param vertex_id the vertex location in the list + \param v the new value + \note If the mesh is used by the GPU, data will be udpated. + */ + inline void replaceVertice(int vertex_id, const sibr::Vector3f & v) ; + + /** \return a deep copy of the mesh. */ + Mesh::Ptr clone() const; + + /** \return vertices in an array using the following format: + {0x, 0y, 0z, 1x, 1y, 1z, 2x, 2y, 2z, ...}. + Useful for rendering and converting to another mesh + struct. + */ + inline const float* vertexArray( void ) const; + + /** Set triangles. Each triangle contains 3 indices and + each indice correspond to a vertex in the vertices list. + \param triangles the list of indices to use + */ + inline void triangles(const Triangles& triangles); + + /** Set triangles. Using a flat vector of uints. + \param triangles the new indices + */ + void triangles(const std::vector& triangles); + + /** \return a reference to the triangles list. */ + inline const Triangles& triangles( void ) const; + + /** \return triangles in an array using the following format: + {0a, 0b, 0c, 1a, 1b, 1c, 2a, 2b, 2c, ...}. + Useful for rendering and converting to another mesh + struct. + */ + inline const uint* triangleArray( void ) const; + + /** Set vertex colors. + \param colors the new vertex colors + */ + inline void colors( const Colors& colors ); + + /** \return a reference to the vertex color list. */ + inline const Colors& colors( void ) const; + + /** \return true if each vertex has a color assigned. */ + inline bool hasColors( void ) const; + + /** \return colors in an array using the following format: + {0r, 0g, 0b, 1r, 1g, 1b, 2r, 2g, 2b, ...}. + Useful for rendering and converting to another mesh + struct.*/ + inline const float* colorArray( void ) const; + + /** Set vertex texture coordinates. + \param texcoords the new vertex texture coordinates + */ + inline void texCoords( const UVs& texcoords ); + + /** Set texture coordinates using a flat vector of floats. + \param texcoords the new vertex texture coordinates + */ + void texCoords( const std::vector& texcoords ); + + /** \return a reference to the vertex texture coordinates list. */ + inline const UVs& texCoords( void ) const; + + /** \return true if each vertex has texture coordinates assigned. */ + inline bool hasTexCoords( void ) const; + + /** \return texture coordinate in an array using the following format: + {0u, 0v, 1u, 1v, 2u, 2v, ...} + Useful for rendering and converting to another mesh + struct.*/ + inline const float* texCoordArray( void ) const; + + /** \return texture image file name */ + std::string getTextureImageFileName() const { return _textureImageFileName; } + + /** Set vertex normals. + \param normals the new vertex normals + */ + inline void normals(const Normals& normals); + + /** Set normals using a flat vector of floats. + \param normals the new vertex normals + */ + void normals(const std::vector& normals); + + /** \return a reference to the vertex normals list. */ + inline const Normals& normals( void ) const; + + /** \return true if each vertex has a normal assigned. */ + inline bool hasNormals( void ) const; + + /** \return normals in an array using the following format: + {0x, 0y, 0z, 1x, 1y, 1z, 2x, 2y, 2z, ...}. + Useful for rendering and converting to another mesh + struct.*/ + inline const float* normalArray( void ) const; + + /** Make the mesh whole, ie it will have default values for all components (texture, materials, colors, etc) + It is useful when merging two meshes. If the second one is missing some attributes, the merging will break the mesh state if it isn't made whole. + */ + void makeWhole(void); + + /** Generate vertex normals by using the average of + all triangle normals around a each vertex. + */ + void generateNormals( void ); + + /** Generate smooth vertex normals by using the average of + all triangle normals around a each vertex and iterating this process. + Takes also the area of triangles as a weight. + \param numIter iteration count + */ + void generateSmoothNormals(int numIter); + + /** Generate smooth vertex normals by using the average of + all triangle normals around a each vertex and iterating this process. + Takes also the area of triangles as a weight. + This methods also consider the fact that because of texture coordinates we may have duplicates vertices + \param numIter iteration count + */ + void generateSmoothNormalsDisconnected(int numIter); + + /** Perform laplacian smoothing on the mesh vertices. + \param numIter smoothing iteration count + \param updateNormals should the normals be recomputed after smoothing + */ + void laplacianSmoothing(int numIter, bool updateNormals); + + /** Perform adaptive Taubin smoothing on the mesh vertices. + \param numIter smoothing iteration count + \param updateNormals should the normals be recomputed after smoothing + */ + void adaptativeTaubinSmoothing(int numIter, bool updateNormals); + + /** Generate a new mesh given a boolean function that + state if each vertex should be kept or not. + \param func the function that, based on a vertex ID, tells if it should be kept or not + \return the submesh + */ + Mesh generateSubMesh(std::function func) const; + + /** Load a mesh from the disk. + \param filename the file path + \return a success flag + \note Supports OBJ and PLY for now. + */ + bool load( const std::string& filename, const std::string& dataset_path = "" ); + /* test for SfM */ + bool loadSfM( const std::string& filename, const std::string& dataset_path = "" ); + + /** Load a scene from a set of mitsuba XML scene files (referencing multiple OBJs/PLYs). + It handles instances (duplicating the geoemtry and applying the per-instance transformation). + \param filename the file path + \return a success flag + */ + bool loadMtsXML(const std::string& filename); + + /** Save the mesh to the disk. When saving as a PLY, use the universal flag to indicate if you want this mesh to be readable + by most 3d applications (e.g. MeshLab). In this other case, the mesh will be saved with higher-precision custom PLY attributes. + \param filename the file path + \param universal if true, the mesh will be compatible with external 3D viewers + \param textureName name of a texture to reference in the file (Meshlab compatible) + \note Supports OBJ (ignoring the universal flag) and PLY for now. + */ + void save( const std::string& filename, bool universal=false, const std::string& textureName="TEXTURE_NAME_TO_PUT_IN_THE_FILE" ) const; + + /** Save the mesh to .ply file (using the binary version). + \param filename the file path + \param universal indicates if you want this mesh to be readable by most 3d viewer application (e.g. MeshLab). In this other case, the mesh will be saved with higher-precision custom PLY attributes. + \param textureName name of a texture to reference in the file (Meshlab compatible) + */ + bool saveToBinaryPLY( const std::string& filename, bool universal=false, const std::string& textureName = "TEXTURE_NAME_TO_PUT_IN_THE_FILE") const; + + /** Save the mesh to .ply file (using the ASCII version). + \param filename the file path + \param universal indicates if you want this mesh to be readable by most 3d viewer application (e.g. MeshLab). + \param textureName name of a texture to reference in the file (Meshlab compatible) + In this other case, the mesh will be saved with higher-precision custom PLY attributes. + */ + bool saveToASCIIPLY( const std::string& filename, bool universal=false, const std::string& textureName="TEXTURE_NAME_TO_PUT_IN_THE_FILE" ) const; + + /** Save the mesh to .obj file. + \param filename the file path + \warning the vertex colros won't be saved + */ + bool saveToObj( const std::string& filename) const; + + /* Export to OFF file format stream, can be used to convert to CGAL mesh data structures. + \param verbose display additional info + \return a stream containing the content of the mesh in the OFF format + */ + std::stringstream getOffStream(bool verbose = false) const; + + /* Load from OFF file format stream, can be used to convert from CGAL mesh data structures. + \param stream a stream containing the content of the mesh in the OFF format + \param generateNormals should the normals be generated + */ + void fromOffStream(std::stringstream& stream, bool generateNormals = true); + + /** Render the geometry using OpenGL. + \param depthTest should depth testing be performed + \param backFaceCulling should culling be performed + \param mode the primitives rendering mode + \param frontFaceCulling should the culling test be flipped + \param invertDepthTest should the depth test be flipped (GL_GREATER_THAN) + \param tessellation should the rendering call tesselation shaders + \param adjacency should we get adjacent triangles info in geometry shader + */ + void render( + bool depthTest = true, + bool backFaceCulling = true, + RenderMode mode = FillRenderMode, + bool frontFaceCulling = false, + bool invertDepthTest = false, + bool tessellation = false, + bool adjacency = false + ) const; + + /** Render a part of the geometry (taken either from the index buffer or directly in the vertex buffer) using OpenGL. + \param begin first item to render index + \param end last item to render index + \param depthTest should depth testing be performed + \param backFaceCulling should culling be performed + \param mode the primitives rendering mode + \param frontFaceCulling should the culling test be flipped + \param invertDepthTest should the depth test be flipped (GL_GREATER_THAN) + */ + void renderSubMesh(unsigned int begin, unsigned int end, + bool depthTest = true, + bool backFaceCulling = true, + RenderMode mode = FillRenderMode, + bool frontFaceCulling = false, + bool invertDepthTest = false + ) const; + + /** Force upload of data to the GPU. + \param adjacency should we give adjacent triangles info in buffer + */ + void forceBufferGLUpdate( bool adjacency = false ) const; + + /** Delete GPU mesh data. */ + void freeBufferGLUpdate(void) const; + + /** Render the mesh vertices as points. + \param depthTest should depth testing be performed + */ + void render_points(bool depthTest) const; + + /** Render the mesh vertices as points. + \note The depth test state will be whatever it is currently set to. + */ + void render_points(void) const; + + /** Render the mesh vertices as successive lines. + \note The depth test state will be whatever it is currently set to. + */ + void render_lines(void) const; + + /** Merge another mesh into this one. + \param other the mesh to merge + \sa makeWhole + */ + void merge( const Mesh& other ); + + /** Erase some of the triangles. + \param faceIDList a list of triangle IDs to erase + */ + void eraseTriangles(const std::vector& faceIDList); + + /** Submesh extraction options. */ + enum class VERTEX_LIST_CHOICE { KEEP, REMOVE }; + + /** Submesh structure. */ + struct SubMesh { + std::shared_ptr meshPtr; ///< Mesh composed of the extracted vertices. + std::vector complementaryVertices; /// < Vertices present in at least one removed triangle, can be used as an arg to extractSubMesh() to get the complementary mesh. + }; + + /** Extract a submesh based on a list of vertices to keep/remove. + \param vertices a list of vertex indices + \param v_choice should the listed vertices be removed or kept + \return the extracted submesh with additional information + */ + SubMesh extractSubMesh(const std::vector & vertices, VERTEX_LIST_CHOICE v_choice) const; + + /** \return a copy of the mesh with inverted faces (flipping IDs). */ + sibr::Mesh invertedFacesMesh() const; + + /** \return a copy of the mesh with "doubled" faces (obtained by merging the current mesh with a copy with inverted faces. */ + sibr::Mesh::Ptr invertedFacesMesh2() const; + + /** \return the path the mesh was loaded from. */ + inline const std::string getMeshFilePath( void ) const; + + /** \return the mesh bouding box. */ + Eigen::AlignedBox getBoundingBox( void ) const; + + /** \return the mesh centroid. */ + sibr::Vector3f centroid() const; + + /** Estimated the mesh bounding sphere. + \param outCenter will contain the sphere center + \param outRadius will contain the sphere radius + \param referencedOnly if true, only consider vertices that are part of at least one face + \param usePCcenter if true, only consider vertices for center computation. Intended to be true when using the function on point clouds. + */ + void getBoundingSphere(Vector3f& outCenter, float& outRadius, bool referencedOnly=false, bool usePCcenter=false) const; + + /** Subdivide a mesh triangles until an edge size threshold is reached. + \param limitSize the maximum edge length allowed + \param maxRecursion maximum subdivision iteration count + \return the subdivided mesh + \bug SR: Can be stuck in a loop in some cases. + */ + sibr::Mesh::Ptr subDivide(float limitSize, size_t maxRecursion = std::numeric_limits::max()) const; + + /** \return the mean edge size computed over all triangles. */ + float meanEdgeSize() const; + + /** Split a mesh in its connected components. + \return a list of list of vertex indices, each list defining a component + */ + std::vector > removeDisconnectedComponents(); + + /** Generate a simple cube with normals. + \param withGraphics should the mesh be on the GPU + \return a cube mesh + */ + static sibr::Mesh::Ptr getTestCube(bool withGraphics = true); + + /** Generate a sphere mesh. + \param center the sphere center + \param radius the sphere radius + \param withGraphics should the mesh be on the GPU + \param precision number of subdivisions on each dimension + \return the sphere mesh + */ + static Mesh::Ptr getSphereMesh(const Vector3f& center, float radius, bool withGraphics = true, int precision = 50); + + /** Environment sphere generation options: top/bottom parts or both. */ + enum class PartOfSphere {WHOLE, UP, BOTTOM}; + + /* Generate a simple environment sphere with UVs coordinates to use with lat-long environment maps. + \param center the sphere center + \param radius the sphere radius + \param zenith the up axis to orient the sphere around + \param north the horizontal north axis + \param part which aprt of the sphere should be generated + \return the sphere mesh + */ + static sibr::Mesh::Ptr getEnvSphere(sibr::Vector3f center, float radius, sibr::Vector3f zenith, sibr::Vector3f north, + PartOfSphere part = PartOfSphere::WHOLE); + + protected: + + /** Wrapper around a MeshBuffer, used to prevent copying OpenGL object IDs. */ + struct BufferGL + { + /** Default constructor. */ + BufferGL(void) : dirtyBufferGL(true), bufferGL(nullptr) { } + + /** Copy constructor. Copy the GPU buffers wrapper if it exists. + \param other object to copy. + */ + BufferGL(const BufferGL& other) { operator =(other); } + + /** Copy operator. Copy the GPU buffers wrapper if it exists. + \param other object to copy. + \return itself + */ + BufferGL& operator =(const BufferGL& other) { + bufferGL.reset(other.bufferGL? new MeshBufferGL() : nullptr); + dirtyBufferGL = (other.bufferGL!=nullptr); + return *this; + } + + bool dirtyBufferGL; ///< Should GL data be updated. + std::unique_ptr bufferGL; ///< Internal OpenGL data. + }; + public: mutable BufferGL _gl; ///< Internal OpenGL data. + + // Seb: It would be better if MeshBufferGL (and GL stuffs) were outside this class. + // It should work exactly like Image (CPU, here it's Mesh) and Texture(GPU version + // of Image, here it's MeshBufferGL) + + Vertices _vertices; ///< Vertex positions. + Triangles _triangles; ///< Triangle indices. + Normals _normals; ///< Vertex normals. + Colors _colors; ///< Vertex colors. + UVs _texcoords; ///< Vertex UVs. + + private: + std::string _meshPath; ///< Source path, can be used to reload the mesh with/without graphics option in constructor + std::string _textureImageFileName; // filename of texture image + mutable RenderingOptions _renderingOptions; // Keeps last rendering options + }; + + ///// DEFINITION ///// + + void Mesh::vertices( const Vertices& vertices ) { + _vertices = vertices; _gl.dirtyBufferGL = true; + } + + const Mesh::Vertices& Mesh::vertices( void ) const { + return _vertices; + } + + inline void Mesh::replaceVertice(int vertex_id, const sibr::Vector3f & v) + { + if (vertex_id >= 0 && vertex_id < (int)(vertices().size())) { + _vertices[vertex_id] = v; + _gl.dirtyBufferGL = true; + } + } + + void Mesh::triangles( const Triangles& triangles ) { + _triangles = triangles; _gl.dirtyBufferGL = true; + } + + const Mesh::Triangles& Mesh::triangles( void ) const { + return _triangles; + } + + void Mesh::colors( const Colors& colors ) { + _colors = colors; _gl.dirtyBufferGL = true; + } + const Mesh::Colors& Mesh::colors( void ) const { + return _colors; + } + bool Mesh::hasColors( void ) const { + return (_vertices.size() > 0 && _vertices.size() == _colors.size()); + } + + void Mesh::normals( const Normals& normals ) { + _normals = normals; _gl.dirtyBufferGL = true; + } + const Mesh::Normals& Mesh::normals( void ) const { + return _normals; + } + bool Mesh::hasNormals( void ) const { + return (_vertices.size() > 0 && _vertices.size() == _normals.size()); + } + + const float* Mesh::vertexArray( void ) const { + return _vertices.empty()? nullptr : &(_vertices[0][0]); + } + const uint* Mesh::triangleArray( void ) const { + return _triangles.empty() ? nullptr : &(_triangles[0][0]); + } + const float* Mesh::colorArray( void ) const { + return _colors.empty() ? nullptr : &(_colors[0][0]); + } + const float* Mesh::normalArray( void ) const { + return _normals.empty() ? nullptr : &(_normals[0][0]); + } + + void Mesh::texCoords( const UVs& texcoords ) { + _texcoords = texcoords; _gl.dirtyBufferGL = true; + } + + const Mesh::UVs& Mesh::texCoords( void ) const { + return _texcoords; + } + + bool Mesh::hasTexCoords( void ) const { + return (_vertices.size() > 0 && _vertices.size() == _texcoords.size()); + //return !_texcoords.empty(); + } + + const float* Mesh::texCoordArray( void ) const { + return _texcoords.empty() ? nullptr : &(_texcoords[0][0]); + } + + //*/ + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/MeshBufferGL.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/MeshBufferGL.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3ab64a76e31d4bb014976a9ac9e80a4e870ccd3f --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/MeshBufferGL.cpp @@ -0,0 +1,331 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#include "core/graphics/Mesh.hpp" +#include "core/graphics/MeshBufferGL.hpp" + +#include + +namespace sibr +{ + template + static std::vector prepareVertexData( + const std::vector& fromData, uint numVertices ) + { + static_assert(sizeof(TFrom) >= sizeof(TTo), + "Conversion not automatically managed with these two types"); + /*constexpr*/ const uint typeSize = sizeof(TFrom)/sizeof(TTo); + static_assert((typeSize*sizeof(TTo)) == sizeof(TFrom), + "Provided types have not a correct size"); + + if (fromData.empty()) + return std::vector(); // empty + //// If no data available, generate null ones + //if (fromData.empty()) + // return std::vector(numIndices*typeSize, 0); + + // We are supposed to have ONE data element per Vertex + SIBR_ASSERT(fromData.size() == numVertices); + + const TTo* beginptr = reinterpret_cast(fromData.data()); + const TTo* endptr = beginptr + (fromData.size()*typeSize); + return std::vector(beginptr, endptr); + } + + template + static void appendVertexData( + std::vector& toData, + const std::vector& fromData) + { + if (fromData.empty()) + return; + + /*constexpr*/ const uint typeSize = sizeof(TFrom)/sizeof(TTo); + static_assert((typeSize*sizeof(TTo)) == sizeof(TFrom), + "Provided types have not a correct size"); + + const TTo* beginptr = reinterpret_cast(fromData.data()); + const TTo* endptr = beginptr + (fromData.size()*typeSize); + toData.insert(toData.end(), beginptr, endptr); + } + + template + static inline uint getVectorDataSize( const std::vector& v ) + { + return (uint)(sizeof(T)*v.size()); + } + //=========================================================================== + + MeshBufferGL::MeshBufferGL( void ) + : _vaoId(0), _indexCount(0), _adjacentIndexCount(0), _vertexCount(0) + { + _bufferIds.fill(0); + } + + MeshBufferGL::~MeshBufferGL( void ) + { + free(); + } + + MeshBufferGL::MeshBufferGL( MeshBufferGL&& other ) : + _vaoId (std::move(other._vaoId)), + _bufferIds (std::move(other._bufferIds)), + _indexCount (std::move(other._indexCount)), + _adjacentIndexCount (std::move(other._adjacentIndexCount)), + _vertexCount (std::move(other._vertexCount)) + { + } + + MeshBufferGL& MeshBufferGL::operator =( MeshBufferGL&& other ) + { + _vaoId = std::move(other._vaoId); + _bufferIds = std::move(other._bufferIds); + _indexCount = std::move(other._indexCount); + _adjacentIndexCount = std::move(other._adjacentIndexCount); + _vertexCount = std::move(other._vertexCount); + + return *this; + } + + void MeshBufferGL::fetchIndices( const Mesh& mesh, bool adjacency ) + { + // Create buffer for indices (called elements in opengl) + std::vector indices; + + if(adjacency) { + + std::unordered_map, GLuint, hash_pair> trianglesByEdges(mesh.triangles().size() * 3); + indices.reserve(mesh.triangles().size() * 6); + + for(int i = 0; i < mesh.triangles().size(); i++) + { + // store triangles vertices by edges + + trianglesByEdges.insert({ { mesh.triangles()[i][0], mesh.triangles()[i][1] }, mesh.triangles()[i][2] }); + trianglesByEdges.insert({ { mesh.triangles()[i][1], mesh.triangles()[i][2] }, mesh.triangles()[i][0] }); + trianglesByEdges.insert({ { mesh.triangles()[i][2], mesh.triangles()[i][0] }, mesh.triangles()[i][1] }); + } + + for (int i = 0; i < mesh.triangles().size(); i++) + { + // input triangle + // 1 - 2 + // \ / + // 0 + + // adjacency list + // 3 + // / \ + // 2 - 4 + // / \ / \ + // 1 - 0 - 5 + + // use reverse edges to find adjacent triangles + + // 0 + indices.push_back(mesh.triangles()[i][0]); + // 1 + indices.push_back(trianglesByEdges[{ mesh.triangles()[i][1], mesh.triangles()[i][0] }]); + // 2 + indices.push_back(mesh.triangles()[i][1]); + // 3 + indices.push_back(trianglesByEdges[{ mesh.triangles()[i][2], mesh.triangles()[i][1] }]); + // 4 + indices.push_back(mesh.triangles()[i][2]); + // 5 + indices.push_back(trianglesByEdges[{ mesh.triangles()[i][0], mesh.triangles()[i][2] }]); + } + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _bufferIds[BUFADJINDEX]); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)*indices.size(), indices.data(), GL_STATIC_DRAW); + _adjacentIndexCount = (uint)indices.size(); + + CHECK_GL_ERROR; + } + else { + + indices.insert(indices.begin(), mesh.triangleArray(), mesh.triangleArray() + mesh.triangles().size()*3); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _bufferIds[BUFINDEX]); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)*indices.size(), indices.data(), GL_STATIC_DRAW); + _indexCount = (uint)indices.size(); + + CHECK_GL_ERROR; + } + } + + void MeshBufferGL::build( const Mesh& mesh, bool adjacency ) + { + if (!_vaoId) + { + glGenVertexArrays(1, &_vaoId); + glGenBuffers(BUFCOUNT, &_bufferIds[0]); + } + + glBindVertexArray(_vaoId); + + CHECK_GL_ERROR; + + fetchIndices(mesh, false); + + if(adjacency) + fetchIndices(mesh, true); + + uint numVertices = (uint)mesh.vertices().size(); + _vertexCount = numVertices; + //SIBR_DEBUG(mesh.triangles().size()); + std::vector vertices = prepareVertexData( + mesh.vertices(), numVertices); + std::vector colors = prepareVertexData( + mesh.colors(), numVertices); + std::vector texcoords = prepareVertexData( + mesh.texCoords(), numVertices); + std::vector normals = prepareVertexData( + mesh.normals(), numVertices); + + // Following this order: + //VertexAttribLocation = 0, + //ColorAttribLocation = 1, + //TexCoordAttribLocation = 2, + //NormalAttribLocation = 3, + + // Every data (from different types) are all put together into vertexData + std::vector vertexData; + vertexData.reserve( + getVectorDataSize(vertices) + + getVectorDataSize(colors) + + getVectorDataSize(texcoords)+ + getVectorDataSize(normals)); + + appendVertexData(vertexData, vertices); + appendVertexData(vertexData, colors); + appendVertexData(vertexData, texcoords); + appendVertexData(vertexData, normals); + + glBindBuffer(GL_ARRAY_BUFFER, _bufferIds[BUFVERTEX]); + glBufferData(GL_ARRAY_BUFFER, sizeof(uint8)*vertexData.size(), vertexData.data(), GL_STATIC_DRAW); + CHECK_GL_ERROR; + + glVertexAttribPointer(VertexAttribLocation, 3, GL_FLOAT, GL_FALSE, 0, (uint8_t*)(0)); + glEnableVertexAttribArray(VertexAttribLocation); + glVertexAttribPointer(ColorAttribLocation, 3, GL_FLOAT, GL_FALSE, 0, (uint8_t*)(0) + getVectorDataSize(vertices)); + glEnableVertexAttribArray(ColorAttribLocation); + glVertexAttribPointer(TexCoordAttribLocation, 2, GL_FLOAT, GL_FALSE, 0, (uint8_t*)(0) + getVectorDataSize(vertices) + getVectorDataSize(colors)); + glEnableVertexAttribArray(TexCoordAttribLocation); + glVertexAttribPointer(NormalAttribLocation, 3, GL_FLOAT, GL_FALSE, 0, (uint8_t*)(0) + getVectorDataSize(vertices) + getVectorDataSize(colors) + getVectorDataSize(texcoords)); + glEnableVertexAttribArray(NormalAttribLocation); + + /// \todo TODO: + /// We could ignore attrib that are empty (where mesh.colors().empty() == true, don't do anything with this). + /// This could improve a bit performances. + + glBindVertexArray(0); + } + + void MeshBufferGL::free(void) + { + if (_bufferIds[0] && _bufferIds[1] && _bufferIds[2]) + { + glDeleteBuffers(3, _bufferIds.data()); + _bufferIds.fill(0); + } + + if (_vaoId) + { + glDeleteVertexArrays(1, &_vaoId); + _vaoId = 0; + } + } + + void MeshBufferGL::draw(bool adjacency) const + { + glBindVertexArray(_vaoId); + + if(adjacency) + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _bufferIds[BUFADJINDEX]); + glDrawElements(GL_TRIANGLES_ADJACENCY, _adjacentIndexCount, GL_UNSIGNED_INT, (void*)0); + } + else + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _bufferIds[BUFINDEX]); + glDrawElements(GL_TRIANGLES, _indexCount, GL_UNSIGNED_INT, (void*)0); + } + + glBindVertexArray(0); + } + + void MeshBufferGL::draw(unsigned int begin, unsigned int end, bool adjacency) const + { + const unsigned int count = end-begin; + glBindVertexArray(_vaoId); + + if(adjacency) + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _bufferIds[BUFADJINDEX]); + glDrawElements(GL_TRIANGLES_ADJACENCY, count, GL_UNSIGNED_INT, (void*)(sizeof(GLuint) * begin)); + } + else + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _bufferIds[BUFINDEX]); + glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, (void*)(sizeof(GLuint) * begin)); + } + + glBindVertexArray(0); + } + + void MeshBufferGL::drawTessellated(void) const + { + glBindVertexArray(_vaoId); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _bufferIds[BUFINDEX]); + glDrawElements(GL_PATCHES, _indexCount, GL_UNSIGNED_INT, (void*)0); + glBindVertexArray(0); + } + + void MeshBufferGL::draw_lines(void) const + { + glBindVertexArray(_vaoId); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _bufferIds[BUFINDEX]); + glDrawElements(GL_LINES, _indexCount, GL_UNSIGNED_INT, (void*)0); + glBindVertexArray(0); + } + + void MeshBufferGL::draw_points() const + { + glBindVertexArray(_vaoId); + glDrawArrays(GL_POINTS, 0, _vertexCount); + glBindVertexArray(0); + } + + void MeshBufferGL::draw_points(unsigned int begin, unsigned int end) const + { + const unsigned int count = end - begin + 1; + glBindVertexArray(_vaoId); + glDrawArrays(GL_POINTS, begin, count); + glBindVertexArray(0); + } + + void MeshBufferGL::bind(void) const + { + glBindVertexArray(_vaoId); + } + + void MeshBufferGL::unbind(void) const + { + glBindVertexArray(0); + + } + + + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/MeshBufferGL.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/MeshBufferGL.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1ad9ebac416aa42ae04b16b30aab62798d34746a --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/MeshBufferGL.hpp @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include +# include +# include "core/graphics/Config.hpp" + + +namespace sibr +{ + template + static std::vector prepareVertexData(const std::vector& fromData, uint numVertices); + + template + static void appendVertexData(std::vector& toData, const std::vector& fromData); + + template + static uint getVectorDataSize(const std::vector& v); + + + class Mesh; + + /** + * This class is used to render mesh. It act like a vertex buffer object + * (in reality there also a vertex array object and maybe other data). + * \ingroup sibr_graphics + */ + class SIBR_GRAPHICS_EXPORT MeshBufferGL + { + public: + + /** Predefined shader attribute location. */ + enum AttribLocation + { + VertexAttribLocation = 0, + ColorAttribLocation = 1, + TexCoordAttribLocation = 2, + NormalAttribLocation = 3, + + AttribLocationCount + }; + + /** Predefined buffer location. */ + enum + { + BUFINDEX = 0, + BUFVERTEX = 1, + BUFADJINDEX = 2, + + BUFCOUNT + }; + + // A hash function used to hash a pair of any kind + struct hash_pair { + template + size_t operator()(const std::pair& p) const + { + auto hash1 = std::hash{}(p.first); + auto hash2 = std::hash{}(p.second); + return hash1 ^ hash2; + } + }; + + public: + + /// Constructor. + MeshBufferGL( void ); + + /// Destructor. + ~MeshBufferGL( void ); + + /// Move constructor. + MeshBufferGL( MeshBufferGL&& other ); + + /// Move operator. + MeshBufferGL& operator =( MeshBufferGL&& other ); + + /** Fetch indices from a mesh to insert them in the element buffer + * \param mesh the mesh to upload + * \param adjacency tells whether the indices should contain adjacents vertices + * \note This function can't fail (errors stop the program with a message). + */ + void fetchIndices( const Mesh& mesh, bool adjacency = false ); + + /** Build from a mesh so you can then draw() it to render it. + * \param mesh the mesh to upload + * \param adjacency tells whether the indices should contain adjacents vertices + * \note This function can't fail (errors stop the program with a message). + */ + void build( const Mesh& mesh, bool adjacency = false ); + + /** Delete the GPU buffer, freeing memory. */ + void free(void); + + /** This bind and draw elements stored in the buffer. + \param adjacency adds adjacent triangles info to geometry shader + */ + void draw(bool adjacency = false) const; + + /** This bind and draw elements in [begin, end[ stored in the buffer. + \param begin ID of the first primitive to render + \param end ID after the last primitive to render + \param adjacency adds adjacent triangles info to geometry shader + */ + void draw(unsigned int begin, unsigned int end, bool adjacency = false) const; + + /** This bind and draw elements stored in the buffer with tessellation shader enabled. */ + void drawTessellated(void) const; + + /** This bind and draw elements stored in the buffer, using pairs of indices to draw lines. */ + void draw_lines(void) const; + + /** This bind and draw vertex points stored in the buffer. */ + void draw_points( void ) const; + + /** This bind and draw vertex points in [begin, end[ stored in the buffer. + \param begin ID of the first primitive to render + \param end ID after the last primitive to render + */ + void draw_points( unsigned int begin, unsigned int end ) const; + + /** Bind the vertex and index buffers. */ + void bind(void) const; + + /** Bind only indexes (useful for combining with other form of mesh. e.g. SlicedMesh) */ + void bindIndices(void) const; + + /** Unbind arrays and buffers. */ + void unbind(void) const; + + /** Copy constructor (disabled). */ + MeshBufferGL(const MeshBufferGL&) = delete; + + /** Copy operator (disabled). */ + MeshBufferGL& operator =(const MeshBufferGL&) = delete; + + private: + + GLuint _vaoId; ///< Vertex array object ID. + std::array _bufferIds; ///< Buffers IDs. + uint _indexCount; ///< Number of elements in the index buffer. + uint _adjacentIndexCount; ///< Number of elements in the triangles_adjacency index buffer. + uint _vertexCount; ///< Number of elements in the vertex buffer. + + bool initVertexBuffer = false, + initIndexBuffer = false, + initAdjacentIndexBuffer = false; + }; + + ///// DEFINITION ///// + + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/RenderTarget.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/RenderTarget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..06b3bbcf8ecd9b165acf3c4825678ea9aa8b36d5 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/RenderTarget.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#include "core/graphics/RenderTarget.hpp" +//#define HEADLESS + +namespace sibr +{ + void blit(const IRenderTarget& src, const IRenderTarget& dst, GLbitfield mask, GLenum filter) + { +#ifdef HEADLESS + SIBR_ERR << "No named blit frame buffer in headless " << std::endl; +#else + glBlitNamedFramebuffer( + src.fbo(), dst.fbo(), + 0, 0, src.w(), src.h(), + 0, 0, dst.w(), dst.h(), + mask, filter); +#endif + } + + void blit_and_flip(const IRenderTarget& src, const IRenderTarget& dst, GLbitfield mask, GLenum filter) + { +#ifdef HEADLESS + SIBR_ERR << "No named blit frame buffer in headless " << std::endl; +#else + glBlitNamedFramebuffer( + src.fbo(), dst.fbo(), + 0, 0, src.w(), src.h(), + 0, dst.h(), dst.w(), 0, + mask, filter); +#endif + } + + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/RenderTarget.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/RenderTarget.hpp new file mode 100644 index 0000000000000000000000000000000000000000..67fcab2df1d1261531c37ace0fa0326a6eb64320 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/RenderTarget.hpp @@ -0,0 +1,664 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include "core/graphics/Config.hpp" +# include "core/system/Vector.hpp" +# include "core/graphics/Image.hpp" +# include "core/graphics/Types.hpp" +# include "core/system/Vector.hpp" +# include "core/graphics/RenderUtility.hpp" + + +# define SIBR_MAX_SHADER_ATTACHMENTS (1<<3) + +namespace sibr +{ + + + + /** Rendertarget interface. A render target wraps an OpenGL framebuffer, + * that can have one depth buffer, one stencil buffer, and one or more color attachments. + * This generic interface is typeless, \sa RenderTarget. + * \ingroup sibr_graphics + */ + class SIBR_GRAPHICS_EXPORT IRenderTarget + { + public: + typedef std::shared_ptr Ptr; + typedef std::unique_ptr UPtr; + public: + /// Destructor. + virtual ~IRenderTarget(void) { } + + /** Get the texture handle of the t-th color attachment. + \param t the color attachment slot + \return the texture handle + \deprecated Use handle instead. + */ + virtual GLuint texture(uint t = 0) const = 0; + + /** Get the texture handle of the t-th color attachment. + \param t the color attachment slot + \return the texture handle + */ + virtual GLuint handle(uint t = 0) const = 0; + + /** Bind the rendertarget for drawing. All color buffers are bound, along + with the depth and optional stencil buffers.*/ + virtual void bind(void) = 0; + + /** Unbind the rendertarget. + \note This will bind the window rendertarget. */ + virtual void unbind(void) = 0; + + /** Clear the content of the rendertarget. */ + virtual void clear(void) = 0; + + /** \return the rendertarget width. */ + virtual uint w(void) const = 0; + + /** \return the rendertarget height. */ + virtual uint h(void) const = 0; + + /** \return the framebuffer handle. */ + virtual GLuint fbo(void) const = 0; + }; + + /** + * A render target wraps an OpenGL framebuffer, that can have one depth buffer, + * one stencil buffer, and one or more color attachments. + * \sa IRenderTarget. + * \ingroup sibr_graphics + */ + template + class RenderTarget : public IRenderTarget { + SIBR_DISALLOW_COPY(RenderTarget); + public: + typedef Image PixelImage; + typedef typename PixelImage::Pixel PixelFormat; + typedef std::shared_ptr> Ptr; + typedef std::unique_ptr> UPtr; + + private: + + GLuint m_fbo = 0; ///< Framebuffer handle. + GLuint m_depth_rb = 0; ///< Depth renderbuffer handle. + GLuint m_stencil_rb = 0; ///< Stencil renderbuffer handle. + GLuint m_textures[SIBR_MAX_SHADER_ATTACHMENTS]; ///< Color texture handles. + uint m_numtargets = 0; ///< Number of active color attachments. + bool m_autoMIPMAP = false; ///< Generate mipmaps on the fly. + bool m_msaa = false; ///< Use multisampled targets. + bool m_stencil = false; ///< Has a stencil buffer. + uint m_W = 0; ///< Width. + uint m_H = 0; ///< Height. + + public: + + /// Constructor. + RenderTarget(void); + + /** Constructor and allocation. + \param w the target width + \param h the target height + \param flags options + \param num the number of color attachments. + */ + RenderTarget(uint w, uint h, uint flags = 0, uint num = 1); + + /// Destructor. + ~RenderTarget(void); + + /** Get the texture handle of the t-th color attachment. + \param t the color attachment slot + \return the texture handle + \deprecated Use handle instead. + */ + GLuint texture(uint t = 0) const; + + /** Get the texture handle of the t-th color attachment. + \param t the color attachment slot + \return the texture handle + */ + GLuint handle(uint t = 0) const; + + /** \return the depth buffer handle. */ + GLuint depthRB() const; + + /** Bind the rendertarget for drawing. All color buffers are bound, along + with the depth and optional stencil buffers.*/ + void bind(void); + + /** Unbind the rendertarget. + \note This will bind the window rendertarget. */ + void unbind(void); + + /** Clear the rendertarget buffers with default values. + * \warning This function will unbind the render target after clearing. + */ + void clear(void); + + /** Clear the rendertarget buffers, using a custom clear color. + * \param v the clear color + * \warning This function will unbind the render target after clearing. + * \bug This function does not rescale values for uchar (so background is either 0 or 1) + */ + void clear(const typename RenderTarget::PixelFormat& v); + + /** Clear the stencil buffer only. */ + void clearStencil(void); + + /** Clear the depth buffer only. */ + void clearDepth(void); + + /** Readback the content of a color attachment into an sibr::Image on the CPU. + \param image will contain the texture content + \param target the color attachment index to read + \warning Might cause a GPU flush/sync. + */ + template + void readBack(sibr::Image& image, uint target = 0) const; + + /** Readback the content of a color attachment into a cv::Mat on the CPU. + \param image will contain the texture content + \param target the color attachment index to read + \warning Might cause a GPU flush/sync. + */ + template + void readBackToCVmat(cv::Mat& image, uint target = 0) const; + + /** Readback the content of the depth attachment into an sibr::Image on the CPU. + \param image will contain the depth content + \warning Might cause a GPU flush/sync. + \warning Image orientation might be inconsistent with readBack (flip around horizontal axis). + */ + template + void readBackDepth(sibr::Image& image) const; + + /** \return the number of active color targets. */ + uint numTargets(void) const; + + /** \return the target width. */ + uint w(void) const; + + /** \return the target height. */ + uint h(void) const; + + /** \return the framebuffer handle. */ + GLuint fbo(void) const; + }; + + /** + Copy the content of a render target to another render target, resizing if needed. + \param src source rendertarget + \param dst destination rendertarget + \param mask which part of the buffer to copy (color, depth, stencil). + \param filter filtering mode if the two rendertargets have different dimensions (linear or nearest) + \note The blit can only happen for color attachment 0 in both src and dst. + \warning If the mask contains the depth or stencil, filter must be GL_NEAREST + \ingroup sibr_graphics + */ + SIBR_GRAPHICS_EXPORT void blit(const IRenderTarget& src, const IRenderTarget& dst, GLbitfield mask = GL_COLOR_BUFFER_BIT, GLenum filter = GL_LINEAR); + + /** + Copy the content of a render target to another render target, resizing if needed and flipping the result. + \param src source rendertarget + \param dst destination rendertarget + \param mask which part of the buffer to copy (color, depth, stencil). + \param filter filtering mode if the two rendertargets have different dimensions (linear or nearest) + \note The blit can only happen for color attachment 0 in both src and dst. + \warning If the mask contains the depth or stencil, filter must be GL_NEAREST + \ingroup sibr_graphics + */ + SIBR_GRAPHICS_EXPORT void blit_and_flip(const IRenderTarget& src, const IRenderTarget& dst, GLbitfield mask = GL_COLOR_BUFFER_BIT, GLenum filter = GL_LINEAR); + + /** Display a rendertarget color content in a popup window (backed by OpenCV). + \param rt the rendertarget to display + \param layer the color attachment to display + \param windowTitle name of the window + \param closeWindow should the window be closed when pressing a key + \ingroup sibr_graphics + */ + template + static void show( const RenderTarget & rt, uint layer=0, const std::string& windowTitle="sibr::show()" , bool closeWindow = true ) { + sibr::Image img(rt.w(), rt.h()); + rt.readBack(img, layer); + show(img, windowTitle, closeWindow); + } + + /** Display a rendertarget depth content in a popup window (backed by OpenCV). + \param rt the rendertarget to display + \param windowTitle name of the window + \param closeWindow should the window be closed when pressing a key + \ingroup sibr_graphics + */ + template + static void showDepth( const RenderTarget & rt, const std::string& windowTitle="sibr::show()" , bool closeWindow = true ) { + sibr::Image img(rt.w(), rt.h()); + rt.readBackDepth(img); + show(img, windowTitle, closeWindow); + } + + /** Display a rendertarget alpha content as a grey map in a popup window (backed by OpenCV). + \param rt the rendertarget to display + \param windowTitle name of the window + \param closeWindow should the window be closed when pressing a key + \ingroup sibr_graphics + */ + template + static void showDepthFromAlpha( const RenderTarget & rt, const std::string& windowTitle="sibr::show()" , bool closeWindow = true ) { + sibr::Image img(rt.w(), rt.h()); + rt.readBack(img); + + for (uint y = 0; y < img.h(); ++y) + { + for (uint x = 0; x < img.w(); ++x) + { + sibr::ColorRGBA c = img.color(x, y); + c = sibr::ColorRGBA(1.f, 1.f, 1.f, 0.f) * c[3]; + c[3] = 1.f; + img.color(x, y, c); + } + } + + show(img, windowTitle, closeWindow); + } + + + // --- Typedef RenderTarget -------------------------------------------------- + + typedef RenderTarget RenderTargetRGB; + typedef RenderTarget RenderTargetRGBA; + typedef RenderTarget RenderTargetLum; + + typedef RenderTarget RenderTargetLum16; + typedef RenderTarget RenderTargetUV16; + typedef RenderTarget RenderTargetRGB16; + typedef RenderTarget RenderTargetRGBA16; + + typedef RenderTarget RenderTargetInt1; + + typedef RenderTarget RenderTargetRGB32F; + typedef RenderTarget RenderTargetRGBA32F; + typedef RenderTarget RenderTargetLum32F; + typedef RenderTarget RenderTargetUV32F; + + + // --- DEFINITIONS RenderTarget -------------------------------------------------- + + template + RenderTarget::RenderTarget(void) { + m_fbo = 0; + m_depth_rb = 0; + m_numtargets = 0; + m_W = 0; + m_H = 0; + } + + template + RenderTarget::RenderTarget(uint w, uint h, uint flags, uint num) { + RenderUtility::useDefaultVAO(); + + m_W = w; + m_H = h; + + bool is_depth = (GLFormat::isdepth != 0); + + int maxRenterTargets = 0; + glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &maxRenterTargets); + + SIBR_ASSERT(num <= uint(maxRenterTargets) && num > 0); + SIBR_ASSERT(!is_depth || num == 1); + + if (flags & SIBR_GPU_INTEGER) { + if (GLFormat::int_internal_format < 0) { + throw std::runtime_error("Integer render - format does not support integer mapping"); + } + } + + glGenFramebuffers(1, &m_fbo); + + if (!is_depth) { + glGenRenderbuffers(1, &m_depth_rb); // depth buffer for color rt + //glGenRenderbuffers(1, &m_stencil_rb); // stencil buffer for color rt + } else + m_depth_rb = 0; + + m_numtargets = num; + m_autoMIPMAP = ((flags & SIBR_GPU_AUTOGEN_MIPMAP) != 0); + + m_msaa = ((flags & SIBR_GPU_MULSTISAMPLE) != 0); + m_stencil = ((flags & SIBR_STENCIL_BUFFER) != 0); + + if (m_msaa && (m_numtargets != 1)) + throw std::runtime_error("Only one MSAA render target can be attached."); + for (uint n = 0; n < m_numtargets; n++) { + if (m_msaa) + break; + + glGenTextures(1, &m_textures[n]); + + + glBindTexture(GL_TEXTURE_2D, m_textures[n]); + + if (flags & SIBR_CLAMP_UVS) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + + /// \todo: following causes enum compare warning -Wenum-compare + glTexImage2D(GL_TEXTURE_2D, + 0, + (flags & SIBR_GPU_INTEGER) + ? GLFormat::int_internal_format + : GLFormat::internal_format, + w, h, + 0, + (flags & SIBR_GPU_INTEGER) + ? GLFormat::int_format + : GLFormat::format, + GLType::type, + NULL); + + + if (!m_autoMIPMAP) { +#if SIBR_COMPILE_FORCE_SAMPLING_LINEAR + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +#else + if (flags & SIBR_GPU_LINEAR_SAMPLING) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } else { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } +#endif + } else { /// \todo TODO: this crashes with 16F RT + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + } + + + if (!m_msaa) { + if (!is_depth) { + glBindRenderbuffer(GL_RENDERBUFFER, m_depth_rb); + if (!m_stencil) + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32, w, h); + else + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, w, h); + + //CHECK_GL_ERROR; + //glBindRenderbuffer(GL_RENDERBUFFER, m_stencil_rb); + //glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, w, h); + CHECK_GL_ERROR; + glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); + for (uint n = 0; n < m_numtargets; n++) { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + n, GL_TEXTURE_2D, m_textures[n], 0); + } + CHECK_GL_ERROR; + if (!m_stencil) + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depth_rb); + else + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_depth_rb); + //CHECK_GL_ERROR; + //glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_stencil_rb); + } else { + glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_textures[0], 0); + glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); + } + } + + if (m_msaa) { + uint msaa_samples = ((flags >> 7) & 0xF) << 2; + + if (msaa_samples == 0) + throw std::runtime_error("Number of MSAA Samples not set. Please use SIBR_MSAA4X, SIBR_MSAA8X, SIBR_MSAA16X or SIBR_MSAA32X as an additional flag."); + + glGenTextures(1, &m_textures[0]); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_textures[0]); + CHECK_GL_ERROR; + /// TODO: following causes enum compare warning -Wenum-compare + glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, + msaa_samples, + (flags & SIBR_GPU_INTEGER) + ? GLFormat::int_internal_format + : GLFormat::internal_format, + w, h, + GL_TRUE + ); + glBindRenderbuffer(GL_RENDERBUFFER, m_depth_rb); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa_samples, GL_DEPTH_COMPONENT32, w, h); + glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); + glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_textures[0], 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depth_rb); + } + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + switch (status) { + case GL_FRAMEBUFFER_UNSUPPORTED: + throw std::runtime_error("Cannot create FBO - GL_FRAMEBUFFER_UNSUPPORTED error"); + break; + default: + SIBR_DEBUG(status); + throw std::runtime_error("Cannot create FBO (unknow reason)"); + break; + } + } + + if (m_autoMIPMAP) { + for (uint i = 0; i < m_numtargets; i++) { + glBindTexture(GL_TEXTURE_2D, m_textures[i]); + glGenerateMipmap(GL_TEXTURE_2D); + } + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); + CHECK_GL_ERROR; + } + + template + RenderTarget::~RenderTarget(void) { + for (uint i = 0; i < m_numtargets; i++) + glDeleteTextures(1, &m_textures[i]); + glDeleteFramebuffers(1, &m_fbo); + glDeleteRenderbuffers(1, &m_depth_rb); + CHECK_GL_ERROR; + } + + template + GLuint RenderTarget::depthRB() const { + return m_depth_rb; + } + + template + GLuint RenderTarget::texture(uint t) const { + SIBR_ASSERT(t < m_numtargets); + return m_textures[t]; + } + template + GLuint RenderTarget::handle(uint t) const { + SIBR_ASSERT(t < m_numtargets); + return m_textures[t]; + } + + template + void RenderTarget::bind(void) { + glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); + bool is_depth = (GLFormat::isdepth != 0); + if (!is_depth) { + if (m_numtargets > 0) { + GLenum drawbuffers[SIBR_MAX_SHADER_ATTACHMENTS]; + for (uint i = 0; i < SIBR_MAX_SHADER_ATTACHMENTS; i++) + drawbuffers[i] = GL_COLOR_ATTACHMENT0 + i; + glDrawBuffers(m_numtargets, drawbuffers); + } + } else { + glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); + } + } + + template + void RenderTarget::unbind(void) { + if (m_autoMIPMAP) { + for (uint i = 0; i < m_numtargets; i++) { + glBindTexture(GL_TEXTURE_2D, m_textures[i]); + glGenerateMipmap(GL_TEXTURE_2D); + } + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + + template + void RenderTarget::clear(void) { + clear(PixelFormat()); + } + + template + void RenderTarget::clear(const typename RenderTarget::PixelFormat& v) { + bind(); + if (PixelFormat::NumComp == 1) { + glClearColor(GLclampf(v[0]), 0, 0, 0); + } else if (PixelFormat::NumComp == 2) { + glClearColor(GLclampf(v[0]), GLclampf(v[1]), 0, 0); + } else if (PixelFormat::NumComp == 3) { + glClearColor(GLclampf(v[0]), GLclampf(v[1]), GLclampf(v[2]), 0); + } else if (PixelFormat::NumComp == 4) { + glClearColor(GLclampf(v[0]), GLclampf(v[1]), GLclampf(v[2]), GLclampf(v[3])); + } + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + unbind(); + } + + template + void RenderTarget::clearStencil() { + bind(); + glClearStencil(0); + glClear(GL_STENCIL_BUFFER_BIT); + unbind(); + } + + template + void RenderTarget::clearDepth() { + bind(); + glClear(GL_DEPTH_BUFFER_BIT); + unbind(); + } + + template + template + void RenderTarget::readBack(sibr::Image& img, uint target) const { + //void RenderTarget::readBack(PixelImage& img, uint target) const { + glFinish(); + if (target >= m_numtargets) + SIBR_ERR << "Reading back texture out of bounds" << std::endl; + + glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); + bool is_depth = (GLFormat::isdepth != 0); + if (!is_depth) { + if (m_numtargets > 0) { + sibr::Image buffer(m_W, m_H); + + GLenum drawbuffers = GL_COLOR_ATTACHMENT0 + target; + glDrawBuffers(1, &drawbuffers); + glReadBuffer(drawbuffers); + + glReadPixels(0, 0, m_W, m_H, + GLFormat::format, + GLType::type, + buffer.data() + ); + + sibr::Image out; + img.fromOpenCV(buffer.toOpenCV()); + } + } else + SIBR_ERR << "RenderTarget::readBack: This function should be specialized " + "for handling depth buffer." << std::endl; + img.flipH(); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + } + + + template + template + void RenderTarget::readBackToCVmat(cv::Mat& img, uint target) const { + + using Infos = GLTexFormat; + + if (target >= m_numtargets) + SIBR_ERR << "Reading back texture out of bounds" << std::endl; + + cv::Mat tmp(m_H, m_W, Infos::cv_type()); + + glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); + bool is_depth = (Infos::isdepth != 0); + if (!is_depth) { + if (m_numtargets > 0) { + GLenum drawbuffers = GL_COLOR_ATTACHMENT0 + target; + glDrawBuffers(1, &drawbuffers); + glReadBuffer(drawbuffers); + + glReadPixels(0, 0, m_W, m_H, + Infos::format, + Infos::type, + Infos::data(tmp) + ); + } + } else { + SIBR_ERR << "RenderTarget::readBack: This function should be specialized " + "for handling depth buffer." << std::endl; \ + } + img = Infos::flip(tmp); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + + template + template + void RenderTarget::readBackDepth(sibr::Image& image) const { + glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); + + glReadBuffer(GL_COLOR_ATTACHMENT0); + + sibr::Image buffer(m_W, m_H); + glReadPixels(0, 0, m_W, m_H, + GL_DEPTH_COMPONENT, + GL_FLOAT, + buffer.data() + ); + + sibr::Image out(buffer.w(), buffer.h()); + for (uint y = 0; y < buffer.h(); ++y) + for (uint x = 0; x < buffer.w(); ++x) + out.color(x, y, sibr::ColorRGBA(1, 1, 1, 1.f) * buffer(x, y)[0]); + image = std::move(out); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + + template + uint RenderTarget::numTargets(void) const { return m_numtargets; } + template + uint RenderTarget::w(void) const { return m_W; } + template + uint RenderTarget::h(void) const { return m_H; } + template + uint RenderTarget::fbo(void) const { return m_fbo; } + + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/RenderUtility.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/RenderUtility.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f0ec419725c1b55ff9994bea06152edfda852a54 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/RenderUtility.cpp @@ -0,0 +1,329 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#include "core/graphics/Shader.hpp" +#include "core/graphics/RenderUtility.hpp" +#include "core/graphics/Window.hpp" + +#define SIBR_WRITESHADER(src) "#version 420 core\n" #src + + +//#define RenderUtility::camStubDrawSize() 0.10f + + + +namespace sibr +{ + + + static const std::vector& getCameraStubVertices(float camStubSize = 0.1f) + { + std::vector _vBuffer(3*5); + _vBuffer[3*0+0]= 1*camStubSize; _vBuffer[3*0+1]= 1*camStubSize; _vBuffer[3*0+2]=-3*camStubSize; + _vBuffer[3*1+0]=-1*camStubSize; _vBuffer[3*1+1]= 1*camStubSize; _vBuffer[3*1+2]=-3*camStubSize; + _vBuffer[3*2+0]=-1*camStubSize; _vBuffer[3*2+1]=-1*camStubSize; _vBuffer[3*2+2]=-3*camStubSize; + _vBuffer[3*3+0]= 1*camStubSize; _vBuffer[3*3+1]=-1*camStubSize; _vBuffer[3*3+2]=-3*camStubSize; + _vBuffer[3*4+0]= 0*camStubSize; _vBuffer[3*4+1]= 0*camStubSize; _vBuffer[3*4+2]= 0*camStubSize; + return _vBuffer; + } + + static const std::vector& getCameraStubIndices( void ) + { + static std::vector _iBuffer; + + if (_iBuffer.empty()) + { + _iBuffer.resize(3*6); + + _iBuffer[3*0+0]=0; _iBuffer[3*0+1]=1; _iBuffer[3*0+2]=4; + _iBuffer[3*1+0]=1; _iBuffer[3*1+1]=2; _iBuffer[3*1+2]=4; + _iBuffer[3*2+0]=2; _iBuffer[3*2+1]=4; _iBuffer[3*2+2]=3; + _iBuffer[3*3+0]=0; _iBuffer[3*3+1]=4; _iBuffer[3*3+2]=3; + _iBuffer[3*4+0]=0; _iBuffer[3*4+1]=1; _iBuffer[3*4+2]=3; + _iBuffer[3*5+0]=1; _iBuffer[3*5+1]=2; _iBuffer[3*5+2]=3; + } + return _iBuffer; + } + + + void RenderUtility::sendVertsTexToGPU(GLuint vertTexVBO, GLfloat vert[], GLfloat tcoord[], int svert, int stcoord) { + glBindBuffer(GL_ARRAY_BUFFER, vertTexVBO); + glBufferData(GL_ARRAY_BUFFER, svert+stcoord, NULL, GL_STATIC_DRAW); + glBufferSubData(GL_ARRAY_BUFFER, 0, svert, vert); + glBufferSubData(GL_ARRAY_BUFFER, svert, stcoord, tcoord); + } + + + /*static*/ void RenderUtility::renderScreenQuad( bool reverse, GLfloat tex_coor[] ) + { + static GLfloat vert[] = { -1,-1,0, 1,-1,0, 1,1,0, -1,1,0 }; + static GLfloat tcoord[8]; + static GLuint indexVBO, VAO, vertTexVBO; + + static bool firstTime = true; + + if(reverse) + { + GLfloat tmp[] = { 0,1, 0,0, 1,0, 1,1 }; + if( tex_coor ) + std::memcpy(tmp, tex_coor, sizeof tmp ); + + std::memcpy(tcoord, tmp, sizeof tcoord); + if( !firstTime ) // re-transfer to GPUs + sendVertsTexToGPU(vertTexVBO, vert, tcoord, sizeof(vert), sizeof(tcoord)); + } + else + { + GLfloat tmp[] = { 0,0, 1,0, 1,1, 0,1 }; + if( tex_coor ) + std::memcpy(tmp, tex_coor, sizeof tmp ); + + std::memcpy(tcoord, tmp, sizeof tcoord); + if( !firstTime ) // re-transfer to GPU + sendVertsTexToGPU(vertTexVBO, vert, tcoord, sizeof(vert), sizeof(tcoord)); + } + + static GLuint ind[] = { 0,1,2, 0,2,3 }; + + if( firstTime ) { + firstTime = false; + + glGenVertexArrays(1, &VAO); + glBindVertexArray(VAO); + + glGenBuffers(1, &indexVBO); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexVBO); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(ind), ind, GL_STATIC_DRAW); + + glGenBuffers(1, &vertTexVBO); + sendVertsTexToGPU(vertTexVBO, vert, tcoord, sizeof(vert), sizeof(tcoord)); + } + + glBindVertexArray(VAO); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexVBO); + glBindBuffer(GL_ARRAY_BUFFER, vertTexVBO); + + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)sizeof(vert) ); + + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, (void*)0); + + glDisableVertexAttribArray(1); + glDisableVertexAttribArray(0); + } + + void RenderUtility::renderScreenQuad() + { + static GLfloat Fvert[] = { -1,-1,0, 1,-1,0, 1,1,0, -1,1,0 }; + static GLfloat Ftcoord[] = { 0, 0, 1, 0, 1, 1, 0, 1 }; + static GLuint Find[] = { 0,1,2, 0,2,3 }; + static GLuint FindexVBO, FVAO, FvertTexVBO; + static bool FfirstTime = true; + static int lastContextId = -1; + + //std::cout << lastContextId << " " << Window::contextId << std::endl; + if (lastContextId != Window::contextId || FfirstTime) { + lastContextId = Window::contextId; + FfirstTime = false; + + glGenVertexArrays(1, &FVAO); + glBindVertexArray(FVAO); + + glGenBuffers(1, &FindexVBO); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, FindexVBO); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Find), Find, GL_STATIC_DRAW); + + glGenBuffers(1, &FvertTexVBO); + sendVertsTexToGPU(FvertTexVBO, Fvert, Ftcoord, sizeof(Fvert), sizeof(Ftcoord)); + + glBindBuffer(GL_ARRAY_BUFFER, FvertTexVBO); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)sizeof(Fvert)); + + glBindVertexArray(0); + } + + + glBindVertexArray(FVAO); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, FindexVBO); + + const GLboolean cullingWasEnabled = glIsEnabled(GL_CULL_FACE); + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, (void*)0); + + if (!cullingWasEnabled) { + glDisable(GL_CULL_FACE); + } + + glBindVertexArray(0); + } + + + /*static*/ Mesh RenderUtility::createCameraStub(float camStubSize) + { + + Mesh m; + m.vertices( getCameraStubVertices(camStubSize) ); + m.triangles( getCameraStubIndices() ); + return m; + } + + /*static*/ Mesh RenderUtility::createScreenQuad( void ) + { + Mesh::Vertices v; + v.emplace_back(-1.0f, -1.0f, 0.0f); + v.emplace_back( 1.0f, -1.0f, 0.0f); + v.emplace_back( 1.0f, 1.0f, 0.0f); + v.emplace_back(-1.0f, 1.0f, 0.0f); + Mesh::UVs tc; + tc.emplace_back(0.0f,0.0f); + tc.emplace_back(1.0f,0.0f); + tc.emplace_back(1.0f,1.0f); + tc.emplace_back(0.0f,1.0f); + Mesh::Triangles t; + t.emplace_back(0); + t.emplace_back(1); + t.emplace_back(2); + t.emplace_back(0); + t.emplace_back(2); + t.emplace_back(3); + + + Mesh m; + m.vertices(v); + m.texCoords(tc); + m.triangles(t); + return m; + } + + Mesh::Ptr RenderUtility::createAxisGizmo() + { + const float arrowShift = 0.2f; + const float arrowSpread = 0.1f; + + Mesh::Vertices v = { + // Axis X + {-1,0,0}, {1,0,0}, + // Arrow X + {1.0f - arrowShift, -arrowSpread, 0.0f}, + {1.0f - arrowShift, 0.0f, -arrowSpread}, + {1.0f - arrowShift, arrowSpread, 0.0f}, + {1.0f - arrowShift, 0.0f, arrowSpread}, + + // Axis Y + {0,-1,0}, {0,1,0}, + // Arrow Y + {-arrowSpread, 1.0f - arrowShift, 0.0f}, + {0.0f, 1.0f - arrowShift, -arrowSpread}, + {arrowSpread, 1.0f - arrowShift, 0.0f}, + {0.0f, 1.0f - arrowShift, arrowSpread}, + + // Axis Z + {0, 0, -1}, {0, 0, 1}, + // Arrow Z + {-arrowSpread, 0.0f, 1.0f - arrowShift}, + {0.0f, -arrowSpread, 1.0f - arrowShift}, + {arrowSpread, 0.0f, 1.0f - arrowShift}, + {0.0f, arrowSpread, 1.0f - arrowShift}, + + // Letter X + {1.0f + arrowShift - arrowSpread, -arrowSpread, 0.0f}, + {1.0f + arrowShift + arrowSpread, arrowSpread, 0.0f}, + {1.0f + arrowShift - arrowSpread, arrowSpread, 0.0f}, + {1.0f + arrowShift + arrowSpread, -arrowSpread, 0.0f}, + // Letter Y + {0.0f, 1.0f + arrowShift - arrowSpread, 0.0f}, + {0.0f, 1.0f + arrowShift, 0.0f}, + {-arrowSpread, 1.0f + arrowShift + arrowSpread, 0.0f}, + {arrowSpread, 1.0f + arrowShift + arrowSpread, 0.0f}, + // Letter Z + {0.0f, -arrowSpread, 1.0f + arrowShift - arrowSpread}, + {0.0f, -arrowSpread, 1.0f + arrowShift + arrowSpread}, + {0.0f, arrowSpread, 1.0f + arrowShift - arrowSpread}, + {0.0f, arrowSpread, 1.0f + arrowShift + arrowSpread} + }; + + Mesh::Colors c = { + // Colors X + {1, 0, 0}, {1, 0, 0}, {1, 0, 0}, + {1, 0, 0}, {1, 0, 0}, {1, 0, 0}, + // Colors Y + {0, 1, 0}, {0, 1, 0}, {0, 1, 0}, + {0, 1, 0}, {0, 1, 0}, {0, 1, 0}, + // Colors Z + {0, 0, 1}, {0, 0, 1}, {0, 0, 1}, + {0, 0, 1}, {0, 0, 1}, {0, 0, 1}, + // Colors Letter X + {1, 0, 0}, {1, 0, 0}, + {1, 0, 0}, {1, 0, 0}, + // Colors Letter Y + {0, 1, 0}, {0, 1, 0}, + {0, 1, 0}, {0, 1, 0}, + // Colors Letter Z + {0, 0, 1}, {0, 0, 1}, + {0, 0, 1}, {0, 0, 1} + }; + + Mesh::Triangles t = { + // Axis X + {0, 1, 0}, + // Arrow X + {1, 2, 3}, {1, 3, 4}, {1, 4, 5}, + {1, 5, 2}, {2, 3, 4}, {2, 3, 5}, + // Axis Y + {6, 7, 6}, + // Arrow Y + {7, 8, 9}, {7, 9, 10}, {7, 10, 11}, + {7, 11, 8}, {8, 9, 10}, {8, 9, 11}, + // Axis Z + {12, 13, 12}, + // Arrow Z + {13, 14, 15}, {13, 15, 16}, {13, 16, 17}, + {13, 17, 14}, {14, 15, 16}, {14, 15, 17}, + + // Letter X + {18, 19, 18}, {20, 21, 20}, + //Letter Y + {22, 23, 22}, {24, 23, 24}, {25, 23, 25}, + //Letter Z + {26, 28, 26}, {26, 29, 26}, {27, 29, 27} + }; + + + auto out = std::make_shared(); + out->vertices(v); + out->colors(c); + out->triangles(t); + return out; + } + + + /*static*/ void RenderUtility::useDefaultVAO( void ) + { + static GLuint gDefaultVAO = 0; + + if (!gDefaultVAO) + glGenVertexArrays(1, &gDefaultVAO); + + glBindVertexArray(gDefaultVAO); + } + + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/RenderUtility.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/RenderUtility.hpp new file mode 100644 index 0000000000000000000000000000000000000000..37dd42b9979773c01957f0b820e75d6a6609b9d8 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/RenderUtility.hpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include "core/graphics/Config.hpp" +# include "core/system/Matrix.hpp" +# include "core/system/Vector.hpp" +# include "core/graphics/Mesh.hpp" + +namespace sibr +{ + + /** + Helpers for rendering basic debug objects (cameras, simple meshes,...) + \todo Clarify duplication with functionality in SceneDebugView. + * \ingroup sibr_graphics + */ + class SIBR_GRAPHICS_EXPORT RenderUtility + { + public: + + /** Create a basic cmaera stub. + \param camStubSize the stub scale + \return the mesh + */ + static Mesh createCameraStub( float camStubSize = 0.1f); + + /** Create a screenquad. + \return the mesh + */ + static Mesh createScreenQuad(); + + /** Create a gizmo with X,Y,Z axis and labels (using R,G,B respectively). + \return the gizmo mesh + */ + static Mesh::Ptr createAxisGizmo(); + + /** Bind a static VAO for which you can redefine vertices or do vertex pulling. */ + static void useDefaultVAO( void ); + + /** Draw a screenquad. */ + static void renderScreenQuad(); + + /** Draw a screenquad. + \param reverse should the triangles be flipped + \param texCoor custom texture coordinates to use. + */ + static void renderScreenQuad( bool reverse, GLfloat texCoor[] = NULL ); + + private: + + /** Send vertices to the GPU. + \param vertTexVBO the VBO id + \param vert the vertices data + \param tcoord the UV data + \param svert the vert size + \param stcoord the tcoord size + */ + static void sendVertsTexToGPU(GLuint vertTexVBO, GLfloat vert[], GLfloat tcoord[], int svert, int stcoord); + + + }; + + ///// DEFINITIONS ///// + + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Shader.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Shader.cpp new file mode 100755 index 0000000000000000000000000000000000000000..e215221fe9ce464cf2d008f640c00e79ac43f8f5 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Shader.cpp @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +# include "core/graphics/Shader.hpp" +# include "core/system/Matrix.hpp" +#include "core/system/String.hpp" + + +# ifndef SIBR_MAXIMIZE_INLINE +# include "Shader.inl" +# endif + +namespace sibr +{ + GLuint GLShader::compileShader(const char* shader_code, GLuint type) + { + std::string shader_type; + switch (type) { + case GL_VERTEX_SHADER: shader_type = "vertex"; break; + case GL_FRAGMENT_SHADER: shader_type = "fragment"; break; + case GL_GEOMETRY_SHADER: shader_type = "geometry"; break; + default: std::runtime_error("Shader types other than vertex/fragment/geometry not supported"); + } + + GLuint id = glCreateShader(type); + glShaderSource(id,1,&shader_code,NULL); + glCompileShader(id); + + GLint compiled; + glGetShaderiv(id,GL_COMPILE_STATUS, &compiled); + if (!compiled) { + GLint maxLength; + glGetShaderiv(id, GL_INFO_LOG_LENGTH, &maxLength); + char* infoLog = new char[maxLength+1]; + GLint len = 0; + glGetShaderInfoLog(id, maxLength, &len, infoLog); + SIBR_WRG << "GLSL " << shader_type.c_str() << " shader compilation failed for program " + << m_Name.c_str() << std::endl + << infoLog << std::endl; + delete [] infoLog; + (void)glGetError(); + return 0; + } + return id; + } + + GLShader::GLShader(void) : + m_Shader(0), + m_Name(""), + m_Strict(false), + m_Active(false) + {} + + GLShader::~GLShader(void) { + terminate(); + } + + void GLShader::init ( GLuint s_handle ) + { + m_Shader = s_handle; + } + + void GLShader::setStrict ( bool s ) + { + m_Strict = s; + } + + GLuint GLShader::shader ( void ) const + { + return m_Shader; + } + + std::string GLShader::name ( void ) const + { + return m_Name; + } + + bool GLShader::isReady ( void ) const + { + return m_Shader!=0; + } + + bool GLShader::isActive ( void ) const + { + return m_Active; + } + + bool GLShader::isStrict ( void ) const + { + return m_Strict; + } + + bool GLShader::init(std::string name, + std::string vp_code, + std::string fp_code, + std::string gp_code, + bool exitOnError, + std::string tcs_code, + std::string tes_code) + { + terminate(); + + m_Name = name; + m_Shader = glCreateProgram(); + + CHECK_GL_ERROR; + + GLint vp = 0, fp = 0, gp = 0, tcs = 0, tes = 0; + + if (!vp_code.empty()) { + vp = compileShader(vp_code.c_str(), GL_VERTEX_SHADER); + if (!vp) return false; + glAttachShader(m_Shader, vp); + } + + if (!fp_code.empty()) { + fp = compileShader(fp_code.c_str(), GL_FRAGMENT_SHADER); + if (!fp) return false; + glAttachShader(m_Shader, fp); + } + + if (!gp_code.empty()) { + gp = compileShader(gp_code.c_str(), GL_GEOMETRY_SHADER); + if (!gp) return false; + glAttachShader(m_Shader, gp); + } + + if (!tcs_code.empty()) { + tcs = compileShader(tcs_code.c_str(), GL_TESS_CONTROL_SHADER); + if (!tcs) return false; + glAttachShader(m_Shader, tcs); + } + + if (!tes_code.empty()) { + tes = compileShader(tes_code.c_str(), GL_TESS_EVALUATION_SHADER); + if (!tes) return false; + glAttachShader(m_Shader, tes); + } + + CHECK_GL_ERROR; + + glLinkProgram(m_Shader); + + CHECK_GL_ERROR; + + GLint shader_linked; + + CHECK_GL_ERROR; + + glGetProgramiv(m_Shader, GL_LINK_STATUS, &shader_linked); + if (!shader_linked) { + GLint maxLength; + glGetProgramiv(m_Shader, GL_INFO_LOG_LENGTH, &maxLength); + char* infoLog = new char[maxLength + 1]; + glGetProgramInfoLog(m_Shader, maxLength, NULL, infoLog); + SIBR_WRG << "GLSL program failed to link " << m_Name.c_str() << std::endl + << "Shader linking log:" << std::endl + << infoLog << std::endl; + delete[] infoLog; + + if (exitOnError) + SIBR_ERR << "GLSL program failed to link" << std::endl; + } + + if (vp) glDeleteShader(vp); + if (fp) glDeleteShader(fp); + if (gp) glDeleteShader(gp); + if (tcs) glDeleteShader(tcs); + if (tes) glDeleteShader(tes); + + glUseProgram(0); + + CHECK_GL_ERROR; + return true; + } + + + bool GLShader::reload( + std::string vp_code, + std::string fp_code, + std::string gp_code ) { + { // Simple way to test if it compiles + sibr::GLShader tester; + if (tester.init(m_Name, vp_code, fp_code, gp_code) == false) + { + SIBR_WRG << "Can't reload shader '" << m_Name << "' (see previous log entries)" << std::endl; + return false; + } + } + return init(m_Name, vp_code, fp_code, gp_code); + } + + void GLShader::getBinary(std::vector & binary) + { + int count = 0; + glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &count); + if (count <= 0) { + SIBR_WRG << "GL driver does not support program binary export." << std::endl; + return; + } + int length = 0; + glGetProgramiv(m_Shader, GL_PROGRAM_BINARY_LENGTH, &length); + if (length <= 0) { + SIBR_WRG << "No binary for program " << m_Name << "." << std::endl; + return; + } + GLenum format; + binary.clear(); + binary.resize(length); + glGetProgramBinary(m_Shader, length, NULL, &format, &binary[0]); + + } + + void GLShader::terminate( void ) + { + if (m_Shader) { + glUseProgram(0); + glDeleteProgram(m_Shader); + m_Shader = 0; + CHECK_GL_ERROR; + } + } + + GLParameter::GLParameter(void) : + m_Shader(NULL), + m_Handle(-1), + m_Name(""), + m_Strict(false) + {} + + bool GLParameter::isInitialized( void ) const + { + return (m_Handle != -1 && m_Shader != NULL); + } + + GLint GLParameter::handle( void ) const + { + return m_Handle; + } + + void GLParameter::init( sibr::GLShader& shader, std::string name ) + { + m_Shader = &shader; + m_Name = name; + m_Handle = glGetUniformLocation(m_Shader->shader(),name.c_str()); + m_Strict = m_Shader->isStrict(); + if (m_Handle == -1) { + std::string message = "GLParameter " + m_Name + " does not exist in shader " + shader.name(); + if (m_Strict) { + throw std::runtime_error(message); + } else { + std::cerr << "Warning: " << message.c_str() << std::endl; + } + } + } + + static std::string strRemoveSpaces( const std::string& str ) + { + std::string out; + for (char c : str) + if (c != ' ' && c != '\t') + out.push_back(c); + return out; + } + + std::string loadFile( const std::string& filename, const GLShader::Define::List& defines ) + { + std::string file = loadFile(filename); + + if (file.empty()) + return file; + + std::vector lines = sibr::split(file, '\n'); + for ( const GLShader::Define& define : defines ) + { + std::string tag = "#define"+define.nameToSearch; + for (std::string& line : lines) + { + std::string formatted = strRemoveSpaces(line); + if (formatted.find(tag) == 0) + { + std::size_t pos = line.find(define.nameToSearch) + define.nameToSearch.size(); + line.insert(pos, std::string(" (") + define.valueToSet + ") //"); + break; + } + } + } + + std::string out; + for ( std::string& line : lines ) + out = out + line + '\n'; + return out; + } + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Shader.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Shader.hpp new file mode 100644 index 0000000000000000000000000000000000000000..427cbf0a8bdb1575ff6342c9a9948ba331e11184 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Shader.hpp @@ -0,0 +1,391 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include +# include +# include "core/graphics/Config.hpp" +# include "core/system/Matrix.hpp" + +#define SIBR_SHADER(version, shader) std::string("#version " #version "\n" #shader) + +namespace sibr +{ + /** + OpenGL shader wrapper. + * \ingroup sibr_graphics + */ + class SIBR_GRAPHICS_EXPORT GLShader + { + SIBR_DISALLOW_COPY( GLShader ); + SIBR_CLASS_PTR(GLShader); + public: + + /** Macro-like substitution in shaders. */ + struct Define + { + typedef std::vector List; + + /** Constructor. + \param nameToSearch_ the macro value to replace + \param valueToSet_ the replacement value (stringified) + */ + template + Define( const std::string& nameToSearch_, const TValue& valueToSet_ ) : + nameToSearch(nameToSearch_) { + std::ostringstream oss; + oss << valueToSet_; + valueToSet = oss.str(); + } + + std::string nameToSearch; ///< the macro value to replace + std::string valueToSet; ///< String representation of the replacement value. + }; + + public: + + /// Constructor. + GLShader( void ); + + /// Destructor. + ~GLShader( void ); + + /** Create and compile a GPU program composed of a vertex/fragment shader (and optionally geometry/tesselation shaders). + \param name the name of the shader (for logging) + \param vp_code vertex shader code string + \param fp_code fragment shader code string + \param gp_code geometry shader code string + \param exitOnError should the application exit on a shader compilation error + \param tcs_code tesselation control shader code string + \param tes_code tesselation evaluation shader code string + \return a success flag + */ + bool init(std::string name, + std::string vp_code, std::string fp_code, + std::string gp_code = std::string(), + bool exitOnError = true, + std::string tcs_code = std::string(), + std::string tes_code = std::string()); + + /** Recompile a GPU program with updated shaders. + \param vp_code vertex shader code string + \param fp_code fragment shader code string + \param gp_code geometry shader code string + \return a success flag + */ + bool reload( + std::string vp_code, std::string fp_code, + std::string gp_code = std::string()); + + /** + Query the dissassembly of the shader program. + \param binary will contain the compiled shader code + \note This is not supported on all GPUs. + */ + void getBinary(std::vector & binary); + + /** Bind (activate) the sahder for rendering. */ + SIBR_OPT_INLINE void begin( void ); + + /** Unbind the shader. */ + SIBR_OPT_INLINE void end( void ); + + /** Init from an existing GPU program. + \param s_handle the existing program handle + */ + void init ( GLuint s_handle ); + + /** Cleanup and delete the program. */ + void terminate( void ); + + /** If set to true, uniforms that are linked but not referenced + by the shader will cause an error to be raised. + \param s the validation level + */ + void setStrict ( bool s ); + + /** \return the program handle. */ + GLuint shader ( void ) const; + + /** \return the shader name. */ + std::string name ( void ) const; + + /** \return true if the shader is properly setup. */ + bool isReady ( void ) const; + + /** \return true if the shader is currently bound for drawing. */ + bool isActive ( void ) const; + + /** \return true if the shader will validate linked uniforms. */ + bool isStrict ( void ) const; + + private: + + /** Compile a shader for a given stage. + \param shader_code the string containing the sahder code + \param type the stage to compile for + \return the compiled shader stage handle. + */ + GLuint compileShader( const char* shader_code, GLuint type ); + + /** Check if the shader is properly setup, or raise an error. */ + SIBR_OPT_INLINE void authorize( void ) const; + + GLuint m_Shader; ///< Shader program handle. + std::string m_Name; ///< Shader name. + bool m_Strict; ///< Should uniforms be validated. + bool m_Active; ///< Is the shader currently bound. + }; + + // ------------------------------------------------------------------------ + + + /** + OpenGL shader uniform wrapper. Prefer using GLuniform instead. + \sa GLuniform + * \ingroup sibr_graphics + */ + class SIBR_GRAPHICS_EXPORT GLParameter + { + public: + + /// Constructor. + GLParameter( void ); + + /** Link the uniform to a shader. + \param shader the shader to link to + \param name the name of the uniform in the shader + */ + void init( sibr::GLShader& shader, std::string name ); + + /** \return true if the uniform was linked to a shader. */ + bool isInitialized( void ) const; + + /** \return the OpenGL uniform location handle. */ + GLint handle( void ) const; + + /** Set the uniform float value. + \param f the new value + */ + SIBR_OPT_INLINE void set( float f ); + + /** Set the uniform vec2 value. + \param a first component + \param b second component + */ + SIBR_OPT_INLINE void set( float a, float b ); + + /** Set the uniform vec3 value. + \param a first component + \param b second component + \param c third component + */ + SIBR_OPT_INLINE void set( float a, float b, float c ); + + /** Set the uniform vec4 value. + \param a first component + \param b second component + \param c third component + \param d fourth component + */ + SIBR_OPT_INLINE void set( float a, float b, float c, float d ); + + /** Set the uniform mat4 value. + \param matrix the 16 matrix components, in row order + */ + SIBR_OPT_INLINE void set( const float *matrix ); + + /** Set the uniform sampler value. + \param tex the new value (ie the binding location of the texture) + */ + SIBR_OPT_INLINE void set( GLuint tex ); + + /** Set the uniform integer value. + \param v the new value + */ + SIBR_OPT_INLINE void set( int v ); + + /** Set the uniform boolean value (converted to an int). + \param b the new value + */ + SIBR_OPT_INLINE void set( bool b); + + /** Set the uniform values defined as an array of floats. + \param pv pointer to the float array + \param size number of elements + */ + SIBR_OPT_INLINE void setArray( const float *pv, int size ); + + /** Set the uniform values defined as an array of integers. + \param pv pointer to the int array + \param size number of elements + */ + SIBR_OPT_INLINE void setArray( const std::vector& pv, int size ); + + /** Set the uniform ivec2 value. + \param v the new value + */ + SIBR_OPT_INLINE void set(const Vector2i& v); + + /** Set the uniform ivec3 value. + \param v the new value + */ + SIBR_OPT_INLINE void set(const Vector3i& v); + + /** Set the uniform ivec4 value. + \param v the new value + */ + SIBR_OPT_INLINE void set(const Vector4i& v); + + /** Set the uniform vec2 value. + \param v the new value + */ + SIBR_OPT_INLINE void set( const Vector2f& v ); + + /** Set the uniform vec3 value. + \param v the new value + */ + SIBR_OPT_INLINE void set( const Vector3f& v ); + + /** Set the uniform vec4 value. + \param v the new value + */ + SIBR_OPT_INLINE void set( const Vector4f& v ); + + /** Set the uniform mat4 value. + \param m the new value + */ + SIBR_OPT_INLINE void set( const Matrix4f& m ); + + /** Set the uniform values defined as an array of mat4s (row major). + \param m pinter to the beginning of the matrix array + \param num number of matrices + */ + SIBR_OPT_INLINE void setMatrixArray(const float * m, int num); + + private: + + sibr::GLShader* m_Shader; ///< Linked shader. + GLint m_Handle; ///< Uniform location. + std::string m_Name; ///< Uniform name. + bool m_Strict; ///< Should the program raise an error if the uniform is not found in the linked shader. + + /** Check if the uniform/shader link is valid. */ + SIBR_OPT_INLINE void authorize( void ) const; + }; + + /** Load a file from disk and apply macro-like substitutions. + \param filename the file path + \param defines a list of substitutions to apply + \return the loaded string + \ingroup sibr_graphics + */ + SIBR_GRAPHICS_EXPORT std::string loadFile( const std::string& filename, const GLShader::Define::List& defines ); + + /** + OpenGL shader uniform wrapper with additional update/storage functions. + It will behave as an element of the type it wraps, but can also be set/sent to the GPU. + This limits duplication, as you can replace a float+GLParameter by a GLuniform + When you need a reference to the value (for instance in imGui), use uniform.get(). + \sa GLParameter + * \ingroup sibr_graphics + */ + template class GLuniform { + + public: + /** Constructor. + \param t initial value to use + */ + GLuniform(const T & t) : value(t) {} + + /** \return a reference to the value. */ + operator T & () { return value; } + + /** \return a reference to the value. */ + T & get() { return value; } + + /** Copy operator. Update the stored value. + \param t the new value + \return a reference to the value. + */ + T & operator=(const T & t) { value = t; return *this; } + + /** Copy operator. Update the stored value using the one of the other uniform. + \param other uniform to get the new value from + \return a reference to itself + */ + GLuniform & operator=(const GLuniform& other) { value = other.value; return *this; }; + + /** not-equal-to operator. Compares the stored values with the argument and returns + the not-equal-to operator. + \param t value to compare to. + \return the boolean result of the operation. + */ + bool operator!=(const T& t) { return value != t; } + + /** Copy constructor. Update the stored value using the one of the other uniform. + \param other uniform to get the new value from + */ + explicit GLuniform(const GLuniform&other) : value(other.value) { }; + + /// Default constructor. + GLuniform() = default; + + /** Link the uniform to a shader. + \param shader the shader to link to + \param name the name of the uniform in the shader + */ + void init(sibr::GLShader& shader, std::string name) { + parameter.init(shader, name); + } + + /** Send the value to the shader if it was initialized. + \note the shader has to be active + */ + void send() { + if (parameter.isInitialized()) { + parameter.set(value); + } + } + + /** Set the value and send it to the shader if it was initialized. + \param t the new value + \note the shader has to be active + */ + void set(const T & t) { + value = t; + send(); + } + + /** Set a list of values and send it to the shader if it was initialized. + \param t the new values + \param size the number of values + \note the shader has to be active + */ + void setArray(const T & t,int size) { + value = t; + if (parameter.isInitialized()) { + parameter.setArray(value,size); + } + } + + protected : + T value = T(); ///< The underlying value. + sibr::GLParameter parameter; ///< The underlying uniform. + }; + +} // namespace sibr + +# ifdef SIBR_MAXIMIZE_INLINE +# include "Shader.inl" +# endif diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Shader.inl b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Shader.inl new file mode 100644 index 0000000000000000000000000000000000000000..c0822cf36804fe63cc02071ce003b7db15d263b8 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Shader.inl @@ -0,0 +1,168 @@ + +namespace sibr +{ + void GLShader::authorize(void) const + { + if (!m_Shader) { + std::string message = "sibr::GLShader " + m_Name + " used without having been initialized"; + throw std::runtime_error(message); + } + } + + void GLShader::begin( void ) + { + CHECK_GL_ERROR; + authorize(); + glUseProgram(m_Shader); + m_Active = true; + CHECK_GL_ERROR; + } + + void GLShader::end( void ) + { + glUseProgram(0); + m_Active = false; + CHECK_GL_ERROR; + } + + void GLParameter::authorize(void) const + { + if (m_Shader == NULL) { + std::string message = "GLParameter " + m_Name + " does not have a valid shader program"; + throw std::runtime_error(message); + } + if (m_Strict && m_Handle == -1) { + std::string message = "GLParameter " + m_Name + " used without having been initialized"; + throw std::runtime_error(message); + } + if (!m_Shader->isActive()) { + std::string message = "GLParameter " + m_Name + " used with shader is not active"; + throw std::runtime_error(message); + } + } + + void GLParameter::set( float f ) + { + authorize(); + if (!m_Strict && m_Handle == -1) return; + glUniform1f(m_Handle,f); + } + + void GLParameter::set( float a,float b ) + { + authorize(); + if (!m_Strict && m_Handle == -1) return; + glUniform2f(m_Handle,a,b); + } + + void GLParameter::set( float a, float b, float c ) + { + authorize(); + if (!m_Strict && m_Handle == -1) return; + glUniform3f(m_Handle,a,b,c); + } + + void GLParameter::set( float a, float b, float c, float d ) + { + authorize(); + if (!m_Strict && m_Handle == -1) return; + glUniform4f(m_Handle,a,b,c,d); + } + + void GLParameter::set( const float *matrix ) + { + authorize(); + if (!m_Strict && m_Handle == -1) return; + glUniformMatrix4fv(m_Handle,1,GL_TRUE,matrix); // row major + } + + void GLParameter::set( GLuint tex ) + { + authorize(); + if (!m_Strict && m_Handle == -1) return; + glUniform1i(m_Handle,tex); + } + + void GLParameter::set( int v ) + { + authorize(); + if (!m_Strict && m_Handle == -1) return; + glUniform1i(m_Handle,v); + } + + void GLParameter::set(bool b) + { + set((int)b); + } + + void GLParameter::setArray( const float *pv, int size ) + { + authorize(); + if (!m_Strict && m_Handle == -1) return; + glUniform1fv(m_Handle,size,pv); + } + + void GLParameter::setArray( const std::vector& pv, int size ) + { + authorize(); + if (!m_Strict && m_Handle == -1) return; + glUniform1iv(m_Handle,size,&pv[0]); + } + + void GLParameter::set(const Vector2i& v) + { + authorize(); + if (!m_Strict && m_Handle == -1) return; + glUniform2i(m_Handle, v[0], v[1]); + } + + void GLParameter::set(const Vector3i& v) + { + authorize(); + if (!m_Strict && m_Handle == -1) return; + glUniform3i(m_Handle, v[0], v[1], v[2]); + } + + void GLParameter::set(const Vector4i& v) + { + authorize(); + if (!m_Strict && m_Handle == -1) return; + glUniform4i(m_Handle, v[0], v[1], v[2], v[3]); + } + + void GLParameter::set( const Vector2f& v ) + { + authorize(); + if (!m_Strict && m_Handle == -1) return; + glUniform2f(m_Handle,v[0],v[1]); + } + + void GLParameter::set( const Vector3f& v ) + { + authorize(); + if (!m_Strict && m_Handle == -1) return; + glUniform3f(m_Handle,v[0],v[1],v[2]); + } + + void GLParameter::set( const Vector4f& v ) + { + authorize(); + if (!m_Strict && m_Handle == -1) return; + glUniform4f(m_Handle,v[0],v[1],v[2],v[3]); + } + + void GLParameter::set( const Matrix4f& m ) + { + authorize(); + if (!m_Strict && m_Handle == -1) return; + glUniformMatrix4fv(m_Handle,1,GL_FALSE,m.data()); // row major + } + + void GLParameter::setMatrixArray(const float* m, int num) + { + authorize(); + if (!m_Strict && m_Handle == -1) return; + glUniformMatrix4fv(m_Handle, num, GL_FALSE, m); // row major + } + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Texture.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Texture.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ba6c401685f9a02e5a77a7d14ddad397b6efe694 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Texture.cpp @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#include "core/graphics/Texture.hpp" +//#define HEADLESS + +namespace sibr +{ + void blit(const ITexture2D& src, const IRenderTarget& dst, GLbitfield mask, GLenum filter, bool flip) + { + GLuint sourceFrameBuffer = 0; + glGenFramebuffers(1, &sourceFrameBuffer); + glBindFramebuffer(GL_READ_FRAMEBUFFER, sourceFrameBuffer); + glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, src.handle(), 0); + + SIBR_ASSERT(glCheckFramebufferStatus(GL_READ_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); + +#ifdef HEADLESS + + SIBR_ERR << "No named frame buffers in headless " << std::endl; +#else + glBlitNamedFramebuffer( + sourceFrameBuffer, dst.fbo(), + 0, 0, src.w(), src.h(), + 0, (flip ? dst.h() : 0), dst.w(), (flip ? 0 : dst.h()), + mask, filter); + + glDeleteFramebuffers(1, &sourceFrameBuffer); +#endif + } + + void blit_and_flip(const ITexture2D& src, const IRenderTarget& dst, GLbitfield mask, GLenum filter) + { + blit(src, dst, mask, filter, true); + } + + void blitToColorAttachment(const ITexture2D& src, IRenderTarget& dst, int location, GLenum filter, bool flip) + { + // To blit only to a specific color attachment, it should be the only draw buffer registered. + // So we override the drawbuffer from dst temporarily. + glBindFramebuffer(GL_FRAMEBUFFER, dst.fbo()); + glDrawBuffer(GL_COLOR_ATTACHMENT0 + location); + + GLuint sourceFrameBuffer = 0; + glGenFramebuffers(1, &sourceFrameBuffer); + glBindFramebuffer(GL_READ_FRAMEBUFFER, sourceFrameBuffer); + glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, src.handle(), 0); + + SIBR_ASSERT(glCheckFramebufferStatus(GL_READ_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); + +#ifdef HEADLESS + SIBR_ERR << "No named frame buffers in headless " << std::endl; +#else + glBlitNamedFramebuffer( + sourceFrameBuffer, dst.fbo(), + 0, 0, src.w(), src.h(), + 0, (flip ? dst.h() : 0), dst.w(), (flip ? 0 : dst.h()), + GL_COLOR_BUFFER_BIT, filter); + + glDeleteFramebuffers(1, &sourceFrameBuffer); +#endif + + // Restore the drawbuffers. + // We use bind() as it guarantees that all color buffers will be bound. + dst.bind(); + dst.unbind(); + } + + void blit(const IRenderTarget& src, const ITexture2D& dst, GLbitfield mask, GLenum filter) + { + GLuint dstFrameBuffer = 0; + glGenFramebuffers(1, &dstFrameBuffer); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFrameBuffer); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dst.handle(), 0); + + SIBR_ASSERT(glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); + +#ifdef HEADLESS + SIBR_ERR << "No named frame buffers in headless " << std::endl; +#else + glBlitNamedFramebuffer( + src.fbo(), dstFrameBuffer, + 0, 0, src.w(), src.h(), + 0, 0, dst.w(), dst.h(), + mask, filter); + glDeleteFramebuffers(1, &dstFrameBuffer); +#endif + } + + void blit(const ITexture2D& src, const ITexture2D& dst, GLbitfield mask, GLenum filter) + { + GLuint fbo[2]; + glGenFramebuffers(2, fbo); + glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo[0]); + glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, src.handle(), 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo[0]); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dst.handle(), 0); + + SIBR_ASSERT(glCheckFramebufferStatus(GL_READ_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); + SIBR_ASSERT(glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); + +#ifdef HEADLESS + SIBR_ERR << "No named frame buffers in headless " << std::endl; +#else + glBlitNamedFramebuffer( + fbo[0], fbo[1], + 0, 0, src.w(), src.h(), + 0, 0, dst.w(), dst.h(), + mask, filter); + glDeleteFramebuffers(2, fbo); +#endif + } + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Texture.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Texture.hpp new file mode 100644 index 0000000000000000000000000000000000000000..87d9a68c24d48984924e63d78331b5ade551ac11 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Texture.hpp @@ -0,0 +1,1522 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include + +# include "core/graphics/Config.hpp" +# include "core/system/Vector.hpp" +# include "core/graphics/Image.hpp" +# include "core/graphics/Types.hpp" +# include "core/graphics/RenderTarget.hpp" + +namespace sibr +{ + + /** Interface for a generic GPU 2D texture. + * \sa Texture2D + * \ingroup sibr_graphics + */ + class ITexture2D + { + public: + typedef std::shared_ptr Ptr; + typedef std::unique_ptr UPtr; + public: + + /// Destructor. + virtual ~ITexture2D(void) { } + + /** \return the texture handle. */ + virtual GLuint handle(void) const = 0; + + /** \return the texture width. */ + virtual uint w(void) const = 0; + + /** \return the texture height. */ + virtual uint h(void) const = 0; + }; + + /** Represent a 2D texture on the GPU, with custom format and type. + * \sa ITexture2D + * \ingroup sibr_graphics + */ + template + class Texture2D : public ITexture2D { + SIBR_DISALLOW_COPY(Texture2D); + public: + typedef Image PixelImage; + typedef typename PixelImage::Pixel PixelFormat; + typedef std::shared_ptr> Ptr; + typedef std::unique_ptr> UPtr; + + public: + + /// Constructor. + Texture2D(void); + + /** Constructor from an image. + \param img the image to upload to the GPU + \param flags options + */ + template Texture2D(const ImageType& img, uint flags = 0); + + /** Constructor from a list of images, one for each mip level. + \param miparray the images to upload to the GPU + \param flags options + */ + Texture2D(const std::vector& miparray, uint flags = 0); + + /// Destructor. + ~Texture2D(void); + + /** \return the texture handle. */ + GLuint handle(void) const; + + /** \return the texture width. */ + uint w(void) const; + + /** \return the texture height. */ + uint h(void) const; + + /** \return a CPU image containing the texture content. + \warning Can cause a GPU flush/sync. + */ + sibr::Image readBack(void) const; + + /** Update the content of the txeture with a new image. + \param img the new content. + */ + template void update(const ImageType& img); + + /** Trigger an update of the mipmaps for level 0 to maxLOD. + \param maxLOD the maximum level of mipmap to generate. If -1, as many as possible based on the texture size. + */ + void mipmap(int maxLOD = -1); + + private: + GLuint m_Handle = 0; ///< Texture handle. + uint m_W = 0; ///< Texture width. + uint m_H = 0; ///< Texture height. + uint m_Flags = 0; ///< Options. + bool m_autoMIPMAP = false; ///< Should the mipmaps be generated automatically. + + /** Create 2D texture from a generic image (sibr::image or cv::Mat). + \param array the image + \param flags options + \return the handle of the texture + */ + template static GLuint create2D(const ImageType& array, uint flags); + + /** Create 2D texture with custom mipmaps from a list of generic images (sibr::image or cv::Mat). + \param miparray the images + \param flags options + \return the handle of the texture + */ + static GLuint create2D(const std::vector& miparray, uint flags); + + /** Send the CPU image data to the GPU. + \param id the created texture + \param array the image data + \param flags options + */ + template static void send2D(GLuint id, const ImageType& array, uint flags); + + /** Send the CPU images data for each mipmap to the GPU. + \param id the created texture + \param miparray the image data + \param flags options + */ + static void send2Dmipmap(GLuint id, const std::vector& miparray, uint flags); + + }; + + + /** Interface for a generic GPU 2D array texture. + * \sa Texture2DArray + * \ingroup sibr_graphics + */ + class ITexture2DArray + { + public: + typedef std::shared_ptr Ptr; + typedef std::unique_ptr UPtr; + public: + /// Destructor. + virtual ~ITexture2DArray(void) { } + + /** \return the texture handle. */ + virtual GLuint handle(void) const = 0; + + /** \return the texture width. */ + virtual uint w(void) const = 0; + + /** \return the texture height. */ + virtual uint h(void) const = 0; + + /** \return the texture layer count. */ + virtual uint depth(void) const = 0; + + /** \return the number of mipmap levels. */ + virtual uint numLODs(void) const = 0; + + /** Read back the value of a given pixel to the CPU. + \param i layer + \param x x coordinate in [0,w-1] + \param y y coordinate in [0,h-1] + \param lod the mip level + \return a converted RGBA float color + \warning Use only for debugging, can cause a GPU flush/sync. + */ + virtual Vector4f readBackPixel(int i, int x, int y, uint lod = 0) const = 0; + }; + + /** + * Represent an array of 2D textures on the GPU, with custom format, type and slice count. + * \sa ITexture2DArray + * \ingroup sibr_graphics + */ + template + class Texture2DArray : public ITexture2DArray { + SIBR_DISALLOW_COPY(Texture2DArray); + public: + typedef Image PixelImage; + typedef typename PixelImage::Pixel PixelFormat; + typedef RenderTarget PixelRT; + typedef std::shared_ptr> Ptr; + typedef std::unique_ptr> UPtr; + + public: + + /** Constructor. + \param d number of layers + \param flags options + */ + Texture2DArray(const uint d = 0, uint flags = 0); + + /** Constructor. + \param w width + \param h height + \param d number of layers + \param flags options + */ + Texture2DArray(const uint w, const uint h, const uint d, uint flags = 0); + + /** Constructor from a set of rendertargets. + \param images list of rendertargets, one for each layer + \param flags options + \warning RTs should be of the same size. + */ + Texture2DArray(const std::vector& images, uint flags = 0); + + /** Constructor from a set of CPU images. + \param images list of images, one for each layer + \param flags options + \note All images will be resized to the dimensions of the largest one. + */ + template + Texture2DArray(const std::vector& images, uint flags = 0); + + /** Constructor from a set of CPU images that will be resized to a fix size. + \param images list of images, one for each layer + \param w the target width + \param h the target height + \param flags options + */ + template + Texture2DArray(const std::vector& images, uint w, uint h, uint flags = 0); + + /** Constructor from a set of CPU images, with custom mipmaps. + \param images list of lists of images, one for each mip level, each containing an image for each layer + \param flags options + \note All images will be resized to the dimensions of the largest one. + */ + template + Texture2DArray(const std::vector>& images, uint flags = 0); + + /** Constructor from a set of CPU images, with custom mipmaps. + \param images list of lists of images, one for each mip level, each containing an image for each layer + \param w the target width + \param h the target height + \param flags options + */ + template + Texture2DArray(const std::vector>& images, uint w, uint h, uint flags = 0); + + /** Create the texture from a set of images and send it to GPU. + \param images list of images, one for each layer + \param flags options + \note All images will be resized to the dimensions of the largest one. + */ + template + void createFromImages(const std::vector& images, uint flags = 0); + + /** Create the texture from a set of images and send it to GPU. images will be resized to the target size. + \param images list of images, one for each layer + \param w the target width + \param h the target height + \param flags options + */ + template + void createFromImages(const std::vector& images, uint w, uint h, uint flags = 0); + + /** Create the texture from a set of images and send it to GPU while compressing them. + \param images list of images, one for each layer + \param compression the GL_COMPRESSED format. It must be choosen accordingly to the texture internal format. + \param flags options + \note All images will be resized to the dimensions of the largest one. + */ + template + void createCompressedFromImages(const std::vector& images, uint compression, uint flags = 0); + + /** Create the texture from a set of images and send it to GPU while compressing them. images will be resized to the target size. + \param images list of images, one for each layer + \param w the target width + \param h the target height + \param compression the GL_COMPRESSED format. It must be choosen accordingly to the texture internal format. + \param flags options + */ + template + void createCompressedFromImages(const std::vector& images, uint w, uint h, uint compression, uint flags = 0); + + /** Create the texture from a set of images with custom mipmaps and send it to GPU. + \param images list of lists of images, one for each mip level, each containing an image for each layer + \param flags options + \note All images will be resized to the dimensions of the largest one. + */ + template + void createFromImages(const std::vector>& images, uint flags = 0); + + /** Create the texture from a set of images with custom mipmaps and send it to GPU. + \param images list of lists of images, one for each mip level, each containing an image for each layer + \param w the target width + \param h the target height + \param flags options + */ + template + void createFromImages(const std::vector>& images, uint w, uint h, uint flags = 0); + + /** Update the content of all layers of the texture. + \param images the new content to use + \note All images will be resized to the size of the largest one. + */ + template + void updateFromImages(const std::vector& images); + + /** Create the texture from a set of rendertargets and send it to GPU. + \param RTs list of rendertargets, one for each layer + \param flags options + \warning RTs should be of the same size. + */ + void createFromRTs(const std::vector& RTs, uint flags = 0); + + /** Update the content of specific layers of the texture. + \param images the new content to use + \param slices the indices of the slices to update + \note All images will be resized to the size of the largest one. + */ + template + void updateSlices(const std::vector& images, const std::vector& slices); + + /// Destructor. + ~Texture2DArray(void); + + /** \return the texture handle. */ + GLuint handle(void) const; + + /** \return the texture width. */ + uint w(void) const; + + /** \return the texture height. */ + uint h(void) const; + + /** \return the texture layer count. */ + uint depth(void) const; + + /** \return the number of mipmap levels. */ + uint numLODs(void) const; + + /** Read back the value of a given pixel to the CPU. + \param i layer + \param x x coordinate in [0,w-1] + \param y y coordinate in [0,h-1] + \param lod the mip level + \return a converted RGBA float color + \warning Use only for debugging, can cause a GPU flush/sync. + */ + Vector4f readBackPixel(int i, int x, int y, uint lod = 0) const; + + private: + + /** Create the texture array. */ + void createArray(uint compression = 0); + + /** Upload the images data to the GPU. + \param images the data to upload + */ + template + void sendArray(const std::vector& images); + + /** Copy the rendertargets data to the texture. + \param RTs the rendertargets to copy + */ + void sendRTarray(const std::vector& RTs); + + /** Upload the images data to the GPU. + \param images the data to upload + */ + template + void sendMipArray(const std::vector>& images); + + /** Flip and rescale a subset of images from a list. + \param images the images to resize + \param tmp a temporary buffer + \param tw the target width + \param th the target height + \param slices the indices of the images to process in the list + \return a list of pointers to the transformed images + */ + template + std::vector applyFlipAndResize( + const std::vector& images, + std::vector& tmp, uint tw, uint th, + const std::vector& slices + ); + + /** Flip and rescale a set of images. + \param images the images to resize + \param tmp a temporary buffer + \param tw the target width + \param th the target height + \return a list of pointers to the transformed images + */ + template + std::vector applyFlipAndResize( + const std::vector& images, + std::vector& tmp, uint tw, uint th + ); + + GLuint m_Handle = 0; ///< Texture handle. + uint m_W = 0; ///< Texture width. + uint m_H = 0; ///< Texture height. + uint m_Flags = 0; ///< Options. + uint m_Depth = 0; ///< Layers count. + uint m_numLODs = 1; ///< Mipmap level count. + }; + + + /** Interface for a generic GPU cubemap texture. + * \sa TextureCubeMap + * \ingroup sibr_graphics + */ + class ITextureCubeMap + { + public: + typedef std::shared_ptr Ptr; + typedef std::unique_ptr UPtr; + public: + /// Destructor. + virtual ~ITextureCubeMap(void) { } + + /** \return the texture handle. */ + virtual GLuint handle(void) const = 0; + + /** \return the texture width. */ + virtual uint w(void) const = 0; + + /** \return the texture height. */ + virtual uint h(void) const = 0; + }; + + /** + * Represent a cubemap composed of 6 2D faces on the GPU, with custom format and type. + * \sa ITextureCubeMap + * \ingroup sibr_graphics + */ + template + class TextureCubeMap : public ITextureCubeMap { + SIBR_DISALLOW_COPY(TextureCubeMap); + + public: + typedef Image PixelImage; + typedef typename PixelImage::Pixel PixelFormat; + typedef RenderTarget PixelRT; + typedef std::shared_ptr> Ptr; + typedef std::unique_ptr> UPtr; + + public: + + /// Constructor. + TextureCubeMap(void); + + /** Constructor. + \param w width + \param h height + \param flags options + */ + TextureCubeMap(const uint w, const uint h, uint flags = 0); + + /** Create a cubemap from 6 images. + \param xpos positive X face + \param xneg negative X face + \param ypos positive Y face + \param yneg negative Y face + \param zpos positive Z face + \param zneg negative Z face + \param flags options + */ + TextureCubeMap(const PixelImage& xpos, const PixelImage& xneg, + const PixelImage& ypos, const PixelImage& yneg, + const PixelImage& zpos, const PixelImage& zneg, uint flags = 0); + + /** Create the texture from 6 images. + \param xpos positive X face + \param xneg negative X face + \param ypos positive Y face + \param yneg negative Y face + \param zpos positive Z face + \param zneg negative Z face + \param flags options + */ + void createFromImages(const PixelImage& xpos, const PixelImage& xneg, + const PixelImage& ypos, const PixelImage& yneg, + const PixelImage& zpos, const PixelImage& zneg, uint flags = 0); + + /// Destructor. + ~TextureCubeMap(void); + + /** \return the texture handle. */ + GLuint handle(void) const; + + /** \return the texture width. */ + uint w(void) const; + + /** \return the texture height. */ + uint h(void) const; + + private: + + /** Create the cubemap texture object. */ + void createCubeMap(); + + /** Upload cubemap data. + \param xpos positive X face + \param xneg negative X face + \param ypos positive Y face + \param yneg negative Y face + \param zpos positive Z face + \param zneg negative Z face + */ + void sendCubeMap(const PixelImage& xpos, const PixelImage& xneg, + const PixelImage& ypos, const PixelImage& yneg, + const PixelImage& zpos, const PixelImage& zneg); + + GLuint m_Handle = 0; ///< Texture handle. + uint m_W = 0; ///< Texture width. + uint m_H = 0; ///< Texture height. + uint m_Flags = 0; ///< Options. + + }; + + + /** + Copy the content of a texture to another texture, resizing if needed. + \param src source texture + \param dst destination texture + \param mask which part of the buffer to copy (color, depth, stencil). + \param filter filtering mode if the two buffers have different dimensions (linear or nearest) + \warning If the mask contains the depth or stencil, filter must be GL_NEAREST + \ingroup sibr_graphics + */ + SIBR_GRAPHICS_EXPORT void blit(const ITexture2D& src, const ITexture2D& dst, GLbitfield mask = GL_COLOR_BUFFER_BIT, GLenum filter = GL_LINEAR); + + + /** + Copy the content of a texture to a render target, resizing if needed. + \param src source texture + \param dst destination rendertarget + \param mask which part of the buffer to copy (color, depth, stencil). + \param filter filtering mode if the two buffers have different dimensions (linear or nearest) + \param flip flip the texture vertically when copying it + \note The blit can only happen for color attachment 0 in dst. + \warning If the mask contains the depth or stencil, filter must be GL_NEAREST + \ingroup sibr_graphics + */ + SIBR_GRAPHICS_EXPORT void blit(const ITexture2D& src, const IRenderTarget& dst, GLbitfield mask = GL_COLOR_BUFFER_BIT, GLenum filter = GL_LINEAR, bool flip = false); + + /** + Copy the content of a texture to a render target, resizing if needed and flipping the result. + \param src source texture + \param dst destination rendertarget + \param mask which part of the buffer to copy (color, depth, stencil). + \param filter filtering mode if the two buffers have different dimensions (linear or nearest) + \note The blit can only happen for color attachment 0 in dst. + \warning If the mask contains the depth or stencil, filter must be GL_NEAREST + \ingroup sibr_graphics + */ + SIBR_GRAPHICS_EXPORT void blit_and_flip(const ITexture2D& src, const IRenderTarget& dst, GLbitfield mask = GL_COLOR_BUFFER_BIT, GLenum filter = GL_LINEAR); + + /** + Copy the content of a texture to a specific color attachment of the destination render target, resizing if needed. + \param src source texture + \param dst destination rendertarget + \param location the color attachment to blit to + \param filter filtering mode if the two buffers have different dimensions (linear or nearest) + \param flip flip the texture vertically when copying it + \note No mask to specify, as this is assumed to be COLOR. + \ingroup sibr_graphics + */ + SIBR_GRAPHICS_EXPORT void blitToColorAttachment(const ITexture2D& src, IRenderTarget& dst, int location, GLenum filter = GL_LINEAR, bool flip = false); + + /** + Copy the content of a rendertarget first color attachment to a texture, resizing if needed. + \param src source rendertarget + \param dst destination texture + \param mask which part of the buffer to copy (color, depth, stencil). + \param filter filtering mode if the two buffers have different dimensions (linear or nearest) + \note The blit can only happen for color attachment 0 in dst. + \warning If the mask contains the depth or stencil, filter must be GL_NEAREST + \ingroup sibr_graphics + */ + SIBR_GRAPHICS_EXPORT void blit(const IRenderTarget& src, const ITexture2D& dst, GLbitfield mask = GL_COLOR_BUFFER_BIT, GLenum filter = GL_LINEAR); + + /** Display a RenderTarget into a popup OpenCV window. + \param rt the rendertarget to display + \param winTitle the window title + \ingroup sibr_graphics + */ + template + static void show(const RenderTarget& rt, const std::string& winTitle = "sibr::show()") { + Image img; + rt.readBack(img); + show(img, winTitle); + } + + /** Display a texture into a popup OpenCV window. + \param texture the texture to display + \param winTitle the window title + \ingroup sibr_graphics + */ + template + static void show(const Texture2D& texture, const std::string& winTitle = "sibr::show()") { + Image img(texture.w(), texture.h()); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture.handle()); + + glGetTexImage(GL_TEXTURE_2D, 0, sibr::GLFormat::format, sibr::GLType::type, img.data()); + show(img, winTitle); + } + + // --- TYPEDEFS -------------------------------------------------- + + typedef Texture2D Texture2DRGB; + typedef Texture2D Texture2DRGBA; + typedef Texture2D Texture2DLum; + + typedef Texture2D Texture2DRGBA16; + typedef Texture2D Texture2DLum16; + typedef Texture2D Texture2DUV16; + + typedef Texture2D Texture2DUV16s; + + typedef Texture2D Texture2DRGB32F; + typedef Texture2D Texture2DRGBA32F; + typedef Texture2D Texture2DUV32F; + typedef Texture2D Texture2DLum32F; + + + typedef Texture2DArray Texture2DArrayLum; + typedef Texture2DArray Texture2DArrayUV; + typedef Texture2DArray Texture2DArrayRGB; + typedef Texture2DArray Texture2DArrayRGBA; + + typedef Texture2DArray Texture2DArrayLum16; + typedef Texture2DArray Texture2DArrayUV16; + typedef Texture2DArray Texture2DArrayRGB16; + typedef Texture2DArray Texture2DArrayRGBA16; + + typedef Texture2DArray Texture2DArrayLum16s; + typedef Texture2DArray Texture2DArrayUV16s; + typedef Texture2DArray Texture2DArrayRGB16s; + typedef Texture2DArray Texture2DArrayRGBA16s; + + typedef Texture2DArray Texture2DArrayInt1; + typedef Texture2DArray Texture2DArrayInt2; + typedef Texture2DArray Texture2DArrayInt3; + typedef Texture2DArray Texture2DArrayInt4; + + typedef Texture2DArray Texture2DArrayLum32F; + typedef Texture2DArray Texture2DArrayUV32F; + typedef Texture2DArray Texture2DArrayRGB32F; + typedef Texture2DArray Texture2DArrayRGBA32F; + + + typedef TextureCubeMap TextureCubeMapLum; + typedef TextureCubeMap TextureCubeMapRGB; + typedef TextureCubeMap TextureCubeMapRGBA; + + typedef TextureCubeMap TextureCubeMapLum16; + typedef TextureCubeMap TextureCubeMapUV16; + typedef TextureCubeMap TextureCubeMapRGBA16; + + typedef TextureCubeMap TextureCubeMapUV16s; + + typedef TextureCubeMap TextureCubeMapLum32F; + typedef TextureCubeMap TextureCubeMapRGB32F; + typedef TextureCubeMap TextureCubeMapRGBA32F; + + /* Note concerning depth buffers : + * We don't support depth only rendertargets. + * Other kinds of RenderTarget (e.g. RenderTargetRGB) creates + * also a new depth buffer that is bound with the color buffer, so no need to explicitely create one. + * typedef RenderTarget RenderTargetDepth24; + */ + + + // ----DEFINITIONS Texture2D -------------------------------------------------- + + template template + GLuint Texture2D::create2D(const ImageType& img, uint flags) { + GLuint id = 0; + CHECK_GL_ERROR; + glGenTextures(1, &id); + glBindTexture(GL_TEXTURE_2D, id); + if (flags & SIBR_CLAMP_UVS) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + else if (flags & SIBR_CLAMP_TO_BORDER) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + } + if (flags & SIBR_GPU_AUTOGEN_MIPMAP) { + if (flags & SIBR_GPU_INTEGER) { + throw std::runtime_error("Mipmapping on integer texture not supported, probably not even by OpenGL"); + } + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + else { +#if SIBR_COMPILE_FORCE_SAMPLING_LINEAR + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +#else + if (flags & SIBR_GPU_LINEAR_SAMPLING) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + else { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } +#endif + } + send2D(id, img, flags); + CHECK_GL_ERROR; + return id; + } + + template + /*static*/ GLuint Texture2D::create2D(const std::vector& miparray, uint flags) { + GLuint id = 0; + CHECK_GL_ERROR; + glGenTextures(1, &id); + glBindTexture(GL_TEXTURE_2D, id); + if (flags & SIBR_CLAMP_UVS) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + else if (flags & SIBR_CLAMP_TO_BORDER) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + } + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, int(miparray.size()) - 1); + send2Dmipmap(id, miparray, flags); + CHECK_GL_ERROR; + return id; + } + + template template + void Texture2D::send2D(GLuint id, const ImageType& img, uint flags) { + using FormatInfos = GLTexFormat; + + if (flags & SIBR_GPU_INTEGER) { + if (FormatInfos::int_internal_format < 0) { + throw std::runtime_error("Texture format does not support integer mapping"); + } + } + + bool flip = flags & SIBR_FLIP_TEXTURE; + ImageType flippedImg; + if (flip) { + flippedImg = FormatInfos::flip(img); + } + const ImageType& sendedImg = flip ? flippedImg : img; + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glBindTexture(GL_TEXTURE_2D, id); + glTexImage2D(GL_TEXTURE_2D, + 0, + (flags & SIBR_GPU_INTEGER) ? FormatInfos::int_internal_format : FormatInfos::internal_format, + FormatInfos::width(sendedImg), FormatInfos::height(sendedImg), + 0, + (flags & SIBR_GPU_INTEGER) ? FormatInfos::int_format : FormatInfos::format, + FormatInfos::type, + FormatInfos::data(sendedImg) + ); + + bool autoMIPMAP = ((flags & SIBR_GPU_AUTOGEN_MIPMAP) != 0); + if (autoMIPMAP) + glGenerateMipmap(GL_TEXTURE_2D); + CHECK_GL_ERROR; + } + + // Send 2D texture to GPU memory, each mipmap is specified + template + /*static*/ void Texture2D::send2Dmipmap(GLuint id, const std::vector& miparray, uint flags) { + CHECK_GL_ERROR; + if (flags & SIBR_GPU_INTEGER) { + throw std::runtime_error("Mipmapping on integer texture not supported, probably not even by OpenGL"); + } + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glBindTexture(GL_TEXTURE_2D, id); + + std::vector flippedMipArray; + bool flip = flags & SIBR_FLIP_TEXTURE; + if (flip) { + flippedMipArray.resize(miparray.size()); +#pragma omp parallel for + for (uint l = 0; l < miparray.size(); l++) { + flippedMipArray[l] = miparray[l].clone(); + flippedMipArray[l].flipH(); + } + } + const std::vector& sendedMipArray = flip ? flippedMipArray : miparray; + + for (uint l = 0; l < miparray.size(); l++) { + glTexImage2D(GL_TEXTURE_2D, + l, + GLFormat::internal_format, + miparray[l].w(), miparray[l].h(), + 0, + GLFormat::format, + GLType::type, + sendedMipArray[l].data() + ); + } + CHECK_GL_ERROR; + } + + template + Texture2D::Texture2D(void) { + m_Flags = 0; + m_W = 0; + m_H = 0; + m_Handle = 0; + m_autoMIPMAP = false; + } + + template template + Texture2D::Texture2D(const ImageType& img, uint flags) { + using TexFormat = GLTexFormat; + m_Flags = flags; + m_W = TexFormat::width(img); + m_H = TexFormat::height(img); + m_Handle = create2D(img, m_Flags); + m_autoMIPMAP = ((flags & SIBR_GPU_AUTOGEN_MIPMAP) != 0); + } + + template + Texture2D::Texture2D(const std::vector& miparray, uint flags) { + m_Flags = flags; + m_W = miparray[0].w(); + m_H = miparray[0].h(); + m_Handle = create2D(miparray, m_Flags); + m_autoMIPMAP = false; + } + + template + Texture2D::~Texture2D(void) { + CHECK_GL_ERROR; + glDeleteTextures(1, &m_Handle); + CHECK_GL_ERROR; + } + + template + GLuint Texture2D::handle(void) const { return m_Handle; } + template + uint Texture2D::w(void) const { return m_W; } + template + uint Texture2D::h(void) const { return m_H; } + + + template + sibr::Image Texture2D::readBack(void) const { + + // makes sure Vertex have the correct size (read back relies on pointers) + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glBindTexture(GL_TEXTURE_2D, handle()); + + int w, h; + glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w); + glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h); + + sibr::Image img(w, h); + + glGetTexImage(GL_TEXTURE_2D, + 0, + GLFormat::format, + GLType::type, + img.data() + ); + + // flip data vertically to get origin on lower left corner + img.flipH(); + + CHECK_GL_ERROR; + + return img; + } + + template template + void Texture2D::update(const ImageType& img) { + using FormatInfos = GLTexFormat; + if (FormatInfos::width(img) == w() && FormatInfos::height(img) == h()) + { + bool flip = m_Flags & SIBR_FLIP_TEXTURE; + ImageType flippedImg; + if (flip) { + flippedImg = FormatInfos::flip(img); + } + const ImageType& sendedImg = flip ? flippedImg : img; + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glBindTexture(GL_TEXTURE_2D, handle()); + glTexSubImage2D(GL_TEXTURE_2D, 0, + 0, 0, FormatInfos::width(sendedImg), FormatInfos::height(sendedImg), + FormatInfos::format, + FormatInfos::type, + FormatInfos::data(sendedImg) + ); + if (m_autoMIPMAP) + glGenerateMipmap(GL_TEXTURE_2D); + } + else { + m_W = FormatInfos::width(img); + m_H = FormatInfos::height(img); + send2D(m_Handle, img, m_Flags); + } + } + + template + void Texture2D::mipmap(int maxLOD) { + glBindTexture(GL_TEXTURE_2D, handle()); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, maxLOD >= 0 ? maxLOD : 1000); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + m_autoMIPMAP = true; + glGenerateMipmap(GL_TEXTURE_2D); + } + + + + // ----DEFINITIONS Texture2DArray -------------------------------------------------- + + template + Texture2DArray::Texture2DArray(const uint d, uint flags) { + m_Depth = d; + m_Flags = flags; + } + + template + Texture2DArray::Texture2DArray(const uint w, const uint h, const uint d, uint flags) { + m_W = w; + m_H = h; + m_Depth = d; + m_Flags = flags; + createArray(); + } + + template template + Texture2DArray::Texture2DArray(const std::vector& images, uint flags) { + m_Flags = flags; + createFromImages(images, flags); + } + + template template + Texture2DArray::Texture2DArray(const std::vector& images, uint w, uint h, uint flags) { + m_Flags = flags; + createFromImages(images, w, h, flags); + } + + template template + Texture2DArray::Texture2DArray(const std::vector>& images, uint flags) { + m_Flags = flags; + createFromImages(images, flags); + } + + template template + Texture2DArray::Texture2DArray(const std::vector>& images, uint w, uint h, uint flags) { + m_Flags = flags; + createFromImages(images, w, h, flags); + } + + template + Texture2DArray::Texture2DArray(const std::vector& RTs, uint flags) { + m_Flags = flags; + createFromRTs(RTs, flags); + } + + template + void Texture2DArray::createArray(uint compression) { + CHECK_GL_ERROR; + glGenTextures(1, &m_Handle); + glBindTexture(GL_TEXTURE_2D_ARRAY, m_Handle); + + const bool autoMIPMAP = ((m_Flags & SIBR_GPU_AUTOGEN_MIPMAP) != 0); + const int numMipMap = autoMIPMAP ? (int)std::floor(std::log2(std::max(m_W, m_H))) : m_numLODs; + + m_numLODs = numMipMap; + + if (m_numLODs == 1) { + if (m_Flags & SIBR_GPU_LINEAR_SAMPLING) { + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + else { + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + + } + else { + if (m_Flags & SIBR_GPU_LINEAR_SAMPLING) { + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + else { + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + } + + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + uint internal_format = GLFormat::internal_format; + if (compression) + internal_format = compression; + + glTexStorage3D(GL_TEXTURE_2D_ARRAY, numMipMap, + internal_format, + m_W, + m_H, + m_Depth + ); + + CHECK_GL_ERROR; + } + + template template + void Texture2DArray::sendArray(const std::vector& images) { + using ImgTypeInfo = GLTexFormat; + glBindTexture(GL_TEXTURE_2D_ARRAY, m_Handle); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + + // Make sure all images have the same size. + std::vector tmp; + std::vector imagesPtrToSend = applyFlipAndResize(images, tmp, m_W, m_H); + + for (int im = 0; im < (int)m_Depth; ++im) { + glTexSubImage3D(GL_TEXTURE_2D_ARRAY, + 0, + 0, 0, im, + m_W, + m_H, + 1, // one slice at a time + ImgTypeInfo::format, + ImgTypeInfo::type, + ImgTypeInfo::data(*imagesPtrToSend[im]) + ); + //CHECK_GL_ERROR; + } + bool autoMIPMAP = ((m_Flags & SIBR_GPU_AUTOGEN_MIPMAP) != 0); + if (autoMIPMAP) { + glGenerateMipmap(GL_TEXTURE_2D_ARRAY); + } + CHECK_GL_ERROR; + } + + template template + void Texture2DArray::sendMipArray(const std::vector>& images) { + using ImgTypeInfo = GLTexFormat; + glBindTexture(GL_TEXTURE_2D_ARRAY, m_Handle); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + + assert(m_numLODs == images.size()); + for (int lid = 0; lid < int(images.size()); ++lid) { + + assert(m_Depth == images[lid].size()); + + // Make sure all images have the same size. + const uint dW = m_W / (1 << lid); + const uint dH = m_H / (1 << lid); + std::vector tmp; + std::vector imagesPtrToSend = applyFlipAndResize(images[lid], tmp, dW, dH); + + for (int im = 0; im < (int)m_Depth; ++im) { + glTexSubImage3D(GL_TEXTURE_2D_ARRAY, + lid, + 0, 0, im, + dW, + dH, + 1, // one slice at a time + ImgTypeInfo::format, + ImgTypeInfo::type, + ImgTypeInfo::data(*imagesPtrToSend[im]) + ); + } + } + // No auto mipmap when specifying the mips. + m_Flags &= ~SIBR_GPU_AUTOGEN_MIPMAP; + CHECK_GL_ERROR; + } + + template template + std::vector Texture2DArray::applyFlipAndResize( + const std::vector& images, + std::vector& tmp, uint tw, uint th, + const std::vector& slices) + { + using ImgTypeInfo = GLTexFormat; + + std::vector imagesPtrToSend(images.size()); + tmp.resize(images.size()); + + bool flip = m_Flags & SIBR_FLIP_TEXTURE; + //#pragma omp parallel for // Disabled due to performance reasons when live-updating slices. + for (int slice_id = 0; slice_id < (int)slices.size(); ++slice_id) { + int im = slices[slice_id]; + + bool resize = !(tw == ImgTypeInfo::width(images[im]) && th == ImgTypeInfo::height(images[im])); + if (!flip && !resize) { + imagesPtrToSend[im] = &images[im]; + } + else { + if (resize) { + tmp[im] = ImgTypeInfo::resize(images[im], tw, th); + } + if (flip) { + tmp[im] = ImgTypeInfo::flip(resize ? tmp[im] : images[im]); + } + imagesPtrToSend[im] = &tmp[im]; + } + } + + return imagesPtrToSend; + } + + template + template + std::vector Texture2DArray::applyFlipAndResize( + const std::vector& images, + std::vector& tmp, uint tw, uint th + ) { + std::vector slices(m_Depth); + for (int i = 0; i < (int)m_Depth; ++i) { + slices[i] = i; + } + return applyFlipAndResize(images, tmp, tw, th, slices); + } + + template + void Texture2DArray::sendRTarray(const std::vector& RTs) { + CHECK_GL_ERROR; + glBindTexture(GL_TEXTURE_2D_ARRAY, m_Handle); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + for (int im = 0; im < (int)m_Depth; ++im) { + // Set correct RT as read-framebuffer. + + RTs[im]->bind(); + glCopyTexSubImage3D(GL_TEXTURE_2D_ARRAY, + 0, + 0, 0, im, + 0, 0, + m_W, + m_H + ); + RTs[im]->unbind(); + } + CHECK_GL_ERROR; + } + + template template + void Texture2DArray::createFromImages(const std::vector& images, uint flags) { + using ImgTypeInfo = GLTexFormat; + + sibr::Vector2u maxSize(0, 0); + for (const auto& img : images) { + maxSize = maxSize.cwiseMax(sibr::Vector2u(ImgTypeInfo::width(img), ImgTypeInfo::height(img))); + } + createFromImages(images, maxSize[0], maxSize[1], flags); + } + + template template + void Texture2DArray::createFromImages(const std::vector& images, uint w, uint h, uint flags) { + m_W = w; + m_H = h; + m_Depth = (uint)images.size(); + m_Flags = flags; + createArray(); + sendArray(images); + } + + template template + void Texture2DArray::createCompressedFromImages(const std::vector& images, uint compression, uint flags) { + using ImgTypeInfo = GLTexFormat; + + sibr::Vector2u maxSize(0, 0); + for (const auto& img : images) { + maxSize = maxSize.cwiseMax(sibr::Vector2u(ImgTypeInfo::width(img), ImgTypeInfo::height(img))); + } + createCompressedFromImages(images, maxSize[0], maxSize[1], compression, flags); + } + + template template + void Texture2DArray::createCompressedFromImages(const std::vector& images, uint w, uint h, uint compression, uint flags) { + m_W = w; + m_H = h; + m_Depth = (uint)images.size(); + m_Flags = flags; + createArray(compression); + sendArray(images); + } + + template template + void Texture2DArray::createFromImages(const std::vector>& images, uint flags) { + using ImgTypeInfo = GLTexFormat; + + sibr::Vector2u maxSize(0, 0); + for (const auto& img : images[0]) { + maxSize = maxSize.cwiseMax(sibr::Vector2u(ImgTypeInfo::width(img), ImgTypeInfo::height(img))); + } + createFromImages(images, maxSize[0], maxSize[1], flags); + } + + template template + void Texture2DArray::createFromImages(const std::vector>& images, uint w, uint h, uint flags) { + m_W = w; + m_H = h; + m_Depth = uint(images[0].size()); + m_Flags = flags & ~SIBR_GPU_AUTOGEN_MIPMAP; + m_numLODs = uint(images.size()); + createArray(); + + sendMipArray(images); + } + + + template template + void Texture2DArray::updateFromImages(const std::vector& images) { + using ImgTypeInfo = GLTexFormat; + + sibr::Vector2u maxSize(0, 0); + for (const auto& img : images) { + maxSize = maxSize.cwiseMax(sibr::Vector2u(ImgTypeInfo::width(img), ImgTypeInfo::height(img))); + } + if (images.size() == m_Depth && m_W == maxSize[0] && m_H == maxSize[1]) { + sendArray(images); + } + else { + createFromImages(images, m_Flags); + } + } + + template template + void Texture2DArray::updateSlices(const std::vector& images, const std::vector& slices) { + using ImgTypeInfo = GLTexFormat; + + int numSlices = (int)slices.size(); + if (numSlices == 0) { + return; + } + + sibr::Vector2u maxSize(0, 0); + for (int i = 0; i < numSlices; ++i) { + maxSize = maxSize.cwiseMax(sibr::Vector2u(ImgTypeInfo::width(images[slices[i]]), ImgTypeInfo::height(images[slices[i]]))); + } + if (m_W != maxSize[0] || m_H != maxSize[1]) { + m_W = maxSize[0]; + m_H = maxSize[1]; + } + + glBindTexture(GL_TEXTURE_2D_ARRAY, m_Handle); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + + std::vector tmp; + std::vector imagesPtrToSend = applyFlipAndResize(images, tmp, m_W, m_H, slices); + + for (int i = 0; i < numSlices; ++i) { + glTexSubImage3D(GL_TEXTURE_2D_ARRAY, + 0, + 0, 0, slices[i], + m_W, + m_H, + 1, // one slice at a time + ImgTypeInfo::format, + ImgTypeInfo::type, + ImgTypeInfo::data(*imagesPtrToSend[slices[i]]) + ); + } + CHECK_GL_ERROR; + } + + template + void Texture2DArray::createFromRTs(const std::vector& RTs, uint flags) { + m_W = 0; + m_H = 0; + for (const auto& RT : RTs) { + m_W = (std::max)(m_W, RT->w()); + m_H = (std::max)(m_H, RT->h()); + } + m_Depth = (uint)RTs.size(); + m_Flags = flags; + createArray(); + sendRTarray(RTs); + } + + template + Texture2DArray::~Texture2DArray(void) { + CHECK_GL_ERROR; + glDeleteTextures(1, &m_Handle); + CHECK_GL_ERROR; + } + + template + GLuint Texture2DArray::handle(void) const { return m_Handle; } + + template + uint Texture2DArray::w(void) const { return m_W; } + + template + uint Texture2DArray::h(void) const { return m_H; } + + template + uint Texture2DArray::depth(void) const { return m_Depth; } + + template + uint Texture2DArray::numLODs(void) const { return m_numLODs; } + + template + Vector4f Texture2DArray::readBackPixel(int i, int x, int y, uint lod) const { + Vector4f out; +//#define HEADLESS +#ifdef HEADLESS + SIBR_ERR << "HEADLESS -- No support for readBackPixel" << std::endl; +#else + glGetTextureSubImage(handle(), + lod, x, y, i, 1, 1, 1, + GL_RGBA, GL_FLOAT, 4 * sizeof(float), out.data() + ); +#endif + CHECK_GL_ERROR; + for (uint c = T_NumComp; c < 4; ++c) { + out[c] = 0; + } + return out; + } + + + // ----DEFINITIONS TextureCubeMap -------------------------------------------------- + + template + TextureCubeMap::TextureCubeMap(void) {} + + template + TextureCubeMap::TextureCubeMap(const uint w, const uint h, uint flags) { + m_W = w; + m_H = h; + m_Flags = flags; + createCubeMap(); + } + + template + TextureCubeMap::TextureCubeMap(const PixelImage& xpos, const PixelImage& xneg, + const PixelImage& ypos, const PixelImage& yneg, + const PixelImage& zpos, const PixelImage& zneg, uint flags) { + m_Flags = flags; + createFromImages(xpos, xneg, ypos, yneg, zpos, zneg, flags); + } + + + template + void TextureCubeMap::createCubeMap() { + + // We enable seamless junctions between cubemap faces. + static bool enableStates = false; + if (enableStates == false) + { + glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); + enableStates = true; + } + CHECK_GL_ERROR; + + glGenTextures(1, &m_Handle); + glBindTexture(GL_TEXTURE_CUBE_MAP, m_Handle); + + if (m_Flags & SIBR_GPU_LINEAR_SAMPLING) { + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + else { + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + + CHECK_GL_ERROR; + } + + + + template + void TextureCubeMap::sendCubeMap(const PixelImage& xpos, const PixelImage& xneg, + const PixelImage& ypos, const PixelImage& yneg, + const PixelImage& zpos, const PixelImage& zneg) { + CHECK_GL_ERROR; + + if (m_Flags & SIBR_GPU_INTEGER) { + if (GLFormat::int_internal_format < 0) { + throw std::runtime_error("Texture format does not support integer mapping"); + } + } + + // Handle flipping. + const PixelImage* sendedXpos = &xpos; + const PixelImage* sendedYpos = &ypos; + const PixelImage* sendedZpos = &zpos; + const PixelImage* sendedXneg = &xneg; + const PixelImage* sendedYneg = &yneg; + const PixelImage* sendedZneg = &zneg; + + PixelImage flippedXpos, flippedYpos, flippedZpos; + PixelImage flippedXneg, flippedYneg, flippedZneg; + + // ... + if (m_Flags & SIBR_FLIP_TEXTURE) { + flippedXpos = xpos.clone(); + flippedXpos.flipH(); + sendedXpos = &flippedXpos; + + flippedYpos = ypos.clone(); + flippedYpos.flipH(); + sendedYpos = &flippedYpos; + + flippedZpos = zpos.clone(); + flippedZpos.flipH(); + sendedZpos = &flippedZpos; + + flippedXneg = xneg.clone(); + flippedXneg.flipH(); + sendedXneg = &flippedXneg; + + flippedYneg = yneg.clone(); + flippedYneg.flipH(); + sendedYneg = &flippedYneg; + + flippedZneg = zneg.clone(); + flippedZneg.flipH(); + sendedZneg = &flippedZneg; + } + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + + glBindTexture(GL_TEXTURE_CUBE_MAP, m_Handle); + + const auto tinternal_format = (m_Flags & SIBR_GPU_INTEGER) + ? GLFormat::int_internal_format + : GLFormat::internal_format; + const auto tformat = (m_Flags & SIBR_GPU_INTEGER) + ? GLFormat::int_format + : GLFormat::format; + const auto ttype = GLType::type; + + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, tinternal_format, xpos.w(), xpos.h(), 0, tformat, ttype, xpos.data()); + glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, tinternal_format, xneg.w(), xneg.h(), 0, tformat, ttype, xneg.data()); + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, tinternal_format, ypos.w(), ypos.h(), 0, tformat, ttype, ypos.data()); + glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, tinternal_format, yneg.w(), yneg.h(), 0, tformat, ttype, yneg.data()); + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, tinternal_format, zpos.w(), zpos.h(), 0, tformat, ttype, zpos.data()); + glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, tinternal_format, zneg.w(), zneg.h(), 0, tformat, ttype, zneg.data()); + + + bool autoMIPMAP = ((m_Flags & SIBR_GPU_AUTOGEN_MIPMAP) != 0); + if (autoMIPMAP) { + glGenerateMipmap(GL_TEXTURE_CUBE_MAP); + } + + + } + + + template + void TextureCubeMap::createFromImages(const PixelImage& xpos, const PixelImage& xneg, + const PixelImage& ypos, const PixelImage& yneg, + const PixelImage& zpos, const PixelImage& zneg, uint flags) { + const int numMipMap = 1; + sibr::Vector2u maxSize(0, 0); + /// \todo TODO: check if the six images have the same size. + m_W = xpos.w(); + m_H = xpos.h(); + m_Flags = flags; + createCubeMap(); + sendCubeMap(xpos, xneg, ypos, yneg, zpos, zneg); + } + + + template + TextureCubeMap::~TextureCubeMap(void) { + CHECK_GL_ERROR; + glDeleteTextures(1, &m_Handle); + CHECK_GL_ERROR; + } + + template + GLuint TextureCubeMap::handle(void) const { return m_Handle; } + + template + uint TextureCubeMap::w(void) const { return m_H; } + + template + uint TextureCubeMap::h(void) const { return m_W; } + +} // namespace sibr + + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Types.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Types.hpp new file mode 100644 index 0000000000000000000000000000000000000000..38928196108c8934711895ab48e11a2bd241ade2 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Types.hpp @@ -0,0 +1,556 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include + +# include "core/graphics/Config.hpp" +# include "core/system/Vector.hpp" +# include "core/graphics/Image.hpp" + + +# define SIBR_GPU_AUTOGEN_MIPMAP (1<<0) +# define SIBR_GPU_MULSTISAMPLE (1<<1) +# define SIBR_GPU_LINEAR_SAMPLING (1<<2) +# define SIBR_GPU_INTEGER (1<<4) +# define SIBR_MSAA4X (1<<5) +# define SIBR_MSAA8X (1<<6) +# define SIBR_MSAA16X (1<<7) +# define SIBR_MSAA32X (1<<8) +# define SIBR_STENCIL_BUFFER (1<<9) +# define SIBR_CLAMP_UVS (1<<10) +# define SIBR_CLAMP_TO_BORDER (1<<11) +# define SIBR_FLIP_TEXTURE (1<<12) + +# define SIBR_COMPILE_FORCE_SAMPLING_LINEAR 0 + +namespace sibr{ + + + /** + * Contain type utilities to match C, cv and sibr types to OpenGL formats. + * \addtogroup sibr_graphics + * @{ + */ + + // --- TYPE HELPERS --------------------------------------------------- + + /** Helper building the correspondence between a GL type and a C type. */ + template class GLType; + + /** Helper building the correspondence between a GL type and a C type. */ + template <> class GLType { + public: + enum { type = GL_UNSIGNED_BYTE }; + }; + + /** Helper building the correspondence between a GL type and a C type. */ + template <> class GLType { + public: + enum { type = GL_UNSIGNED_SHORT }; + }; + + /** Helper building the correspondence between a GL type and a C type. */ + template <> class GLType { + public: + enum { type = GL_SHORT }; + }; + + /** Helper building the correspondence between a GL type and a C type. */ + template <> class GLType { + public: + enum { type = GL_FLOAT }; + }; + + /** Helper building the correspondence between a GL type and a C type. */ + template <> class GLType { + public: + enum { type = GL_INT }; + }; + + // --- FORMAT HELPERS ------------------------------------------------------- + + /** Helper building the correspondence between a GL format and a C type and number of components. */ + template class GLFormat; + + /** Helper building the correspondence between a GL format and a C type and number of components. */ + template <> class GLFormat { + public: + enum { + internal_format = GL_R8, + format = GL_RED, + int_internal_format = GL_R8UI, + int_format = GL_RED_INTEGER, + isdepth = 0 + }; + }; + + /** Helper building the correspondence between a GL format and a C type and number of components. */ + template <> class GLFormat { + public: + enum { + internal_format = GL_RG8, + format = GL_RG, + int_internal_format = GL_RG8UI, + int_format = GL_RG_INTEGER, + isdepth = 0 + }; + }; + + /** Helper building the correspondence between a GL format and a C type and number of components. */ + template <> class GLFormat { + public: + enum { + internal_format = GL_RGB8, + format = GL_RGB, + int_internal_format = GL_RGB8UI, + int_format = GL_RGB_INTEGER, + isdepth = 0 + }; + }; + + /** Helper building the correspondence between a GL format and a C type and number of components. */ + template <> class GLFormat { + public: + enum { + internal_format = GL_RGBA8, + format = GL_RGBA, + int_internal_format = GL_RGBA8UI, + int_format = GL_RGBA_INTEGER, + isdepth = 0 + }; + }; + + /** Helper building the correspondence between a GL format and a C type and number of components. */ + template <> class GLFormat { + public: + enum { + internal_format = GL_R16, + format = GL_R, + int_internal_format = GL_R16UI, + int_format = GL_RED_INTEGER, + isdepth = 0 + }; + }; + + /** Helper building the correspondence between a GL format and a C type and number of components. */ + template <> class GLFormat { + public: + enum { + internal_format = GL_RG16, + format = GL_RG, + int_internal_format = GL_RG16UI, + int_format = GL_RG_INTEGER, + isdepth = 0 + }; + }; + + /** Helper building the correspondence between a GL format and a C type and number of components. */ + template <> class GLFormat { + public: + enum { + internal_format = GL_RGB16, + format = GL_RGB, + int_internal_format = GL_RGB16UI, + int_format = GL_RGB_INTEGER, + isdepth = 0 + }; + }; + + /** Helper building the correspondence between a GL format and a C type and number of components. */ + template <> class GLFormat { + public: + enum { + internal_format = GL_RGBA16, + format = GL_RGBA, + int_internal_format = GL_RGBA16UI, + int_format = GL_RGBA_INTEGER, + isdepth = 0 + }; + }; + + /** Helper building the correspondence between a GL format and a C type and number of components. */ + template <> class GLFormat { + public: + enum { + internal_format = GL_R32I, + format = GL_RED_INTEGER, + int_internal_format = GL_R32I, + int_format = GL_RED_INTEGER, + isdepth = 0 + }; + }; + + /** Helper building the correspondence between a GL format and a C type and number of components. */ + template <> class GLFormat { + public: + enum { + internal_format = GL_RG32I, + format = GL_RG_INTEGER, + int_internal_format = GL_RG32I, + int_format = GL_RG_INTEGER, + isdepth = 0 + }; + }; + + /** Helper building the correspondence between a GL format and a C type and number of components. */ + template <> class GLFormat { + public: + enum { + internal_format = GL_RGB32I, + format = GL_RGB_INTEGER, + int_internal_format = GL_RGB32I, + int_format = GL_RGB_INTEGER, + isdepth = 0 + }; + }; + + /** Helper building the correspondence between a GL format and a C type and number of components. */ + template <> class GLFormat { + public: + enum { + internal_format = GL_RGBA32I, + format = GL_RGBA_INTEGER, + int_internal_format = GL_RGBA32I, + int_format = GL_RGBA_INTEGER, + isdepth = 0 + }; + }; + + /** Helper building the correspondence between a GL format and a C type and number of components. */ + template <> class GLFormat { + public: + enum { + internal_format = GL_R32F, + format = GL_RED, + int_internal_format = -1, + int_format = -1, + isdepth = 0 + }; + }; + + /** Helper building the correspondence between a GL format and a C type and number of components. */ + template <> class GLFormat { + public: + enum { + internal_format = GL_RG32F, + format = GL_RG, + int_internal_format = -1, + int_format = -1, + isdepth = 0 + }; + }; + + /** Helper building the correspondence between a GL format and a C type and number of components. */ + template <> class GLFormat { + public: + enum { + internal_format = GL_RGB32F, + format = GL_RGB, + int_internal_format = -1, + int_format = -1, + isdepth = 0 + }; + }; + + /** Helper building the correspondence between a GL format and a C type and number of components. */ + template <> class GLFormat { + public: + enum { + internal_format = GL_RGBA32F, + format = GL_RGBA, + int_internal_format = -1, + int_format = -1, + isdepth = 0 + }; + }; + + // Depth texture format (unsupported) + + //template <> class GLFormat { + //public: + // enum { + // internal_format = GL_DEPTH_COMPONENT32F, + // format = GL_DEPTH_COMPONENT, + // int_internal_format = -1, + // int_format = -1, + // isdepth = 1}; + //}; + + // --- MAT HELPERS ----------------------- + + /** Helper building the correspondence between a GL format and a cv::Mat */ + template class GLFormatCVmat; + + /** Helper building the correspondence between a GL format and a cv::Mat */ + template <> class GLFormatCVmat { + public: + enum { + internal_format = GLFormat::internal_format, + format = GLFormat::format, + int_internal_format = GLFormat::int_internal_format, + int_format = GLFormat::int_format, + isdepth = GLFormat::isdepth + }; + }; + + /** Helper building the correspondence between a GL format and a cv::Mat */ + template <> class GLFormatCVmat { + public: + enum { + internal_format = GLFormat::internal_format, + format = GL_BGR, + int_internal_format = GLFormat::int_internal_format, + int_format = GLFormat::int_format, + isdepth = GLFormat::isdepth + }; + }; + + /** Helper building the correspondence between a GL format and a cv::Mat */ + template <> class GLFormatCVmat { + public: + enum { + internal_format = GLFormat::internal_format, + format = GL_BGRA, + int_internal_format = GLFormat::int_internal_format, + int_format = GLFormat::int_format, + isdepth = GLFormat::isdepth + }; + }; + + /** Helper building the correspondence between a GL type and a cv::Mat depth. */ + template struct OpenCVdepth; + + /** Helper building the correspondence between a GL type and a cv::Mat depth. */ + template<> struct OpenCVdepth { + static const uint value = CV_8U; + }; + + /** Helper building the correspondence between a GL type and a cv::Mat depth. */ + template<> struct OpenCVdepth { + static const uint value = CV_32F; + }; + + /** Helper building the correspondence between a GL type and a cv::Mat depth. */ + template<> struct OpenCVdepth { + static const uint value = CV_64F; + }; + + /** Helper to create a cv::Mat type from its depth and number of components. */ + template constexpr uint getOpenCVtype = CV_MAKE_TYPE(OpenCVdepth::value, N); + + /** Helper to create a one-channel cv::Mat from its depth. */ + template constexpr uint getOpenCVtypeSingleChannel = getOpenCVtype; + + /** Helper class to specify for which image type we can find a valid texture format. */ + template struct ValidGLTexFormat { + static const bool value = false; + }; + + /** Helper class to specify for which image type we can find a valid texture format. */ + template struct ValidGLTexFormat> { + static const bool value = true; + }; + + /** Helper class to specify for which image type we can find a valid texture format. */ + template<> struct ValidGLTexFormat { + static const bool value = true; + }; + + /** Helper class to provide, from a generic image type, all the information needed for OpenGL textures + Right now it can work with all sibr::Image and with cv::Mat (3U8 only) + You can add more using explicit template instanciation to specify both + ValidGLTexFormat and the following GLTexFormat properties. + */ + template struct GLTexFormat { + static_assert(ValidGLTexFormat::value, "ImageWrapper currently only specialized for sibr::Image and cv::Mat "); + + /** Flip an image. + \param img image to flip + \return the fliped image. + */ + static ImageType flip(const ImageType& img); + + /** Resize an image. + \param img image to resize + \param w new width + \param h new height + \return the resize image. + */ + static ImageType resize(const ImageType& img, uint w, uint h); + + /** Get an image width. + \param img the image + \return the width + */ + static uint width(const ImageType& img); + + /** Get an image height. + \param img the image + \return the height + */ + static uint height(const ImageType& img); + + /** Get an image data. + \param img the image + \return pointer to the beginning of the data. + */ + static const void* data(const ImageType& img); + + static const uint internal_format; ///< Internal GL format. + static const uint format; ///< Generic GL format. + static const uint int_internal_format; ///< Internal GL format for integer textures. + static const uint int_format; ///< Generic GL format for integer textures. + static const uint isdepth; ///< Is it a depth format. + static const uint type; ///< The component GL type. + }; + + /** Helper class to provide, for an sibr::Image, all the information needed for OpenGL textures. */ + template struct GLTexFormat, ScalarType, N > { + using ImageType = sibr::Image; + + /** \copydoc GLTexFormat::flip */ + static ImageType flip(const ImageType& img) { + ImageType temp = img.clone(); + temp.flipH(); + return temp; + } + + /** \copydoc GLTexFormat::resize */ + static ImageType resize(const ImageType& img, uint w, uint h) { + return img.resized(w, h); + } + + /** \copydoc GLTexFormat::width */ + static uint width(const ImageType& img) { + return img.w(); + } + + /** \copydoc GLTexFormat::height */ + static uint height(const ImageType& img) { + return img.h(); + } + + /** \copydoc GLTexFormat::data */ + static const void* data(const ImageType& img) { + return img.data(); + } + + static const uint internal_format = GLFormat::internal_format; ///< Internal GL format. + static const uint format = GLFormat::format; ///< Generic GL format. + static const uint int_internal_format = GLFormat::int_internal_format; ///< Internal GL format for integer textures. + static const uint int_format = GLFormat::int_format; ///< Generic GL format for integer textures. + static const uint isdepth = GLFormat::isdepth; ///< Is it a depth format. + static const uint type = GLType::type; ///< The component GL type. + }; + + /** Helper class to provide, for an sibr::Image::Ptr, all the information needed for OpenGL textures. */ + template struct GLTexFormat, ScalarType, N > { + using ImageType = ImagePtr; + + /** \copydoc GLTexFormat::flip */ + static ImageType flip(const ImageType& img) { + ImageType temp = ImageType::fromImg(*img); + temp->flipH(); + return temp; + } + + /** \copydoc GLTexFormat::resize */ + static ImageType resize(const ImageType& img, uint w, uint h) { + return ImageType::fromImg(img->resized(w, h)); + } + + /** \copydoc GLTexFormat::width */ + static uint width(const ImageType& img) { + return img->w(); + } + + /** \copydoc GLTexFormat::height */ + static uint height(const ImageType& img) { + return img->h(); + } + + /** \copydoc GLTexFormat::data */ + static const void* data(const ImageType& img) { + return img->data(); + } + + static const uint internal_format = GLFormat::internal_format; ///< Internal GL format. + static const uint format = GLFormat::format; ///< Generic GL format. + static const uint int_internal_format = GLFormat::int_internal_format; ///< Internal GL format for integer textures. + static const uint int_format = GLFormat::int_format; ///< Generic GL format for integer textures. + static const uint isdepth = GLFormat::isdepth; ///< Is it a depth format. + static const uint type = GLType::type; ///< The component GL type. + + }; + + /** Helper class to provide, for a cv::Mat, all the information needed for OpenGL textures. */ + template struct GLTexFormat { + static_assert(std::is_same_v && (N == 3 || N == 4 || N == 1) , "GLTexFormat with cv::Mat currently only defined for 3U8 or 4U8"); + + /** \copydoc GLTexFormat::flip */ + static cv::Mat flip(const cv::Mat& img) { + cv::Mat temp; + cv::flip(img, temp, 0); //0 for flipH + return temp; + } + + /** \copydoc GLTexFormat::resize */ + static cv::Mat resize(const cv::Mat& img, uint w, uint h) { + cv::Mat temp; + cv::resize(img, temp, cv::Size(w, h)); + return temp; + } + + /** \copydoc GLTexFormat::width */ + static uint width(const cv::Mat& img) { + return img.cols; + } + + /** \copydoc GLTexFormat::height */ + static uint height(const cv::Mat& img) { + return img.rows; + } + + /** \copydoc GLTexFormat::data */ + static const void* data(const cv::Mat& img) { + return img.ptr(); + } + + /** \copydoc GLTexFormat::data */ + static void* data(cv::Mat& img) { + return img.ptr(); + } + + /** \return the matrix OpenCV type. */ + static uint cv_type() { + return CV_MAKE_TYPE(cv::DataDepth::value, N); + } + + static const uint internal_format = GLFormatCVmat::internal_format; ///< Internal GL format. + static const uint format = GLFormatCVmat::format; ///< Generic GL format. + static const uint int_internal_format = GLFormatCVmat::int_internal_format; ///< Internal GL format for integer textures. + static const uint int_format = GLFormatCVmat::int_format; ///< Generic GL format for integer textures. + static const uint isdepth = GLFormatCVmat::isdepth; ///< Is it a depth format. + static const uint type = GLType::type; ///< The component GL type. + }; + + /** Helper class to provide, for a cv::Mat, all the information needed for OpenGL textures. */ + template + struct GLTexFormat >, ScalarType, N> + : GLTexFormat + { + }; + + /*** @} */ +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Utils.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6b266754c2b2ce7ff76abe5bc0da4ad31282efab --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Utils.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#include "core/graphics/Utils.hpp" + +namespace sibr +{ + + + cv::Scalar jetColor(float gray) { + const sibr::Vector3ub col = jetColor(gray); + return toOpenCV(col); + } + + sibr::Vector3ub getLinearColorFromProbaV(double proba) { + const double scProba = 3.0 * proba; + const unsigned char red = double(sibr::clamp(scProba, 0.0, 1.0)) * 255; + const unsigned char green = double(sibr::clamp(scProba - 1, 0.0, 1.0)) * 255; + const unsigned char blue = double(sibr::clamp(scProba - 2, 0.0, 1.0)) * 255; + + return sibr::Vector3ub(red, green, blue); + } + + double getProbaFromLinearColor(const sibr::Vector3ub & color) { + const double red = double(color[0]) / 255.0; + const double green = double(color[1]) / 255.0; + const double blue = double(color[2]) / 255.0; + return (red + green + blue) / 3.0; + } + + sibr::Vector2d cartesianToSpherical(const sibr::Vector3d & dir) + { + double theta = std::acos(dir.z()); + + double phi = 0; + if (dir.x() != 0 && dir.y() != 0) { + phi = std::atan2(dir.y(), dir.x()); + } + + return sibr::Vector2d(phi, theta); + } + + sibr::Vector2d cartesianToSphericalUVs(const sibr::Vector3d & dir) + { + const sibr::Vector2d angles = cartesianToSpherical(dir); + const double & phi = angles[0]; + const double & theta = angles[1]; + + return sibr::Vector2d(0.5*(phi / M_PI + 1.0), theta / M_PI); + } + + float sRGB2LinF(float inF) { + if (inF < 0.04045f) { + return inF / 12.92f; + } + else { + return std::pow((inF + 0.055f) / (1.055f), 2.4f); + } + } + + float lin2sRGBF(float inF) { + + if (inF < 0.0031308f) { + return std::max(0.0f, std::min(1.0f, 12.92f*inF)); + } + else { + return std::max(0.0f, std::min(1.0f, 1.055f*std::pow(inF, 1.0f / 2.4f) - 0.055f)); + } + + } + + void sRGB2Lin(sibr::ImageRGB32F& img) { +#pragma omp parallel for + for (int j = 0; j < int(img.h()); j++) { + for (int i = 0; i < int(img.w()); i++) { + for (int c = 0; c < 3; c++) { + img(i, j)[c] = sRGB2LinF(img(i, j)[c]); + } + } + } + } + + void lin2sRGB(sibr::ImageRGB32F& img) { +#pragma omp parallel for + for (int j = 0; j < int(img.h()); j++) { + for (int i = 0; i < int(img.w()); i++) { + for (int c = 0; c < 3; c++) { + img(i, j)[c] = lin2sRGBF(img(i, j)[c]); + } + } + } + + } + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Utils.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Utils.hpp new file mode 100644 index 0000000000000000000000000000000000000000..136e98fb864d68b2ee74d52cb4cce848aeeaccda --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Utils.hpp @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include "core/graphics/Config.hpp" +# include "core/system/Vector.hpp" +# include "core/graphics/Image.hpp" + + +namespace sibr +{ + /** + * \addtogroup sibr_graphics + * @{ + */ + + /** Generate a random color. + \return a random RGB triplet + */ + template + static Eigen::Matrix randomColor(){ + // We just use rand here, we don't need 'proper' PRNG. + const uint8_t r = uint8((std::rand() % 255 + 192) * 0.5f); + const uint8_t g = uint8((std::rand() % 255 + 192) * 0.5f); + const uint8_t b = uint8((std::rand() % 255 + 192) * 0.5f); + const sibr::Vector3ub output(r, g,b); + return output.unaryExpr([](float f) { return f * sibr::opencv::imageTypeRange(); }).template cast(); + } + + /** Generate a color for a given scalar score, using the jet color map. + \param gray the probability value + \return the associated jet color. + */ + template + static Eigen::Matrix jetColor(float gray) + { + sibr::Vector3f output(1, 1, 1); + float g = std::min(1.0f, std::max(0.0f, gray)); + float dg = 0.25f; + float d = 4.0f; + if (g < dg) { + output.x() = 0.0f; + output.y() = d*g; + } else if (g < 2.0f*dg) { + output.x() = 0.0f; + output.z() = 1.0f + d*(dg - g); + } else if (g < 3.0f*dg) { + output.x() = d*(g - 0.5f); + output.z() = 0.0f; + } else { + output.y() = 1.0f + d*(0.75f - g); + output.z() = 0.0f; + } + + return output.unaryExpr([](float f) { return f * sibr::opencv::imageTypeRange(); }).template cast(); + } + + /** Generate a jet color associated to the input probability, as a 3-channels cv::Scalar. + \param gray the probability value + \return the associated jet color. + */ + SIBR_GRAPHICS_EXPORT cv::Scalar jetColor(float gray); + + /** Generate a color for a given scalar score, using a reversible mapping. + \param proba the probability value + \return the associated color + */ + SIBR_GRAPHICS_EXPORT sibr::Vector3ub getLinearColorFromProbaV(double proba); + + /** Convert a color to the associated scalar score, using a reversible mapping. + \param color the color + \return the probability value + */ + SIBR_GRAPHICS_EXPORT double getProbaFromLinearColor(const sibr::Vector3ub & color); + + /** Convert a direction from cartesian to spherical coordinates. + \param dir a direction in cartesian 3D space + \return the spherical coordinates [phi,theta] in [-pi,pi]x[0,pi] + \warning dir is assumed to be normalized + */ + SIBR_GRAPHICS_EXPORT sibr::Vector2d cartesianToSpherical(const sibr::Vector3d & dir); + + /** Convert a direction from cartesian to spherical UVs. + \param dir a direction in cartesian 3D space + \return the spherical UVs [u,v] in [0,1]^2 + \warning dir is assumed to be normalized + */ + SIBR_GRAPHICS_EXPORT sibr::Vector2d cartesianToSphericalUVs(const sibr::Vector3d & dir); + + /**Inplace conversion of float image from sRGB space to linear. + \param img the image to convert + */ + SIBR_GRAPHICS_EXPORT void sRGB2Lin(sibr::ImageRGB32F& img); + + /** Inplace conversion of a float image from linear space to sRGB. + \param img the image to convert + */ + SIBR_GRAPHICS_EXPORT void lin2sRGB(sibr::ImageRGB32F& img); + + /** Debug helper: wrap a rendering task in an openGL debug group (visible in Renderdoc). + \param s debug group name + \param f the task to wrap + \param args the task arguments + */ + template + void renderTask(const std::string & s, FunType && f, ArgsType && ... args) { + glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, -1, s.c_str()); + f(args...); + glPopDebugGroup(); + }; + + /** Interpolate between two values. + \param A first value + \param B second value + \param fac interpolation factor + \return A+fac*(B-A) + */ + inline float lerp( float A, float B, float fac ) { + return A*(1.f-fac)+B*fac; + } + + /** Express a value as the linear combination of two other values. + \param from first value + \param to second value + \param current value to express as a combination + \return the interpolation factor + */ + inline float inverseLerp( float from, float to, float current ) { + return (current - from)/(to - from); + } + + /*** @} */ + +} // namespace sibr + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Viewport.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Viewport.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1753d0dc672bd7d0a03f1d19fac5d03904df5e6b --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Viewport.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#include "core/graphics/Window.hpp" +#include "core/graphics/Viewport.hpp" + +namespace sibr +{ + void Viewport::bind( uint screenWidth, uint screenHeight ) const + { + glViewport( + (GLint)(left()*screenWidth), (GLint)(top()*screenHeight), + (GLsizei)(width()*screenWidth), (GLsizei)(height()*screenHeight)); + } + + void Viewport::clear( const Vector3f& bgColor ) const + { + //if (width() < 1.f) + // return; + + GLint l = (GLint)finalLeft(); + GLint t = (GLint)finalTop(); + GLsizei w = (GLsizei)finalWidth(); + GLsizei h = (GLsizei)finalHeight(); + + glViewport(l, t, w, h); + glScissor(l, t, w, h); + glEnable(GL_SCISSOR_TEST); + glClearColor(bgColor[0], bgColor[1], bgColor[2], 0.f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glDisable(GL_SCISSOR_TEST); + + glViewport(l, t, w, h); + } + + void Viewport::bind( void ) const + { + //assert((_parent != nullptr || width() > 1.f) + // && "Too small viewport detected (Set a parent viewport from a window using Viewport::parent(...) and Window::viewport()"); + + glViewport( + (GLint)(finalLeft()), (GLint)(finalTop()), + (GLsizei)(finalWidth()), (GLsizei)(finalHeight())); + } + + bool Viewport::contains( float x, float y ) const + { + return (x > finalLeft() && x < finalRight() && y > finalTop() && y < finalBottom()); + } + + bool Viewport::contains( int x, int y ) const + { + return (x > (int)finalLeft() && x < (int)finalRight() && y > (int)finalTop() && y < (int)finalBottom()); + } + + bool Viewport::contains(const Vector2f & xy) const + { + return contains(xy.x(), xy.y()); + } + + bool Viewport::isEmpty() const { + return width() == 0.0 && height() == 0.0; + } + + Vector2f Viewport::pixAt(const Vector2f & uv) const { + return uv.cwiseProduct(finalSize()) + finalTopLeft(); + } + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Viewport.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Viewport.hpp new file mode 100644 index 0000000000000000000000000000000000000000..39456f13f0ba26b39b927ef42d41d29bfb6c899c --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Viewport.hpp @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include "core/graphics/Config.hpp" +# include "core/system/Vector.hpp" + +namespace sibr +{ + + /** Represent an on-screen viewport using normalized coordinates, which can be nested into another viewport. + * \ingroup sibr_graphics + */ + class SIBR_GRAPHICS_EXPORT Viewport + { + public: + + /** Default constructor: unit viewport. */ + Viewport( void ): + _parent(nullptr), + _left(0.f), _top(0.f), _right(1.f), _bottom(1.f) { } + + /** Constructor from extents. + *\param left left extent + *\param top top extent + *\param right right extent + *\param bottom bottom extent + */ + Viewport( float left, float top, float right, float bottom ) : + _parent(nullptr), + _left(left), _top(top), _right(right), _bottom(bottom) { } + + /** Constructor from a parent and relative extents. + *\param parent_ the parent viewport + *\param left left relative extent + *\param top top relative extent + *\param right right relative extent + *\param bottom bottom relative extent + */ + Viewport( const Viewport* parent_, float left, float top, float right, float bottom ) : + _left(left), _top(top), _right(right), _bottom(bottom) { parent(parent_); } + + /** Constructor from a parent and relative extents. + *\param parent_ the parent viewport + *\param left left relative extent + *\param top top relative extent + *\param right right relative extent + *\param bottom bottom relative extent + */ + Viewport(const Viewport & parent_, float left, float top, float right, float bottom) : + Viewport(&parent_, left, top, right, bottom) { + *this = Viewport(finalLeft(), finalTop(), finalRight(), finalBottom()); + } + + /** \return the relative left extent. */ + inline float left( void ) const { return _left; } + /** \return the relative top extent. */ + inline float top( void ) const { return _top; } + /** \return the relative right extent. */ + inline float right( void ) const { return _right; } + /** \return the relative bottom extent. */ + inline float bottom( void ) const { return _bottom; } + + /** \return the relative viewport width */ + inline float width( void ) const { return _right-_left; } + /** \return the relative viewport height */ + inline float height( void ) const { return _bottom-_top; } + + /** \return the absolute left extent. */ + float finalLeft( void ) const; + /** \return the absolute top extent. */ + float finalTop( void ) const; + /** \return the absolute right extent. */ + float finalRight( void ) const; + /** \return the absolute bottom extent. */ + float finalBottom( void ) const; + + /** \return the absolute viewport width. */ + float finalWidth( void ) const; + /** \return the absolute viewport height. */ + float finalHeight( void ) const; + + /** \return the absolute viewport size. */ + sibr::Vector2f finalSize() const; + /** \return the absolute cooridnates of the top left corner. */ + Vector2f finalTopLeft() const; + + + /** Compute the absolute pixel coordinates based on relative normalized coordinates. + *\param uv the normalized UVs + *\return the pixel coordinates + */ + Vector2f pixAt(const Vector2f & uv) const; + + /** Check if a point is inside the viewport. + *\param x horizontal coordinate + *\param y vertical coordinate + *\return true if the point is inside + */ + bool contains( float x, float y ) const; + + /** Check if a point is inside the viewport. + *\param x horizontal coordinate + *\param y vertical coordinate + *\return true if the point is inside + */ + bool contains( int x, int y ) const; + + /** Check if a point is inside the viewport. + *\param xy coordinates + *\return true if the point is inside + */ + bool contains(const Vector2f & xy) const; + + /** Bind an OpenGL viewport whose values are determined based on the viewport final dimensions and the target size. + *\param screenWidth the width of the rendertarget + *\param screenHeight the height of the rendertarget + */ + void bind( uint screenWidth, uint screenHeight ) const; + + /** Bind an OpenGL viewport whose values are determined based on the viewport final dimensions. */ + void bind( void ) const; + + /** Perform a full OpenGL clear of the region defined by the viewport in the currently bound target. + *\param bgColor clear color + */ + void clear( const Vector3f& bgColor=Vector3f(0.f, 0.f, 0.f) ) const; + + /** Set the viewport parent + *\param view the new parent + */ + void parent( const Viewport* view ); + + /** \return the parent viewport if it exists or nullptr. */ + const Viewport* parent( void ) const; + + /** \return true if the viewport is empty (0x0). */ + bool isEmpty() const; + + private: + const Viewport* _parent; ///< (optional) + + float _left; ///< Left extent. + float _top; ///< Top extent. + float _right; ///< Right extent. + float _bottom; ///< Bottom extent. + + }; + + ///// DEFINITIONS ///// + + inline void Viewport::parent( const Viewport* view ) { + _parent = view; + + //if (_parent == this) // means 'is the root' + // _parent = nullptr; + } + inline const Viewport* Viewport::parent( void ) const { + return _parent; + } + + inline float Viewport::finalLeft( void ) const { + return (_parent)? (_parent->finalLeft() + _parent->finalWidth()*left()) : left(); + } + + inline float Viewport::finalTop( void ) const { + return (_parent)? ( _parent->finalTop() + _parent->finalHeight()*top() ) : top(); + } + + inline float Viewport::finalRight( void ) const { + return (_parent)? (_parent->finalLeft() + _parent->finalWidth()*right()) : right(); + } + + inline float Viewport::finalBottom( void ) const { + return (_parent)? (_parent->finalTop() + _parent->finalHeight()*bottom()) : bottom(); + } + + inline float Viewport::finalWidth( void ) const { + return (_parent)? _parent->finalWidth()*width() : width(); + } + + inline float Viewport::finalHeight( void ) const { + return (_parent)? _parent->finalHeight()*height() : height(); + } + + inline sibr::Vector2f Viewport::finalSize(void) const { + return sibr::Vector2f(finalWidth(),finalHeight()); + } + + inline Vector2f Viewport::finalTopLeft() const { + return { finalLeft(), finalTop() }; + } + + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Window.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Window.cpp new file mode 100755 index 0000000000000000000000000000000000000000..7a33379383e95ebc2dfd27d8bef277f030e649e0 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Window.cpp @@ -0,0 +1,504 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#include "core/graphics/Input.hpp" +#include "core/graphics/Window.hpp" +#include "core/graphics/RenderUtility.hpp" + +#include "imgui/imgui.cpp" // needed for loading ini settings +#include "imgui/imgui.h" +#include "imgui_impl_glfw_gl3.h" + +#include + +namespace sibr +{ + int Window::contextId = -1; + + static void glfwErrorCallback(int error, const char* description) + { + SIBR_ERR << description << std::endl; + } + + static void glErrorCallback(GLenum src, GLenum type, GLuint id, GLenum severity, GLsizei size, const GLchar* str, const void* user) { + // For now we only log errors, and we ignore severity. + if(type != GL_DEBUG_TYPE_ERROR) { + //SIBR_LOG << "[API]" << "(" << src << "," << type << "," << id << "," << severity << "): " << std::string(str, size) << std::endl; + return; + } + std::string errStr; + switch(src) { + case GL_DEBUG_SOURCE_API: + errStr = "[API] "; + break; + case GL_DEBUG_SOURCE_SHADER_COMPILER: + errStr = "[Shader] "; + break; + case GL_DEBUG_SOURCE_THIRD_PARTY: + errStr = "[3rd party] "; + break; + case GL_DEBUG_SOURCE_APPLICATION: + errStr = "[Application] "; + break; + case GL_DEBUG_SOURCE_OTHER: + errStr = "[Other] "; + break; + default: + break; + } + + const std::string errStr2(str, size); + + SIBR_ERR << "OpenGL: " << errStr << errStr2 << std::endl; + + } + + static void glfwKeyboardCallback(GLFWwindow* window, int key, int scancode, int action, int mods) + { + key = std::max(0, key); + + // We only pass the key input to our code if the interface isn't currently using it. + if (!ImGui::GetIO().WantCaptureKeyboard) { + if (action == GLFW_PRESS) { + sibr::Input::global().key().press((sibr::Key::Code)key); + } else if (action == GLFW_RELEASE) { + sibr::Input::global().key().release((sibr::Key::Code)key); + } + } else { + sibr::Input::global() = sibr::Input(); + } + ImGui_ImplGlfw_KeyCallback(window, key, scancode, action, mods); + } + + static void glfwResizeCallback(GLFWwindow* window, int w, int h) + { + void* userptr = glfwGetWindowUserPointer(window); + Window* win = reinterpret_cast(userptr); + + // TT : should be the right thing to do, but might break some old stuff + win->viewport(Viewport(0.f, 0.f, (float)(w), (float)(h))); + } + + static void glfwCursorPosCallback(GLFWwindow* /*window*/, double x, double y) + { + // We pass the mouse position to our code iff the interface doesn't need it. + if (!ImGui::GetIO().WantCaptureMouse) { + sibr::Input::global().mousePosition(Vector2i((int)x, (int)y)); + } else { + sibr::Input::global() = sibr::Input(); + } + + } + + static void glfwMouseButtonCallback(GLFWwindow* window, int button, int action, int mods) + { + // We only pass the mouse input to our code if the interface isn't currently using it. + if (!ImGui::GetIO().WantCaptureMouse) { + if (action == GLFW_PRESS) { + sibr::Input::global().mouseButton().press((sibr::Mouse::Code)button); + } else if (action == GLFW_RELEASE) { + sibr::Input::global().mouseButton().release((sibr::Mouse::Code)button); + } + } else { + // We have to pass release events in the case where we pressed while inside our views, and released outside. + if(sibr::Input::global().mouseButton().isActivated((sibr::Mouse::Code)button)) { + sibr::Input::global().mouseButton().release((sibr::Mouse::Code)button); + } + } + + ImGui_ImplGlfw_MouseButtonCallback(window, button, action, mods); + } + + static void glfwMouseScrollCallback(GLFWwindow* window, double x, double y) + { + sibr::Input::global().mouseScroll(y); + ImGui_ImplGlfw_ScrollCallback(window, x, y); + } + /////////////////////////////////////////////////////////////////////////// + + static int windowCounter = 0; + + /*static*/ bool Window::contextIsRunning( void ) + { + return windowCounter > 0; + } + + Window::AutoInitializer::AutoInitializer( const WindowArgs & args ) : _useGUI(!args.no_gui && !args.offscreen) + { + if (windowCounter == 0) + { + SIBR_LOG << "Initialization of GLFW" << std::endl; + glfwSetErrorCallback(glfwErrorCallback); + + if (!glfwInit()) + SIBR_ERR << "cannot init glfw" << std::endl; + if (!args.offscreen) + sibr::Input::global().key().clearStates(); + + } + ++windowCounter; + } + + Window::AutoInitializer::~AutoInitializer( void ) + { + --windowCounter; + if (windowCounter == 0) + { + if(_useGUI) { + ImGui_ImplGlfwGL3_Shutdown(); /// \todo TODO: not sure if safe with multi-context + ImGui::DestroyContext(); + } + glfwSetErrorCallback(nullptr); + SIBR_LOG << "Deinitialization of GLFW" << std::endl; + glfwTerminate(); + } + } + + Window::Window(uint w, uint h, const std::string& title, const WindowArgs & args, const std::string& defaultSettingsFilename) + : _hiddenInit(args), _useGUI(!args.no_gui && !args.offscreen), _shouldClose(false) + { + + setup(w, h, title, args, defaultSettingsFilename); + + if (!(args.fullscreen)) { + glfwSetWindowPos(_glfwWin.get(), 200, 200); + } + } + + Window::Window(const std::string& title, const WindowArgs & args, const std::string& defaultSettingsFilename) + : Window(args.win_width, args.win_height, title, args, defaultSettingsFilename) + { + } + + Window::Window(const std::string& title, const sibr::Vector2i & margins, const WindowArgs & args, const std::string& defaultSettingsFilename) + : _hiddenInit(args), _useGUI(!args.no_gui && !args.offscreen), _shouldClose(false) + { + sibr::Vector2i winSize; + if (args.offscreen) { + winSize = sibr::Vector2i(args.win_width, args.win_height); + } + else { + winSize = desktopSize(); + } + + // Here autoInitializer is already initialized, thus glfwInit() has been called + setup(winSize.x() - 2*margins.x(), winSize.y() - 2*margins.y(), title, args, defaultSettingsFilename); + + if (!(args.fullscreen)) { + glfwSetWindowPos(_glfwWin.get(), margins.x(), margins.y()); + } + + } + + void Window::swapBuffer(void) { + if (_useGUI) { + glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, -1, "ImGui interface"); + ImGui::Render(); + ImGui_ImplGlfwGL3_RenderDrawData(ImGui::GetDrawData()); + glPopDebugGroup(); + } + glfwSwapBuffers(_glfwWin.get()); + // Keep the call below in all cases to avoid accumulating all interfaces in one frame. + if (_useGUI) + ImGui_ImplGlfwGL3_NewFrame(); + } + + void Window::resetSettingsToDefault() { + std::string iniFilename = ImGui::GetIO().IniFilename; + if(iniFilename != "" && fileExists(iniFilename)) { + if(remove(iniFilename.c_str())) + SIBR_WRG << "Settings file " << iniFilename << " was not removed due to an error." << std::endl; + else + SIBR_LOG << "Settings file " << iniFilename << " was removed successfully." << std::endl; + } + else { + SIBR_WRG << "Settings file " << iniFilename << " not found." << std::endl; + } + + ImGuiContext& g = *ImGui::GetCurrentContext(); + + for (int i = 0; i < g.SettingsWindows.Size; i++) + IM_DELETE(g.SettingsWindows[i].Name); + + g.SettingsWindows.clear(); + + loadSettings(); + + for (ImGuiWindow * window: g.Windows) { + if (ImGuiWindowSettings* settings = ImGui::FindWindowSettings(window->ID)) { + SetWindowPos(window, settings->Pos, ImGuiCond_Always); + SetWindowSize(window, settings->Size, ImGuiCond_Always); + SetWindowCollapsed(window, settings->Collapsed, ImGuiCond_Always); + } + } + } + + void Window::loadSettings() { + // Load defaults from core + LoadIniSettingsFromDisk(std::string(getResourcesDirectory() + "/core/" + _defaultImguiSettingsFilename).c_str()); + + // Load defaults from Window constructor + if(fileExists(_windowImguiSettingsFilename)) + LoadIniSettingsFromDisk(_windowImguiSettingsFilename.c_str()); + + // Load user specific settings for this particular window + LoadIniSettingsFromDisk(ImGui::GetIO().IniFilename); + } + + void Window::setup(int width, int height, const std::string& title, const WindowArgs & args, const std::string& defaultSettingsFilename) { + // IMPORTANT NOTE: if you got compatibility problem with old opengl function, + // try to load compat 3.2 instead of core 4.2 + + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE); + +#ifdef GLEW_EGL + glfwWindowHint(GLFW_CONTEXT_CREATION_API, (args.offscreen) ? + GLFW_EGL_CONTEXT_API : + GLFW_NATIVE_CONTEXT_API); +#else + if(args.offscreen) SIBR_WRG << "Offscreen enabled without EGL implementation. Using native context (Offscreen might run into issues if no real display is available)." << std::endl; +#endif + + glfwWindowHint(GLFW_RED_BITS, 8); + glfwWindowHint(GLFW_GREEN_BITS, 8); + glfwWindowHint(GLFW_BLUE_BITS, 8); + glfwWindowHint(GLFW_ALPHA_BITS, 8); + glfwWindowHint(GLFW_DEPTH_BITS, 24); + glfwWindowHint(GLFW_STENCIL_BITS, 8); + + if (args.offscreen) { + glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); + } + + _glfwWin = GLFWwindowptr( + glfwCreateWindow( + width, height, title.c_str(), + (args.fullscreen && !args.offscreen) ? glfwGetPrimaryMonitor() : NULL + , NULL ), + glfwDestroyWindow + ); + + if (_glfwWin == nullptr) + SIBR_ERR << "failed to create a glfw window (is your graphics driver updated ?)" << std::endl; + + makeContextCurrent(); + + + + //SR, TT fix for image size non divisible by 4 + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + + //// Print available OpenGL version + GLint major, minor; + glGetIntegerv(GL_MAJOR_VERSION, &major); + glGetIntegerv(GL_MINOR_VERSION, &minor); + SIBR_LOG << "OpenGL Version: " << glGetString(GL_VERSION) + << "[major: " << major << ", minor: " << minor << "]" << std::endl; + + glewExperimental = GL_TRUE; + GLenum err = glewInit(); +#ifdef GLEW_EGL +// if (err != GLEW_OK && (!args.offscreen || err != GLEW_ERROR_NO_GLX_DISPLAY)) // Small hack for glew, this error occurs but does not concern offscreen + if (err != GLEW_OK && (!args.offscreen )) // Small hack for glew, this error occurs but does not concern offscreen +#else + if (err != GLEW_OK) +#endif + SIBR_ERR << "cannot initialize GLEW (used to load OpenGL function)" << std::endl; + (void)glGetError(); // I notice that glew might do wrong things during its init() + // some drivers complain about it. So I reset OpenGL's errors to discard this. + + glfwSetWindowUserPointer(_glfwWin.get(), this); + /// \todo TODO: fix, width and height might be erroneous. SR + viewport(Viewport(0.f, 0.f, (float)width, (float)height)); /// \todo TODO: bind both + + _useVSync = args.vsync; + glfwSwapInterval(args.vsync); + glfwSetKeyCallback(_glfwWin.get(), glfwKeyboardCallback); + glfwSetScrollCallback(_glfwWin.get(), glfwMouseScrollCallback); + glfwSetMouseButtonCallback(_glfwWin.get(), glfwMouseButtonCallback); + glfwSetCursorPosCallback(_glfwWin.get(), glfwCursorPosCallback); + glfwSetWindowSizeCallback(_glfwWin.get(), glfwResizeCallback); + + // SR: we don't use it by default because you won't get callstack/file/line info. + if(args.gl_debug) { + glEnable(GL_DEBUG_OUTPUT); + glDebugMessageCallback(glErrorCallback, nullptr); + } + + if(_useGUI) { + //contextId + ++Window::contextId; + + // Setup ImGui binding + ImGui::CreateContext(); + ImGui_ImplGlfwGL3_Init(_glfwWin.get(), false); + glfwSetCharCallback(_glfwWin.get(), ImGui_ImplGlfw_CharCallback); + + ImGui_ImplGlfwGL3_NewFrame(); + + _windowImguiSettingsFilename = defaultSettingsFilename; + + // Set user specific file for this particular window as default ini file + std::string iniFilename = std::string(getAppDataDirectory() + "/" + std::regex_replace(title, std::regex("[^0-9A-Za-z\\-_]"), "_") + ".ini").c_str(); + char* iniFilenameCStr = new char[iniFilename.length()+1]; + strcpy(iniFilenameCStr, iniFilename.c_str()); + ImGui::GetIO().IniFilename = iniFilenameCStr; + + loadSettings(); + } + + if(!args.offscreen) { + _oldPosition = position(); + _oldSize = size(); + + // Support for HiDPI on Windows. The default is 96. + // Compute the pixel density at the current definition. + int widthmm, heightmm; + glfwGetMonitorPhysicalSize(glfwGetPrimaryMonitor(), &widthmm, &heightmm); + const float defaultDPI = 96.0f; + sibr::Vector2i dsize = desktopSize(); + + _scaling = sibr::clamp(std::round(dsize.x() / (widthmm / 25.4f) / defaultDPI), 1.0f, 2.0f); + + if (_useGUI && args.hdpi) { + ImGui::GetStyle().ScaleAllSizes(scaling()); + ImGui::GetIO().FontGlobalScale = scaling(); + } + } + + /** \todo + TODO: fix issue on some HiDPI screens + interaction with GUI labels generation. + // If we have a screen in HiDPI mode, scale the interface accordingly. + if (_scaling > 1.0f) { + ImGui::GetStyle().ScaleAllSizes(_scaling); + ImGui::GetIO().FontGlobalScale = _scaling; + } + */ + } + + Vector2i Window::desktopSize( void ) + { + const GLFWvidmode * mode = glfwGetVideoMode(glfwGetPrimaryMonitor()); + return Vector2i(mode->width, mode->height); + } + + Vector2i Window::size( void ) const + { + Vector2i s; + glfwGetWindowSize(_glfwWin.get(), &s[0], &s[1]); + return s; + } + + void Window::position(const unsigned int x, const unsigned int y) + { + glfwSetWindowPos(_glfwWin.get(), x, y); + } + + Vector2i Window::position() const { + Vector2i s; + glfwGetWindowPos(_glfwWin.get(), &s[0], &s[1]); + return s; + } + + bool Window::isOpened( void ) const + { + return (!_shouldClose && !glfwWindowShouldClose(_glfwWin.get())); + } + + void Window::close( void ) + { + _shouldClose = true; + glfwSetWindowShouldClose(_glfwWin.get(), GL_TRUE); + } + + bool Window::isFullscreen(void) const + { + return glfwGetWindowMonitor(_glfwWin.get()) != NULL; + } + + void Window::setFullscreen(const bool fullscreen) { + const bool currentState = isFullscreen(); + if((fullscreen && currentState) || (!fullscreen && !currentState)) { + // Do nothing. + return; + } + if (fullscreen) { + _oldPosition = position(); + _oldSize = size(); + GLFWmonitor* monitor = glfwGetPrimaryMonitor(); + const GLFWvidmode* mode = glfwGetVideoMode(monitor); + glfwSetWindowMonitor(_glfwWin.get(), monitor, 0, 0, mode->width, mode->height, mode->refreshRate); + // There is a bug in glfw (see https://github.com/glfw/glfw/issues/1072). + // We have to manually re-set the swap interval. + glfwSwapInterval(_useVSync ? 1 : 0); + } else { + glfwSetWindowMonitor(_glfwWin.get(), NULL, _oldPosition[0], _oldPosition[1], _oldSize[0], _oldSize[1], 0); + } + } + + void Window::size( int w, int h ) + { + glfwSetWindowSize(_glfwWin.get(), w, h); + Vector2i s = size(); + + if (s[0] != w || s[1] != h) + SIBR_WRG << "Attempting to resize the window to an unsuported resolution " + "(w = " << w << ", h = " << h << " ), using w = " << s[0] << ", h = " << s[1] << " instead." << std::endl; + + // TT : should be the right thing to do, but might brake some old stuff + viewport(Viewport(0.f, 0.f, (float)(s[0]), (float)(s[1]))); + + //viewport(Viewport(0.f, 0.f, (float)(s[0]-1), (float)(s[1]-1))); // TODO: bind both + } + + void Window::setFrameRate(int fps) + { + if (fps == 60) { + glfwSwapInterval(1); + } else if (fps == 30) { + glfwSwapInterval(2); + } else if (fps == 15) { + glfwSwapInterval(3); + } + } + + bool Window::isVsynced(void) const + { + return _useVSync; + } + + bool Window::isGUIEnabled(void) const + { + return _useGUI; + } + + void Window::setVsynced(const bool vsync) { + _useVSync = vsync; + glfwSwapInterval(_useVSync ? 1 : 0); + } + + void Window::enableCursor( bool enable ) + { + glfwSetInputMode(_glfwWin.get(), GLFW_CURSOR, enable? GLFW_CURSOR_NORMAL : GLFW_CURSOR_HIDDEN); + } + + GLFWwindow * Window::GLFW(void) { + return _glfwWin.get(); + } + + + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Window.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Window.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4047bb70e8259adf7cb786b85da2ef8f6fb31899 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/Window.hpp @@ -0,0 +1,277 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include "core/graphics/Config.hpp" +#include "core/system/Vector.hpp" +#include "core/graphics/Viewport.hpp" +#include "core/graphics/Texture.hpp" +#include + +namespace sibr +{ + + /** System window backed by an internal framebuffer. + * \ingroup sibr_graphics + */ + class SIBR_GRAPHICS_EXPORT Window : public IRenderTarget + { + public: + typedef std::shared_ptr Ptr; + + public: + /** Constructor. + *\param title window title + *\param args window setup arguments + *\sa WindowArgs + *\param defaultSettingsFilename default settings file for this specific window + **/ + Window(const std::string& title, const WindowArgs & args = {}, const std::string& defaultSettingsFilename = ""); + + /** Constructor, overriding the window size. + *\param w window width + *\param h window height + *\param title window title + *\param args window setup arguments + *\sa WindowArgs + *\param defaultSettingsFilename default settings file for this specific window + **/ + Window(uint w, uint h, const std::string& title, const WindowArgs & args = {}, const std::string& defaultSettingsFilename = ""); + + /** Constructor, adjust the size to fill the screen except for the margins. + *\param title window title + *\param margins horizontal and vertical margins to preserve on each side of the window + *\param args window setup arguments + *\sa WindowArgs + *\param defaultSettingsFilename default settings file for this specific window + **/ + Window(const std::string & title, const sibr::Vector2i & margins, const WindowArgs & args = {}, const std::string& defaultSettingsFilename = ""); + + /** \return a pointer to the underlying GLFW window */ + GLFWwindow * GLFW(void); + + /** Activate the associated graphics context. */ + void makeContextCurrent(void); + /** \return the context currently in use (represented by a GLFW window) */ + GLFWwindow * getContextCurrent(void); + /** Deactivate the associated graphics context. */ + void makeContextNull(void); + + /** Flush the graphics pipeline and perform rendering, displaying the result in the abck buffer. */ + void swapBuffer(void); + + /** Reset window settings to default. + */ + void resetSettingsToDefault(); + + /** Load Imgui settings. + */ + void loadSettings(); + + /** Set the window size + *\param w width + *\param h height + **/ + void size(int w, int h); + + /** \return the window size */ + Vector2i size(void) const; + + /** Set the window position + *\param x horizontal location + *\param y vertical location + **/ + void position(const unsigned int x, const unsigned int y); + + /** \return the window position on screen */ + Vector2i position() const; + + /** \return the screen size. */ + static Vector2i desktopSize(void); + + /** \return true if an openGL context is active. */ + static bool contextIsRunning(void); + + /** Set the framerate. + *\param fps one of 60, 30, 15 + */ + void setFrameRate(int fps); + + /** Display the cursor in the window. + * \param enable boolean flag + */ + void enableCursor(bool enable); + + /** \return if the window is currently opened */ + bool isOpened(void) const; + /** Mark the window as closed. */ + void close(void); + + /** \return true if the window is fullscreen. */ + bool isFullscreen(void) const; + /** Toggle fullscreen. + *\param fullscreen if true the window will be resized to occupy the whole screen, without visible borders. + */ + void setFullscreen(const bool fullscreen); + + /** \return true if the window is using V-sync. */ + bool isVsynced(void) const; + + /** \return true if the window is enabling GUI. */ + bool isGUIEnabled(void) const; + + /** Toggle V-sync. + *\param vsync if true, framerate will be limited to 60 FPS + *\note When set to false, tearing might be visible. + */ + void setVsynced(const bool vsync); + + /** \return the window viewport */ + const Viewport& viewport(void) const; + + /** Set the window viewport. + *\param view the new viewport + */ + void viewport(const Viewport& view); + + // From IRenderTarget + /** Get the backbuffer texture ID. unsuported. */ + GLuint texture(uint t = 0) const; + + /** Get the backbuffer texture ID. unsuported. */ + GLuint handle(uint t = 0) const; + + /** \return the window buffer ID (0) */ + GLuint fbo(void) const; + + /** Bind the window buffer. */ + void bind(void); + + /** Unind the window buffer. */ + void unbind(void); + + /** Clear the window buffer. */ + void clear(void); + + /** \return the window buffer width */ + uint w(void) const; + + /** \return the window buffer height */ + uint h(void) const; + + /** \return the screens caling factor. */ + float scaling() const; + + static int contextId; ///< Last created window context ID (-1 initially). + + private: + + /** Setup the window. + *\param width window width on screen + *\param height window height on screen + *\param title window title + *\param args window setup arguments + *\param defaultSettingsFilename default settings file for this specific window + *\sa WindowArgs + */ + void setup(int width, int height, const std::string & title, const WindowArgs & args, const std::string& defaultSettingsFilename = ""); + + /// Window pointer for callbacks. + typedef std::unique_ptr> GLFWwindowptr; + + /// Helper to handle window creation/destruction. + struct AutoInitializer + { + AutoInitializer(const WindowArgs & args = {}); + ~AutoInitializer(void); + + const bool _useGUI; ///< Should ImGui windows be displayed. + }; + + bool _shouldClose; ///< Is the window marked as closed. + GLFWwindowptr _glfwWin; ///< Undelrying GLF window. + Vector2i _size; ///< Window size. + const bool _useGUI; ///< Should ImGui windows be displayed. + bool _useVSync; ///< is the window using vsync. + Vector2i _oldPosition; ///< Backup for handling fullscreen/windowed mode restoration. + Vector2i _oldSize; ///< Backup for handling fullscreen/windowed mode restoration. + Viewport _viewport; ///< Current viewport. + float _scaling = 1.0f; ///< Internal scaling for HiDPI screens. + // Must be placed add the end of member data . + AutoInitializer _hiddenInit; ///< nifty counter used to auto-init window system + std::string _defaultImguiSettingsFilename = "imgui_default.ini"; ///< string of default Imgui settings filename + std::string _windowImguiSettingsFilename; ///< string of default Window specific Imgui settings filename + }; + + ///// INLINES ///// + inline void Window::makeContextCurrent(void) { + glfwMakeContextCurrent(_glfwWin.get()); + } + + inline void Window::makeContextNull(void) { + glfwMakeContextCurrent(0); + } + + inline GLFWwindow * Window::getContextCurrent(void) { + return glfwGetCurrentContext(); + } + + inline GLuint Window::texture(uint /*t*/) const { + SIBR_ERR << "You are trying to read the Window's backbuffer (use sibr::blit instead)." << std::endl; + return 0; + } + inline GLuint Window::handle(uint /*t*/) const { + SIBR_ERR << "You are trying to read the Window's backbuffer (use sibr::blit instead)." << std::endl; + return 0; + } + inline GLuint Window::fbo(void) const { + return 0; + } + + inline void Window::bind(void) { + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + + } + + inline void Window::unbind(void) { + /*nothing*/ + } + + inline void Window::clear(void) { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } + + inline uint Window::w(void) const { + return (uint)size().x(); + } + + inline uint Window::h(void) const { + return (uint)size().y(); + } + + inline float Window::scaling() const + { + return _scaling; + } + + inline const Viewport& Window::viewport(void) const { + return _viewport; + } + + inline void Window::viewport(const Viewport& view) { + _viewport = view; + } + + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/resources/imgui_default.ini b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/resources/imgui_default.ini new file mode 100644 index 0000000000000000000000000000000000000000..97a1963e72545a4ab3cb4bbd7c4f393823b878f2 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/resources/imgui_default.ini @@ -0,0 +1,4 @@ +[Window] +Pos=60,60 +Size=400,400 +Collapsed=0 \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/sibr_graphics.dox b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/sibr_graphics.dox new file mode 100644 index 0000000000000000000000000000000000000000..312964912b137a062f0d904992d11aa4391ca61e --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/graphics/sibr_graphics.dox @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +/*! + \defgroup sibr_graphics sibr_graphics + + \brief OpenGL and graphics utilities. + +*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/CMakeLists.txt b/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..ec77a26f0e162ab420df65a37c9bfb5ab72cc185 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/CMakeLists.txt @@ -0,0 +1,66 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +project(sibr_imgproc) + +file(GLOB SOURCES "*.cpp" "*.h" "*.hpp") +source_group("Source Files" FILES ${SOURCES}) + +## Specify target rules +add_library(${PROJECT_NAME} SHARED ${SOURCES}) + +include_directories( + ${Boost_INCLUDE_DIRS} + ${mrf_INCLUDE_DIRS} +) +if(WIN32) +target_link_libraries(${PROJECT_NAME} + ${Boost_LIBRARIES} + ${OpenCV_LIBRARIES} + OpenMP::OpenMP_CXX + glfw3 + mrf + sibr_system + sibr_graphics + sibr_assets + sibr_raycaster +) +else() +target_link_libraries(${PROJECT_NAME} + ${Boost_LIBRARIES} + ${OpenCV_LIBRARIES} + OpenMP::OpenMP_CXX + ${GLFW_LIBRARY} + mrf + sibr_system + sibr_graphics + sibr_assets + sibr_raycaster +) +endif() + +if (NOT WIN32) + target_link_libraries(${PROJECT_NAME} + # GLEW + rt m dl X11 pthread Xrandr Xinerama Xxf86vm Xcursor + # X11 Xi Xrandr Xxf86vm Xinerama Xcursor dl rt m pthread + ) +endif() + +add_definitions( -DSIBR_IMGPROC_EXPORTS -DBOOST_ALL_DYN_LINK ) + +set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER ${SIBR_FOLDER}) + + +## High level macro to install in an homogen way all our ibr targets +include(install_runtime) +ibr_install_target(${PROJECT_NAME} + INSTALL_PDB ## mean install also MSVC IDE *.pdb file (DEST according to target type) +) diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/Config.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/Config.hpp new file mode 100644 index 0000000000000000000000000000000000000000..326ca128039a6e0933967f319a286204a11aeb10 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/Config.hpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include "core/system/Config.hpp" +# include "core/system/Utils.hpp" + +# ifdef SIBR_OS_WINDOWS +//// Export Macro (used for creating DLLs) //// +# ifdef SIBR_STATIC_DEFINE +# define SIBR_EXPORT +# define SIBR_NO_EXPORT +# else +# ifndef SIBR_IMGPROC_EXPORT +# ifdef SIBR_IMGPROC_EXPORTS + /* We are building this library */ +# define SIBR_IMGPROC_EXPORT __declspec(dllexport) +# else + /* We are using this library */ +# define SIBR_IMGPROC_EXPORT __declspec(dllimport) +# endif +# endif +# ifndef SIBR_NO_EXPORT +# define SIBR_NO_EXPORT +# endif +# endif +# else +# define SIBR_IMGPROC_EXPORT +# endif + + + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/CropScaleImageUtility.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/CropScaleImageUtility.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2619691770e4bff1fc44542aa87067b3c863a24f --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/CropScaleImageUtility.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "CropScaleImageUtility.hpp" + +namespace sibr { + + std::vector CropScaleImageUtility::getPathToImgs(const std::string & inputFileName) + { + std::ifstream inputFile(inputFileName); + std::string line; + std::vector pathToImgs; + while (getline(inputFile, line)) { + std::stringstream ss(line); + std::string path; + unsigned width, height; + ss >> path >> width >> height; + pathToImgs.push_back(path); + } + inputFile.close(); + return pathToImgs; + } + + void CropScaleImageUtility::logExecution(const sibr::Vector2i & originalResolution, unsigned nrImages, long long elapsedTime, bool wasTransformed, const char* log_file_name) + { + // check if file exists + const bool isEmptyFile = !sibr::fileExists(log_file_name); + std::ofstream outputFile(log_file_name, std::ios::app); + + if (isEmptyFile) { + outputFile << "date\t\t\tresolution\tnrImgs\telapsedTime\twas transformed?\n"; + } + + time_t now = std::time(nullptr); + +#ifdef SIBR_OS_WINDOWS + tm ltm = {0,0,0,0,0,0,0,0,0}; + localtime_s(<m, &now); +#else + tm ltm = *(std::localtime(&now)); +#endif + + std::stringstream dateSS; + dateSS << "[" << 1900 + ltm.tm_year << "/" << 1 + ltm.tm_mon << "/" << ltm.tm_mday << "] " + << ltm.tm_hour << ":" << ltm.tm_min << ":" << ltm.tm_sec; + + outputFile << dateSS.str() << "\t" << originalResolution[0] << "x" << originalResolution[1] << "\t\t" << nrImages << "\t" << elapsedTime << "\t" << wasTransformed << "\n"; + + outputFile.close(); + } + + void CropScaleImageUtility::writeListImages(const std::string path_to_file, const std::vector & listOfImages) + { + std::ofstream outputFile(path_to_file); + + for (unsigned i = 0; i < listOfImages.size(); i++) { + outputFile << listOfImages[i].filename << " " << listOfImages[i].width << " " << listOfImages[i].height << "\n"; + } + + outputFile.close(); + } + + sibr::Vector2i CropScaleImageUtility::parseResolution(const std::string & param) + { + size_t delimiterPos = param.find('x'); + std::string widthStr = param.substr(0, delimiterPos); + std::string heightStr = param.substr(delimiterPos + 1); + return sibr::Vector2i(std::stoi(widthStr), std::stoi(heightStr)); + } + + void CropScaleImageUtility::writeScaleFactor(const std::string path_to_file, float scaleFactor) + { + std::ofstream outputFile(path_to_file); + + outputFile << scaleFactor << "\n"; + + outputFile.close(); + } + + void CropScaleImageUtility::writeTargetResolution(const std::string path_to_file, const sibr::Vector2i & targetResolution) + { + std::ofstream outputFile(path_to_file); + + outputFile << targetResolution[0] << " " << targetResolution[1] << "\n"; + + outputFile.close(); + } +} \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/CropScaleImageUtility.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/CropScaleImageUtility.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6a8d912c15723ddfa7f576007532e69bd955dca2 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/CropScaleImageUtility.hpp @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include "Config.hpp" +#include + +#include + +#include +#include +#include + + +namespace sibr { + + /** \brief Utility class to crop and rescale images, especially for uniformizing IBR datasets. + * \ingroup sibr_imgproc + */ + class SIBR_IMGPROC_EXPORT CropScaleImageUtility + { + public: + + /** Image infos. */ + struct Image { + std::string filename; ///< Image file name. + unsigned width; ///< Image width. + unsigned height; ///< Image height. + }; + + /** Load a list_images.txt file and extract the image paths. + * \param inputFileName path to the listing + * \return a list of image paths + */ + std::vector getPathToImgs(const std::string & inputFileName); + + /** + * Log processing informations to a file. + * \param resolution the estimated resolution + * \param nrImages the number of images + * \param elapsedTime the time taken by the processing + * \param wasTransformed was transforamtion applied + * \param log_file_name the destination file path + */ + void logExecution(const sibr::Vector2i & resolution, unsigned nrImages, long long elapsedTime, bool wasTransformed, const char* log_file_name); + + /** + * Save a list of images to a list_images.txt file, where each image has a line "name w h". + * \param path_to_file the destination file path + * \param listOfImages the images to save to the list + */ + void writeListImages(const std::string path_to_file, const std::vector & listOfImages); + + /** + * Write a scale float factor to a text file. + * \param path_to_file the destination file path + * \param scaleFactor the value to write + */ + void writeScaleFactor(const std::string path_to_file, float scaleFactor); + + /** + * Write a resolution to a text file, as "w h". + * \param path_to_file the destination file path + * \param targetResolution the resolution to write + */ + void writeTargetResolution(const std::string path_to_file, const sibr::Vector2i & targetResolution); + + /** + * Extract an image resolution from a "wxh" string. + * \param param the string to parse + * \return the resolution + */ + sibr::Vector2i parseResolution(const std::string & param); + + }; +} \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/DistordCropUtility.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/DistordCropUtility.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e4152f53f4f4f9276c84ce8586753e6462eace7a --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/DistordCropUtility.cpp @@ -0,0 +1,302 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "DistordCropUtility.hpp" + +namespace sibr { + + + bool DistordCropUtility::isBlack(const sibr::Vector3ub & pixelColor, Vector3i backgroundColor, int threshold_black_color) { + sibr::Vector3i c = pixelColor.cast() - backgroundColor; + return c.squaredNorm() < threshold_black_color; + } + + + bool DistordCropUtility::is_number(const std::string& s) + { + return !s.empty() && std::find_if(s.begin(), + s.end(), [](char c) { return !std::isdigit(c); }) == s.end(); + } + + void DistordCropUtility::addPixelToQueue(const sibr::Vector2i & pixel, const sibr::ImageRGB & img, std::priority_queue & queue, sibr::Array2d & arrayVisited, Vector3i backgroundColor, int threshold_black_color) { + if (!arrayVisited(pixel.x(), pixel.y()) && isBlack(img(pixel.x(), pixel.y()), backgroundColor, threshold_black_color)) { + queue.push(pixel); + arrayVisited(pixel.x(), pixel.y()) = true; + } + } + + void DistordCropUtility::findBounds(sibr::Array2d & isBlack, DistordCropUtility::Bounds & bounds, int thinest_bounding_box_size) + { + bool wasUpdated = true; + + while (wasUpdated) { + + wasUpdated = false; + + for (int x = bounds.xMin; x <= bounds.xMax; ++x) { + wasUpdated = wasUpdated || isBlack(x, bounds.yMax) || isBlack(x, bounds.yMin); + } + for (int y = bounds.yMin; y <= bounds.yMax; ++y) { + wasUpdated = wasUpdated || isBlack(bounds.xMax, y) || isBlack(bounds.xMin, y); + } + + if (wasUpdated) { + --bounds.xMax; + ++bounds.xMin; + --bounds.yMax; + ++bounds.yMin; + } + + if (bounds.xMax - bounds.xMin < thinest_bounding_box_size || bounds.yMax - bounds.yMin < thinest_bounding_box_size) { + break; + } + } + } + + + DistordCropUtility::Bounds DistordCropUtility::getBounds(const sibr::ImageRGB & img, Vector3i backgroundColor, int threshold_black_color, int thinest_bounding_box_size, float toleranceFactor) { + int w = img.w() - 1; + int h = img.h() - 1; + + sibr::Array2d wasVisited(img.w(), img.h(), false); + sibr::Array2d isBlack(img.w(), img.h(), false); + std::priority_queue pixelsQueue; + + //init with boundary pixel (set initial pixelQueue) + // add first row and last row of pixels to the pixelsQueue (if they are black) and marked them as visited + for (int x = 0; x shifts(shiftsArray, shiftsArray + sizeof(shiftsArray) / sizeof(sibr::Vector2i)); + + //find all black pixels linked to the boundaries + while (pixelsQueue.size() > 0) { + sibr::Vector2i currentPix = pixelsQueue.top(); + pixelsQueue.pop(); + // if it was in the queue, then it was black + isBlack(currentPix.x(), currentPix.y()) = true; + + for (auto & shift : shifts) { + sibr::Vector2i newPos = currentPix + shift; + if (img.isInRange(newPos.x(), newPos.y())) { + addPixelToQueue(newPos, img, pixelsQueue, wasVisited, backgroundColor, threshold_black_color); + } + } + + } + + //find maximal bounding box not containing black pixels + DistordCropUtility::Bounds bounds(img); + findBounds(isBlack, bounds, thinest_bounding_box_size); + + bounds.xRatio = bounds.xMax / (float)img.w() - 0.5f; + bounds.yRatio = bounds.yMax / (float)img.h() - 0.5f; + + int proposedWidth = bounds.xMax - bounds.xMin; + int proposedHeight = bounds.yMax - bounds.yMin; + + bounds.width = int(float(int(img.w()) - proposedWidth) * toleranceFactor + float(proposedWidth)); + bounds.height = int(float(int(img.h()) - proposedHeight) * toleranceFactor + float(proposedHeight)); + + return bounds; + } + + + sibr::Vector2i DistordCropUtility::calculateAvgResolution(const std::vector& imagePaths, std::vector & resolutions, const int batch_size) + { + const int nrBatches = static_cast(ceil((float)(imagePaths.size()) / batch_size)); + resolutions.resize(imagePaths.size()); + std::vector, unsigned>> sumAndNrItems(nrBatches); + + for (int batchId = 0; batchId < nrBatches; batchId++) { + + const int nrItems = (batchId != nrBatches - 1) ? batch_size : ((nrBatches * batch_size != int(imagePaths.size())) ? (int(imagePaths.size()) - (batch_size * batchId)) : batch_size); + long sumOfWidths = 0; + long sumOfHeights = 0; + + std::vector chunkOfInputImages(nrItems); + +#pragma omp parallel for + for (int localImgIndex = 0; localImgIndex < nrItems; localImgIndex++) { + unsigned globalImgIndex = (batchId * batch_size) + localImgIndex; + chunkOfInputImages.at(localImgIndex).load(imagePaths.at(globalImgIndex).string(), false); + +#pragma omp critical + { + sumOfWidths += long(chunkOfInputImages[localImgIndex].w()); + sumOfHeights += long(chunkOfInputImages[localImgIndex].h()); + resolutions[localImgIndex].x() = chunkOfInputImages[localImgIndex].w(); + resolutions[localImgIndex].y() = chunkOfInputImages[localImgIndex].h(); + } + } + std::pair sums(sumOfWidths, sumOfHeights); + std::pair, unsigned> batch(sums, nrItems); + sumAndNrItems[batchId] = batch; + } + + long sumOfWidth = 0; + long sumOfHeight = 0; + for (unsigned i = 0; i < sumAndNrItems.size(); i++) { + sumOfWidth += sumAndNrItems[i].first.first; + sumOfHeight += sumAndNrItems[i].first.second; + } + + const long globalAvgWidth = sumOfWidth / long(imagePaths.size()); + const long globalAvgHeight = sumOfHeight / long(imagePaths.size()); + + return sibr::Vector2i(int(globalAvgWidth), int(globalAvgHeight)); + } + + sibr::Vector2i DistordCropUtility::findBiggestImageCenteredBox(const Path & root, + const std::vector& imagePaths, + std::vector& resolutions, + int avgWidth, int avgHeight, + const int batch_size, + float resolutionThreshold, + float threshold_ratio_bounding_box_size, + Vector3i backgroundColor, + int threshold_black_color, + int thinest_bounding_box_size, + float toleranceFactor) + { + // check if avg resolution needs to be calculated + if (avgWidth == 0 || avgHeight == 0) { + std::cout << "about to calculate avg resolution. use python get_image_size script if dataset has too many images\n"; + sibr::Vector2i avgResolution = calculateAvgResolution(imagePaths, resolutions, batch_size); + avgWidth = avgResolution.x(); + avgHeight = avgResolution.y(); + } + + std::cout << "[distordCrop] average resolution " << avgWidth << "x" << avgHeight << " and nr resolutions given: " << resolutions.size() << "\n"; + + // discard images with different resolution + std::vector preExcludedCams; + for (unsigned i = 0; i < resolutions.size(); i++) { + bool shrinkHorizontally = ((resolutions[i].x() < avgWidth) && ((avgWidth - resolutions[i].x()) > avgWidth * resolutionThreshold)) ? true : false; + bool shrinkVertically = ((resolutions[i].y() < avgHeight) && ((avgHeight - resolutions[i].y()) > avgHeight * resolutionThreshold)) ? true : false; + if (shrinkHorizontally || shrinkVertically) { + preExcludedCams.push_back(i); + std::cout << "[distordCrop] excluding input image " << i << " resolution=" << resolutions[i].x() << "x" << resolutions[i].y() << "\n"; + } + } + + std::cout << "[distordCrop] nr pre excluded images " << preExcludedCams.size() << "\n"; + + // compute bounding boxes for all non-discarded images + std::vector allBounds(imagePaths.size()); + + const int nrBatches = static_cast(ceil((float)(imagePaths.size()) / batch_size)); + + // processs batches sequentially (we don't want to run out of memory) + for (int batchId = 0; batchId < nrBatches; batchId++) { + + const int nrItems = (batchId != nrBatches - 1) ? batch_size : ((nrBatches * batch_size != int(imagePaths.size())) ? (int(imagePaths.size()) - (batch_size * batchId)) : batch_size); + + std::vector chunkOfInputImages(nrItems); + + // load images in parallel (OpenMP 2.0 doesn't allow unsigned int as index. must be signed integral type) +#pragma omp parallel for + for (int localImgIndex = 0; localImgIndex < nrItems; localImgIndex++) { + const uint globalImgIndex = uint((batchId * batch_size) + localImgIndex); + // if cam was discarded, do nothing + if (std::find(preExcludedCams.begin(), preExcludedCams.end(), globalImgIndex) == preExcludedCams.end()) { + // only now load the img + chunkOfInputImages.at(localImgIndex).load(imagePaths.at(globalImgIndex).string(), false); + allBounds.at(globalImgIndex) = getBounds(chunkOfInputImages.at(localImgIndex), backgroundColor, threshold_black_color, thinest_bounding_box_size, toleranceFactor); + + } + } + } + + Bounds finalBounds(resolutions.at(0)); + + int im_id = 0; + + // generate exclude file based on x and y ratios + std::string excludeFilePath = root.string() + "/exclude_images.txt"; + std::ofstream excludeFile(excludeFilePath, std::ios::trunc); + + int minWidth = -1; + int minHeight = -1; + + for (auto & bounds : allBounds) { + bool wasPreExcluded = std::find(preExcludedCams.begin(), preExcludedCams.end(), im_id) != preExcludedCams.end(); + + if (!wasPreExcluded && bounds.xRatio > threshold_ratio_bounding_box_size && bounds.yRatio > threshold_ratio_bounding_box_size) { + // get global x and y ratios + bool check = false; + if (bounds.xRatio < finalBounds.xRatio) { + finalBounds.xRatio = bounds.xRatio; + check = true; + } + if (bounds.yRatio < finalBounds.yRatio) { + finalBounds.yRatio = bounds.yRatio; + check = true; + } + + minWidth = (minWidth < 0 || bounds.width < minWidth) ? bounds.width : minWidth; + minHeight = (minHeight < 0 || bounds.height < minHeight) ? bounds.height : minHeight; + } + else { + std::cerr << im_id << " "; + excludeFile << im_id << " "; + + std::cout << wasPreExcluded << " " << bounds.xRatio << " " << threshold_ratio_bounding_box_size << " " << bounds.yRatio << " " << threshold_ratio_bounding_box_size << std::endl; + } + + ++im_id; + + } + excludeFile.close(); + std::cout << std::endl; + + return sibr::Vector2i(minWidth, minHeight); + + } + + sibr::Vector2i DistordCropUtility::findMinImageSize(const Path & root, const std::vector& imagePaths) + { + std::vector inputImgs(imagePaths.size()); + std::vector imSizes(imagePaths.size()); + + std::cout << "[distordCrop] loading input images : " << std::flush; + +#pragma omp parallel for + for (int id = 0; id < (int)inputImgs.size(); ++id) { + inputImgs.at(id).load(imagePaths.at(id).string(), false); + imSizes[id] = inputImgs[id].size().cast(); + } + + sibr::Vector2i minSize = imSizes[0]; + for (const auto & size : imSizes) { + minSize = minSize.cwiseMin(size); + } + + // generate exclude file based on x and y ratios + std::string excludeFilePath = root.string() + "/excludeImages.txt"; + std::ofstream excludeFile(excludeFilePath, std::ios::trunc); + excludeFile.close(); + + return minSize; + } + +} \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/DistordCropUtility.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/DistordCropUtility.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b0ee5f4569e82ae2b322bc4fd5e078e43a30d94b --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/DistordCropUtility.hpp @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include "Config.hpp" +#include +#include +#include + +#include +#include + +#include +#include + + +namespace sibr { + + /** \brief Helpers for cropping undistorted dataset images so that margins are removed, while keeping the dataset consistent. + * \ingroup sibr_imgproc + */ + class SIBR_IMGPROC_EXPORT DistordCropUtility + { + public: + + /** Image crop boundaries . */ + struct Bounds + { + /// Default constructor. + Bounds() {} + + /** Initialize with an image boundaries. + *\param img the image to use + **/ + Bounds(const sibr::ImageRGB & img) { + xMax = (int)img.w() - 1; + xMin = 0; + yMax = (int)img.h() - 1; + yMin = 0; + xRatio = 1.0f; + yRatio = 1.0f; + } + + /** Initialize with a given resolution. + *\param res the resolution + **/ + Bounds(const sibr::Vector2i & res) { + xMax = res.x() - 1; + xMin = 0; + yMax = res.y() - 1; + yMin = 0; + xRatio = 1.0f; + yRatio = 1.0f; + } + + /** \return a string representing the bounds, for logging. */ + std::string display() const { + std::stringstream s; + s << "[" << xMin << ", " << xMax << "]x[" << yMin << ", " << yMax << "]"; + return s.str(); + } + + int xMax = 0; ///< Max x value. + int xMin = 0; ///< Min x value. + int yMax = 0; ///< Max y value. + int yMin = 0; ///< Min y value. + int width = 0; ///< Region width. + int height = 0; ////< Region height. + + float xRatio = 1.0f; ///< Scaling ratio along X axis. + float yRatio = 1.0f; ///< Scaling ratio along Y axis. + }; + + /** Check if a pixel color is close to a reference color. + *\param pixelColor the color to test + *\param backgroundColor the reference color + *\param threshold_black_color the tolerance threshold + *\return true if ||pixel - background||^2 < threshold + */ + bool isBlack(const sibr::Vector3ub & pixelColor, Vector3i backgroundColor, int threshold_black_color); + + /* + * Check if a file name is made out only of digits and not letters (like texture file names). + * \param s the filename to test + * \return true if the string only contains digits + */ + bool is_number(const std::string& s); + + /* + * Add pixel(x,y) to the processing queue if it is close to backgroundColor. + * Note that only the visited status of black pixels is updated (to avoid adding them multiple times) because we don't care about other pixels. + * \param pixel the coordinates of the pixel to test + * \param img the image the pixel is coming from + * \param queue the queue, pixel will be added to it if close to backgroundColor + * \param arrayVisited visited status of each pixel (to avoid adding a pixel to the queue multiple times) + * \param backgroundColor the reference color + * \param threshold_black_color the tolerance threshold + * \sa isBlack + */ + void addPixelToQueue(const sibr::Vector2i & pixel, const sibr::ImageRGB & img, std::priority_queue & queue, sibr::Array2d & arrayVisited, Vector3i backgroundColor, int threshold_black_color); + + /** + * Estimate a region that won't contain any black pixels. + * \param isBlack 2D array listing which pixels should be excluded + * \param bounds will contain the region boundaries + * \param thinest_bounding_box_size minimum size of the bounds along any dimension + */ + void findBounds(sibr::Array2d & isBlack, Bounds & bounds, int thinest_bounding_box_size); + + /** Estimate a region of an image so that no pixels of a reference color are contained in it. + *\param img the image to crop + *\param backgroundColor the reference color + *\param threshold_black_color the color tolerance threshold + *\param thinest_bounding_box_size minimum size of the bounds along any dimension + *\param toleranceFactor Additional tolerance factor: if set to 0 the bounds will be tight, if set to 1 it will cover the full image. + *\return the estimated region boundaries + */ + Bounds getBounds(const sibr::ImageRGB & img, Vector3i backgroundColor, int threshold_black_color, int thinest_bounding_box_size, float toleranceFactor); + + /** + * Estimate the average resolution of a set of images quickly using multithread to speed up the required loading. + * \param imagePaths list of paths to the images + * \param resolutions will contain each image resolution + * \param batch_size number of images loaded per thread internally + * \return the average resolution + */ + sibr::Vector2i calculateAvgResolution(const std::vector< Path > & imagePaths, std::vector & resolutions, const int batch_size = 150); + + /** + * Find a common crop region for a set of images so that all pixels of a reference color are excluded from all images, while minimizing information loss. + * \param root the dataset root path (for writing list files) + * \param imagePaths list of image paths + * \param resolutions will contain the image resolutions + * \param avgWidth average image width, if 0 will be recomputed (slow for large datasets) + * \param avgHeight average image height, if 0 will be recomputed (slow for large datasets) + * \param batch_size batch size for multithreaded image loading + * \param resolutionThreshold ratio of the minimum allowed dimensions over the average image dimensions + * \param threshold_ratio_bounding_box_size maximum change in aspect ratio + * \param backgroundColor the reference background color + * \param threshold_black_color the color tolerance threshold + * \param thinest_bounding_box_size minimum size of the bounds along any dimension + * \param toleranceFactor Additional tolerance factor: if set to 0 the bounds will be tight, if set to 1 it will cover the full image. + * \return + */ + sibr::Vector2i findBiggestImageCenteredBox(const Path & root, const std::vector< Path > & imagePaths, std::vector & resolutions, int avgWidth = 0, int avgHeight = 0, + const int batch_size = 150, + float resolutionThreshold = 0.15f, + float threshold_ratio_bounding_box_size = 0.2f, + Vector3i backgroundColor = Vector3i(0, 0, 0), + int threshold_black_color = 10, + int thinest_bounding_box_size = 5, + float toleranceFactor = 0.0f); + + /** + * Find the resolution of the smallest image in a set. + * \note In the past, this function was also supposed to exclude images based on a certain criterion and write them to a file. + * \param root dataset root path (for writing an exclude list file, see note) + * \param imagePaths list of paths to the images + * \return the minimum resolution + */ + sibr::Vector2i findMinImageSize(const Path & root, const std::vector< Path > & imagePaths); + + + }; +} + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/MRFSolver.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/MRFSolver.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d2096195fc861d558d567eaa3e84823d7d420859 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/MRFSolver.cpp @@ -0,0 +1,338 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "MRFSolver.h" + + +namespace sibr { + + MRFSolver::MRFSolver(void) + { + } + + MRFSolver::MRFSolver(std::vector labels_list, std::vector >* neighborMap, int numIterations, + UnaryLabelOnlyFuncPtr unaryLabelOnly, + UnaryFuncPtr unaryFull, + PairwiseLabelOnlyFuncPtr pairwiseLabelsOnly, + PairwiseFuncPtr pairwiseFull) + : ignoreIsolatedNode(false) + { + SIBR_LOG << "[MRFSolver] Initialization ... "; + + _labList = labels_list; + _neighborMap = neighborMap; + _numIterations = numIterations; + _unaryFull = unaryFull; + _pairwiseFull = pairwiseFull; + + SIBR_LOG << "[MRFSolver] Labels : "; + for (int l_id = 0; l_id < _labList.size(); l_id++) { + std::cout << _labList[l_id] << ","; + } + std::cout << std::endl; + + //storing values for the unary part only requiring label + if (unaryLabelOnly.get()) { + SIBR_LOG << "[MRFSolver] unaryLabelOnly exists, precomputing." << std::endl; + _UnaryLabelOnly.resize(_labList.size()); + for (int l_id = 0; l_id < _labList.size(); l_id++) { + _UnaryLabelOnly[l_id] = (*unaryLabelOnly)(_labList[l_id]); + } + } + else { + SIBR_LOG << "[MRFSolver] unaryLabelOnly does not exist, skipping." << std::endl; + } + + //storing values for the pairwise part only requiring labels + if (pairwiseLabelsOnly.get()) { + SIBR_LOG << "[MRFSolver] pairwiseLabelsOnly exists, precomputing." << std::endl; + _PairwiseLabelsOnly.resize(_labList.size()); + + for (int l_id1 = 0; l_id1 < _labList.size(); l_id1++) { + _PairwiseLabelsOnly[l_id1].resize(_labList.size(), -1); + + for (int l_id2 = 0; l_id2 < _labList.size(); l_id2++) { + _PairwiseLabelsOnly[l_id1][l_id2] = (*pairwiseLabelsOnly)(_labList[l_id1], _labList[l_id2]); + } + } + } + else { + SIBR_LOG << "[MRFSolver] pairwiseLabelsOnly does not exist, skipping." << std::endl; + } + + SIBR_LOG << "[MRFSolver] Setup complete." << std::endl; + } + + void MRFSolver::solveLabels(void) + { + SIBR_LOG << "[MRFSolver] Running mincut... " << std::endl; + + double infty = (double)1e20; + double min_unary, temp_unary; + int num_nodes = (int)_neighborMap->size(); + SIBR_LOG << "[MRFSolver] Number of nodes = " << num_nodes; + _labels.resize(num_nodes); + + int numLinks = 0; + for (auto & links : (*_neighborMap)) { + numLinks += (int)links.size(); + } + SIBR_LOG << ", number of links = " << numLinks / 2 << std::endl; + + SIBR_LOG << "[MRFSolver] Initialization : minimizing unaries..." << std::flush; + for (int p = 0; p < num_nodes; p++) { + + int label_id; + min_unary = infty; + int num_cand = 0; + for (int lp_id = 0; lp_id < (int)_labList.size(); lp_id++) { + temp_unary = unaryTotal(p, lp_id); + if (temp_unary < (1 << 10)) { ++num_cand; } + if (temp_unary < min_unary) { + min_unary = temp_unary; + label_id = lp_id; + } + } + _labels[p] = label_id; + } + std::cout << " Done." << std::endl; + + SIBR_LOG << "[MRFSolver] Energies: U: " << computeEnergyU() << ", W: " << computeEnergyW() << std::endl; + + // Alpha-expansion algorithm + SIBR_LOG << "[MRFSolver] Alpha-expansion [label,flow]..." << std::endl; + for (int it = 0; it < _numIterations; it++) { + SIBR_LOG << "[MRFSolver] Iteration " << (it+1) << "/" << (_numIterations) << ": " << std::endl; + + for (int label_id = 0; label_id < (int)_labList.size(); label_id++) { + int label = _labList.at(label_id); + + buildGraphAlphaExp(label_id); + // Solve mincut + _energy = _graph->maxflow(); + + + int num_change = 0; + //assign new labels + for (int p = 0; p < num_nodes; p++) { + if (_graph->what_segment(p) == GraphType::SINK) { + if (_labels[p] != label_id) { ++num_change; } + _labels[p] = label_id; + } + } + SIBR_LOG << "[MRFSolver]\t\tLabel " << label << ": modifications = " << num_change << ", energy = " << _energy << " ]" << std::endl; + + delete _graph; + } + } + SIBR_LOG << "[MRFSolver] Done." << std::endl; + } + + void MRFSolver::buildGraphAlphaExp(int label_iteration_id) + { + double infty = 1 << 25; + int num_nodes = (int)_neighborMap->size(); + int n_nodes_estimation = num_nodes; + int n_edges_estimation = num_nodes * 4; + + _graph = new GraphType(n_nodes_estimation, n_edges_estimation); + + //add nodes associated to pixels + int node_id = 0; + for (int p = 0; p < num_nodes; p++) { + _graph->add_node(); + + if (_labels[p] == label_iteration_id) { + _graph->add_tweights(node_id, unaryTotal(p, label_iteration_id), infty); + } else { + _graph->add_tweights(node_id, unaryTotal(p, label_iteration_id), unaryTotal(p, _labels[p])); + } + ++node_id; + } + + //add nodes associated to connexions between pixels + for (int p = 0; p < num_nodes; p++) { + + std::vector & neighors = (*_neighborMap)[p]; + for (int q_id = 0; q_id < (int)neighors.size(); q_id++) { + + int q = neighors[q_id]; + + if (p == q) { std::cerr << "!"; } + if (q < p) { continue; } + + if (_labels[p] != _labels[q]) { + //extra node associated to edge {p,q} + _graph->add_node(); + + _graph->add_tweights(node_id, 0, pairwiseTotal(q, p, _labels[q], _labels[p])); + + double pairwise_q_a = pairwiseTotal(q, p, _labels[q], label_iteration_id); + _graph->add_edge(q, node_id, pairwise_q_a, pairwise_q_a); + + double pairwise_p_a = pairwiseTotal(q, p, label_iteration_id, _labels[p]); + _graph->add_edge(p, node_id, pairwise_p_a, pairwise_p_a); + + ++node_id; + } + else + { + double pairwise_p_q = pairwiseTotal(q, p, _labels[q], label_iteration_id); + _graph->add_edge(q, p, pairwise_p_q, pairwise_p_q); + } + } + } + + } + + void MRFSolver::solveBinaryLabels(void) + { + int numLabels = (int)_labList.size(); + if (numLabels < 2) { + SIBR_ERR << "[MRFSolver] solveBinaryLabels, expected 2 labels, only " << numLabels << " labels " << std::endl; + } + else if (numLabels > 2) { + SIBR_WRG << "[MRFSolver] solveBinaryLabels, found " << numLabels << " labels, only the first two will be used." << std::endl; + } + + buildGraphBinaryLabels(); + + _graph->maxflow(); + + int num_nodes = (int)_neighborMap->size(); + _labels.resize(num_nodes); + + //assign new labels + for (int p = 0; p < num_nodes; p++) { + + //TODO check this is not the opposite + if (_graph->what_segment(p) == GraphType::SINK) { + _labels[p] = 0; + } + else { + _labels[p] = 1; + } + } + + delete _graph; + } + + void MRFSolver::buildGraphBinaryLabels(void) + { + int num_nodes = (int)_neighborMap->size(); + int n_nodes_estimation = num_nodes; + int n_edges_estimation = num_nodes * 4; + + _graph = new GraphType(n_nodes_estimation, n_edges_estimation); + + for (int p = 0; p < num_nodes; p++) { + _graph->add_node(); + _graph->add_tweights(p, unaryTotal(p, 0), unaryTotal(p, 1)); + } + + for (int p = 0; p < num_nodes; p++) { + std::vector & neighors = (*_neighborMap)[p]; + for (int q_id = 0; q_id < (int)neighors.size(); q_id++) { + + int q = neighors[q_id]; + + if (q < p) { continue; } + + double weight = pairwiseTotal(q, p, 0, 1); + + _graph->add_edge(q, p, weight, weight); + } + } + } + + double MRFSolver::unaryTotal(int p, int lp_id) + { + double u = 0; + if (!_UnaryLabelOnly.empty()) { + u += _UnaryLabelOnly[lp_id]; + } + if (_unaryFull) { + u += (*_unaryFull)(p, _labList[lp_id]); + } + if (u < 0) { std::cerr << "!"; } + return u; + } + + double MRFSolver::pairwiseTotal(int p, int q, int lp_id, int lq_id) + { + double w = 0; + if (!_PairwiseLabelsOnly.empty()) { + w += _PairwiseLabelsOnly[lp_id][lq_id]; + } + + if (_pairwiseFull) { + w += (*_pairwiseFull)(p, q, _labList[lp_id], _labList[lq_id]); + } + if (w < 0) { std::cerr << "?" << w << "?"; } + return w; + } + + std::vector MRFSolver::getLabels(void) + { + std::vector labels(_labels.size()); + + //switch from labels id to actual labels + for (int p = 0; p < (int)labels.size(); p++) { + labels[p] = _labList[_labels[p]]; + } + return labels; + } + + std::vector MRFSolver::getUnariesEnergies(void) + { + if (_labels.size() == 0) { std::cerr << "[MRFSolver] warning getUnariesEnergies without nodes" << std::endl; return std::vector(); } + + std::vector energies(_labels.size()); + for (int p = 0; p < (int)_labels.size(); p++) { + energies[p] = unaryTotal(p, _labels[p]); + } + + return energies; + } + + double MRFSolver::computeEnergyU(void) + { + double e = 0; + for (int p = 0; p < (int)_labels.size(); p++) { + e += unaryTotal(p, _labels[p]); + } + return e; + } + + double MRFSolver::computeEnergyW(void) + { + double e = 0; + for (int p = 0; p < (int)_labels.size(); p++) { + for (int q_id = 0; q_id < (int)(*_neighborMap)[p].size(); q_id++) { + int q = (*_neighborMap)[p][q_id]; + if (q < p) { continue; } + e += pairwiseTotal(q, p, _labels[q], _labels[p]); + } + } + return e; + } + + double MRFSolver::getTotalEnergy(void) + { + return _energy; + } + + MRFSolver::~MRFSolver(void) + { + } + +} \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/MRFSolver.h b/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/MRFSolver.h new file mode 100644 index 0000000000000000000000000000000000000000..25deedb94cfb5cd1fea709b24b0cd10d35ea66fb --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/MRFSolver.h @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include "Config.hpp" +#include "mrf/graph.h" +#include +#include +#include +#include + +namespace sibr { + + + /** Object wrapper around Kolmogorov & Boykov MRF solver. + *Solve labelling problems on regular grids using alpha expension. + \ingroup sibr_imgproc + */ + class SIBR_IMGPROC_EXPORT MRFSolver + { + + public: + + typedef std::shared_ptr > UnaryFuncPtr; ///< Unary cost function that depend on node attributes and its label. + typedef std::shared_ptr > PairwiseFuncPtr; ///< Pairwise cost function that depend on node attributes and their labels. + + typedef std::shared_ptr > UnaryLabelOnlyFuncPtr; ///< Unary cost function that only depend on the label. + typedef std::shared_ptr > PairwiseLabelOnlyFuncPtr; ///< Pairwise cost function that only depend on the labels. + + /// Default constructor. + MRFSolver(void); + + /** Initialize from a set of labels, connections and node/edge weights. + *\param labels list of available labels + *\param neighborMap connectivity map, for each node, list of neighboring nodes linear indices + *\param numIterations number of expansion iterations to perform + *\param unaryLabelOnly optional unary cost that only depends on the label: f(lab0), else provide nullptr + *\param unaryFull unary (per node) cost function evaluator, receiving the node linear index and label: f(ind0, lab0) + *\param pairwiseLabelsOnly optional pairwise cost that only depends on the labels: f(lab0, lab1), else provide nullptr + *\param pairwiseFull pairwise (per pair of nodes) cost function evaluator, receiving the nodes linear indices and their labels: f(ind0, ind1, lab0, lab1) + *\note the "*LabelsOnly" functions are optional and are precomputed and cached for optimized resolution. + */ + MRFSolver(std::vector labels, std::vector >* neighborMap, int numIterations, + UnaryLabelOnlyFuncPtr unaryLabelOnly, + UnaryFuncPtr unaryFull, + PairwiseLabelOnlyFuncPtr pairwiseLabelsOnly, + PairwiseFuncPtr pairwiseFull + ); + + /// Solve using alpha expansion. When you have only two labels, use solveBinaryLabels instead + void solveLabels(void); + + /// Solve for binary labels: if you only more than two labels, call solveLabels instead. + void solveBinaryLabels(void); + + /** For each pixel, get the estimated label (call either solveLabels or solveBinaryLabels before). + \return a list of labels, one per pixel */ + std::vector getLabels(void); + + /** \return the total energy of the current labeling. */ + double getTotalEnergy(void); + + /** \return the unary energy of the current labeling. */ + double computeEnergyU(void); + + /** \return the pairwise energy of the current labeling. */ + double computeEnergyW(void); + + /** \return per label unary energy. */ + std::vector getUnariesEnergies(void); + + /// Destructor. + ~MRFSolver(void); + + private: + + /** Build graph for the general case. + *\param label_iteration_id + **/ + void buildGraphAlphaExp(int label_iteration_id); + + /** Build graph for the binary labeling case. */ + void buildGraphBinaryLabels(void); + + /** Compute the unary cost of a node. + *\param p the node linear index + *\param lp_id the node label to consider + *\return the total unary cost + **/ + double unaryTotal(int p, int lp_id); + + /** Compute the pairwise cost of a pair of nodes. + *\param p the first node linear index + *\param q the second node linear index + *\param lp_id the first node label to consider + *\param lq_id the scond node label to consider + *\return the total pairwise cost + **/ + double pairwiseTotal(int p, int q, int lp_id, int lq_id); + + std::vector _labList; ///< Map the label_id to the actual labels. + std::vector _labels; ///< Assign each node its current best label_id. + std::vector >* _neighborMap; ///< For each variable, gives the list of its neighbor variables + int _numIterations; ///< Number of iterations in alpha expansion. + + std::vector _UnaryLabelOnly; ///< Unaries only requiring label. + std::shared_ptr > _unaryFull; ///< Unaries requiring label and variable. + std::vector > _PairwiseLabelsOnly; ///< Pairwises only requiring labels. + std::shared_ptr > _pairwiseFull; ///< Pairwises requiring labels and variables. + + typedef Graph GraphType; + double _energy; ///< Total energy. + GraphType* _graph; ///< Graph. + bool ignoreIsolatedNode; ///< Ignore nodes with no connections. + }; + +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/MeshTexturing.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/MeshTexturing.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4e5ca32dddfe63d0bf6acdbe37736b323fb88047 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/MeshTexturing.cpp @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "MeshTexturing.hpp" +#include "PoissonReconstruction.hpp" +#include + +namespace sibr { + + MeshTexturing::MeshTexturing(unsigned int sideSize) : + _accum(sideSize, sideSize, Vector3f(0.0f, 0.0f, 0.0f)), + _mask(sideSize, sideSize, 0) + { + + } + + void MeshTexturing::setMesh(const sibr::Mesh::Ptr mesh) { + _mesh = mesh; + + // We need UVs else we can't do anything. + if (!_mesh->hasTexCoords()) { + SIBR_ERR << "[Texturing] The mesh to texture needs to have UVs" << std::endl; + return; + } + // We also need normals. + if (!_mesh->hasNormals()) { + _mesh->generateNormals(); + } + + // Create a mesh in UV space, using the UVs as 2D coordinates. + SIBR_LOG << "[Texturing] Generating UV mesh..." << std::endl; + const int verticesCount = int(_mesh->vertices().size()); + std::vector uvVertices(verticesCount); + +#pragma omp parallel for + for (int vid = 0; vid < verticesCount; ++vid) { + const sibr::Vector2f & uvs = _mesh->texCoords()[vid]; + uvVertices[vid] = sibr::Vector3f(uvs[0], uvs[1], 0.0f); + } + Mesh uvMesh(false); + uvMesh.vertices(uvVertices); + uvMesh.triangles(_mesh->triangles()); + + // Init both raycasters. + // For the world raycaster, we need to have no backface culling. + // Our version of Embree being compiled with backface culling, we have to 'duplicate and flip' the mesh. + Mesh::Ptr doubleMesh = _mesh->clone(); + doubleMesh->merge(_mesh->invertedFacesMesh()); + _worldRaycaster.addMesh(*doubleMesh); + _uvsRaycaster.addMesh(uvMesh); + + } + + void MeshTexturing::interpolate(const sibr::RayHit & hit, sibr::Vector3f & vertex, sibr::Vector3f & normal) const { + const Mesh::Vertices & vertices = _mesh->vertices(); + const Mesh::Normals & normals = _mesh->normals(); + + const sibr::Vector3u& tri = _mesh->triangles()[hit.primitive().triID]; + + const float uCoord = hit.barycentricCoord().u; + const float vCoord = hit.barycentricCoord().v; + const float wCoord = sibr::clamp(1.f - uCoord - vCoord, 0.0f, 1.0f); + + vertex = wCoord * vertices[tri[0]] + uCoord * vertices[tri[1]] + vCoord * vertices[tri[2]]; + normal = (wCoord * normals[tri[0]] + uCoord * normals[tri[1]] + vCoord * normals[tri[2]]).normalized(); + } + + void MeshTexturing::reproject(const std::vector & cameras, const std::vector & images, const float sampleRatio) { + // We need a mesh for reprojection. + if (!_mesh) { + SIBR_WRG << "[Texturing] No mesh available." << std::endl; + return; + } + + + struct SampleInfos { + sibr::Vector3f color; + float weight; + }; + + + const int w = _accum.w(); + const int h = _accum.h(); + + sibr::LoadingProgress progress(h, "[Texturing] Gathering color samples from cameras" ); + SIBR_LOG << "[Texturing] Gathering color samples from " << cameras.size() << " cameras ..." << std::endl; + +#pragma omp parallel for + for (int py = 0; py < h; ++py) { + for (int px = 0; px < w; ++px) { + // Check if we fall inside a triangle in the UV map. + RayHit hit; + const bool hasHit = sampleNeighborhood(px, py, hit); + + // We really have no triangle in the neighborhood to use, skip. + if (!hasHit) { + continue; + } + + // Need the smooth position and normal in the initial mesh. + sibr::Vector3f vertex, normal; + interpolate(hit, vertex, normal); + + sibr::Vector3f avgColor(0.0f, 0.0f, 0.0f); + float totalWeight = 0.0f; + + std::vector samples; + + for (int cid = 0; cid < cameras.size(); ++cid) { + const auto & cam = cameras[cid]; + if (!cam->frustumTest(vertex)) { + continue; + } + + // Check for occlusions. + sibr::Vector3f occDir = (vertex - cam->position()); + const float dist = occDir.norm(); + if (dist > 0.0f) { + occDir /= dist; + } + const RayHit hitOcc = _worldRaycaster.intersect(Ray(cam->position(), occDir)); + if (hitOcc.hitSomething() && (hitOcc.dist() + 0.0001f) < dist) { + continue; + } + + // Reproject, read color. + const sibr::Vector2f pos = cam->projectImgSpaceInvertY(vertex).xy(); + const sibr::Vector3f col = images[cid]->bilinear(pos).cast().xyz(); + // Angle-based weight for now. + const float angleWeight = std::max(-occDir.dot(normal), 0.0f); + const float weight = angleWeight; + //avgColor += weight * col; + //totalWeight += weight; + samples.emplace_back(); + samples.back().color = col; + samples.back().weight = weight; + } + if (samples.empty()) { + continue; + } + + std::sort(samples.begin(), samples.end(), [](const SampleInfos & a, const SampleInfos & b) + { + return a.weight > b.weight; + }); + + // Re-weight and accumulate the samples. + // The code is written this way to support 'best sampleRatio of all samples' approaches. + for(int i = 0; i < sampleRatio * samples.size(); ++i) { + float w = samples[i].weight; + w = w * w; + totalWeight += w; + avgColor += w * samples[i].color; + } + + if (totalWeight > 0.0f) { + _accum(px, py) = avgColor / totalWeight; + _mask(px, py)[0] = 255; + } + } + if( (py % 1000) == 0 ) + progress.walk(1000); + } + } + + sibr::ImageRGB::Ptr MeshTexturing::getTexture(uint options) const { + + ImageRGB32F output; + if (options & Options::FLOOD_FILL) { + output = floodFill(_accum, _mask)->clone(); + } + else if (options & Options::POISSON_FILL) { + output = poissonFill(_accum, _mask)->clone(); + } + else { + output = _accum.clone(); + } + + // Convert as-is to uchar. + ImageRGB::Ptr result(new ImageRGB()); + const cv::Mat3f outputF = output.toOpenCV(); + const cv::Mat3b outputB = cv::Mat3b(outputF); + result->fromOpenCV(outputB); + + /// \todo For extra large images, this might crash because of internal openCV indexing limitations. + if (options & Options::FLIP_VERTICAL) { + result->flipH(); + } + + return result; + } + + sibr::ImageRGB32F::Ptr MeshTexturing::poissonFill(const sibr::ImageRGB32F & image, const sibr::ImageL8 & mask) { + SIBR_LOG << "[Texturing] Poisson filling..." << std::endl; + + const cv::Mat3f guideF = cv::Mat3f(image.toOpenCV()) / 255.0f; + cv::Mat1f maskF; + mask.toOpenCV().convertTo(maskF, CV_32FC1, 1.0f / 255.0f); + + const cv::Mat3f gradX = cv::Mat3f::zeros(guideF.rows, guideF.cols); + const cv::Mat3f gradY = gradX.clone(); + + PoissonReconstruction poisson(gradX, gradY, maskF, guideF); + poisson.solve(); + const cv::Mat3f resultF = 255.0f * poisson.result(); + + ImageRGB32F::Ptr filled(new ImageRGB32F()); + filled->fromOpenCV(resultF); + return filled; + } + + + bool MeshTexturing::hitTest(int px, int py, RayHit & finalHit) + { + // From the UVs find the world space position. + const float u = (float(px) + 0.5f) / float(_accum.w()); + const float v = (float(py) + 0.5f) / float(_accum.h()); + // Spawn a ray from (u,v,0) in the z direction. + const RayHit hit = _uvsRaycaster.intersect(Ray({ u, v, 1.0f }, { 0.0f,0.0f,-1.0f })); + if (hit.hitSomething()) { + finalHit = hit; + return true; + } + // Just in case of backface culling, try the other side. + const RayHit hitBack = _uvsRaycaster.intersect(Ray({ u, v, -1.0f }, { 0.0f,0.0f,1.0f })); + if (hitBack.hitSomething()) { + finalHit = hitBack; + return true; + } + return false; + } + + bool MeshTexturing::sampleNeighborhood(int px, int py, RayHit & hit) + { + bool hasHit = hitTest(px, py, hit); + // Sample a 3x3 neighborhood to counter-act aliasing/interpolation later on, as long as we don't get a hit. + // The order is important, to first fetch in line/column and then in diagonal. Sorry for the cache... + std::vector dxs = { px, px - 1, px + 1 }; + std::vector dys = { py, py - 1, py + 1 }; + for (const int dx : dxs) { + if (hasHit) { + break; + } + for (const int dy : dys) { + if (hasHit) { + break; + } + // Ignore center pixel, already tested. + if (dx == px && dy == py) { + continue; + } + hasHit = hitTest(dx, dy, hit); + } + } + return hasHit; + } + +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/MeshTexturing.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/MeshTexturing.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a5c8e7eb71f106f1c8c828721cc7426458f4bfc2 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/MeshTexturing.hpp @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include "Config.hpp" +#include +#include +#include +#include "core/raycaster/Raycaster.hpp" + + +namespace sibr { + + /** \brief Reproject images onto a mesh using the associated camera poses, + * and accumulate colors in UV-space to generate a texture map. + * \ingroup sibr_imgproc + */ + class SIBR_IMGPROC_EXPORT MeshTexturing + { + public: + + /** \brief Export options + */ + enum Options : uint { + NONE = 0, + FLIP_VERTICAL = 1, ///< Flip the final result. + FLOOD_FILL = 2, ///< Perform flood filling. + POISSON_FILL = 4 ///< Perform poisson filling (slow). + }; + + /** Constructor. + * \param sideSize dimension of the texture + */ + MeshTexturing(unsigned int sideSize); + + /** Set the current mesh to texture. + * \param mesh the mesh to use. + * \warning The mesh MUST have texcoords. + * \note If the mesh has no normals, they will be computed. + */ + void setMesh(const sibr::Mesh::Ptr mesh); + + /** Reproject a set of images into the texture map, using the associated cameras. + * \param cameras the cameras poses + * \param images the images to reproject + */ + void reproject(const std::vector & cameras, const std::vector & images, const float sampleRatio = 1.0); + + /** Get the final result. + * \param options the options to apply to the generated texture map. + */ + sibr::ImageRGB::Ptr getTexture(uint options = NONE) const; + + /** Performs flood fill of an image, following a mask. + * \param image the image to fill + * \param mask mask where the zeros regions will be filled + * \return the filled image. + */ + template + static typename Image< T_Type, T_NumComp>::Ptr floodFill(const Image & image, const sibr::ImageL8 & mask) { + + typename Image< T_Type, T_NumComp>::Ptr filled(new Image< T_Type, T_NumComp>(image.w(), image.h())); + + SIBR_LOG << "[Texturing] Flood filling..." << std::endl; + // Perform filling. + // We need the empty pixels marked as non zeros, and the filled marked as zeros. + cv::Mat1b flipMask = mask.toOpenCV().clone(); + flipMask = 255 - flipMask; + cv::Mat1f dummyDist(flipMask.rows, flipMask.cols, 0.0f); + cv::Mat1i labels(flipMask.rows, flipMask.cols, 0); + + // Run distance transform to obtain the IDs. + cv::distanceTransform(flipMask, dummyDist, labels, cv::DIST_L2, cv::DIST_MASK_5, cv::DIST_LABEL_PIXEL); + + // Build a pixel ID to source pixel table, using the pixels in the mask. + const sibr::Vector2i basePos(-1, -1); + std::vector colorTable(flipMask.rows*flipMask.cols, basePos); +#pragma omp parallel + for (int py = 0; py < flipMask.rows; ++py) { + for (int px = 0; px < flipMask.cols; ++px) { + if (flipMask(py, px) != 0) { + continue; + } + const int label = labels(py, px); + colorTable[label] = { px,py }; + } + } + + // Now we can turn the label image into a color image again. +#pragma omp parallel + for (int py = 0; py < flipMask.rows; ++py) { + for (int px = 0; px < flipMask.cols; ++px) { + // Don't touch existing pixels. + if (flipMask(py, px) == 0) { + filled(px, py) = image(px, py); + continue; + } + const int label = labels(py, px); + filled(px, py) = image(colorTable[label]); + } + } + return filled; + } + + /** Performs poisson fill of an image, following a mask. + * \param image the image to fill + * \param mask mask where the zeros regions will be filled + * \return the filled image. + * \warning This is slow for large images (>8k). + */ + static sibr::ImageRGB32F::Ptr poissonFill(const sibr::ImageRGB32F & image, const sibr::ImageL8 & mask); + + private: + + /** Test if the UV-space mesh covers a pixel of the texture map. + * \param px pixel x coordinate + * \param py pixel y coordinate + * \param finalHit the hit information if there is coverage + * \return true if there is coverage. + */ + bool hitTest(int px, int py, RayHit & finalHit); + + /** Test if the UV-space mesh approximately covers a pixel of the texture map, by sampling a neighborhood in uv-space. + * \param px pixel x coordinate + * \param py pixel y coordinate + * \param hit the hit information if there is coverage + * \return true if there is coverage. + */ + bool sampleNeighborhood(int px, int py, RayHit& hit); + + /** Compute the interpolated position and normal at the intersection point on the initial mesh. + * \param hit the intersection information + * \param vertex will contain the interpolated position + * \param normal will contain the interpolated normal + */ + void interpolate(const sibr::RayHit & hit, sibr::Vector3f & vertex, sibr::Vector3f & normal) const; + + sibr::ImageRGB32F _accum; ///< Color accumulator. + sibr::ImageL8 _mask; ///< Mask indicating which regions of the texture map have been covered. + + sibr::Mesh::Ptr _mesh; ///< The original world-space mesh. + sibr::Raycaster _worldRaycaster; ///< The world-space mesh raycaster. + sibr::Raycaster _uvsRaycaster; ///< The uv-space mesh raycaster. + + + }; + +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/PoissonReconstruction.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/PoissonReconstruction.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8fac3220bb2bdb5095361551312ed4b5cfdcb604 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/PoissonReconstruction.cpp @@ -0,0 +1,316 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "PoissonReconstruction.hpp" +#include +#include + + +namespace sibr { + + + +PoissonReconstruction::PoissonReconstruction( + const cv::Mat3f & gradientsX, + const cv::Mat3f & gradientsY, + const cv::Mat1f & mask, + const cv::Mat3f & img_target) +{ + // Make a copy of the target as we are going to modify it. + _img_target = img_target.clone(); + _gradientsX = gradientsX; + _gradientsY = gradientsY; + _mask = mask; + +} + +void PoissonReconstruction::solve(void) +{ + parseMask(); + + //solve Ai X=bi , Ai = A : coefs , bi : b_terms , i for each RGB + std::vector< Eigen::Triplet > coefs; + std::vector b_terms; + + for (int k = 0; k < 3; ++k) { + b_terms.push_back(Eigen::VectorXd::Zero(_pixels.size())); + } + + for ( int p=0; p<(int)_pixels.size(); p++ ) { + sibr::Vector2i pos(_pixels[p]); + std::vector< sibr::Vector2i > nPos ( getNeighbors(pos, _img_target.cols, _img_target.rows )); + int num_neighbors = 0; + cv::Vec3f new_term(0, 0, 0); + + for( int n_id = 0; n_id(p,nId,-1)); + + // Four possibilities: + if(npos.x() > pos.x()){ // right pixel + new_term -= _gradientsY.at(pos.y(), pos.x()); + } else if (npos.x() < pos.x()){ // left pixel + new_term += _gradientsY.at(npos.y(), npos.x()); + } else if (npos.y() > pos.y()){ // bottom pixel + new_term -= _gradientsX.at(pos.y(), pos.x()); + } else if(npos.y() < pos.y()){ // top pixel + new_term += _gradientsX.at(npos.y(), npos.x()); + } + + } else if(!isIgnored(npos)) { //boundary + new_term += _img_target.at(npos.y(),npos.x()); // color of target + + } + } + + coefs.push_back(Eigen::Triplet(p,p,(double)num_neighbors)); + + for (int k = 0; k < 3; ++k) { + b_terms[k](p) = new_term(k); + } + + } + + Eigen::SparseMatrix A((int)_pixels.size(),(int)_pixels.size()); + A.setFromTriplets(coefs.begin(),coefs.end()); + + std::vector solutions; + Eigen::SimplicialLDLT< Eigen::SparseMatrix > eigenSolver; + + eigenSolver.compute(A); + + if(eigenSolver.info()!=Eigen::Success) { + std::cerr << "decomp = failure" < 1) { + std::cerr << "distance to solution: " << error << std::endl; + } + } + + for (int p = 0; p<(int)_pixels.size(); p++) { + sibr::Vector2i pos(_pixels[p]); + cv::Vec3f color; + for (int k = 0; k < 3; ++k) { + color(k) = std::min(1.0f, std::max((float)solutions[k][p], 0.0f)); + } + _img_target.at(pos.y(), pos.x()) = color; + } + + postProcessing(); + postProcessing(); + +} + +void PoissonReconstruction::parseMask( void ) +{ + _pixels.resize(0); + _boundaryPixels.resize(0); + _pixelsId.resize(_mask.rows*_mask.cols,-2); + + //std::cerr << "size : " << _mask.cols << " x " << _mask.rows << std::endl; + + //first find boundaries + for( int j=0; j<(int)_mask.rows; j++ ) { + for( int i=0; i<(int)_mask.cols; i++) { + sibr::Vector2i pos(i,j); + + if(isIgnored(pos)) { + continue; + } + if( !isInMask(pos) ) { + std::vector< sibr::Vector2i > neighbors = getNeighbors(pos, _img_target.cols, _img_target.rows); + for( int n_id = 0; n_id PoissonReconstruction::getNeighbors( sibr::Vector2i pos, int width, int height ) +{ + std::vector< sibr::Vector2i > output; + int offset_list_4[4][2] = { {0,1},{0,-1},{1,0},{-1,0} }; + + for( int i=0; i<4; i++){ + sibr::Vector2i n_pos( pos[0]+offset_list_4[i][0], pos[1]+offset_list_4[i][1]); + int x = n_pos.x(); + int y = n_pos.y(); + if( x>=0 && x< width && y>=0 && y< height) { + output.push_back(n_pos); + } + } + return output; +} + +void PoissonReconstruction::computeGradients(const cv::Mat3f& src, cv::Mat3f& gradX, cv::Mat3f& gradY) { + gradX = cv::Mat3f(src.size()); + gradY = cv::Mat3f(src.size()); + for (int i = 0; i < src.rows; ++i) { + for (int j = 0; j < src.cols; ++j) { + // Compute forward differences. + const int ip = std::min(i + 1, src.rows - 1); + const int jp = std::min(j + 1, src.cols - 1); + + const cv::Vec3f c = src.at(i, j); + const cv::Vec3f d = src.at(ip, j); + const cv::Vec3f r = src.at(i, jp); + const cv::Vec3f dX = d - c; + const cv::Vec3f dY = r - c; + gradX.at(i, j) = dX; + gradY.at(i, j) = dY; + } + } +} + +void PoissonReconstruction::checkConnectivity( void ) +{ + // R(x) : 0 -> not connected to boundary, 1 -> connected, G(y) : 0 -> not checked, 1 -> checked + sibr::ImageRGB connectivity( _mask.cols , _mask.rows); + + std::queue pixelsToCheck; + for(int p=0; p<(int)_boundaryPixels.size(); p++){ + sibr::Vector2i pos(_boundaryPixels[p]); + pixelsToCheck.push(pos); + connectivity(pos.x(),pos.y()).x() = 1; //boundaries are connected to boundaries + } + + //propagate connectivity + while(pixelsToCheck.size()>0){ + sibr::Vector2i pos(pixelsToCheck.front()); + pixelsToCheck.pop(); + connectivity(pos.x(),pos.y()).y() = 1; + + std::vector neighbors( getNeighbors(pos, _img_target.cols, _img_target.rows) ); + for(int n_id=0; n_id<(int)neighbors.size(); n_id++){ + sibr::Vector2i npos(neighbors[n_id]); + if( connectivity(npos.x(),npos.y()).y()==1 || isIgnored(npos)) { + continue; + } else { + connectivity(npos.x(),npos.y()).x() = 1; + connectivity(npos.x(),npos.y()).y() = 1; + pixelsToCheck.push( npos ); + } + } + } + + //discard non connected pixel + for(int i=0; i<(int)_mask.cols; i++){ + for(int j=0; j<(int)_mask.rows; j++){ + if( connectivity(i,j).x() == 0 ) { + _pixelsId[i + _mask.cols * j] = -2; + sibr::Vector2i coords(i,j); + if( isInMask(coords) && !isIgnored(coords) ) { + _img_target.at(j, i) = cv::Vec3f(0.0f,0.0f,0.0f); + } + } + } + } + +} + +void PoissonReconstruction::postProcessing(void) +{ + //std::cerr << "[PoissonRecons] Post Processing" << std::endl; + /* + * for( int j=0; j<(int)_mask.rows; j++ ) { + for( int i=0; i<(int)_mask.cols; i++) { + sibr::Vector2i pos(i,j); + if( !isInMask(pos) ) { + */ +#pragma omp parallel for + for (int j = 0; j < (int)_mask.rows; j++) { + for (int i = 0; i < (int)_mask.cols; i++) { + // mask: 0 -> in reconstruction, 1 -> keep fixed. + //return (_mask.at(pos.y(), pos.x())<0.5); + if (std::abs(_mask.at(j,i)) < 0.5f && cv::norm(_img_target.at(j,i)) == 0.0f) { + std::vector neighbors(getNeighbors(sibr::Vector2i(i, j), _mask.cols, _mask.rows)); + std::vector neighIsBlack(neighbors.size(), false); + int black_neighbor = false; + for (uint n_id = 0; n_id < neighbors.size() && !black_neighbor; n_id++) { + sibr::Vector2i npos(neighbors[n_id]); + if (cv::norm(_img_target.at(npos.y(), npos.x())) == 0.0f) { + neighIsBlack[n_id] = true; + } + } + if (!black_neighbor && neighbors.size() > 0) { + cv::Vec3f new_color(0, 0, 0); + int count = 0; + for (uint n_id = 0; n_id < neighbors.size(); n_id++) { + if(neighIsBlack[n_id]) { + continue; + } + sibr::Vector2i npos(neighbors[n_id]); + new_color += _img_target.at(npos.y(), npos.x()); + ++count; + } + _img_target.at(j,i) = ((1.0f / (float)count)*new_color); + } + } + } + } +} + +bool PoissonReconstruction::isInMask( sibr::Vector2i & pos) +{ + const float maskVal = _mask.at(pos.y(), pos.x()); + return (std::abs(maskVal) < 0.5f); +} + +bool PoissonReconstruction::isIgnored(sibr::Vector2i & pos) +{ + return (_mask.at(pos.y(), pos.x()) <= -0.5f); +} + + +} \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/PoissonReconstruction.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/PoissonReconstruction.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6b40c2c7387c1955f0ae0e0851aa2cf92c606bc0 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/PoissonReconstruction.hpp @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include "Config.hpp" +#include + + +namespace sibr { + + /** \brief Performs gradient integration for tasks such as Poisson-based inpainting, smooth filling, ... + * See the constructor for additional details. + * \ingroup sibr_imgproc + */ + class SIBR_IMGPROC_EXPORT PoissonReconstruction + { + public: + + /** Initialize reconstructor for a given problem. Gradients and target are expected to be RGB32F, mask is L32F. + In the mask, pixels with value = 0 are to be inpainted, value > 0.5 are pixels to be used as source/constraint, value < -0.5 are pixels to be left unchanged and unused. + To compute the gradients from an image, prefer using PoissonReconstruction::computeGradients (weird results have been observed when using cv::Sobel and similar). + \param gradientsX the RGB32F horizontal color gradients to integrate along + \param gradientsY the RGB32F vertical color gradients to integrate along + \param mask the L32F mask denoting how each pixel should be treated. + \param img_target the RGB32 image to use as a source constraint (will be copied internally) + **/ + PoissonReconstruction( + const cv::Mat3f & gradientsX, + const cv::Mat3f & gradientsY, + const cv::Mat1f & mask, + const cv::Mat3f & img_target + ); + + /** Solve the reconstruction problem. */ + void solve(void); + + /** \return the result of the reconstruction */ + cv::Mat result() const { return _img_target; } + + /** helper to get the pixel coordinates of valid pixels for agiven pixel and image size. + *\param pos the central pixel position + *\param width number of columns/width + *\param height number of rows/height + *\return a vector containing neighboring pixels coordinates. + */ + static std::vector< sibr::Vector2i > getNeighbors(sibr::Vector2i pos, int width, int height); + + /** Compute the gradients of an RGB32F matrix using forward finite differences. + *\param src the matrix to compute the gradients of + *\param gradX will contain the horizontal gradients + *\param gradY will contain the vertical gradients + */ + static void computeGradients(const cv::Mat3f & src, cv::Mat3f & gradX, cv::Mat3f & gradY); + + private: + cv::Mat _img_target; ///< Main image. + cv::Mat _gradientsX; ///< Gradients. + cv::Mat _gradientsY; ///< Gradients. + cv::Mat _mask; ///< Mask guide. + + std::vector _pixels; ///< list of valid pixels. + std::vector _boundaryPixels; ///< List of boundary pixels. + std::vector _pixelsId; ///< Pixel IDs list. + std::vector > _neighborMap; ///< Each pixel valid neighbors. + + /** Parse the mask and the additional label condition into a list of pixels to modified and boundaries conditions. */ + void parseMask(void); + + /** Make sure that every modified pixel is connected to some boundary condition, all non connected pixels are discarded. */ + void checkConnectivity(void); + + /** Heuristic to fill isolated black pixels. */ + void postProcessing(void); + + /** Are we in the mask (ie mask==0). + \param pos the pixel to test for + \return true if mask(pix) == 0 + */ + bool isInMask(sibr::Vector2i & pos); + + /* Are we ignored (ie mask==-1). + \param pos the pixel to test for + \return true if mask(pix) == -1 + */ + bool isIgnored(sibr::Vector2i & pos); + + }; + +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/sibr_imgproc.dox b/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/sibr_imgproc.dox new file mode 100644 index 0000000000000000000000000000000000000000..79c8876f08562b06c9d9546e95f3cebe40475e34 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/imgproc/sibr_imgproc.dox @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +/*! + \defgroup sibr_imgproc sibr_imgproc + + \brief Image processing utilities. + +*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/CMakeLists.txt b/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..f2ddff847551d83e76a22bd7f645278e58ae817a --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/CMakeLists.txt @@ -0,0 +1,51 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +project(sibr_raycaster) + +file(GLOB SOURCES "*.cpp" "*.h" "*.hpp") +source_group("Source Files" FILES ${SOURCES}) + +## Specify target rules +add_library(${PROJECT_NAME} SHARED ${SOURCES} ${LIBS_SOURCES}) + +include_directories( + ${Boost_INCLUDE_DIRS} + ${nanoflann_INCLUDE_DIRS} +) +if(WIN32) +target_link_libraries(${PROJECT_NAME} + OpenMP::OpenMP_CXX + embree3 + sibr_graphics + sibr_assets + nanoflann +) +else() +target_link_libraries(${PROJECT_NAME} + OpenMP::OpenMP_CXX + embree +# CLUSTER +# /data/graphdeco/share/tbb/lib64/libtbb.so + sibr_graphics + sibr_assets + nanoflann +) +endif() + +add_definitions( -DSIBR_RAYCASTER_EXPORTS -DBOOST_ALL_DYN_LINK ) + +set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER ${SIBR_FOLDER}) + +## High level macro to install in an homogen way all our ibr targets +include(install_runtime) +ibr_install_target(${PROJECT_NAME} + INSTALL_PDB ## mean install also MSVC IDE *.pdb file (DEST according to target type) +) diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/CameraRaycaster.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/CameraRaycaster.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2c369a152c45191cc5eb21178b3209719ccca1e2 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/CameraRaycaster.cpp @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include +#include +#include "core/raycaster/CameraRaycaster.hpp" + + +namespace sibr +{ + + /*static*/ void CameraRaycaster::computePixelDerivatives( const sibr::InputCamera& cam, + sibr::Vector3f& dx, sibr::Vector3f& dy, sibr::Vector3f& upLeftOffset ) + { + sibr::Vector3f dir = cam.dir(); + sibr::Vector3f up = cam.up(); + float aspect = cam.aspect(); + + sibr::Vector2f screenWorldSize; + { + // screenWorldSize.y = 2*tan(fov/2) because screenDist = 1 (indeed + // we use normalized cam.dir() to build this derivative) + float heightWorldSize = 2.f*tanf(cam.fovy()/2.f); + screenWorldSize = sibr::Vector2f( heightWorldSize*aspect, heightWorldSize ); + } + + sibr::Vector3f right = cross(cam.dir(), up); + sibr::Vector3f rowSize = right*screenWorldSize[0]; + sibr::Vector3f colSize = -up*screenWorldSize[1]; + + dx = rowSize / (float)cam.w(); + dy = colSize / (float)cam.h(); + + upLeftOffset = dir - rowSize/2.f - colSize/2.f; + //upLeftOffset = upLeftOffset + dx/2.f + dy/2.f; // Used to start from the center of a pixel + upLeftOffset += cam.position(); + } + + void CameraRaycaster::computeClippingPlanes(const sibr::Mesh & mesh, std::vector& cams, std::vector & nearsFars) + { + + nearsFars.clear(); + sibr::Raycaster raycaster; + raycaster.init(); + sibr::Mesh::Ptr localMesh = mesh.invertedFacesMesh2(); + raycaster.addMesh(*localMesh); + SIBR_LOG << " [CameraRaycaster] computeAutoClippingPlanes() : " << std::flush; + + int deltaPix = 15; + + nearsFars.resize(cams.size()); + + #pragma omp parallel for + for (int cam_id = 0; cam_id < (int)cams.size(); ++cam_id) { + sibr::InputCamera & cam = *cams[cam_id]; + + sibr::Vector3f dx, dy, upLeftOffset; + sibr::CameraRaycaster::computePixelDerivatives(cam, dx, dy, upLeftOffset); + sibr::Vector3f camZaxis = cam.dir().normalized(); + float maxD = -1.0f, minD = -1.0f; + + for (int i = 0; i < (int)cam.h(); i += deltaPix) { + for (int j = 0; j < (int)cam.w(); j += deltaPix) { + sibr::Vector3f worldPos = ((float)j + 0.5f)*dx + ((float)i + 0.5f)*dy + upLeftOffset; + sibr::Vector3f dir = (worldPos - cam.position()).normalized(); + + sibr::RayHit hit = raycaster.intersect(sibr::Ray(cam.position(), dir)); + + if (!hit.hitSomething()) { continue; } + + float dist = hit.dist(); + + float clipDist = dist * std::abs(dir.dot(camZaxis)); + + maxD = (maxD<0 || clipDist > maxD ? clipDist : maxD); + minD = (minD<0 || clipDist < minD ? clipDist : minD); + } + } + + + float znear = 0.5f*minD; + float zfar = 2.0f*maxD; + + while (zfar / znear < 100.0f) { + zfar *= 1.1f; + znear *= 0.9f; + } + + cam.znear(znear); + cam.zfar(zfar); + + nearsFars[cam_id] = sibr::Vector2f(znear, zfar); + + std::cout << cam_id << " " << std::flush; + } + std::cout << " done." << std::endl; + + + } + + + sibr::Vector3f CameraRaycaster::computeRayDir( const sibr::InputCamera& cam, const sibr::Vector2f & pixel ) + { + sibr::Vector3f dx, dy, upLeftOffset; + CameraRaycaster::computePixelDerivatives(cam, dx, dy, upLeftOffset); + + sibr::Vector3f worldPos = pixel.x()*dx + pixel.y()*dy + upLeftOffset; //at dist 1 from cam center + return (worldPos - cam.position()).normalized(); + } + + bool CameraRaycaster::init( void ) + { + return _raycaster.init(); + } + + void CameraRaycaster::addMesh( const sibr::Mesh& mesh ) + { + _raycaster.addMesh(mesh); + } + + void CameraRaycaster::castForEachPixel( const sibr::InputCamera& cam, ICameraRaycasterProcessor* processors[], uint nbProcessors, const std::string& optLogMsg ) + { + //SIBR_PROFILESCOPE; + + // Check there is no NULL process + for (uint i = 0; i < nbProcessors; ++i) + if (processors[i] == nullptr) + SIBR_ERR << "camera-raycaster process NULL detected" << std::endl; + + sibr::Vector3f dx, dy, upLeftOffset; + CameraRaycaster::computePixelDerivatives(cam, dx, dy, upLeftOffset); + + //sibr::LoadingProgress progress(cam.w()*cam.h(), optLogMsg); + (void)optLogMsg; + + // For each pixel of the camera's image + for (uint py = 0; py < cam.h(); ++py) + { + for (uint px = 0; px < cam.w(); ++px) + { + //progress.walk(); + sibr::Vector3f worldPos = (float)px*dx + (float)py*dy + upLeftOffset; + // Cast a ray + sibr::Vector3f dir = worldPos - cam.position(); + RayHit hit = _raycaster.intersect(Ray( cam.position(), dir)); + + for (uint i = 0; i < nbProcessors; ++i) + processors[i]->onCast(px, py, hit); + } + } + + } + + RaycastingCamera::RaycastingCamera(const sibr::InputCamera & cam) : sibr::InputCamera(cam) { + CameraRaycaster::computePixelDerivatives(*this, dx, dy, upLeftOffsetMinusPos); + upLeftOffsetMinusPos -= position(); + + std::vector corners = { + {-1,-1}, {-1, 1}, {1, 1}, {1, -1} + }; + std::vector pts_near, pts_far; + for (const auto & c : corners) { + pts_near.push_back(unproject({ c[0], c[1], -1 })); + pts_far.push_back(unproject({ c[0], c[1], +1 })); + } + + frustum_planes = { + //HPlane::Through(pts_near[0], pts_near[3], pts_near[2]), // near_plane, + HPlane::Through(pts_far[0], pts_far[2], pts_far[3]), // far_plane + HPlane::Through(pts_near[2], pts_far[2], pts_far[1]), // top_plane, + HPlane::Through(pts_near[3], pts_near[0], pts_far[3]), // bottom_plane, + HPlane::Through(pts_far[0], pts_near[0], pts_far[1]), // left_plane + HPlane::Through(pts_near[3], pts_far[3], pts_far[2]) // right_plane; + }; + + //sibr::Vector3f pt = unproject({ 0, 0, 0 }); + //std::cout << " debug planes : "; + //for (uint i = 0; i < frustum_planes.size(); ++i) { + // std::cout << sibr::Vector4f(pt[0], pt[1], pt[2], 1).dot(frustum_planes[i].coeffs()) << " "; + //} + //std::cout << std::endl; + + } + + sibr::Vector3f RaycastingCamera::rayDirNotNormalized(const sibr::Vector2f & pixel) const + { + return pixel.x()*dx + pixel.y()*dy + upLeftOffsetMinusPos; + } + + sibr::Vector3f RaycastingCamera::rayDir(const sibr::Vector2f & pixel) const + { + return rayDirNotNormalized(pixel).normalized(); + } + + Ray RaycastingCamera::getRay(const sibr::Vector2f & pixel) const + { + return Ray(position(), rayDir(pixel)); + } + + sibr::Vector2f RaycastingCamera::rayProjection(const Line3 & line) const + { + sibr::Vector2f out(-1, -1); + uint id = 0; + if (isInsideFrustum(line.origin())) { + out[id] = 0; + ++id; + } + + std::vector intersection_params; + intersection_params.reserve(frustum_planes.size()); + + for (uint i = 0; i < frustum_planes.size(); ++i) { + float param = line.intersectionParameter(frustum_planes[i]); + if (param >= 0) { + intersection_params.push_back(param); + } + } + + std::sort(intersection_params.begin(), intersection_params.end()); + for (float t : intersection_params) { + if (isInsideFrustum(line.pointAt(t))) { + out[id] = t; + if (id == 1) { + return out; + } + ++id; + } + } + + return out; + } + + bool RaycastingCamera::isInsideFrustum(const sibr::Vector3f & pt, float eps) const + { + for (uint i = 0; i < frustum_planes.size(); ++i) { + if (sibr::Vector4f(pt[0], pt[1], pt[2], 1).dot(frustum_planes[i].coeffs()) < -eps) { + return false; + } + } + return true; + } + + sibr::Vector2f RaycastingCamera::projectImg_outside_frustum_correction(const Vector3f & pt3d) const + { + sibr::Vector3f pos2dGL = project(pt3d); + + if ((pt3d - position()).dot(dir()) < 0) { + pos2dGL.x() = -pos2dGL.x(); + } else { + pos2dGL.y() = -pos2dGL.y(); + } + return 0.5f*(pos2dGL.xy() + sibr::Vector2f(1, 1)).cwiseProduct(sibr::Vector2f(w(), h())); + + } + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/CameraRaycaster.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/CameraRaycaster.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c2f4833fd0b8fa68cafb78b4a5ac63ad38ebfe38 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/CameraRaycaster.hpp @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include +# include +# include +# include "core/raycaster/Config.hpp" +# include "core/raycaster/Raycaster.hpp" + +namespace sibr +{ + + /** Used to process casted rays from image pixels. Implement + this interface and write your custom behavior. + (e.g. see CameraRaycasterProcessor.hpp for built-in processor) + \ingroup sibr_raycaster + */ + class SIBR_RAYCASTER_EXPORT ICameraRaycasterProcessor + { + public: + + /// Destructor. + virtual ~ICameraRaycasterProcessor( void ) {} + + /** Called for each casted ray (that hit or not). + \param px pixel source pixel x coordinate + \param py pixel source pixel y coordinate + \param hit the (potential) hit information + */ + virtual void onCast( uint px, uint py, const RayHit& hit ) = 0; + + }; + + /** Used for casting each pixel of an image into a raycaster scene. + \ingroup sibr_raycaster + */ + class SIBR_RAYCASTER_EXPORT CameraRaycaster + { + public: + + /// Constructor. + CameraRaycaster( void ) { } + + /// Initialize (will be done when adding a mesh). + bool init( void ); + + /** Add a mesh to the raycaster + \param mesh the mesh + */ + void addMesh( const sibr::Mesh& mesh ); + + /** For each image pixel, send a ray and compute data using the provided processors. + \param cam the source camera + \param processors a list of processors to call for each cast ray + \param nbProcessors the number of processors in the list + \param optLogMessage log message + */ + void castForEachPixel( const sibr::InputCamera& cam, ICameraRaycasterProcessor* processors[], uint nbProcessors, + const std::string& optLogMessage="Executing camera raycasting"); + + /** This function returns the step (in both x- and y-coordinates) between each pixel in the world + space. Thus, if go through each pixel of an can image but you need their 3d world position, + using this function you can get it using: + pixel3d = dx*pixel2d.x + dy*pixel2d.y + upLeftOffset + where dx is the step between each horizontal pixel, + dy is the step between each vertical pixel, + \param cam the source camera + \param dx will contain the horizontal step + \param dy will contain the vertical step + \param upLeftOffset will contain the 3D coordinates of the top-left pixel + */ + static void computePixelDerivatives( const sibr::InputCamera& cam, sibr::Vector3f& dx, sibr::Vector3f& dy, sibr::Vector3f& upLeftOffset ); + + /** Compute the ray direction from the camera position to a given pixel. + \param cam the source camera + \param pixel the pixel in [0,w-1]x[0,h-1] + \return the ray direction from the camera position to the center of the input pixel. + */ + static sibr::Vector3f computeRayDir( const sibr::InputCamera& cam, const sibr::Vector2f & pixel ); + + /** Estimate the clipping planes for a set of cameras so that the mesh is entirely visible in each camera. + \param mesh the mesh to visualize + \param cams the list of cameras + \param nearsFars will contain the near and far plane of each camera + */ + static void computeClippingPlanes(const sibr::Mesh & mesh, std::vector& cams, std::vector & nearsFars); + + /// \return the internal raycaster + Raycaster& raycaster( void ) { return _raycaster; } + /// \return the internal raycaster + const Raycaster& raycaster( void ) const { return _raycaster; } + + private: + + Raycaster _raycaster; ///< Internal raycaster. + }; + + /** A raycasting camera is an input camera augmented with additional casting and frustum helpers. + \ingroup sibr_raycaster + */ + class SIBR_RAYCASTER_EXPORT RaycastingCamera : public sibr::InputCamera { + SIBR_CLASS_PTR(RaycastingCamera); + public: + using HPlane = Eigen::Hyperplane; + using Line3 = Eigen::ParametrizedLine; + + /** Constructor from an InputCamera + \param cam the camera + */ + RaycastingCamera(const sibr::InputCamera & cam); + + /** Compute the unormalized ray direction from the camera position to a given pixel. + \param pixel the pixel in [0,w-1]x[0,h-1] + \return the ray direction from the camera position to the center of the input pixel. + */ + sibr::Vector3f rayDirNotNormalized(const sibr::Vector2f & pixel) const; + + /** Compute the normalized ray direction from the camera position to a given pixel. + \param pixel the pixel in [0,w-1]x[0,h-1] + \return the ray direction from the camera position to the center of the input pixel. + */ + sibr::Vector3f rayDir(const sibr::Vector2f & pixel) const; + + /** Generate the ray going from the camera position to a given pixel. + \param pixel the pixel in [0,w-1]x[0,h-1] + \return the ray from the camera position to the center of the input pixel. + */ + Ray getRay(const sibr::Vector2f & pixel) const; + + /** Compute the (up to) two intersections of a oriented line with the camera frustum. + \param line the parametrized oriented line to test + \return the intersection parameters of the two intersection points with the frustum. + */ + sibr::Vector2f rayProjection(const Line3 & line) const; + + /** Check if a point is in the camera frustum. + \param pt the 3D point to test + \param eps the tolerance threshold + \return true if the point is inside + */ + bool isInsideFrustum(const sibr::Vector3f & pt, float eps = 0.0001) const; + + /** Project a 3D point on the image plane, including points behind the camera (horizontal flip). + \param pt3d the 3d point + \return the pixel coordinates in [0,w]x(0,h] + */ + sibr::Vector2f projectImg_outside_frustum_correction(const Vector3f& pt3d) const; + + sibr::Vector3f dx, dy, upLeftOffsetMinusPos; ///< Camera raycasting parameters. + + std::vector frustum_planes; ///< Frustum planes: near, far, top, bottom, left, right + }; + + ///// DEFINITIONS ///// + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/Config.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/Config.hpp new file mode 100644 index 0000000000000000000000000000000000000000..23febbf42d2a0206f2ea13dbfc32df618c8904ad --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/Config.hpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include + + +# ifdef SIBR_OS_WINDOWS +# ifdef SIBR_STATIC_RAYCASTER_DEFINE +# define SIBR_RAYCASTER_EXPORT +# define SIBR_NO_RAYCASTER_EXPORT +# else +# ifndef SIBR_RAYCASTER_EXPORT +# ifdef SIBR_RAYCASTER_EXPORTS + /* We are building this library */ +# define SIBR_RAYCASTER_EXPORT __declspec(dllexport) +# else + /* We are using this library */ +# define SIBR_RAYCASTER_EXPORT __declspec(dllimport) +# endif +# endif +# endif +# else +# define SIBR_RAYCASTER_EXPORT +# endif + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/Intersector2D.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/Intersector2D.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8fba2174186c979836e9bed606d55cc4fc5a57ab --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/Intersector2D.cpp @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "Intersector2D.h" +#include +#include +#include + +namespace sibr { + + + float Intersector2D::sign(sibr::Vector2f p1, sibr::Vector2f p2, sibr::Vector2f p3) + { + return (p1.x() - p3.x()) * (p2.y() - p3.y()) - (p2.x() - p3.x()) * (p1.y() - p3.y()); + } + + bool Intersector2D::PointInTriangle(sibr::Vector2f pt, sibr::Vector2f v1, sibr::Vector2f v2, sibr::Vector2f v3) + { + bool b1, b2, b3; + + b1 = sign(pt, v1, v2) < 0.0f; + b2 = sign(pt, v2, v3) < 0.0f; + b3 = sign(pt, v3, v1) < 0.0f; + + return ((b1 == b2) && (b2 == b3)); + } + + //Segment are a->b and c->d + bool Intersector2D::LineLineIntersect(sibr::Vector2f a, sibr::Vector2f b, sibr::Vector2f c, sibr::Vector2f d) + { + float den = ((d.y() - c.y())*(b.x() - a.x()) - (d.x() - c.x())*(b.y() - a.y())); + float num1 = ((d.x() - c.x())*(a.y() - c.y()) - (d.y() - c.y())*(a.x() - c.x())); + float num2 = ((b.x() - a.x())*(a.y() - c.y()) - (b.y() - a.y())*(a.x() - c.x())); + float u1 = num1 / den; + float u2 = num2 / den; + + if (den == 0 && num1 == 0 && num2 == 0) + /* The two lines are coincidents */ + return false; + if (den == 0) + /* The two lines are parallel */ + return false; + if (u1 < 0 || u1 > 1 || u2 < 0 || u2 > 1) + /* Lines do not collide */ + return false; + /* Lines DO collide */ + return true; + } + + bool Intersector2D::TriTriIntersect(sibr::Vector2f t0_0, sibr::Vector2f t0_1, sibr::Vector2f t0_2, + sibr::Vector2f t1_0, sibr::Vector2f t1_1, sibr::Vector2f t1_2) { + + //Test if lines intersects + if (LineLineIntersect(t0_0, t0_1, t1_0, t1_1)) { return true; }; + if (LineLineIntersect(t0_0, t0_1, t1_0, t1_2)) { return true; }; + if (LineLineIntersect(t0_0, t0_1, t1_1, t1_2)) { return true; }; + if (LineLineIntersect(t0_0, t0_2, t1_0, t1_1)) { return true; }; + if (LineLineIntersect(t0_0, t0_2, t1_0, t1_2)) { return true; }; + if (LineLineIntersect(t0_0, t0_2, t1_1, t1_2)) { return true; }; + if (LineLineIntersect(t0_1, t0_2, t1_0, t1_1)) { return true; }; + if (LineLineIntersect(t0_1, t0_2, t1_0, t1_2)) { return true; }; + if (LineLineIntersect(t0_1, t0_2, t1_1, t1_2)) { return true; }; + + + //Test if one point in triangle : + if (PointInTriangle(t0_0, t1_0, t1_1, t1_2) || + PointInTriangle(t0_1, t1_0, t1_1, t1_2) || + PointInTriangle(t0_2, t1_0, t1_1, t1_2) || + PointInTriangle(t1_0, t0_0, t0_1, t0_2) || + PointInTriangle(t1_1, t0_0, t0_1, t0_2) || + PointInTriangle(t1_2, t0_0, t0_1, t0_2)) { + return true; + } + + return false; + + } + + bool Intersector2D::QuadQuadIntersect(sibr::Vector2f q0_0, sibr::Vector2f q0_1, sibr::Vector2f q0_2, sibr::Vector2f q0_3, + sibr::Vector2f q1_0, sibr::Vector2f q1_1, sibr::Vector2f q1_2, sibr::Vector2f q1_3) + { + if (TriTriIntersect( + q0_0, q0_1, q0_3, + q1_0, q1_1, q1_3)) { + return true; + } + if (TriTriIntersect( + q0_0, q0_1, q0_3, + q1_1, q1_2, q1_3)) { + return true; + } + if (TriTriIntersect( + q0_1, q0_2, q0_3, + q1_0, q1_1, q1_3)) { + return true; + } + if (TriTriIntersect( + q0_1, q0_2, q0_3, + q1_1, q1_2, q1_3)) { + return true; + } + + return false; + } + + std::vector> Intersector2D::frustrumQuadsIntersect(std::vector & quads, const std::vector & cams) + { + std::clock_t previous; + double duration; + previous = std::clock(); + + std::vector> result(cams.size(), std::vector(quads.size(), false)); + + sibr::GLShader shader; + sibr::GLParameter shader_proj; + + + std::string vertexShader = + "#version 420\n" + "uniform mat4 MVP;\n" + "layout(location = 0) in vec3 in_vertex;\n" + "void main(void) {\n" + " gl_Position = MVP * vec4(in_vertex, 1.0);\n" + "}\n"; + + + std::string fragmentShader = + "#version 420\n" + "out float out_color;\n" + "void main(void) {\n" + " out_color = 1.0;\n" + "}\n"; + + shader.init("quadShader", vertexShader, fragmentShader); + shader_proj.init(shader, "MVP"); + + std::shared_ptr rtLum; + + for (int c = 0; c < cams.size(); c++) { + const sibr::InputCamera & cam = *cams[c]; + + float ratio = (float)cam.h() / (float)cam.w(); + int w = std::min(400, (int)cam.w()); + int h = int(w*ratio); + + rtLum.reset(new sibr::RenderTargetLum(w, h)); + + for (int q = 0; q < quads.size(); q++) { + + quad & quad = quads[q]; + + sibr::ImageL8 imLum; + + std::shared_ptr quadMesh = std::shared_ptr(new sibr::Mesh(true)); + + std::vector vertexBuffer; + vertexBuffer.push_back(quad.q1); + vertexBuffer.push_back(quad.q2); + vertexBuffer.push_back(quad.q3); + vertexBuffer.push_back(quad.q4); + + int indices[12] = { 0, 1, 2, 0, 2, 3, 1, 2, 3, 0, 1, 3 }; //triangle added, can be optimized if quad ensured with good order + std::vector indicesBuffer(&indices[0], &indices[0] + 12); + + quadMesh->vertices(vertexBuffer); + quadMesh->triangles(indicesBuffer); + + glViewport(0, 0, w, h); + rtLum->bind(); + glClearColor(0.0, 0.0, 0.0, 0.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + shader.begin(); + shader_proj.set(cam.viewproj()); + + quadMesh->render(false, false, sibr::Mesh::RenderMode::FillRenderMode); + + shader.end(); + + rtLum->readBack(imLum); + + bool nonBlack = false; + bool breakLoop = false; + for (int j = 0; j < (int)(rtLum->h()); j++) { + for (int i = 0; i < (int)(rtLum->w()); i++) { + if (imLum(i, j).x() != 0) { + nonBlack = true; + breakLoop = true; + break; + } + } + if (breakLoop) + break; + } + + //std::cout << "result " << q << " : " << nonBlack << std::endl; + if (nonBlack) + result[c][q] = true; + + } + } + + duration = (std::clock() - previous) / (double)CLOCKS_PER_SEC; + std::cout << "render : " << duration << std::endl; + previous = std::clock(); + + return result; + } + +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/Intersector2D.h b/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/Intersector2D.h new file mode 100644 index 0000000000000000000000000000000000000000..d8968e2204b883fc836d9b97e78988186f366c85 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/Intersector2D.h @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include "core/raycaster/Config.hpp" +#include +#include +#include + + + +/** Struct representing a 3D quad, along with load/save utilities. + \todo move in proper namespace without breaking anything. + \ingroup sibr_raycaster +*/ +struct quad { + + sibr::Vector3f q1; + sibr::Vector3f q2; + sibr::Vector3f q3; + sibr::Vector3f q4; + + /** Save quad to file on disk. + \param path destination file. + */ + void save(std::string path) { + sibr::ByteStream bs; + bs << q1.x() << q1.y() << q1.z() + << q2.x() << q2.y() << q2.z() + << q3.x() << q3.y() << q3.z() + << q4.x() << q4.y() << q4.z(); + bs.saveToFile(path); + } + + /** Load quad from file on disk. + \param path source file. + */ + void load(std::string path) { + sibr::ByteStream bs; + bs.load(path); + bs >> q1.x() >> q1.y() >> q1.z() + >> q2.x() >> q2.y() >> q2.z() + >> q3.x() >> q3.y() >> q3.z() + >> q4.x() >> q4.y() >> q4.z(); + } + +}; + +namespace sibr { + + + /** This class provides utilities to compute point/line/triangle/quad intersections. + \ingroup sibr_raycaster + */ + class SIBR_RAYCASTER_EXPORT Intersector2D + { + + public: + /// Constructor. + Intersector2D(void) = delete; + + /// Destructor + ~Intersector2D(void) = delete; + + /** + Having defined a straight line in the 2D plane, this method can be used to know in which half-space (defined by the line) a point lies. + \param p1 the 2D point to locate wrt to the line. + \param p2 a 2D point on the line. + \param p3 another 2D point on the line. + \return a signed value indicating on which side of the line the point is. + */ + static float sign(sibr::Vector2f p1, sibr::Vector2f p2, sibr::Vector2f p3); + + /** + Tests if a point falls inside a triangle, in 2D space. + \param pt the point to test. + \param v1 first triangle vertex. + \param v2 second triangle vertex. + \param v3 third triangle vertex. + \return a boolean denoting if the point belong to the triangle or not. + */ + static bool PointInTriangle(sibr::Vector2f pt, sibr::Vector2f v1, sibr::Vector2f v2, sibr::Vector2f v3); + + /** + Tests if a line intersects another line, in 2D space. + \param a first point on the first line. + \param b second point on the first line. + \param c first point on the second line. + \param d second point on the second line. + \return a boolean denoting if the lines intersects. + */ + static bool LineLineIntersect(sibr::Vector2f a, sibr::Vector2f b, sibr::Vector2f c, sibr::Vector2f d); + + /** + Tests if two triangles overlap, in 2D space. + \param t0_0 first vertex of the first triangle. + \param t0_1 second vertex of the first triangle. + \param t0_2 third vertex of the first triangle. + \param t1_0 first vertex of the second triangle. + \param t1_1 second vertex of the second triangle. + \param t1_2 third vertex of the second triangle. + \return a boolean denoting if the triangles overlap. + */ + static bool TriTriIntersect(sibr::Vector2f t0_0, sibr::Vector2f t0_1, sibr::Vector2f t0_2, + sibr::Vector2f t1_0, sibr::Vector2f t1_1, sibr::Vector2f t1_2); + + /** + Tests if two quads overlap, in 2D space. + \param q0_0 first vertex of the first quad. + \param q0_1 second vertex of the first quad. + \param q0_2 third vertex of the first quad. + \param q0_3 fourth vertex of the first quad. + \param q1_0 first vertex of the second quad. + \param q1_1 second vertex of the second quad. + \param q1_2 third vertex of the second quad. + \param q1_3 fourth vertex of the second quad. + \return a boolean denoting if the quads overlap. + */ + static bool QuadQuadIntersect(sibr::Vector2f q0_0, sibr::Vector2f q0_1, sibr::Vector2f q0_2, sibr::Vector2f q0_3, + sibr::Vector2f q1_0, sibr::Vector2f q1_1, sibr::Vector2f q1_2, sibr::Vector2f q1_3); + + /** + Perform multiple quads/camera frusta intersections at once. + \warning Requires an existing and current OpenGL context. + \param quads an array of quads to test against each camera frustum. + \param cams an array of cameras against which frusta the intersections tests should be performed. + \return a double-array of booleans denoting, for each camera, for each quad, if the quad intersects the frustum volume. + */ + static std::vector> frustrumQuadsIntersect(std::vector & quads, const std::vector & cams); + + }; + +} \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/KdTree.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/KdTree.hpp new file mode 100644 index 0000000000000000000000000000000000000000..91574660c0f086db1926c8457f81703f2f34c27a --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/KdTree.hpp @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include "Config.hpp" + +#include "core/system/Vector.hpp" +#include "nanoflann/nanoflann.hpp" + +namespace sibr { + + /** + * \class KdTree + * \brief Represent a 3D hierachical query structure baked by a nanoflann KdTree. + * \note With the default L2 distance, all distances and radii are expected to be + * the squared values (this is a nanoflann constraint). For other metrics, use the distance directly. + * \ingroup sibr_raycaster + */ + template + class KdTree + { + SIBR_CLASS_PTR(KdTree); + + public: + + typedef Eigen::Matrix Vector3X; + typedef KdTree self_t; + typedef typename Distance::template traits::distance_t metric_t; + typedef nanoflann::KDTreeSingleIndexAdaptor< metric_t, self_t, 3, size_t> index_t; + typedef std::vector> Results; + + /** + * Constructor. + * The KdTree will do a copy of the positions vector. + * \param positions a list of 3D points + * \param leafMaxSize maximum number of points per leaf + */ + KdTree(const std::vector & positions, size_t leafMaxSize = 10); + + /** Destructor. */ + ~KdTree(); + + /** Get the closest point stored in the KdTree for the specified distance + * \param pos the reference point + * \param distanceSq will contain the squared distance from pos to the closest point in the tree. + * \return the index of the closest point in the tree. + */ + size_t getClosest(const Vector3X & pos, num_t & distanceSq) const; + + /** Get the closest point stored in the KdTree for the specified distance + * \param pos the reference point + * \param count the number of neighbours to query + * \param idDistSqs will contain the indices of the closest points and their squared distances to the reference point + */ + void getClosest(const Vector3X & pos, size_t count, Results & idDistSqs) const; + + /** Get all points in a sphere of a given radius around a reference point. + *\param pos the reference point + *\param maxDistanceSq the squared sphere radius + *\param sorted should the points be sorted in ascending distance order + *\param idDistSqs will contain the indices of the points in the sphere and their squared distances to the reference point + */ + void getNeighbors(const Vector3X & pos, double maxDistanceSq, bool sorted, Results & idDistSqs) const; + + /// Interface expected by nanoflann for an adapter. + const self_t & derived() const { + return *this; + } + + /// Interface expected by nanoflann for an adapter. + self_t & derived() { + return *this; + } + + /// Interface: Must return the number of data points + inline size_t kdtree_get_point_count() const { + return _points.size(); + } + + /// Interface: Returns the dim'th component of the idx'th point in the class: + inline num_t kdtree_get_pt(const size_t idx, const size_t dim) const { + return _points[idx][dim]; + } + + /// Interface: Optional bounding-box computation: \return false to default to a standard bbox computation loop. + template + bool kdtree_get_bbox(BBOX & /*bb*/) const { + return false; + } + + private: + + const std::vector _points; + index_t * _index; + }; + + template + KdTree::KdTree(const std::vector& positions, size_t leafMaxSize) : _points(positions) { + if(positions.empty()) { + SIBR_ERR << "[KdTree] Trying to build a Kd-Tree from an empty list of points." << std::endl; + } + _index = new index_t(3, *this, nanoflann::KDTreeSingleIndexAdaptorParams(leafMaxSize)); + _index->buildIndex(); + } + + template + KdTree::~KdTree() + { + delete _index; + } + + template + inline size_t KdTree::getClosest(const Vector3X& pos, num_t & distanceSq) const { + size_t index = 0; + _index->knnSearch(&pos[0], 1, &index, &distanceSq); + return index; + } + + template + inline void KdTree::getClosest(const Vector3X & pos, size_t count, Results & idDistSqs) const { + std::vector outIds(count); + std::vector outDists(count); + const size_t foundCount = _index->knnSearch(&pos[0], count, &outIds[0], &outDists[0]); + idDistSqs.resize(foundCount); + for(size_t i = 0; i < foundCount; ++i) { + idDistSqs[i] = std::make_pair(outIds[i], outDists[i]); + } + } + + template + inline void KdTree::getNeighbors(const Vector3X & pos, double maxDistanceSq, bool sorted, Results & idDistSqs) const { + _index->radiusSearch(&pos[0], float(maxDistanceSq), idDistSqs, nanoflann::SearchParams(32, 0.0f, sorted)); + } + + +} /*namespace sibr*/ + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/PlaneEstimator.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/PlaneEstimator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b4a540d0f1960c5aa85189ecc32c190e9333298e --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/PlaneEstimator.cpp @@ -0,0 +1,362 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "PlaneEstimator.hpp" +#include + +typedef Eigen::Array ArrayXb; + +PlaneEstimator::PlaneEstimator() {} + +PlaneEstimator::PlaneEstimator(const std::vector & vertices, bool excludeBB) +{ + + Eigen::AlignedBox boxScaled; + if (excludeBB) { + Eigen::AlignedBox box; + for (const auto & vertex : vertices) { + box.extend(vertex); + } + for (const auto & vertex : vertices) { + boxScaled.extend(box.center()+0.99f*(vertex- box.center())); + } + + } + int bboxReject = 0; + if (vertices.size() > 200000) { + std::cout << "Found more than 200000 points reducing point cloud size ..." << std::endl; + + std::random_device rd; + std::mt19937 mt(rd()); + std::uniform_real_distribution dist(0.0, 1.0); + + for (const auto & v : vertices) { + double random = dist(mt); + if (random < 200000.0 / double(vertices.size())) { + if (!excludeBB || (boxScaled.exteriorDistance(v)==0) ) + _Points.push_back(v); + else if (excludeBB && boxScaled.exteriorDistance(v) > 0) { + bboxReject++; + } + } + } + + if (excludeBB) + std::cout << bboxReject << " points where rejected becaused considered on the bounding box" << std::endl; + } + else { + _Points = vertices; + } + std::cout << "Point Cloud size: " << _Points.size() << std::endl; + _numPoints3D = (int)_Points.size(); + _remainPoints3D.resize(_Points.size(), 3); + _remainNormals3D.resize(_Points.size(), 3); + + for (int i = 0; i < _Points.size(); i++) { + _remainPoints3D.row(i) = _Points[i]; + _remainNormals3D.row(i) = sibr::Vector3f(0, 0, 0); + + } + + _planeComputed = false; +} + +void PlaneEstimator::computePlanes(const int numPlane, const float delta, const int numTry) { + + + _planeComputed = true; // we know that the planes were computed + + std::cout << "Original number of points " << _remainPoints3D.rows() << std::endl; + for (int i = 0; i < numPlane; i++) { + + if (_remainPoints3D.rows() < _numPoints3D * 5 / 100) + { + std::cout << "Not enough points remaining, stop searching. " << i << " planes found." << std::endl; + break; + } + + + sibr::Vector3f color(((float)rand() / (RAND_MAX)), ((float)rand() / (RAND_MAX)), ((float)rand() / (RAND_MAX))); + + Eigen::MatrixXi mask; + //Eigen::MatrixXf maskNormals; + std::pair covMean; + int vote = -1; + sibr::Vector4f plane = estimatePlane(delta, numTry, mask, vote, covMean); + + if (vote < _numPoints3D * 2 / 100 && i >= 12) { + std::cout << "Not enough points in candidate plane, stop searching. " << i << " planes found." << std::endl; + break; + } + // + + Eigen::MatrixXf remainPoints3DTemp(_remainPoints3D.rows() - vote, 3); + Eigen::MatrixXf remainNormals3DTemp(_remainNormals3D.rows() - vote, 3); + //std::vector remainImPosTemp; + + int notSel = 0; + std::vector pointsPlane; + for (int rIt = 0; rIt < _remainPoints3D.rows(); rIt++) { + if (mask.row(rIt)(0) == 0) { // not selected + remainPoints3DTemp.row(notSel) = _remainPoints3D.row(rIt); + remainNormals3DTemp.row(notSel) = _remainNormals3D.row(rIt); + //remainImPosTemp.push_back(_remainImPos[rIt]); + notSel++; + } + + else { // In the plane + pointsPlane.push_back(_remainPoints3D.row(rIt)); + } + } + + std::cout << "vote :" << vote << " notSel " << notSel << " supposed total " << _remainPoints3D.rows() << std::endl; + _remainPoints3D = remainPoints3DTemp; + _remainNormals3D = remainNormals3DTemp; + //_remainImPos=remainImPosTemp; + std::cout << "Remaining number of points " << _remainPoints3D.rows() << std::endl; + + sibr::Vector3f center = plane.w()*plane.xyz(); + + sibr::Vector4f finalPlane = plane; + + _planes.push_back(finalPlane); + _points.push_back(pointsPlane); + // centers and basis + _centers.push_back(center); + + //plane statistical informations + _covMeans.push_back(covMean); + _votes.push_back(vote); + } + +} + +sibr::Vector4f PlaneEstimator::estimatePlane(const float delta, const int numTry, Eigen::MatrixXi & bestMask, int & bestVote, std::pair & bestCovMean) { + + sibr::Vector4f bestPlane; + + float bestWVote = 0; +#pragma omp parallel for + for (int i = 0; i < numTry; i++) { + + Eigen::MatrixXi mask; + sibr::Vector4f plane = plane3Pts(); + if (plane.xyz().norm() > 0) { + std::pair votePair = votePlane(plane, delta, mask); + +#pragma omp critical + { + //std::cout << i << " "; + if (votePair.second > bestWVote) { + bestWVote = votePair.second; + bestVote = votePair.first; + bestPlane = plane; + bestMask = std::move(mask); // move to avoid copy + } + } + } + + } + + std::cout << "Best vote " << bestVote << " Best plane " << bestPlane << std::endl; + /* + std::cout << "Plane refinement ..." << std::endl; + + ////////////////// Plane fitting + + Eigen::MatrixXf data(3, bestVote); + int sel = 0; + + for (int rIt = 0; rIt < _remainPoints3D.rows(); rIt++) { + if (bestMask.row(rIt)(0) == 1) { + data.col(sel) = _remainPoints3D.row(rIt); + sel++; + } + } + + + std::cout << "Sel " << sel << std::endl; + + sibr::Vector3f center = data.rowwise().mean(); + Eigen::MatrixXf dataCentered = data.colwise() - center; + + bestCovMean.first = (dataCentered*dataCentered.adjoint()) / float(dataCentered.cols() - 1); + bestCovMean.second = center; + + std::cout << "Cov Matrix : " << bestCovMean.first << " Mean : " << bestCovMean.second << std::endl; + std::cout << "Cov Determinant : " << bestCovMean.first.determinant() << std::endl; + + Eigen::JacobiSVD svd(dataCentered, Eigen::ComputeFullU | Eigen::ComputeThinV); + + std::cout << "old normal" << " " << bestPlane.xyz(); + //the normal to the fitting plane is the eigenvector associated to the smallest eigenvalue (i.e. the direction in which the variance of all points is the smallest) + sibr::Vector3f normal = svd.matrixU().col(2); + normal.normalize(); + + float d = center.dot(normal); + + bestPlane = sibr::Vector4f(normal.x(), normal.y(), normal.z(), d); + + bestVote = votePlane(bestPlane, 10.0*delta, bestMask, 0.8f).first;*/ + + std::cout << " new normal" << " " << bestPlane.xyz() << std::endl; + // normal coherency + //Eigen::ArrayXf dotWithOriNormal=(_remainNormals3D * bestPlane.xyz()).array().cwiseAbs(); + //bestMaskNormals = (bestMask.array().cast()*dotWithOriNormal); + + std::cout << "Vote refined " << bestVote << " Plane refined " << bestPlane << /*" Normals coherency " << bestMaskNormals.sum()/bestVote <<*/ std::endl; + + return bestPlane; + +} + + +sibr::Vector4f PlaneEstimator::plane3Pts() { + + std::random_device rd; //Will be used to obtain a seed for the random number engine + std::mt19937 gen(rd()); //Standard mersenne_twister_engine seeded with rd() + std::uniform_int_distribution<> dis(0, int(_remainPoints3D.rows() - 1)); + + sibr::Vector3f pointA = _remainPoints3D.row(dis(gen)); + sibr::Vector3f pointB = _remainPoints3D.row(dis(gen)); + sibr::Vector3f pointC = _remainPoints3D.row(dis(gen)); + + sibr::Vector3f normal = (pointB - pointA).cross(pointC - pointA); + normal.normalize(); + + float d = normal.dot(pointA); + + return sibr::Vector4f(normal.x(), normal.y(), normal.z(), d); + +} + +std::pair PlaneEstimator::votePlane(const sibr::Vector4f plane, const float delta, Eigen::MatrixXi & mask, float normalDot) { + + sibr::Vector3f normal = plane.xyz(); + float d = plane.w(); + + //std::cout << "size " << _points3D.size() << " " << normal.size() << " d " << d << std::endl; + + Eigen::ArrayXf distances = (_remainPoints3D * normal).array(); + + Eigen::ArrayXf dotWithOriNormal = (_remainNormals3D * normal).array(); + + /*for(int i=0; i< 10; i++){ + std::cout << distances.row(i) << " "; + } + std::cout << std::endl;*/ + + distances = (distances - d * Eigen::ArrayXf::Ones(distances.rows())).cwiseAbs(); + dotWithOriNormal = dotWithOriNormal.cwiseAbs(); + + /*for(int i=0; i< 10; i++){ + std::cout << distances.row(i) << " "; + } + std::cout << std::endl;*/ + mask = (distances < delta && (dotWithOriNormal > normalDot || dotWithOriNormal == 0)).cast(); + + Eigen::ArrayXf voteW = (distances+ 0.1f*delta* Eigen::ArrayXf::Ones(distances.rows())); + voteW = mask.array().cast().cwiseQuotient(voteW); + //std::cout << "SUM " << mask.sum() << std::endl; + + return std::make_pair(mask.sum(), voteW.sum()); + +} + +sibr::Vector4f PlaneEstimator::estimateGroundPlane(sibr::Vector3f roughUp) +{ + if (_planeComputed) { + + //find the floor plane + int bestId = -1; + int bestVote = 0; + + for (int p = 0; p < _planes.size(); p++) { + if (abs(_planes[p].xyz().dot(roughUp)) > 0.87) { + if (_votes[p] > bestVote) { + bestId = p; + bestVote = _votes[p]; + } + } + } + return _planes[bestId]; + } + else { + std::cout << "Error : Plane not computed, you should call computePlanes first" << std::endl; + SIBR_ERR; + return { 0.0f, 0.0f, 0.0f, 0.0f }; + } +} + + +sibr::Vector3f PlaneEstimator::estimateMedianVec(const std::vector & ups) +{ + + std::vector medUpX; + std::vector medUpY; + std::vector medUpZ; + + for (const auto & up : ups) { + + medUpX.push_back(up.x()); + medUpY.push_back(up.y()); + medUpZ.push_back(up.z()); + + } + std::sort(medUpX.begin(), medUpX.end()); + std::sort(medUpY.begin(), medUpY.end()); + std::sort(medUpZ.begin(), medUpZ.end()); + + const size_t medPos = medUpX.size() / 2; + + sibr::Vector3f upMed(medUpX[medPos], medUpY[medPos], medUpZ[medPos]); + upMed.normalize(); + + return upMed; +} + +sibr::Mesh PlaneEstimator::getMeshPlane(sibr::Vector4f plane, sibr::Vector3f center, float radius) +{ + sibr::Mesh planeMesh; + + sibr::Vector3f projCenter = center - (center - plane.w()*plane.xyz()).dot(plane.xyz())*plane.xyz(); + + sibr::Mesh::Vertices vert; + sibr::Mesh::Triangles tri; + sibr::Mesh::Normals nml; + sibr::Mesh::UVs tex; + + sibr::Vector3f u = (projCenter - plane.w()*plane.xyz()).normalized(); + sibr::Vector3f v = plane.xyz().cross(u).normalized(); + + int numP = 50; + for (int i = 0; i < numP; i++) { + vert.push_back(projCenter + radius * cos(2 * M_PI*i / numP)*u + radius * sin(2 * M_PI*i / numP)*v); + nml.push_back(plane.xyz().normalized()); + tri.push_back(sibr::Vector3u(numP, i, (i + 1) % numP)); + } + + vert.push_back(projCenter); + + planeMesh.vertices(vert); + planeMesh.normals(nml); + planeMesh.triangles(tri); + return planeMesh; +} + +void PlaneEstimator::displayPCAndPlane(sibr::Window::Ptr window) +{ +} + +PlaneEstimator::~PlaneEstimator(void) +{ +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/PlaneEstimator.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/PlaneEstimator.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1b59b348a23cf9e32aa052cdb4f0ac05b23d7a55 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/PlaneEstimator.hpp @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include + +#include +#include +#include +#include +#include +#include + + +/** + Fit a plane to a point cloud using an improved RANSAC approach. + \ingroup sibr_raycaster +*/ +class SIBR_RAYCASTER_EXPORT PlaneEstimator { + +public: + + /// Default constructor. + PlaneEstimator(); + + /** Constructor. + \param vertices the point cloud + \param excludeBB if true, reject points that are close to the vertices bounding box + */ + PlaneEstimator(const std::vector & vertices, bool excludeBB=false); + + /** Compute one or more planes fitting the data using RANSAC. Points that are well fitted by a plan will bre moved from the set. + \param numPlane number of planes to fit + \param delta fit validity threshold + \param numTry number of attempts to perform for each plane + */ + void computePlanes(const int numPlane,const float delta,const int numTry); + + /** Estimate the best plane in the remaining points set using RANSAC. + \param delta fit validity threshold + \param numTry number of attempts to perform for each plane + \param bestMask for each point, will be set to 1 if the plane explains the point well + \param vote will contain the number of points that fit + \param bestCovMean unused + \return the plane parameters + */ + sibr::Vector4f estimatePlane(const float delta,const int numTry, Eigen::MatrixXi & bestMask, int & vote, std::pair & bestCovMean); + + /** Choose randomly 3 points among the vertices and compute the corresponding plane. + \return the plane parameters + */ + sibr::Vector4f plane3Pts(); + + /** Given a plane and a threshold, this function return the num of point that fit the plane in the remaining points and also the associated mask. + \param plane the plane parameters + \param delta validity threshold + \param mask for each point, will be set to 1 if the plane explains the point well + \param normalDot normal validity threshold + \return number of points that fit and overall weighted score (based on normal similarity) + */ + std::pair votePlane(const sibr::Vector4f plane, const float delta, Eigen::MatrixXi & mask, float normalDot=0.98); + + /** For visualization, display the point cloud and fitted plane in a window. + \param window the windo to use for display + \deprecated Empty, won't do anything. + */ + void displayPCAndPlane(sibr::Window::Ptr window); + + /** Estimate a fitting plane that is as orthogonal to the given up vector as possible. + \param roughUp an estimation of the scene up vector + \return the plane parameters. + */ + sibr::Vector4f estimateGroundPlane(sibr::Vector3f roughUp); + + /** Estimate the scene zenith from a set of camera up vectors (assuming photogrametric capture). + \param ups a set of up vector + \return the estimated median zenith vector + */ + static sibr::Vector3f estimateMedianVec(const std::vector & ups); + + /** Generate a mesh representing a plane. + \param plane the parameters of the plane to represent + \param center center of the plane mesh + \param radius extent of the plane mesh + \return the generated plane mesh + */ + static sibr::Mesh getMeshPlane(sibr::Vector4f plane , sibr::Vector3f center, float radius); + + std::vector _Points; ///< All initial points. + int _numPoints3D; ///< Number of initial points. + + std::vector _planes; ///< Planes are represented as Vector4f(n.x,n.y,n.z,d) + std::vector> _points; ///< For each plane, list of fitting points. + std::vector _centers; ///< Plane centers. + std::vector _votes; ///< Number of votes per plane. + std::vector> _covMeans; ///< Unused. + + /// Destructor. + ~PlaneEstimator(void); + +protected: + + Eigen::MatrixXf _remainPoints3D; ///< Points to consider. + Eigen::MatrixXf _remainNormals3D; ///< Associated normals to consider. + std::vector _Triangles; ///< Triangle list. + bool _planeComputed; ///< Has the plane been computed. +}; + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/Ray.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/Ray.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b22f2a1173cde34aea747c5cb6fbf768aaebc75b --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/Ray.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#include "Ray.hpp" + +namespace sibr +{ + /*static*/ SIBR_RAYCASTER_EXPORT const float RayHit::InfinityDist = std::numeric_limits::infinity(); + + Ray::Ray( const sibr::Vector3f& orig, const sibr::Vector3f& dir ) + : _orig(orig), _dir(dir) + { + if (_dir[0] != 0.f || _dir[1] != 0.f || _dir[2] != 0.f) + _dir.normalize(); + } + + RayHit::RayHit( const Ray& r, float dist, const BCCoord& coord, + const sibr::Vector3f& normal, const Primitive& prim ) + : _ray(r), _dist(dist), _coord(coord), _normal(normal), _prim(prim) + { + _dist = std::max(dist, 0.f); + + // normalize '_normal' + float len = length(_normal); + if (len > 1e-10) + _normal = _normal / len; + + } + + sibr::Vector3f RayHit::interpolateUV( void ) const + { + float ucoord = barycentricCoord().u; + float vcoord = barycentricCoord().v; + return sibr::Vector3f(std::max((1.f-ucoord-vcoord), 0.f), ucoord, vcoord); + } + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/Ray.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/Ray.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d950ea9399bf5fb7b6c4c95721b2a1c34a16bfac --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/Ray.hpp @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include +# include +# include +# include "core/raycaster/Config.hpp" + +namespace sibr +{ + + /// + /// Represents a simple ray + /// \ingroup sibr_raycaster + /// + class SIBR_RAYCASTER_EXPORT Ray + { + public: + /** Construct a ray from parameters. + \param orig ray origin + \param dir ray direction + \note The direction will be normalized. + */ + Ray( const sibr::Vector3f& orig = sibr::Vector3f(0.f, 0.f, 0.f), + const sibr::Vector3f& dir = sibr::Vector3f(0.f, 0.f, -1.f) ); + + /** Set the position from where the ray starts. + \param o the new origin + */ + inline void orig( const sibr::Vector3f& o ); + + /// \return the ray origin + inline const sibr::Vector3f& orig( void ) const; + + /** Set the direction of the ray. Additionally, + you can precise if you want this direction to be automatically + normalized or not. + \param d the new direction + \param normalizeIt should normalization be applied + */ + inline void dir( const sibr::Vector3f& d, bool normalizeIt=true ); + + /// \return the direction of the ray. + inline const sibr::Vector3f& dir( void ) const; + + /** Return the 3D point such that p = orig + t * dir; + \param t the distance along the ray + \return the 3D point + */ + Vector3f at(float t) const; + + private: + sibr::Vector3f _orig; ///< Position from where the ray starts + sibr::Vector3f _dir; ///< Direction where the ray goes + }; + + /// + /// Contains information about a ray hit + /// \ingroup sibr_raycaster + /// + class SIBR_RAYCASTER_EXPORT RayHit + { + public: + static const float InfinityDist; + + /// Infos about the object that was hit + struct Primitive + { + uint triID; ///< triangle id of the mesh that was hit + uint geomID; ///< mesh id loaded in the raycaster + uint instID; ///< id of the instance loaded in the raycaster + }; + + /// Barycentric coordinates + struct BCCoord + { + float u; ///< u-coordinates (ranging from 0.0 to 1.0) + float v; ///< v-coordinates (ranging from 0.0 to 1.0) + }; + + /** Construct a hit record. + \param r the ray + \param dist intersection distance + \param coord barycentric coordinates + \param normal surface normal + \param prim intersected primitive + */ + RayHit( const Ray& r, float dist, const BCCoord& coord, + const sibr::Vector3f& normal, const Primitive& prim ); + + /// Non-hit constructor. + RayHit() {}; + + /// \return the ray that was casted + inline const Ray& ray( void ) const; + + /// \return the distance from the ray origin to the hit + inline float dist( void ) const; + + /// \return the barycentric coordinates of the hit point on the triangle that was hit + inline const BCCoord& barycentricCoord( void ) const; + + /** Return the proper barycentric factors for interpolating information stored + at each vertex of a triangle. + e.g: get fragment color using + color = factor[0]*colorVert0 + factor[1]*colorVert1 + factor[2]*colorVert2 + It consider the following triangle: https://embree.github.io/images/triangle_uv.png + \return the barycentric coordinates + */ + sibr::Vector3f interpolateUV( void ) const; + + /// \return the normal of the triangle that was hit. + inline const sibr::Vector3f& normal( void ) const; + + /// \return information about the primitive that was hit. + inline const Primitive& primitive( void ) const; + + /// \return true if an object was hit. + inline bool hitSomething( void ) const; + + private: + Ray _ray; ///< casted ray + float _dist; ///< distance from the ray's origin to the hit + BCCoord _coord; ///< barycentric coordinate on the triangle that was hit + sibr::Vector3f _normal;///< normal of the triangle that was hit + Primitive _prim; ///< infos about the primitive that was hit + }; + + ///// DEFINITION ///// + + void Ray::orig( const sibr::Vector3f& o ) { + _orig = o; + } + const sibr::Vector3f& Ray::orig( void ) const { + return _orig; + } + + void Ray::dir( const sibr::Vector3f& d, bool normalizeIt) { + _dir = (normalizeIt)? sibr::Vector3f(d.normalized()) : d; + } + const sibr::Vector3f& Ray::dir( void ) const { + return _dir; + } + + inline Vector3f Ray::at(float t) const + { + return orig() + t * dir(); + } + + + + const Ray& RayHit::ray( void ) const { + return _ray; + } + float RayHit::dist( void ) const { + return _dist; + } + const RayHit::BCCoord& RayHit::barycentricCoord( void ) const { + return _coord; + } + const sibr::Vector3f& RayHit::normal( void ) const { + return _normal; + } + const RayHit::Primitive& RayHit::primitive( void ) const { + return _prim; + } + + bool RayHit::hitSomething( void ) const { + return (_dist != RayHit::InfinityDist); + } + + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/Raycaster.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/Raycaster.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1733636c141c1303060ef6aa91252c62eea544d5 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/Raycaster.cpp @@ -0,0 +1,404 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#include "Raycaster.hpp" + +namespace sibr +{ + /*static*/ SIBR_RAYCASTER_EXPORT const Raycaster::geomId Raycaster::InvalidGeomId = RTC_INVALID_GEOMETRY_ID; + /*static*/ bool Raycaster::g_initRegisterFlag = false; + /*static*/ Raycaster::RTCDevicePtr Raycaster::g_device = nullptr; + + /*static*/ void Raycaster::rtcErrorCallback(void* userPtr, RTCError code, const char* msg) + { + std::string err; + + switch (code) + { + case RTC_ERROR_UNKNOWN: err = std::string("RTC_ERROR_UNKNOWN"); break; + case RTC_ERROR_INVALID_ARGUMENT: err = std::string("RTC_ERROR_INVALID_ARGUMENT"); break; + case RTC_ERROR_INVALID_OPERATION: err = std::string("RTC_ERROR_INVALID_OPERATION"); break; + case RTC_ERROR_OUT_OF_MEMORY: err = std::string("RTC_ERROR_OUT_OF_MEMORY"); break; + case RTC_ERROR_UNSUPPORTED_CPU: err = std::string("RTC_ERROR_UNSUPPORTED_CPU"); break; + case RTC_ERROR_CANCELLED: err = std::string("RTC_ERROR_CANCELLED"); break; + default: err = std::string("invalid error code"); break; + } + + SIBR_ERR << "Embree reported the following issue - " + << "[" << err << "]'" << msg << "'" << std::endl; + } + + Raycaster::~Raycaster(void) + { + _scene = nullptr; + _devicePtr = nullptr; + if (g_device && g_device.use_count() == 1) + g_device = nullptr; // if nobody use it, free it + } + + bool Raycaster::init(RTCSceneFlags sceneType) + { + if (!g_device) + { + // The two following macros set flagbits on the control register + // used by SSE (see http://softpixel.com/~cwright/programming/simd/sse.php) + _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); // Enable 'Flush Zero' bit + _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); // Enable 'Denormals Zero'bit + + SIBR_LOG << "Initializing Raycaster" << std::endl; + + g_device = std::make_shared(rtcNewDevice(NULL)); + + if (g_device == nullptr) { + SIBR_LOG << "Cannot create an embree device : " << rtcGetDeviceError(*g_device.get()) << std::endl; + } + + rtcSetDeviceErrorFunction(*g_device.get(), &Raycaster::rtcErrorCallback, nullptr); // Set callback error function + _devicePtr = g_device; //Moved in the init + } + + if (_scene) + return true; + + + + _scene = std::make_shared( // define a new scene + /// \todo create a new static scene optimized for primary rays (TODO: test perf with RTC_SCENE_ROBUST) + rtcNewScene(*g_device.get()) + ); // set a custom deleter + + if (_scene == nullptr) + SIBR_LOG << "Cannot create an embree scene" << std::endl; + else { + //SIBR_LOG << "Embree device and scene created" << std::endl; + //SIBR_LOG << "Warning Backface culling state : "<< rtcGetDeviceProperty(*g_device, RTC_DEVICE_PROPERTY_BACKFACE_CULLING_ENABLED) << std::endl; + return true; // Success + } + return false; // Fail + } + + Raycaster::geomId Raycaster::addMesh(const sibr::Mesh& mesh) + { + return addGenericMesh(mesh, RTC_BUILD_QUALITY_HIGH); + } + + Raycaster::geomId Raycaster::addDynamicMesh(const sibr::Mesh& mesh) + { + return addGenericMesh(mesh, RTC_BUILD_QUALITY_LOW); + } + + Raycaster::geomId Raycaster::addGenericMesh(const sibr::Mesh& mesh, RTCBuildQuality type) + { + if (init() == false) + return Raycaster::InvalidGeomId; + + const sibr::Mesh::Vertices& vertices = mesh.vertices(); + const sibr::Mesh::Triangles& triangles = mesh.triangles(); + + RTCGeometry geom_0 = rtcNewGeometry(*g_device.get(), RTC_GEOMETRY_TYPE_TRIANGLE); // EMBREE_FIXME: check if geometry gets properly committed + rtcSetGeometryBuildQuality(geom_0, type); + rtcSetGeometryTimeStepCount(geom_0, 1); + geomId id = rtcAttachGeometry(*_scene.get(), geom_0); + //rtcReleaseGeometry(geom_0); + + if (id == Raycaster::InvalidGeomId) { + rtcCommitGeometry(geom_0); + return Raycaster::InvalidGeomId; + } + + struct Vertex { float x, y, z, a; }; + struct Triangle { int v0, v1, v2; }; + + { // Fill vertices of the geometry + Vertex* vert = (Vertex*)rtcSetNewGeometryBuffer(geom_0, RTC_BUFFER_TYPE_VERTEX, 0, RTC_FORMAT_FLOAT3, 4 * sizeof(float), vertices.size()); + for (uint i = 0; i < mesh.vertices().size(); ++i) + { + vert[i].x = vertices[i][0]; + vert[i].y = vertices[i][1]; + vert[i].z = vertices[i][2]; + vert[i].a = 1.f; + } + + } + + { // Fill triangle indices of the geometry + Triangle* tri = (Triangle*)rtcSetNewGeometryBuffer(geom_0, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT3, 3 * sizeof(int), triangles.size()); + for (uint i = 0; i < triangles.size(); ++i) + { + tri[i].v0 = triangles[i][0]; + tri[i].v1 = triangles[i][1]; + tri[i].v2 = triangles[i][2]; + } + + } + + rtcCommitGeometry(geom_0); + + // Commit all changes on the scene + rtcCommitScene(*_scene.get()); + + return id; + } + + // xform a mesh by transformation matrix "mat". Note that the original positions + // are always stored in mesh.vertices -- we only xform the vertices in the embree buffer + void Raycaster::xformRtcMeshOnly(sibr::Mesh& mesh, geomId mesh_id, sibr::Matrix4f& mat, sibr::Vector3f& centerPt, float& maxlen) + { + struct Vertex { float x, y, z, a; }; + Vertex* vert = (Vertex*)rtcGetGeometryBufferData(rtcGetGeometry(*_scene.get(), mesh_id), RTC_BUFFER_TYPE_VERTEX, 0) /* EMBREE_FIXME: check if this should be rtcSetNewGeometryBuffer */; + sibr::Vector4f averagePt = sibr::Vector4f(0, 0, 0, 1); + maxlen = 0; + + const sibr::Mesh::Vertices& vertices = mesh.vertices(); + //const sibr::Mesh::Normals& normals = mesh.normals(); + for (uint i = 0; i < mesh.vertices().size(); ++i) + { + sibr::Vector4f v; + + // reset to original position + v[0] = vert[i].x = vertices[i][0]; + v[1] = vert[i].y = vertices[i][1]; + v[2] = vert[i].z = vertices[i][2]; + v[3] = vert[i].a = 1.f; + + v = mat * v; + vert[i].x = v[0], vert[i].y = v[1], vert[i].z = v[2]; + averagePt += v; + float d = sibr::Vector3f(sibr::Vector4f(averagePt / (float)((i == 0) ? 1 : i)).xyz() - v.xyz()).norm(); + if (d > maxlen) + maxlen = d; + } + + sibr::Vector4f cp = averagePt / (float)mesh.vertices().size(); + centerPt = sibr::Vector3f(cp[0], cp[1], cp[2]); + + // Update mesh + rtcCommitGeometry(rtcGetGeometry(*_scene.get(), mesh_id)); + // Commit changes to scene + rtcCommitScene(*_scene.get()); + } + + bool Raycaster::hitSomething(const Ray& inray, float minDist) + { + assert(minDist >= 0.f); + + RTCRay ray; + ray.flags = 0; + ray.org_x = inray.orig()[0]; + ray.org_y = inray.orig()[1]; + ray.org_z = inray.orig()[2]; + ray.dir_x = inray.dir()[0]; + ray.dir_y = inray.dir()[1]; + ray.dir_z = inray.dir()[2]; + + ray.tnear = minDist; + ray.tfar = RayHit::InfinityDist; + + if (init() == false) + SIBR_ERR << "cannot initialize embree, failed cast rays." << std::endl; + else + { + RTCIntersectContext context; + rtcInitIntersectContext(&context); + rtcOccluded1(*_scene.get(), &context, &ray); + } + return ray.tfar < 0.0f; + } + + std::array Raycaster::hitSomething8(const std::array & inray, float minDist) + { + assert(minDist >= 0.f); + + RTCRay8 ray; + for (int r = 0; r < 8; r++) { + ray.org_x[r] = inray[r].orig()[0]; + ray.org_y[r] = inray[r].orig()[1]; + ray.org_z[r] = inray[r].orig()[2]; + ray.dir_x[r] = inray[r].dir()[0]; + ray.dir_y[r] = inray[r].dir()[1]; + ray.dir_z[r] = inray[r].dir()[2]; + + ray.tnear[r] = minDist; + ray.tfar[r] = RayHit::InfinityDist; + } + + int valid8[8] = { -1,-1,-1,-1, -1, -1, -1, -1 }; + if (init() == false) + SIBR_ERR << "cannot initialize embree, failed cast rays." << std::endl; + else + { + RTCIntersectContext context; + rtcInitIntersectContext(&context); + rtcOccluded8(valid8, *_scene.get(), &context, &ray); + } + + std::array res; + for (int r = 0; r < 8; r++) { + bool hit = (ray.tfar[r] < 0.0f ); + res[r] = hit; + } + + return res; + } + + RayHit Raycaster::intersect(const Ray& inray, float minDist) + { + assert(minDist >= 0.f); + + RTCRayHit rh; + rh.ray.flags = 0; + rh.ray.org_x = inray.orig()[0]; + rh.ray.org_y = inray.orig()[1]; + rh.ray.org_z = inray.orig()[2]; + rh.ray.dir_x = inray.dir()[0]; + rh.ray.dir_y = inray.dir()[1]; + rh.ray.dir_z = inray.dir()[2]; + + rh.ray.tnear = minDist; + rh.ray.tfar = RayHit::InfinityDist; + rh.hit.geomID = RTC_INVALID_GEOMETRY_ID; + + if (init() == false) + SIBR_ERR << "cannot initialize embree, failed cast rays." << std::endl; + else + { + RTCIntersectContext context; + rtcInitIntersectContext(&context); + rtcIntersect1(*_scene.get(), &context, &rh); + rh.hit.Ng_x = -rh.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces + rh.hit.Ng_y = -rh.hit.Ng_y; + rh.hit.Ng_z = -rh.hit.Ng_z; + } + + // Convert to the RayHit struct (used for abstract embree) + + RayHit::Primitive prim; + prim.geomID = rh.hit.geomID; + prim.instID = rh.hit.instID[0]; + prim.triID = rh.hit.primID; + + RayHit::BCCoord coord; + coord.u = rh.hit.u; + coord.v = rh.hit.v; + + sibr::Vector3f normal = sibr::Vector3f(rh.hit.Ng_x, rh.hit.Ng_y, rh.hit.Ng_z); + + // Return the result. + return RayHit(inray, rh.ray.tfar, coord, normal, prim); + } + + std::array Raycaster::intersect8(const std::array & inray, const std::vector & valid8, float minDist) + { + assert(minDist >= 0.f); + + RTCRayHit8 rh; + for (int r = 0; r < 8; r++) { + rh.ray.org_x[r] = inray[r].orig()[0]; + rh.ray.org_y[r] = inray[r].orig()[1]; + rh.ray.org_z[r] = inray[r].orig()[2]; + rh.ray.dir_x[r] = inray[r].dir()[0]; + rh.ray.dir_y[r] = inray[r].dir()[1]; + rh.ray.dir_z[r] = inray[r].dir()[2]; + + rh.ray.tnear[r] = minDist; + rh.ray.tfar[r] = RayHit::InfinityDist; + rh.hit.geomID[r] = RTC_INVALID_GEOMETRY_ID; + } + + if (init() == false) + SIBR_ERR << "cannot initialize embree, failed cast rays." << std::endl; + else + { + RTCIntersectContext context; + rtcInitIntersectContext(&context); + rtcIntersect8(valid8.data(), *_scene.get(), &context, &rh); + } + + std::array res; + for (int r = 0; r < 8; r++) { + if (valid8[r]) + res[r] = { + inray[r], + rh.ray.tfar[r], + RayHit::BCCoord{ + rh.hit.u[r],rh.hit.v[r] + }, + sibr::Vector3f(rh.hit.Ng_x[r], rh.hit.Ng_y[r], rh.hit.Ng_z[r]), + RayHit::Primitive{ +#ifdef SIBR_OS_WINDOWS + (uint)rh.hit.primID[r] ,(uint)rh.hit.geomID[r],(uint)rh.hit.instID[r] +#else + // Considering RTC_MAX_INSTANCE_LEVEL_COUNT to be 1 (Single-level instancing); see https://www.embree.org/api.html#rtchit + (uint)rh.hit.primID[r] ,(uint)rh.hit.geomID[r],(uint)rh.hit.instID[0][r] +#endif + + } + }; + } + return res; + } + + void Raycaster::clearGeometry() + { + _scene.reset(); + } + + sibr::Vector3f Raycaster::smoothNormal(const sibr::Mesh& mesh, const RayHit& hit) + { + if (!mesh.hasNormals()) { + SIBR_ERR << " cannot compute smoothed normals if the mesh does not have normals " << std::endl; + } + const sibr::Mesh::Normals& normals = mesh.normals(); + const sibr::Vector3u& tri = mesh.triangles()[hit.primitive().triID]; + + const float ucoord = hit.barycentricCoord().u; + const float vcoord = hit.barycentricCoord().v; + float wcoord = 1.f - ucoord - vcoord; + wcoord = (wcoord >= 0.0f ? (wcoord <= 1.0f ? wcoord : 1.0f) : 0.0f); + + return (wcoord * normals[tri[0]] + ucoord * normals[tri[1]] + vcoord * normals[tri[2]]).normalized(); + } + + sibr::Vector3f Raycaster::smoothColor(const sibr::Mesh& mesh, const RayHit& hit) + { + if (!mesh.hasColors()) { + SIBR_ERR << " cannot compute smoothed color if the mesh does not have colors " << std::endl; + } + const sibr::Mesh::Colors& colors = mesh.colors(); + const sibr::Vector3u& tri = mesh.triangles()[hit.primitive().triID]; + + const float ucoord = hit.barycentricCoord().u; + const float vcoord = hit.barycentricCoord().v; + float wcoord = 1.f - ucoord - vcoord; + wcoord = (wcoord >= 0.0f ? (wcoord <= 1.0f ? wcoord : 1.0f) : 0.0f); + + return wcoord * colors[tri[0]] + ucoord * colors[tri[1]] + vcoord * colors[tri[2]]; + } + + sibr::Vector2f Raycaster::smoothUV(const sibr::Mesh& mesh, const RayHit& hit) + { + if (!mesh.hasTexCoords()) { + SIBR_ERR << " cannot compute UV if the mesh does not have texcoords " << std::endl; + } + const sibr::Mesh::UVs& uvs = mesh.texCoords(); + const sibr::Vector3u& tri = mesh.triangles()[hit.primitive().triID]; + + const float ucoord = hit.barycentricCoord().u; + const float vcoord = hit.barycentricCoord().v; + float wcoord = 1.f - ucoord - vcoord; + wcoord = (wcoord >= 0.0f ? (wcoord <= 1.0f ? wcoord : 1.0f) : 0.0f); + + return wcoord * uvs[tri[0]] + ucoord * uvs[tri[1]] + vcoord * uvs[tri[2]]; + } + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/Raycaster.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/Raycaster.hpp new file mode 100644 index 0000000000000000000000000000000000000000..121b5022f80a731e0634097c78916382e5be2619 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/Raycaster.hpp @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# pragma warning(push, 0) +# include +# include +# include // functions for setting the control register +# include // functions for setting the control register +# pragma warning(pop) + +# include +# include +# include "core/raycaster/Config.hpp" +# include "core/raycaster/Ray.hpp" + +namespace sibr +{ + /// + /// This class can be used to cast rays against a scene containing triangular + /// meshes. You can check for intersections with the geometry and get + /// information about the hit (such as coordinates, distance, triangle id). + /// + /// You should have one or few instance of this class (for performance + /// purposes). Each instance can run in parallel. + /// + /// \note This abstraction is built on top of Embree. + /// \warning There is no backface culling applied. + /// \ingroup sibr_raycaster + /// + class SIBR_RAYCASTER_EXPORT Raycaster + { + public: + typedef std::shared_ptr RTCDevicePtr; + typedef std::shared_ptr RTCScenePtr; + typedef std::shared_ptr Ptr; + + typedef uint geomId; + /// Stores a number representing an invalid geom id. + static const geomId InvalidGeomId; + + /// Destructor. + ~Raycaster( void ); + + + /// Init the raycaster. + /// Called automatically whenever you call a member that need this + /// instance to be init. However, you can call it manually to check + /// error on init. + /// \param sceneType the type of scene, see Embree doc. + /// \return a success flag + bool init(RTCSceneFlags sceneType = RTC_SCENE_FLAG_NONE ); + + /// Add a triangle mesh to the raycast scene, taht you won't modify frequently + /// Return the id of the geometry added so you can track your mesh (and compare + /// its id to the one stored in RayHits). + /// \param mesh the mesh to add + /// \return the mesh ID or Raycaster::InvalidGeomId if it fails. + geomId addMesh( const sibr::Mesh& mesh ); + + /// Add a triangle mesh to the raycast scene, that you will frequently update. + /// \param mesh the mesh to add + /// \return the mesh ID or Raycaster::InvalidGeomId if it fails. + geomId addDynamicMesh( const sibr::Mesh& mesh ); + + /// Add a triangle mesh to the raycast scene. + /// \param mesh the mesh to add + /// \param type the type of mesh + /// \return the mesh ID or Raycaster::InvalidGeomId if it fails. + geomId addGenericMesh( const sibr::Mesh& mesh, RTCBuildQuality type ); + + /// Transform the vertices of a mesh by applying a sibr::Matrix4f mat. + /// \note The original positions are always stored *unchanged* in mesh.vertices -- we only xform the vertices in the embree buffer + /// \param mesh the mesh to transform + /// \param mesh_id the corresponding raycaster mesh id + /// \param mat the transformation to apply + /// \param centerPt will contain the new centroid + /// \param maxlen will contain the maximum distance from a vertex to the centroid + /// \bug maxlen is computed incrementally and may be incorrect + void xformRtcMeshOnly(sibr::Mesh& mesh, geomId mesh_id, sibr::Matrix4f& mat, sibr::Vector3f& centerPt, float& maxlen); + + /// Launch a ray into the raycaster scene. Return information about + /// this cast in RayHit. To simply know if something has been hit, use RayHit::hitSomething(). + /// \sa hitSomething + /// \param ray the ray to cast + /// \param minDist Any intersection closer than minDist from the ray origin will be ignored. Useful to avoid self intersections. + /// \return the (potential) intersection information + RayHit intersect( const Ray& ray, float minDist=0.f ); + + /// Launch 8 rays into the raycaster scene in an optimized fashion, reporting intersections infos. + /// \param inray the rays to cast + /// \param valid8 an indication of which of the rays should be cast + /// \param minDist Any intersection closer than minDist from the ray origin will be ignored. Useful to avoid self intersections. + /// \return the list of (potential) intersection informations + std::array intersect8(const std::array& inray,const std::vector & valid8=std::vector(8,-1), float minDist = 0.f ); + + /// Optimized ray-cast that only tells you if an intersection occured. + /// \sa intersect + /// \param ray the ray to cast + /// \param minDist Any intersection closer than minDist from the ray origin will be ignored. Useful to avoid self intersections. + /// \return true if an intersection took place + bool hitSomething( const Ray& ray, float minDist=0.f ); + + /// Launch 8 rays into the raycaster scene in an optimized fashion, reporting if intersections occured. + /// \param inray the rays to cast + /// \param minDist Any intersection closer than minDist from the ray origin will be ignored. Useful to avoid self intersections. + /// \return a list of boolean denoting if intersections happened + std::array hitSomething8(const std::array& inray, float minDist = 0.f); + + /// Disable geometry to avoid raycasting against it (eg background when only intersecting a foreground object). + /// \param id the mesh to disable + /// \todo Untested. + void disableGeom(geomId id) { rtcDisableGeometry(rtcGetGeometry((*_scene.get()),id)); rtcCommitGeometry(rtcGetGeometry(*_scene.get(),id)); rtcCommitScene(*_scene.get()); } + + /// Enable geometry to start raycasting it again. + /// \param id the geometry to enable + /// \todo Untested. + void enableGeom(geomId id) { rtcEnableGeometry(rtcGetGeometry((*_scene.get()),id)); rtcCommitGeometry(rtcGetGeometry(*_scene.get(),id)); rtcCommitScene(*_scene.get());} + + /// Delete geometry + /// \param id the geometry to delete + void deleteGeom(geomId id) { rtcReleaseGeometry(rtcGetGeometry((*_scene.get()),id)); rtcCommitGeometry(rtcGetGeometry(*_scene.get(),id)); rtcCommitScene(*_scene.get());} + + /// Clears internal scene.. + void clearGeometry(); + + /// Returns the normalized smooth normal (shading normal) from a hit, assuming the mesh has normals + /// \param mesh sibr::Mesh used by raycaster + /// \param hit intersection basic information + /// \return the interpolated normalized normal + static sibr::Vector3f smoothNormal(const sibr::Mesh & mesh, const RayHit & hit); + + /// Interpolate color at a hit (barycentric interpolation), assuming the mesh has colors. + /// \param mesh sibr::Mesh used by raycaster + /// \param hit intersection basic information + /// \return the interpolated color + static sibr::Vector3f smoothColor(const sibr::Mesh & mesh, const RayHit & hit); + + /// Interpolate texcoords from a hit (barycentric interpolation), assuming the mesh has UVs. + /// \param mesh sibr::Mesh used by raycaster + /// \param hit intersection basic information + /// \β€šeturn the interpolated texture coordinates + static sibr::Vector2f smoothUV(const sibr::Mesh & mesh, const RayHit & hit); + + /// \return true if the raycaster is initialized. + bool isInit() { return g_device && _scene; } + + private: + + /// Will be called by embree whenever an error occurs + /// \param userPtr the user data pointer + /// \param code the error code + /// \param msg additional info message. + static void rtcErrorCallback(void* userPtr, RTCError code, const char* msg); + + + static bool g_initRegisterFlag; ///< Used to initialize flag of registers used by SSE + static RTCDevicePtr g_device; ///< embree device (context for a raycaster) + + /// \return the internal scene pointer + RTCScenePtr scene() { return _scene; } + + RTCScenePtr _scene; ///< scene storing raycastable meshes + RTCDevicePtr _devicePtr; ///< embree device (context for a raycaster) + }; + + ///// DEFINITION ///// + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/VoxelGrid.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/VoxelGrid.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3c903db99bbccff7ecfb7692832a59e16f31735a --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/VoxelGrid.cpp @@ -0,0 +1,403 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "VoxelGrid.hpp" + +namespace sibr { + + VoxelGridBase::VoxelGridBase(const Box & boundingBox, int n, bool forceCube) + : VoxelGridBase(boundingBox, sibr::Vector3i(n, n, n), forceCube) + { + } + + VoxelGridBase::VoxelGridBase(const Box & boundingBox, const sibr::Vector3i & numsPerDim, bool forceCube) + : box(boundingBox), dims(numsPerDim), _generator(0), _distribution(-1.0, 1.0) + { + if (forceCube) { + float maxDimSize = box.sizes().cwiseQuotient(dims.cast()).maxCoeff(); + for (int c = 0; c < 3; ++c) { + dims[c] = (int)std::round(box.sizes()[c] / maxDimSize); + } + } + cellSize = box.sizes().cwiseQuotient(dims.cast()); + cellSizeNorm = cellSize.norm(); + + //std::cout << dims << std::endl; + //std::cout << getCellSize() << std::endl; + + static const sibr::Mesh::Triangles trianglesBorders = + { + { 0,4, 4 }, + { 5,1, 1 }, + { 4,5, 5 }, + { 0,1, 1 }, + { 2,6, 6 }, + { 7,3, 3 }, + { 6,7, 7 }, + { 2,3, 3 }, + { 0,2, 2 }, + { 1,3, 3 }, + { 4,6, 6 }, + { 5,7, 7 } + }; + + + Box baseCell; + baseCell.extend(box.min()); + baseCell.extend(box.min() + getCellSize()); + + + sibr::Mesh::Vertices vs(8); + for (int i = 0; i < 8; ++i) { + vs[i] = baseCell.corner((Box::CornerType)i); + } + + baseCellMesh.reset(new sibr::Mesh(false)); + baseCellMesh->vertices(vs); + baseCellMesh->triangles(trianglesBorders); + + static const sibr::Mesh::Triangles trianglesFilled = + { + { 0,1,5 }, + { 0,5,4 }, + { 1,3,7 }, + { 1,7,5 }, + { 3,2,6 }, + { 3,6,7 }, + { 2,0,4 }, + { 2,4,6 }, + { 0,2,3 }, + { 0,3,1 }, + { 4,5,7 }, + { 4,7,6 } + }; + + + baseCellMeshFilled.reset(new sibr::Mesh(false)); + baseCellMeshFilled->vertices(vs); + baseCellMeshFilled->triangles(trianglesFilled); + } + + bool VoxelGridBase::isInside(const sibr::Vector3f & worldPos) const + { + return box.contains(worldPos); + } + + bool VoxelGridBase::outOfBounds(const sibr::Vector3i & v) const + { + return (v.array() < 0).any() || (v.array() >= dims.array()).any(); + //return v[0] < 0 || v[0] >= dims[0] || v[1] < 0 || v[1] >= dims[1] || v[2] < 0 || v[2] >= dims[2]; + } + + size_t VoxelGridBase::getNumCells() const + { + return (size_t)dims.prod(); + } + + const sibr::Vector3i & VoxelGridBase::getDims() const + { + return dims; + } + + sibr::Vector3i VoxelGridBase::getCell(size_t cellId) const + { + if (cellId >= getNumCells()) { + SIBR_ERR; + } + + sibr::Vector3i cell; + + std::div_t div; + for (int i = 0; i < 2; ++i) { + div = std::div((int)cellId, dims[i]); + cell[i] = div.rem; + cellId = div.quot; + } + cell[2] = (int)cellId; + + if (outOfBounds(cell)) { + SIBR_ERR << cell << " " << dims; + } + + //if ((cell.array() < 0).any() || (cell.array() >= dims.array()).any()) { + // SIBR_ERR; + //} + + return cell; + } + + sibr::Vector3i VoxelGridBase::getCell(const sibr::Vector3f & worldPos) const + { + sibr::Vector3f posUV = (worldPos - box.min()).cwiseQuotient(box.sizes()); + sibr::Vector3i cellCoord = (dims.cast().cwiseProduct(posUV)).unaryExpr([](float f) { return std::floor(f); }).cast(); + + if ((cellCoord.array() < 0).any() || (cellCoord.array() >= dims.array()).any()) { + SIBR_ERR; + } + + return cellCoord; + } + + sibr::Vector3i VoxelGridBase::getCellInclusive(const sibr::Vector3f & worldPos) const + { + sibr::Vector3f posUV = (worldPos - box.min()).cwiseQuotient(box.sizes()); + sibr::Vector3i cellCoord = (dims.cast().cwiseProduct(posUV).unaryExpr([](float f) { return std::floor(f); })).cast(); + + //because of the floor function, a pixel exactly at the boundary would be outside + for (int c = 0; c < 3; c++) { + if (cellCoord[c] == -1){ + ++cellCoord[c]; + } + if (cellCoord[c] == dims[c]) { + --cellCoord[c]; + } + } + + if ((cellCoord.array() < 0).any() || (cellCoord.array() >= dims.array()).any()) { + SIBR_ERR << worldPos << " " << box.min() << " " << box.max() << " " << cellCoord; + } + + return cellCoord; + } + + std::vector VoxelGridBase::rayMarch(const Ray & ray) const + { + sibr::Vector3f start = ray.orig(); + + if (!isInside(start)) { + sibr::Vector3f intersection; + if (intersectionWithBox(ray, intersection)) { + start = intersection; + } else { + return {}; + } + } + + start = start.cwiseMax(box.min()).cwiseMin(box.max() - 0.01f*getCellSize()); + + sibr::Vector3i currentVoxel = getCell(start); + + sibr::Vector3i steps = ray.dir().unaryExpr([](float f) { return f >= 0 ? 1 : -1; }).cast(); + + const sibr::Vector3f deltas = getCellSize().cwiseQuotient(ray.dir().cwiseAbs()); + const sibr::Vector3f frac = (start - box.min()).cwiseQuotient(getCellSize()).unaryExpr([](float f) { return f - std::floor(f); }); + sibr::Vector3i finalVoxels; + sibr::Vector3f ts; + for (int c = 0; c < 3; c++) { + ts[c] = deltas[c] * (ray.dir()[c] >= 0 ? 1.0f - frac[c] : frac[c]); + finalVoxels[c] = (ray.dir()[c] >= 0 ? dims[c] : -1); + } + + std::vector visitedCellsIds; + while (true) { + visitedCellsIds.push_back(getCellId(currentVoxel)); + + int c = getMinIndex(ts); + currentVoxel[c] += steps[c]; + if (currentVoxel[c] == finalVoxels[c]) { + break; + } + ts[c] += deltas[c]; + } + + return visitedCellsIds; + } + + sibr::Mesh::Ptr VoxelGridBase::getCellMesh(const sibr::Vector3i & cell) const + { + return getCellMeshInternal(cell, false); + } + + sibr::Mesh::Ptr VoxelGridBase::getAllCellMesh() const + { + return getAllCellMeshInternal(false); + } + + sibr::Mesh::Ptr VoxelGridBase::getCellMeshFilled(const sibr::Vector3i & cell) const + { + return getCellMeshInternal(cell, true); + } + + sibr::Mesh::Ptr VoxelGridBase::getAllCellMeshFilled() const + { + return getAllCellMeshInternal(true); + } + + Eigen::AlignedBox3f VoxelGridBase::getCellBox(size_t cellId) const + { + sibr::Vector3i cell = getCell(cellId); + sibr::Vector3f center = getCellCenter(cell); + sibr::Vector3f half_diagonal = 0.5f*getCellSize(); + + Eigen::AlignedBox3f out; + out.extend(center - half_diagonal); + out.extend(center + half_diagonal); + return out; + } + + std::vector VoxelGridBase::getNeighbors(size_t cellId) const + { + static const sibr::Vector3f shifts[6] = { + {-1, 0, 0}, { +1 ,0, 0 }, + {0, -1, 0},{0, +1, 0}, + {0, 0, -1},{0, 0, +1} + }; + + sibr::Vector3f pos = getCellCenter(cellId); + + std::vector n_ids; + for (int i = 0; i < 6; ++i) { + sibr::Vector3f n_pos = pos + shifts[i].cwiseProduct(getCellSize()); + if (getBBox().contains(n_pos)) { + n_ids.push_back(getCellId(n_pos)); + } + } + return n_ids; + } + + VoxelGridBase VoxelGridBase::extend(int numCells) const + { + sibr::Vector3f additionalSize = ((float)numCells)*getCellSize(); + //sibr::Vector3f half_diagonal = 0.5*box.diagonal() + additionalSize; + + Box extendedBox; + extendedBox.extend(box.max() + additionalSize); + extendedBox.extend(box.min() - additionalSize); + + //extendedBox.extend(box.center() + (additionalSize.norm() + 0.5f*box.diagonal().norm()) *box.diagonal().normalized()); + //extendedBox.extend(box.center() - (additionalSize.norm() + 0.5f*box.diagonal().norm()) *box.diagonal().normalized()); + + VoxelGridBase extendedGrid = VoxelGridBase(extendedBox, dims.array() + 2*numCells); + return extendedGrid; + } + + bool VoxelGridBase::intersectionWithBox(const Ray & ray, sibr::Vector3f & intersection) const + { + //adpated from https://github.com/papaboo/smalldacrt/ + + sibr::Vector3f minTs = (box.min() - ray.orig()).cwiseQuotient(ray.dir()); + sibr::Vector3f maxTs = (box.max() - ray.orig()).cwiseQuotient(ray.dir()); + + float nearT = (minTs.cwiseMin(maxTs)).maxCoeff(); + float farT = (minTs.cwiseMax(maxTs)).minCoeff(); + + if (nearT <= farT && 0 <= nearT) { + intersection = ray.orig() + nearT*ray.dir(); + return true; + } + return false; + } + + const sibr::Vector3f & VoxelGridBase::getCellSize() const + { + return cellSize; + } + + float VoxelGridBase::getCellSizeNorm() const + { + return cellSizeNorm; + } + + sibr::Vector3f VoxelGridBase::sampleCell(size_t cellId) + { + sibr::Vector3f out; + out[0] = float(_distribution(_generator)); + out[1] = float(_distribution(_generator)); + out[2] = float(_distribution(_generator)); + return getCellCenter(getCell(cellId)) + out.cwiseProduct(getCellSize()); + } + + sibr::Mesh::Ptr VoxelGridBase::getCellMeshInternal(const sibr::Vector3i & cell, bool filled) const + { + sibr::Mesh::Ptr baseMesh = filled ? baseCellMeshFilled : baseCellMesh; + + const sibr::Vector3f offset = cell.cast().array()*getCellSize().array(); + + auto out = std::make_shared(true); + out->triangles(baseMesh->triangles()); + sibr::Mesh::Vertices vs(8); + for (int i = 0; i < 8; ++i) { + vs[i] = baseMesh->vertices()[i] + offset; + } + out->vertices(vs); + return out; + } + + sibr::Mesh::Ptr VoxelGridBase::getAllCellMeshInternal(bool filled) const + { + auto out = std::make_shared(); + + sibr::Mesh::Ptr baseMesh = filled ? baseCellMeshFilled : baseCellMesh; + + const int numT = int(baseMesh->triangles().size()); + const int numTtotal = int(getNumCells())*numT; + const int numV = int(baseMesh->vertices().size()); + const int numVtotal = int(getNumCells())*numV; + const sibr::Vector3u offsetT = sibr::Vector3u(numV, numV, numV); + + sibr::Mesh::Vertices vs(numVtotal); + sibr::Mesh::Triangles ts(numTtotal); + for (int i = 0; i < getNumCells(); ++i) { + const auto cell = getCell(i); + const sibr::Vector3f offsetV = cell.cast().array()*getCellSize().array(); + + for (int v = 0; v < numV; ++v) { + vs[i*numV + v] = baseMesh->vertices()[v] + offsetV; + } + for (int t = 0; t < numT; ++t) { + ts[i*numT + t] = baseMesh->triangles()[t] + i * offsetT; + } + } + + out->vertices(vs); + out->triangles(ts); + return out; + } + + size_t VoxelGridBase::getCellId(const sibr::Vector3i & v) const + { + if (outOfBounds(v)) { + SIBR_ERR << v << " " << dims; + } + return v[0] + dims[0] * (v[1] + dims[1] * v[2]); //v[2] + dims[2] * (v[1] + dims[1] * v[0]); + } + + size_t VoxelGridBase::getCellId(const sibr::Vector3f & world_pos) const + { + return getCellId(getCell(world_pos)); + } + + sibr::Vector3f VoxelGridBase::getCellCenter(const sibr::Vector3i & cell) const + { + return box.min() + (0.5f*sibr::Vector3f(1, 1, 1) + cell.cast()).cwiseProduct(getCellSize()); + } + + sibr::Vector3f VoxelGridBase::getCellCenter(size_t cellId) const + { + return getCellCenter(getCell(cellId)); + } + + int VoxelGridBase::getMinIndex(const sibr::Vector3f & v) + { + if (v.x() < v.y()) { + return v.x() < v.z() ? 0 : 2; + } else { + return v.y() < v.z() ? 1 : 2; + } + } + + sibr::Vector3f orthoVector(const sibr::Vector3f & v) + { + return std::abs(v[2]) < std::abs(v[0]) ? sibr::Vector3f(v[1], -v[0], 0) : sibr::Vector3f(0, -v[2], v[1]); + } + +} \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/VoxelGrid.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/VoxelGrid.hpp new file mode 100644 index 0000000000000000000000000000000000000000..362cf0935b9c10ab2dd5fe983cb9aa6cc46f2c6e --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/VoxelGrid.hpp @@ -0,0 +1,408 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + + +# include +#include + +# include + +#include +#include + +namespace sibr +{ + /** + \addtogroup sibr_raycaster + @{ + */ + + /** Generate a vector orthogonal to the input one. + \param v the input vector + \return the ortogonal vector + \warning The output vector is not necessarily of unit length. + */ + sibr::Vector3f orthoVector(const sibr::Vector3f & v); + + /** Default voxel type, storing binary occupancy. */ + struct BasicVoxelType { + + /** \return true if filled. */ + operator bool() const { return used; } + + bool used = true; ///< The voxel status. + }; + + /** Basic voxel grid interface provinding cell manipulation and query helpers. + It doesn't store any voxel data. */ + class SIBR_RAYCASTER_EXPORT VoxelGridBase { + SIBR_CLASS_PTR(VoxelGridBase); + + public: + + typedef Eigen::AlignedBox Box; + + /** Constructor. + \param boundingBox bounding box delimiting the voxellized region + \param numPerDim number of voxels along each dimension + \param forceCube if true, the largest dimension will be split in numPerDim voxels and the other such that the voxels are cubes in world space + */ + VoxelGridBase(const Box & boundingBox, int numPerDim, bool forceCube = true); + + + /** Constructor. + \param boundingBox bounding box delimiting the voxellized region + \param numsPerDim number of voxels along each dimension + \param forceCube if true, the largest dimension will be split in numPerDims voxels and the other such that the voxels are cubes in world space + */ + VoxelGridBase(const Box & boundingBox, const sibr::Vector3i & numsPerDim, bool forceCube = true); + + /** Check if a position is in the voxel grid. + \param worldPos the world 3D position + \return true if the position is in the grid bounding box + */ + bool isInside(const sibr::Vector3f & worldPos) const; + + /** Check if a set of indices correspond to a reachable voxel. + \param cell the voxel integer coordinates + \return true if the voxel exists in the grid + */ + bool outOfBounds(const sibr::Vector3i & cell) const; + + /** \return the number of voxels. */ + size_t getNumCells() const; + + /** \return the number of voxels along each axis. */ + const sibr::Vector3i & getDims() const; + + /** Convert a linear cell ID to a set of 3D indices. + \param cellId linear ID + \return the indices of the voxel along each axis + */ + sibr::Vector3i getCell(size_t cellId) const; + + /** Convert a voxel 3D indices to a linear ID. + \param cell the voxel integer coordinates + \return the linear ID + */ + size_t getCellId(const sibr::Vector3i & cell) const; + + /** Convert a 3D position to the linear ID of the voxel containing it. + \param world_pos the position + \return the linear ID of the voxel + */ + size_t getCellId(const sibr::Vector3f & world_pos) const; + + /** Get the position of a voxel center in world space. + \param cell the voxel integer coordinates + \return the center 3D position + */ + sibr::Vector3f getCellCenter(const sibr::Vector3i & cell) const; + + /** Get the position of a voxel center in world space. + \param cellId linear voxel ID + \return the center 3D position + */ + sibr::Vector3f getCellCenter(size_t cellId) const; + + /** Intersect a ray with the voxel grid, listing all intersected voxels. + \param ray the ray to cast + \return linear IDs of the intersected voxels + */ + std::vector rayMarch(const Ray & ray) const; + + /** Generate a wireframe mesh representing a voxel. + \param cell the voxel integer coordinates + \return the generated wireframe cube mesh + */ + sibr::Mesh::Ptr getCellMesh(const sibr::Vector3i & cell) const; + + /** Generate a wireframe mesh representing all voxels. + \return the generated wireframe cube mesh + */ + sibr::Mesh::Ptr getAllCellMesh() const; + + /** Generate a triangle mesh representing a voxel. + \param cell the voxel integer coordinates + \return the generated filled cube mesh + */ + sibr::Mesh::Ptr getCellMeshFilled(const sibr::Vector3i & cell) const; + + /** Generate a triangle mesh representing all voxels. + \return the generated filled cube mesh + */ + sibr::Mesh::Ptr getAllCellMeshFilled() const; + + /** Get a voxel bounding box. + \param cellId the voxel linear index + \return the bounding box. + */ + Eigen::AlignedBox3f getCellBox(size_t cellId) const; + + /** Get a voxel neighbors linear IDs. + \param cellId linear voxel ID + \return the linear IDs of the neigbors. + */ + std::vector getNeighbors(size_t cellId) const; + + /** Extend the voxel grid along all dimensions. + This means that if the initial count along a given axis was N, the new is N+2*numCells. + \param numCells the number of cells to add + \return the extended voxel grid + */ + VoxelGridBase extend(int numCells) const; + + /** \return the voxel grid bounding box. */ + const Box & getBBox() const { return box; } + + /** Return the index of the smallest coefficient of the input vector. + \param v the vector + \return the location of the minimum + */ + static int getMinIndex(const sibr::Vector3f & v); + + /** Get the integer coordinates of the cell containing a position. + \param worldPos the position + \return the cell integer coordinates + */ + sibr::Vector3i getCell(const sibr::Vector3f & worldPos) const; + + /** Get the integer coordinates of the cell containing a position. + Positions along the boundaries of the voxel grid are considered as belonging to the closest cell. + \param worldPos the position + \return the cell integer coordinates + */ + sibr::Vector3i getCellInclusive(const sibr::Vector3f & worldPos) const; + + /** Check if a ray intersect the voxel grid. + \param ray the ray to cast + \param intersection will contain the intersection position if it exists + \return true if there is an intersection + */ + bool intersectionWithBox(const Ray & ray, sibr::Vector3f & intersection) const; + + /** \return the size of a voxel. */ + const sibr::Vector3f & getCellSize() const; + + /** \return the length of a voxel diagonal. */ + float getCellSizeNorm() const; + + /** Sample a random position in a given voxel. + \param cellId the voxel to sample from + \return the sampled position + \note The random generator is seeded at 0 when creating the grid. + \warning The current implementation is sampling in center+(random(-1,1)^3)*cellSize. + */ + sibr::Vector3f sampleCell(size_t cellId); + + protected: + + /** Helper to generate a voxel mesh. + \param cell the coordinates of the voxel to generate + \param filled should the mesh be wireframe (false) or faceted (true) + \return the generated mesh + */ + sibr::Mesh::Ptr getCellMeshInternal(const sibr::Vector3i & cell, bool filled) const; + + /** Helper to generate the voxel grid mesh. + \param filled should the mesh be wireframe (false) or faceted (true) + \return the generated mesh + */ + sibr::Mesh::Ptr getAllCellMeshInternal(bool filled) const; + + sibr::Vector3i dims; ///< Integer grid dimensions. + sibr::Vector3f cellSize; ///< World space voxel size. + float cellSizeNorm; ///< World space voxel diagonal length. + Box box; ///< Grid bounding box. + sibr::Mesh::Ptr baseCellMesh, baseCellMeshFilled; ///< Base meshes for visualisation. + + std::mt19937 _generator; ///< Generator for sampling, seeded at 0. + std::uniform_real_distribution _distribution; ///< (-1,1) distribution. + + }; + + + /** Voxel grid with custom data storage. */ + template class VoxelGrid : public VoxelGridBase { + + SIBR_CLASS_PTR(VoxelGrid); + public: + using VoxelType = CellType; + + public: + + /** Constructor. + \param boundingBox bounding box delimiting the voxellized region + \param numPerDim number of voxels along each dimension + \param forceCube if true, the largest dimension will be split in numPerDim voxels and the other such that the voxels are cubes in world space + */ + VoxelGrid(const Box & boundingBox, int numPerDim, bool forceCube = true) + : VoxelGrid(boundingBox, sibr::Vector3i(numPerDim, numPerDim, numPerDim) , forceCube) + { + } + + /** Constructor. + \param boundingBox bounding box delimiting the voxellized region + \param numsPerDim number of voxels along each dimension + \param forceCube if true, the largest dimension will be split in numPerDim voxels and the other such that the voxels are cubes in world space + */ + VoxelGrid(const Box & boundingBox, const sibr::Vector3i & numsPerDim, bool forceCube = true) + : VoxelGridBase(boundingBox, numsPerDim, forceCube) { + data.resize(getNumCells()); + } + + /** Get voxel at a given linear index. + \param cell_id the linear index + \return a reference to the voxel + */ + CellType & operator[](size_t cell_id) { + return data[cell_id]; + } + + /** Get voxel at a given linear index. + \param cell_id the linear index + \return a reference to the voxel + */ + const CellType & operator[](size_t cell_id) const { + return data[cell_id]; + } + + /** Get voxel at given integer 3D coordinates. + \param x x integer coordinate + \param y y integer coordinate + \param z z integer coordinate + \return a reference to the voxel + */ + CellType & operator()(int x, int y, int z) { + sibr::Vector3i v(x,y,z); + return data[getCellId(v)]; + } + + /** Get voxel at given integer 3D coordinates. + \param x x integer coordinate + \param y y integer coordinate + \param z z integer coordinate + \return a reference to the voxel + */ + const CellType & operator()(int x, int y, int z) const { + sibr::Vector3i v(x,y,z); + return data[getCellId(v)]; + } + + /** Get voxel at given integer 3D coordinates. + \param v integer coordinates + \return a reference to the voxel + */ + CellType & operator[](const sibr::Vector3i & v) { + return data[getCellId(v)]; + } + + /** Get voxel at given integer 3D coordinates. + \param v integer coordinates + \return a reference to the voxel + */ + const CellType & operator[](const sibr::Vector3i & v) const { + return data[getCellId(v)]; + } + + /** Generate a mesh from all voxels satisfying a condition. + \param filled should the mesh be wireframe (false) or faceted (true) + \param func the predicate to evaluate, will receive as unique argument a voxel (CellType). + \return the generated mesh + */ + template + sibr::Mesh::Ptr getAllCellMeshWithCond(bool filled, const FuncType & func) const; + + /** Get cell meshes from their ids. + \param filled should the mesh be wireframe (false) or faceted (true) + \param cell_ids ids of cell meshes. + \return the generated mesh + */ + sibr::Mesh::Ptr getAllCellMeshWithIds(bool filled, std::vector cell_ids) const; + + /** List the voxels that statisfy a condition (for instance fullness) + \param func the predicate to evaluate, will receive as unique argument a voxel (CellType). + \return a list of linear indices of all voxels such that func(voxel) is true. + */ + template + std::vector detect_non_empty_cells(const FuncType & func) const; + + /** \return the voxel grid data. */ + const std::vector & getData() const { + return data; + } + + protected: + + std::vector data; ///< Voxels storage. + }; + + + + template template + inline std::vector VoxelGrid::detect_non_empty_cells(const FuncType & func) const { + std::vector out_ids; + for (size_t i = 0; i < data.size(); ++i) { + if (func(data[i])) { + out_ids.push_back(i); + } + } + return out_ids; + } + + template template + inline sibr::Mesh::Ptr VoxelGrid::getAllCellMeshWithCond(bool filled, const FuncType & f) const + { + std::vector cell_ids = detect_non_empty_cells(f); + return getAllCellMeshWithIds(filled, cell_ids); + } + + /** }@ */ + + template + inline sibr::Mesh::Ptr VoxelGrid::getAllCellMeshWithIds(bool filled, std::vector cell_ids) const + { + int numNonZero = (int)cell_ids.size(); + + auto out = std::make_shared(); + + sibr::Mesh::Ptr baseMesh = filled ? baseCellMeshFilled : baseCellMesh; + + const int numT = (int)baseMesh->triangles().size(); + const int numTtotal = numNonZero * numT; + const int numV = (int)baseMesh->vertices().size(); + const int numVtotal = numNonZero * numV; + const sibr::Vector3u offsetT = sibr::Vector3u(numV, numV, numV); + + sibr::Mesh::Vertices vs(numVtotal); + sibr::Mesh::Triangles ts(numTtotal); + for (int i = 0; i < numNonZero; ++i) { + const auto cell = getCell(cell_ids[i]); + const sibr::Vector3f offsetV = cell.cast().array() * getCellSize().array(); + + for (int v = 0; v < numV; ++v) { + vs[i * numV + v] = baseMesh->vertices()[v] + offsetV; + } + for (int t = 0; t < numT; ++t) { + ts[i * numT + t] = baseMesh->triangles()[t] + i * offsetT; + } + } + + out->vertices(vs); + out->triangles(ts); + return out; + } + +} // namespace sibr + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/sibr_raycaster.dox b/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/sibr_raycaster.dox new file mode 100644 index 0000000000000000000000000000000000000000..51c1d570d2af4c7e178a041ff83df385384e8a24 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/raycaster/sibr_raycaster.dox @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +/*! + \defgroup sibr_raycaster sibr_raycaster + + \brief Raycasting utilities. + + This module provides functionalities related to raycasting on 2D and 3D geometry. + It contains basic 2D intersection tests, a wrapper around the embree raycasting library (http://embree.github.io/), + and helpers to perform raycasting over all pixels of an image. + +*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/AddShadowRenderer.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/AddShadowRenderer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5b832f66ee30172ac1f4caa8eeab4176ca59e16a --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/AddShadowRenderer.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#include + +namespace sibr { + AddShadowRenderer::AddShadowRenderer( void ) + { + _shader.init("AddShadowShader", + sibr::loadFile(sibr::getShadersDirectory("core") + "/texture.vert"), + sibr::loadFile(sibr::getShadersDirectory("core") + "/addshadow.frag")); + _paramInvProj.init(_shader, "in_inv_proj"); + _paramImgSize.init(_shader, "in_image_size"); + } + + void AddShadowRenderer::process( + uint backgroundTextureID, + uint foregroundTextureID, + const Vector2f& textureSize, + const Camera& camera, + + IRenderTarget& dst ) + { + dst.bind(); + + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, foregroundTextureID ); + glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, backgroundTextureID ); + glDisable(GL_DEPTH_TEST); + glDisable(GL_BLEND); + glDepthMask(GL_TRUE); // but write the current values + _shader.begin(); + _paramInvProj.set(camera.invViewproj()); + _paramImgSize.set(textureSize); + RenderUtility::renderScreenQuad(); + _shader.end(); + + dst.unbind(); + } + +} /*namespace sibr*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/AddShadowRenderer.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/AddShadowRenderer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e007da091062a4b91a29f562e5737e16fcb9a31b --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/AddShadowRenderer.hpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include +# include +# include + +# include + +namespace sibr { + + /** Composite two rendered scenes while generating local cast shadows from the top one to the bottom one. + \ingroup sibr_renderer + */ + class SIBR_EXP_RENDERER_EXPORT AddShadowRenderer + { + public: + typedef std::shared_ptr Ptr; + + public: + + /// Constructor. + AddShadowRenderer( void ); + + /** Composite the two textures, they sjould contain color+depth information in the alpha channel. + \param backgroundTextureID handle of the background image + \param foregroundTextureID handle of the foreground image + \param textureSize the texture size (should be the same) + \param camera the viewpoint used + \param dst the destination rendertarget + */ + void process( + /*input*/ uint backgroundTextureID, + uint foregroundTextureID, + const Vector2f& textureSize, + const Camera& camera, + /*output*/ IRenderTarget& dst ); + + private: + + GLShader _shader; ///< Composite shader. + GLParameter _paramInvProj; ///< Inverse proj matrix uniform. + GLParameter _paramImgSize; ///< Image size uniform. + + }; + +} /*namespace sibr*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/BinaryMeshRenderer.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/BinaryMeshRenderer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c63f946f4bbdbb59b9ac9ac9188e6cf8c2748535 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/BinaryMeshRenderer.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "BinaryMeshRenderer.hpp" + +namespace sibr { + + BinaryMeshRenderer::BinaryMeshRenderer() + { + std::string vertex_shader = + SIBR_SHADER(420, + uniform mat4 MVP; + layout(location = 0) in vec3 in_vertex; + void main(void) { + gl_Position = MVP * vec4(in_vertex, 1.0); + } + ); + + std::string fragment_shader = SIBR_SHADER(420, + out vec4 out_color; + uniform float epsilon; + void main(void) { + out_color = vec4(1, 1, 1, 1); + gl_FragDepth = gl_FragCoord.z * (1.0 - epsilon); + } + ); + + _shader.init("binaryMeshShader", vertex_shader, fragment_shader); + _paramMVP.init(_shader, "MVP"); + epsilon.init(_shader, "epsilon"); + } + + void BinaryMeshRenderer::process(const Mesh & mesh, const Camera & eye, IRenderTarget & dst) + { + dst.bind(); + _shader.begin(); + _paramMVP.set(eye.viewproj()); + epsilon.send(); + + mesh.render(true, false); + + _shader.end(); + dst.unbind(); + } +} \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/BinaryMeshRenderer.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/BinaryMeshRenderer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b628b043651f6eb0d28e8f34c55e9d56344f925d --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/BinaryMeshRenderer.hpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include +# include +# include +# include + +# include + +namespace sibr { + + /** Render a binary mask of a mesh, with options to limit Z-fighting. + \ingroup sibr_renderer + */ + class SIBR_EXP_RENDERER_EXPORT BinaryMeshRenderer + { + SIBR_CLASS_PTR(BinaryMeshRenderer); + + public: + + /// Constructor. + BinaryMeshRenderer(); + + /** Render the mesh mask. + Regions covered by the mesh will be filled with (1,1,1,1). + \param mesh the mesh to render + \param eye the viewpoint to use + \param dst the destination rendertarget + */ + void process( const Mesh& mesh, const Camera& eye, IRenderTarget& dst ); + + /** Shift that can be used to modify the depth written, + to avoid Z-fighting when rendering multiple masks of + the same mesh or combining masks. + If set to 0.0: no shift, if set to 1.0: all vertices sent to depth 0.0. + \return a reference to the shift + */ + float & getEpsilon() { + return epsilon.get(); + } + + private: + + GLShader _shader; ///< Mask shader. + GLuniform _paramMVP; ///< MVP uniform. + GLuniform epsilon = 0; ///< Epsilon uniform. + + }; + +} /*namespace sibr*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/BlurRenderer.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/BlurRenderer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d8aa6784521fc688120bd5c1dcb1153cd236d9d9 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/BlurRenderer.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#include + +namespace sibr { + BlurRenderer::BlurRenderer( void ) + { + _shader.init("BlurShader", + sibr::loadFile(sibr::getShadersDirectory("core") + "/texture.vert"), + sibr::loadFile(sibr::getShadersDirectory("core") + "/blur.frag")); + _paramImgSize.init(_shader, "in_image_size"); + } + + void BlurRenderer::process( uint textureID, const Vector2f& textureSize, IRenderTarget& dst ) + { + dst.bind(); + + glDisable(GL_DEPTH_TEST); + glDisable(GL_BLEND); + + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textureID ); + glDisable(GL_DEPTH_TEST); + _shader.begin(); + _paramImgSize.set(textureSize); + RenderUtility::renderScreenQuad(); + _shader.end(); + + dst.unbind(); + } + +} /*namespace sibr*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/BlurRenderer.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/BlurRenderer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8daf4693bc8dcac316b4683e148698700bb6c6e9 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/BlurRenderer.hpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include +# include + +# include + +namespace sibr { + + /** Blur on color edges present in a texture. + \ingroup sibr_renderer + */ + class SIBR_EXP_RENDERER_EXPORT BlurRenderer + { + public: + typedef std::shared_ptr Ptr; + + public: + + /// Constructor. + BlurRenderer( void ); + + /** Process the texture. + \param textureID the texture to blur + \param textureSize the texture dimensions + \param dst the destination rendertarget + */ + void process( + /*input*/ uint textureID, + /*input*/ const Vector2f& textureSize, + /*output*/ IRenderTarget& dst ); + + private: + + GLShader _shader; ///< Blur shader. + GLParameter _paramImgSize; ///< Texture size uniform. + + }; + +} /*namespace sibr*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/CMakeLists.txt b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..212b23816c3443a15248b4beb0769ff624377d8b --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/CMakeLists.txt @@ -0,0 +1,65 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +project(sibr_renderer) + +file(GLOB SOURCES "*.cpp" "*.h" "*.hpp") +source_group("Source Files" FILES ${SOURCES}) + +file(GLOB SHADERS "shaders/*.frag" "shaders/*.vert" "shaders/*.geom" "shaders/*.fp" "shaders/*.gp" "shaders/*.vp") +source_group("Source Files\\shaders" FILES ${SHADERS}) + +file(GLOB SOURCES "*.cpp" "*.h" "*.hpp" "shaders/*.frag" "shaders/*.vert" "shaders/*.geom" "shaders/*.fp" "shaders/*.gp" "shaders/*.vp") + +## Specify target rules +add_library(${PROJECT_NAME} SHARED ${SOURCES}) + +include_directories(${Boost_INCLUDE_DIRS} .) +if(WIN32) +target_link_libraries(${PROJECT_NAME} + ${Boost_LIBRARIES} + ${ASSIMP_LIBRARIES} + ${GLEW_LIBRARIES} + ${OPENGL_LIBRARIES} + ${OpenCV_LIBRARIES} + glfw3 + sibr_system + sibr_view + sibr_assets + sibr_scene +) +else() +target_link_libraries(${PROJECT_NAME} + ${Boost_LIBRARIES} + ${ASSIMP_LIBRARIES} + ${GLEW_LIBRARIES} + ${OPENGL_LIBRARIES} + ${OpenCV_LIBRARIES} + ${GLFW_LIBRARY} + sibr_system + sibr_view + sibr_assets + sibr_scene +) +endif() + +add_definitions( -DSIBR_EXP_RENDERER_EXPORTS -DBOOST_ALL_DYN_LINK ) + +set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER ${SIBR_FOLDER}) + +## High level macro to install in an homogen way all our ibr targets +include(install_runtime) +ibr_install_target(${PROJECT_NAME} + INSTALL_PDB ## mean install also MSVC IDE *.pdb file (DEST according to target type) + SHADERS "${SHADERS}" + RSC_FOLDER "core" + COMPONENT ${PROJECT_NAME}_install ## will create custom target to install only this project +) + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/ColoredMeshRenderer.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/ColoredMeshRenderer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ceb0e2723e7fb98d7a69cbd3e8ada39e84388517 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/ColoredMeshRenderer.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#include "core/graphics/Texture.hpp" +#include + +namespace sibr { + ColoredMeshRenderer::ColoredMeshRenderer( void ) + { + _shader.init("ColoredMesh", + sibr::loadFile(sibr::getShadersDirectory("core") + "/colored_mesh.vert"), + sibr::loadFile(sibr::getShadersDirectory("core") + "/colored_mesh.frag")); + _paramMVP.init(_shader,"MVP"); + } + + void ColoredMeshRenderer::process( const Mesh& mesh, const Camera& eye, IRenderTarget& target, sibr::Mesh::RenderMode mode, bool backFaceCulling ) + { + //glViewport(0.f, 0.f, target.w(), target.h()); + target.bind(); + glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + _shader.begin(); + _paramMVP.set(eye.viewproj()); + mesh.render(true, backFaceCulling); + _shader.end(); + target.unbind(); + } + +} /*namespace sibr*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/ColoredMeshRenderer.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/ColoredMeshRenderer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..507cdd75b627e39af85a93dd07fa71808050341e --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/ColoredMeshRenderer.hpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include +# include +# include +# include + +# include + +namespace sibr { + + /** Render a mesh colored using the per-vertex color attribute. + \ingroup sibr_renderer + */ + class SIBR_EXP_RENDERER_EXPORT ColoredMeshRenderer + { + public: + typedef std::shared_ptr Ptr; + + public: + + /// Constructor. + ColoredMeshRenderer( void ); + + /** Render the mesh using its vertices colors, interpolated over triangles. + \param mesh the mesh to render + \param eye the viewpoint to use + \param dst the destination rendertarget + \param mode the rendering mode of the mesh + \param backFaceCulling should backface culling be performed + */ + void process( + /*input*/ const Mesh& mesh, + /*input*/ const Camera& eye, + /*output*/ IRenderTarget& dst, + /*mode*/ sibr::Mesh::RenderMode mode = sibr::Mesh::FillRenderMode, + /*BFC*/ bool backFaceCulling = true); + + private: + + GLShader _shader; ///< Color shader. + GLParameter _paramMVP; ///< MVP uniform. + + }; + +} /*namespace sibr*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/Config.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/Config.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d031cf46912538fd2d2c667856237ac61618f47a --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/Config.hpp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include + +# ifdef SIBR_OS_WINDOWS +# ifdef SIBR_STATIC_DEFINE +# define SIBR_EXPORT +# define SIBR_NO_EXPORT +# else +# ifndef SIBR_EXP_RENDERER_EXPORT +# ifdef SIBR_EXP_RENDERER_EXPORTS +/* We are building this library */ +# define SIBR_EXP_RENDERER_EXPORT __declspec(dllexport) +# else +/* We are using this library */ +# define SIBR_EXP_RENDERER_EXPORT __declspec(dllimport) +# endif +# endif +# ifndef SIBR_NO_EXPORT +# define SIBR_NO_EXPORT +# endif +# endif +# else +# define SIBR_EXP_RENDERER_EXPORT +# endif diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/CopyRenderer.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/CopyRenderer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b491aacf7ca2ee91fa7c2f76670c1d628c941815 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/CopyRenderer.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#include + +namespace sibr { + CopyRenderer::CopyRenderer(const std::string& vertFile, const std::string& fragFile) + { + _shader.init("CopyShader", + sibr::loadFile(vertFile), + sibr::loadFile(fragFile)); + + _flip.init(_shader, "flip"); + } + + void CopyRenderer::process( uint textureID, IRenderTarget& dst, bool disableTest ) + { + if (disableTest) + glDisable(GL_DEPTH_TEST); + else + glEnable(GL_DEPTH_TEST); + + _shader.begin(); + _flip.send(); + + dst.clear(); + dst.bind(); + + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textureID ); + sibr::RenderUtility::renderScreenQuad(); + + dst.unbind(); + _shader.end(); + } + + void CopyRenderer::copyToWindow(uint textureID, Window& dst) + { + glDisable(GL_DEPTH_TEST); + + _shader.begin(); + + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textureID); + sibr::RenderUtility::renderScreenQuad(); + + _shader.end(); + } + +} /*namespace sibr*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/CopyRenderer.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/CopyRenderer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..2baf4f57fc251838630ed8fa1a5a76c532587367 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/CopyRenderer.hpp @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include +# include +# include + +# include + +namespace sibr { + + /** Copy the content of an input texture to another rendertarget or to the window. + If you need a basic copy, prefer using blit. + \sa sibr::blit + \ingroup sibr_renderer + */ + class SIBR_EXP_RENDERER_EXPORT CopyRenderer + { + public: + typedef std::shared_ptr Ptr; + + public: + + /** Constructor. You can specify custom shaders, refer to noproj.vert and copy.frag for examples. + \param vertFile pah to the vertex shader file + \param fragFile pah to the fragment shader file + */ + CopyRenderer( + const std::string& vertFile = sibr::getShadersDirectory("core") + "/noproj.vert", + const std::string& fragFile = sibr::getShadersDirectory("core") + "/copy.frag" + ); + + /** Copy input texture to the output texture, copy also the input alpha into depth. + \param textureID the texture to copy + \param dst the destination + \param disableTest disable depth testing (depth won't be written) + */ + void process( uint textureID, IRenderTarget& dst, + bool disableTest=true); + + /** Copy input texture to a window. + \param textureID the texture to copy + \param dst the destination window + */ + void copyToWindow( uint textureID, Window& dst); + + /** \return option to flip the texture when copying. */ + bool & flip() { return _flip.get(); } + + private: + + GLShader _shader; ///< Copy shader. + GLuniform _flip = false; ///< Flip the texture when copying. + }; + +} /*namespace sibr*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/DepthRenderer.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/DepthRenderer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..76503b3465f7954b1d2486ff6a2a972fc9487d6b --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/DepthRenderer.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +# include +# include "core/graphics/RenderUtility.hpp" + + +namespace sibr +{ + + DepthRenderer::~DepthRenderer() {}; + + DepthRenderer::DepthRenderer(int w,int h) + { + _depthShader.init("DepthShader", + sibr::loadFile(sibr::Resources::Instance()->getResourceFilePathName("depthRenderer.vp")), + sibr::loadFile(sibr::Resources::Instance()->getResourceFilePathName("depthRenderer.fp"))); + + _depthShader_MVP.init(_depthShader,"MVP"); + _depth_RT.reset(new sibr::RenderTargetLum32F(w,h)); + + } + + void DepthRenderer::render( const sibr::InputCamera& cam, const Mesh& mesh, bool backFaceCulling, bool frontFaceCulling) + { + + //sibr::Vector1f cc(1.0); + //_depth_RT->clear(cc); + + glViewport(0, 0, _depth_RT->w(), _depth_RT->h()); + _depth_RT->bind(); + glClearColor(1.0, 1.0, 1.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + _depthShader.begin(); + _depthShader_MVP.set(cam.viewproj()); + + mesh.render(true, backFaceCulling, sibr::Mesh::FillRenderMode, frontFaceCulling); + + _depthShader.end(); + + } + +} // namespace \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/DepthRenderer.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/DepthRenderer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9c3c83d047064530866674d8e5cd93b55b22df11 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/DepthRenderer.hpp @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include +# include "core/assets/InputCamera.hpp" +# include "core/graphics/Texture.hpp" +# include "core/graphics/Camera.hpp" +# include "core/graphics/RenderUtility.hpp" +# include "core/assets/Resources.hpp" +# include "core/graphics/Shader.hpp" +# include "core/graphics/Mesh.hpp" + + +namespace sibr +{ + + /** Render a mesh to a depth rendertarget. + \ingroup sibr_renderer + */ + class SIBR_EXP_RENDERER_EXPORT DepthRenderer + { + + public: + + using Ptr = std::shared_ptr; + + /** Constructor with a target size. + \param w target width + \param h target height + */ + DepthRenderer(int w,int h) ; + + /// Destructor. + ~DepthRenderer(); + + /** Render a mesh depth in the result rendertarget. + \param cam the viewpoint to use + \param mesh the mesh to render + \param backFaceCulling should perform backface culling + \param frontFaceCulling flip culling test orientation + */ + void render( const sibr::InputCamera &cam, const Mesh& mesh, bool backFaceCulling=false, bool frontFaceCulling=false); + + std::shared_ptr _depth_RT; ///< The result depth rendertarget. + + private: + + sibr::GLShader _depthShader; ///< Depth shader. + sibr::GLParameter _depthShader_MVP; ///< Shader MVP. + + }; + +} // namespace + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/NormalRenderer.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/NormalRenderer.cpp new file mode 100755 index 0000000000000000000000000000000000000000..f9f3a492cffdaf62a9b4d31fc4b9b4aacaa1aa1b --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/NormalRenderer.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +# include +# include "core/graphics/RenderUtility.hpp" + +# define USE_PIXELART_MODEN 0 // just for fun (and e-art!) + +namespace sibr +{ + + NormalRenderer::~NormalRenderer() {}; + + NormalRenderer::NormalRenderer(int w, int h, bool generate, bool useFloats, bool imSpace) + { + _generate = generate; + _useFloats = useFloats; + + if (_generate) { + + _normalShader.init("NormalShader", + sibr::loadFile(sibr::Resources::Instance()->getResourceFilePathName("normalRendererGen.vp")), + sibr::loadFile(sibr::Resources::Instance()->getResourceFilePathName("normalRenderer.fp")), + sibr::loadFile(sibr::Resources::Instance()->getResourceFilePathName("normalRendererGen.gp"))); + + _normalShader_projInv.init(_normalShader, "MVPinv"); + } + else { + + _normalShader.init("NormalShader", + sibr::loadFile(sibr::Resources::Instance()->getResourceFilePathName("normalRenderer.vp")), + sibr::loadFile(sibr::Resources::Instance()->getResourceFilePathName("normalRenderer.fp"))); + } + + _normalShader_proj.init(_normalShader, "MVP"); + _normalShader_view.init(_normalShader, "V"); + _normalShader_model.init(_normalShader, "M"); + _normalShader_imSpace.init(_normalShader, "imSpaceNormals"); + _normalShader.begin(); + _normalShader_imSpace.set(imSpace); + _normalShader.end(); + + if (_useFloats) { + _normal_RT_32F.reset(new sibr::RenderTargetRGBA32F(w, h)); + } else { + _normal_RT.reset(new sibr::RenderTargetRGB(w, h)); + } + + + } + + void NormalRenderer::setWH(int w, int h) { + if (_useFloats) { + _normal_RT_32F.reset(new sibr::RenderTargetRGBA32F(w, h)); + } + else { + _normal_RT.reset(new sibr::RenderTargetRGB(w, h)); + } + } + + void NormalRenderer::render(const sibr::InputCamera& cam, const Mesh& mesh, const Matrix4f &modelMat, bool clear) + { +#if USE_PIXELART_MODEN + glPointSize(10.f); +#else + glPointSize(2.f); +#endif + + if (_useFloats) { + if(clear) + _normal_RT_32F->clear(sibr::Vector4f(0.5f,0.5f,0.5f,1.0f)); + glViewport(0, 0, _normal_RT_32F->w(), _normal_RT_32F->h()); + _normal_RT_32F->bind(); + } else { + _normal_RT->bind(); + if (clear) { + glClearColor(0.5f, 0.5f, 0.5f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } + glViewport(0, 0, _normal_RT->w(), _normal_RT->h()); + glScissor(0, 0, _normal_RT->w(), _normal_RT->h()); + } + + _normalShader.begin(); + const Matrix4f MVP = cam.viewproj() * modelMat; + _normalShader_proj.set(MVP); + _normalShader_view.set(cam.view()); + _normalShader_model.set(modelMat); + + if (_generate) { + const Matrix4f MVPinv = (cam.viewproj()*modelMat).inverse(); + _normalShader_projInv.set(MVPinv); + } + + // std::cout << cam.znear() << " " << cam.zfar() << " " << cam.viewproj() << std::endl; + mesh.render(true, true, sibr::Mesh::FillRenderMode); + + _normalShader.end(); + + } + +} // namespace \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/NormalRenderer.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/NormalRenderer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f1a48800cde357131e5e793b488f1275af3bac5d --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/NormalRenderer.hpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include + +# include "core/assets/InputCamera.hpp" +# include "core/graphics/Texture.hpp" +# include "core/graphics/Camera.hpp" +# include "core/graphics/RenderUtility.hpp" +# include "core/assets/Resources.hpp" +# include "core/graphics/Shader.hpp" +# include "core/graphics/Mesh.hpp" + + +namespace sibr +{ + + /** Render the world or view space normals of a mesh. + \ingroup sibr_renderer + */ + class SIBR_EXP_RENDERER_EXPORT NormalRenderer + { + + public: + + /** Constructor. + \param w target width + \param h target height + \param generate if true, use a geoemtry shader to compute normals on the fly, else use vertex normals + \param useFloats if true, render in a 32F rendertarget, else use 8U + \param imSpace if true, render view space normals, else render world space normals + */ + NormalRenderer(int w,int h, bool generate = true, bool useFloats = false, bool imSpace = false) ; + + /// Destructor. + ~NormalRenderer(); + + /** Render the mesh normals in the internal render target. + \param cam the viewpoint to use + \param mesh the mesh to render + \param modelMat additional model matrix + \param clear clear the rendertarget before rendering + */ + void render( const sibr::InputCamera &cam, const Mesh& mesh, const Matrix4f &modelMat = Matrix4f::Identity(), bool clear=true); + + /** Resize the internal rendertarget. + \param w the new width + \param h the new height + */ + void setWH(int w, int h); + + std::shared_ptr _normal_RT; ///< The low-precision normal result rendertarget (used if useFloats is false). + std::shared_ptr _normal_RT_32F; ///< The high-precision normal result rendertarget (used if useFloats is true). + + private: + + sibr::GLShader _normalShader; ///< Normal shader. + sibr::GLParameter _normalShader_proj; ///< Projection matrix uniform. + sibr::GLParameter _normalShader_view; ///< View matrix uniform. + sibr::GLParameter _normalShader_model; ///< Model matrix uniform. + sibr::GLParameter _normalShader_projInv; ///< Inverse projection matrix uniform. + sibr::GLParameter _normalShader_imSpace; ///< View space toggle uniform. + bool _generate; ///< Should normals be generated on the fly. + bool _useFloats; ///< Should the normals be rendered to a 32F precision target. + + }; + + +} // namespace + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/PointBasedRenderer.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/PointBasedRenderer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ea7b043cdcc8e7e5d9cb1534a2c1a6411958bcfa --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/PointBasedRenderer.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#include + +namespace sibr { + PointBasedRenderer::PointBasedRenderer() + { + _shader.init("PointBased", + sibr::loadFile(sibr::getShadersDirectory("core") + "/alpha_points.vert"), + sibr::loadFile(sibr::getShadersDirectory("core") + "/alpha_points.frag")); + _paramMVP.init(_shader,"mvp"); + _paramAlpha.init(_shader,"alpha"); + _paramRadius.init(_shader,"radius"); + _paramUserColor.init(_shader,"user_color"); + } + + void PointBasedRenderer::meshToDevice(const Mesh& mesh) + { + mesh.forceBufferGLUpdate(); + } + + void PointBasedRenderer::process(const Mesh& mesh, const Camera& eye, IRenderTarget& dst, bool backfaceCull) + { + glEnable(GL_DEPTH_TEST); + glEnable(GL_PROGRAM_POINT_SIZE); + dst.bind(); + _shader.begin(); + _paramMVP.set(eye.viewproj()); + _paramAlpha.set(float(1.0)); + _paramRadius.set(3); + _paramUserColor.set(Vector3f(.1, .1, 1.0)); + + mesh.render_points(); + _shader.end(); + dst.unbind(); + glDisable(GL_PROGRAM_POINT_SIZE); + glDisable(GL_DEPTH_TEST); + } + + void PointBasedRenderer::process(const Mesh& mesh, const Camera& eye, const sibr::Matrix4f& model, IRenderTarget& dst, bool backfaceCull) + { + glEnable(GL_DEPTH_TEST); + glEnable(GL_PROGRAM_POINT_SIZE); + dst.bind(); + _shader.begin(); + _paramMVP.set(sibr::Matrix4f(eye.viewproj() * model)); + _paramAlpha.set(float(1.0)); + _paramRadius.set(2); + _paramUserColor.set(Vector3f(.1, .1, 1.0)); + mesh.render_points(); + _shader.end(); + dst.unbind(); + glDisable(GL_PROGRAM_POINT_SIZE); + glDisable(GL_DEPTH_TEST); + } + +} /*namespace sibr*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/PointBasedRenderer.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/PointBasedRenderer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..87bbd40e4eda9497f34931bebd416c617d3045ba --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/PointBasedRenderer.hpp @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include +# include +# include +# include + +# include + +namespace sibr { + + /** Render a Point Cloud with colors + \ingroup sibr_renderer + */ + class SIBR_EXP_RENDERER_EXPORT PointBasedRenderer + { + public: + typedef std::shared_ptr Ptr; + + public: + + /** Constructor. + */ + PointBasedRenderer(); + + void meshToDevice(const Mesh& mesh); + + /** Render the textured mesh. + \param mesh the mesh to render (should have UV attribute) + \param eye the viewpoint to use + \param dst destination rendertarget + \param backfaceCull should backface culling be performed + */ + void process(const Mesh& mesh, const Camera& eye, IRenderTarget& dst, bool backfaceCull = true); + + /** Render the textured mesh. + \param mesh the mesh to render (should have UV attribute) + \param eye the viewpoint to use + \param model additional transformation matrix + \param dst destination rendertarget + \param backfaceCull should backface culling be performed + */ + void process(const Mesh & mesh, const Camera & eye, const sibr::Matrix4f & model, IRenderTarget & dst, bool backfaceCull = true); + + protected: + + GLShader _shader; ///< The point based shader. + GLuniform _paramMVP; ///< MVP uniform. + GLuniform _paramAlpha; ///< Alpha uniform. + GLuniform _paramRadius; ///< Radius uniform. + GLuniform _paramUserColor; + }; + +} /*namespace sibr*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/PoissonRenderer.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/PoissonRenderer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f0804df95fc5d46e2c22b12c0591db2e08aada30 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/PoissonRenderer.cpp @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +/** +* +* Poisson synthesis. +*/ + +#include +#include + +#include +#include + +#include + +using namespace sibr; + +/** Number of levels poisson multi-grid */ +#define POISSON_LEVELS 5 + +/** Number of relaxation/jacobi iterations at each level */ +#define POISSON_ITERATIONS 2 + +/** Ratio of successive levels of poisson multi-grid */ +#define MULTIGRID_SCALE 2 + +namespace sibr { + // ----------------------------------------------------------------------- + + PoissonRenderer ::PoissonRenderer ( uint w, uint h ) : + _size(w, h) + { + std::string vp = sibr::loadFile(sibr::getShadersDirectory("core") + "/texture.vert"); + _jacobiShader .init("Jacobi", vp, sibr::loadFile(sibr::getShadersDirectory("core") + "/poisson_jacobi.frag")); + _restrictShader.init("Restrict",vp, sibr::loadFile(sibr::getShadersDirectory("core") + "/poisson_restrict.frag")); + _interpShader .init("Interp", vp, sibr::loadFile(sibr::getShadersDirectory("core") + "/poisson_interp.frag")); + _divergShader .init("Diverg", vp, sibr::loadFile(sibr::getShadersDirectory("core") + "/poisson_diverg.frag")); + + // GLParameters + _jacobi_weights.init(_jacobiShader, "weights"); + _jacobi_scale.init(_jacobiShader, "scale"); + _restrict_scale.init(_restrictShader, "scale"); + _interp_scale .init(_interpShader, "scale"); + + _poisson_div_RT.resize(POISSON_LEVELS); + for (uint i=0; i<_poisson_div_RT.size(); i++) { + uint ww = std::max(1u, uint(w/pow( (float)MULTIGRID_SCALE, (int)i))); + uint hh = std::max(1u, uint(h/pow( (float)MULTIGRID_SCALE, (int)i))); + _poisson_div_RT[i].reset(new sibr::RenderTargetRGBA(ww,hh, SIBR_CLAMP_UVS)); + } + _poisson_RT.reset(new sibr::RenderTargetRGBA(w,h, SIBR_CLAMP_UVS | SIBR_GPU_LINEAR_SAMPLING)); + _poisson_tmp_RT.reset(new sibr::RenderTargetRGBA(w,h, SIBR_CLAMP_UVS | SIBR_GPU_LINEAR_SAMPLING)); + _enableFix = true; + + } + + // ----------------------------------------------------------------------- + + uint PoissonRenderer::render( uint texture ) + { + glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, -1, "Poisson filling"); + // divergence of gradient map and dirichlet constraints + _divergShader.begin(); + _poisson_div_RT[0]->clear(); + _poisson_div_RT[0]->bind(); + glViewport(0, 0, _poisson_div_RT[0]->w(), _poisson_div_RT[0]->h()); + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture); + RenderUtility::renderScreenQuad(); + _poisson_div_RT[0]->unbind(); + _divergShader.end(); + + // restrict the divergence + for (int k=0; kclear(); + _poisson_div_RT[k+1]->bind(); + glViewport(0,0, _poisson_div_RT[k+1]->w(), _poisson_div_RT[k+1]->h()); + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, _poisson_div_RT[k]->texture()); + _restrict_scale.set(float(_poisson_div_RT[k]->w())/_poisson_div_RT[k+1]->w()); + RenderUtility::renderScreenQuad(); + _poisson_div_RT[k+1]->unbind(); + _restrictShader.end(); + } + + // perform jacobi iterations and upsample the result to higher level + bool isFirst = _enableFix; + for (int k=(int)_poisson_div_RT.size()-1; k>=0; k--) { + for (uint i=0; iclear(); + _poisson_RT->bind(); + glViewport(0,0, _poisson_div_RT[k]->w(), _poisson_div_RT[k]->h()); + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, _poisson_tmp_RT->texture()); + _jacobi_weights.set((float)xh, (float)e, (float)c, (float)(1.0/(m-xh))); + _jacobi_scale.set( isFirst ? (float(_poisson_tmp_RT->w()) / _poisson_div_RT[k]->w()) : 1.0f); + RenderUtility::renderScreenQuad(); + _poisson_RT->unbind(); + _jacobiShader.end(); + + isFirst = false; + } + + if (k > 0) { + std::swap(_poisson_tmp_RT, _poisson_RT); + _interpShader.begin(); + _poisson_RT->clear(); + _poisson_RT->bind(); + glViewport(0,0, _poisson_div_RT[k-1]->w(), _poisson_div_RT[k-1]->h()); + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, _poisson_tmp_RT->texture()); + glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, _poisson_div_RT[k-1]->texture()); + _interp_scale.set(float(_poisson_div_RT[k-1]->w()) / _poisson_div_RT[k]->w()); + RenderUtility::renderScreenQuad(); + _poisson_RT->unbind(); + _interpShader.end(); + } else { + std::swap(_poisson_tmp_RT, _poisson_RT); + _interpShader.begin(); + _poisson_RT->clear(); + _poisson_RT->bind(); + glViewport(0,0, _poisson_RT->w(), _poisson_RT->h()); + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, _poisson_tmp_RT->texture()); + glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, texture); + _interp_scale.set(1.0f); + RenderUtility::renderScreenQuad(); + _poisson_RT->unbind(); + _interpShader.end(); + } + } + glPopDebugGroup(); + return _poisson_RT->texture(); + } + + void PoissonRenderer::process( const RenderTargetRGBA::Ptr& src, RenderTargetRGBA::Ptr& dst ) + { + SIBR_ASSERT(src != nullptr); + /// \todo TODO SR: support IRenderTarget instead of just RGBA + render(src->texture()); + std::swap(dst, _poisson_RT); + } + + void PoissonRenderer::process( uint texID, RenderTargetRGBA::Ptr& dst ) + { + render(texID); + std::swap(dst, _poisson_RT); + } + +} /*namespace sibr*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/PoissonRenderer.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/PoissonRenderer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ecc91ed45fbed190eb96fa09cbff5aac57199fb1 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/PoissonRenderer.hpp @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include "Config.hpp" + +# include +# include +# include + +# include +# include +# include "core/graphics/Shader.hpp" + +namespace sibr { + + /** + * Hole filling by poisson synthesis on an input texture; + * contains all shaders, render targets and render passes. + * All black pixels on the input texture are considered holes + * and Poisson synthesis affects these pixels only, all + * other pixels are treated at Dirichlet boundary conditions. + * \ingroup sibr_renderer + */ + class SIBR_EXP_RENDERER_EXPORT PoissonRenderer + { + public: + typedef std::shared_ptr Ptr; + + public: + + /** + * Initialize Poisson solvers render targets and shaders. + * \param w width of highest resolution multigrid level + * \param h height of highest resolution multigrid level + */ + PoissonRenderer ( uint w, uint h ); + + /** Perform poisson filling. + \param src source rendertarget, black pixels will be filled + \param dst destination rendertarget + */ + void process( + /*input*/ const RenderTargetRGBA::Ptr& src, + /*ouput*/ RenderTargetRGBA::Ptr& dst ); + + /** Perform poisson filling. + \param texID source texture handle, black pixels will be filled + \param dst destination rendertarget + */ + void process( + /*input*/ uint texID, + /*ouput*/ RenderTargetRGBA::Ptr& dst ); + + /** + * \return the size used for in/out textures (defined in ctor) + */ + const Vector2i& getSize( void ) const; + + /** If true, fix a bug caused by erroneous viewport when initializing the internal pyramid. + Left exposed for retrocompatibility reasons. + \return a reference to the bugfix toggle. */ + bool & enableFix() { return _enableFix; } + + private: + /** + * Render the full Poisson synthesis on the holes in texture 'tex'. + * \param tex OpenGL texture handle of input texture + * \returns OpenGL texture handle of texture containing Poisson synthesis solution + */ + uint render( uint tex ); + + /** Size defined in the ctor */ + Vector2i _size; + + /** Shader to perform Jacobi relaxations */ + sibr::GLShader _jacobiShader; + + /** Shader to downsample input texture and boundary conditions from + * higher multigrid level to next lower level */ + sibr::GLShader _restrictShader; + + /** Shader to interpolate Poisson synthesis solution from + * lower multigrid level to next higher level */ + sibr::GLShader _interpShader; + + /** Shader to compute divergence (second derivative) field of input texture */ + sibr::GLShader _divergShader; + + /** Render target to store Poisson synthesis result */ + RenderTargetRGBA::Ptr _poisson_RT; + + /** Helper render target for \p _poisson_RT to + * perform ping-pong render passes during Jacobi relaxations */ + RenderTargetRGBA::Ptr _poisson_tmp_RT; + + /** Dirichlet constraints for each multigrid level */ + std::vector _poisson_div_RT; + + /** Jacobi step parameters. */ + sibr::GLParameter _jacobi_weights, _jacobi_scale, _restrict_scale; + /** Interpolation scale. */ + sibr::GLParameter _interp_scale; + + /** Enable the "weird large regions of color" bugfix. */ + bool _enableFix = true; + }; + +} /*namespace sibr*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/PositionRender.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/PositionRender.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e357d3bc7351b0fbb97922dc9ed046918960444d --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/PositionRender.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +# include "PositionRender.hpp" + +#include + +namespace sibr +{ + PositionRenderer::PositionRenderer(int w,int h) + { + _shader.init("positionRendere", + sibr::loadFile(sibr::Resources::Instance()->getResourceFilePathName("positionRenderer.vert")), + sibr::loadFile(sibr::Resources::Instance()->getResourceFilePathName("positionRenderer.frag"))); + + _MVP.init(_shader,"MVP"); + _RT.reset(new sibr::RenderTargetRGB32F(w,h)); + } + + void PositionRenderer::render( const sibr::Camera& cam, const Mesh& mesh, bool backFaceCulling, bool frontFaceCulling) + { + glViewport(0, 0, _RT->w(), _RT->h()); + _RT->bind(); + glClearColor(0.0, 0.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + _shader.begin(); + _MVP.set(cam.viewproj()); + + mesh.render(true, backFaceCulling, sibr::Mesh::FillRenderMode, frontFaceCulling); + + _shader.end(); + _RT->unbind(); + } + +} // namespace \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/PositionRender.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/PositionRender.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e59f756f5b20eb30d9fcc40f275f43b2ef950243 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/PositionRender.hpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include "Config.hpp" + +# include +# include +# include +# include + +# include + + +namespace sibr +{ + /** Render the world space positions of a mesh surface. + \ingroup sibr_renderer + */ + class SIBR_EXP_RENDERER_EXPORT PositionRenderer + { + SIBR_CLASS_PTR(PositionRenderer); + + public: + + /** Constructor with a target size. + \param w the target width + \param h the target height + */ + PositionRenderer(int w,int h); + + /** Render the mesh world positions. + \param cam the viewpoint to use + \param mesh the mesh to render + \param backFaceCulling should backface culling be performed + \param frontFaceCulling flip the culling test orientation + */ + void render( const sibr::Camera &cam, const Mesh& mesh, bool backFaceCulling=false, bool frontFaceCulling=false); + + /** \return the result rendertarget containing world space positions. */ + const sibr::RenderTargetRGB32F::Ptr & getPositionsRT() { return _RT; } + + private: + + sibr::GLShader _shader; ///< The positions shader. + sibr::GLuniform _MVP; ///< MVP uniform. + sibr::RenderTargetRGB32F::Ptr _RT; ///< Destination render target. + + }; + +} // namespace + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/RenderMaskHolder.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/RenderMaskHolder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ed68b03fc565f8b677c14cc737ac5ab797c34363 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/RenderMaskHolder.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include +#include + +namespace sibr { + void RenderMaskHolder::setMasks( const std::vector& masks ) + { + _masks = masks; + } + + const std::vector& RenderMaskHolder::getMasks( void ) const + { + return _masks; + } + + bool RenderMaskHolder::useMasks( void ) const + { + return _masks.empty() == false; + } + + void RenderMaskHolder::uploadMaskGPU(sibr::ImageL8& img, int i, std::vector & masks, bool invert) + { + sibr::GLShader textureShader; + textureShader.init("Texture", + sibr::loadFile(sibr::Resources::Instance()->getResourceFilePathName("texture.vp")), + invert ? sibr::loadFile(sibr::getShadersDirectory("core") + "/texture-invert.frag") : sibr::loadFile(sibr::getShadersDirectory("core") + "/texture.frag")); + + std::shared_ptr maskRTPtr; + maskRTPtr.reset(new sibr::RenderTargetLum(img.w(), img.h())); + + img.flipH(); + std::shared_ptr rawInputImage(new sibr::Texture2DLum(img)); + img.flipH(); + + glViewport(0,0, img.w(), img.h()); + maskRTPtr->clear(); + maskRTPtr->bind(); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, rawInputImage->handle()); + + glDisable(GL_DEPTH_TEST); + textureShader.begin(); + sibr::RenderUtility::renderScreenQuad(); + textureShader.end(); + + maskRTPtr->unbind(); +/* + maskRTPtr->readBack(img); + sibr::show(img); +*/ + masks.push_back(maskRTPtr); + } + + + void RenderMaskHolder::loadMasks(const sibr::BasicIBRScene::Ptr& ibrScene, const std::string& maskDir, + const std::string& preFileName, const std::string& postFileName, int w, int h) + { + if( boost::filesystem::exists(maskDir) ) { + + for(int i=0; i<(int)ibrScene->cameras()->inputCameras().size(); i++ ) { + sibr::ImageRGB mask; + std::string filename = maskDir + "/" + preFileName + sibr::imageIdToString(i) + postFileName; + + if( boost::filesystem::exists(filename)) { + mask.load(filename,false); + // Split the image in its channels and keep only the first. + cv::Mat channels[3]; + cv::split(mask.toOpenCV(), channels); + sibr::ImageL8 maskOneChan; + maskOneChan.fromOpenCV(channels[0]); + uploadMaskGPU(maskOneChan, i, _masks, false); + } + else { + if( ibrScene->cameras()->inputCameras()[i]->isActive() ) + SIBR_ERR << "[RenderMaskHolder] couldnt find " << filename << std::endl; + else { /// push back empty mask so array is consistent + /// \todo TODO GD -- this is wasteful, should fine better way + std::shared_ptr maskRTPtr; + maskRTPtr.reset(new sibr::RenderTargetLum(w, h)); + _masks.push_back(maskRTPtr); + } + } + } + + } + else + SIBR_ERR << "[RenderMaskHolder] Cant find directory " << maskDir << std::endl; + } + + void RenderMaskHolderArray::setMasks(const MaskArrayPtr& masks) + { + _masks = masks; + } + + const RenderMaskHolderArray::MaskArrayPtr & RenderMaskHolderArray::getMasks(void) const { + return _masks; + } + + void RenderMaskHolderArray::loadMasks( + const sibr::BasicIBRScene::Ptr& ibrScene, + const std::string& maskDir, const std::string& preFileName, + const std::string& postFileName, int w, int h + ) { + std::string maskdir = (maskDir == "" ? ibrScene->data()->basePathName() + "/images/" : maskDir); + + if (!boost::filesystem::exists(maskdir)) { + SIBR_ERR << "[RenderMaskHolder] Cant find directory " << maskDir << std::endl; + } else { + int numInputImgs = (int)ibrScene->cameras()->inputCameras().size(); + std::vector masks(numInputImgs); + for (int i = 0; i < numInputImgs; i++) { + std::string filename = maskDir + "/" + preFileName + sibr::imageIdToString(i) + postFileName; + + cv::Mat mask = cv::imread(filename); + + if (mask.empty()) { + SIBR_ERR << "[RenderMaskHolderArray] couldnt find or read " << filename << std::endl; + } + + cv::Mat channels[3]; + cv::split(mask, channels); + if (w > 0 && h > 0) { + cv::resize(channels[0], channels[0], cv::Size(w, h)); + } + masks[i] = channels[0]; + } + + _masks = MaskArrayPtr(new MaskArray(masks, SIBR_FLIP_TEXTURE)); + } + } +} /*namespace sibr*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/RenderMaskHolder.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/RenderMaskHolder.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5af2996d2fb99daefbe85e9e9d6d216d5916a246 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/RenderMaskHolder.hpp @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include "Config.hpp" +# include +# include +# include +# include +# include + +namespace sibr { + + /** Store a set of masks associated to a set of images (dataset input images for instance), on the GPU. + This version uses a list of R8 rendertargets. + \note Might want to use textures instead of RTs here. + \ingroup sibr_renderer + */ + class SIBR_EXP_RENDERER_EXPORT RenderMaskHolder + { + typedef RenderTargetLum::Ptr MaskPtr; + public: + + /** Update the masks + \param masks the new masks to use + */ + void setMasks( const std::vector& masks ); + + /** \return the masks rendertargets. */ + const std::vector& getMasks( void ) const; + + /** \return true if masks are available (non empty list). */ + bool useMasks( void ) const; + + /** Load masks from black and white images on disk. + \param ibrScene the dataset scene associated to the masks + \param maskDir the masks directory + \param preFileName mask filename prefix + \param postFileName mask filename suffix and extension + \param w target width + \param h target height + */ + void loadMasks( + const sibr::BasicIBRScene::Ptr& ibrScene, + const std::string& maskDir, const std::string& preFileName, + const std::string& postFileName, int w, int h); + + /** Upload a mask image to the GPU. + \param img the mask image to upload + \param i the mask index in the list + \param masks the uploaded masks list (will be updated) + \param invert should the mask be inverted + **/ + void uploadMaskGPU(sibr::ImageL8& img, int i, std::vector & masks, bool invert) ; + + private: + + std::vector _masks; ///< List of masks on the GPU. + + }; + + /** Store a set of masks associated to a set of images (dataset input images for instance), on the GPU. + This version uses a R8 texture array. + \ingroup sibr_renderer + */ + class SIBR_EXP_RENDERER_EXPORT RenderMaskHolderArray + { + using MaskArray = sibr::Texture2DArrayLum; + using MaskArrayPtr = MaskArray::Ptr; + + public: + + /** Update the masks + \param masks the new masks to use + */ + void setMasks(const MaskArrayPtr& masks); + + /** \return the masks texture array. */ + const MaskArrayPtr & getMasks(void) const; + + /** Load masks from black and white images on disk. + \param ibrScene the dataset scene associated to the masks + \param maskDir the masks directory + \param preFileName mask filename prefix + \param postFileName mask filename suffix and extension + \param w target width + \param h target height + */ + void loadMasks( + const sibr::BasicIBRScene::Ptr& ibrScene, + const std::string& maskDir = "", const std::string& preFileName = "masks" , + const std::string& postFileName = "", int w = -1, int h = -1 + ); + + protected: + + MaskArrayPtr _masks; ///< The masks texture array. + + }; + +} /*namespace sibr*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/ShadowMapRenderer.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/ShadowMapRenderer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a6ee3663d50cd313d12d6ce2987e13ec56b373c0 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/ShadowMapRenderer.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +# include "ShadowMapRenderer.hpp" +# include "core/graphics/RenderUtility.hpp" + +float SUN_APP_DIAM = 0.5358f; + +namespace sibr +{ + + ShadowMapRenderer::~ShadowMapRenderer() {}; + + ShadowMapRenderer::ShadowMapRenderer(const sibr::InputCamera& depthMapCam, std::shared_ptr depthMap_RT):_depthMap_RT(depthMap_RT) + { + _shadowMapShader.init("ShadowMapShader", + sibr::loadFile(sibr::Resources::Instance()->getResourceFilePathName("shadowMapRenderer.vp")), + sibr::loadFile(sibr::Resources::Instance()->getResourceFilePathName("shadowMapRenderer.fp"))); + + _shadowMapShader_MVP.init(_shadowMapShader,"MVP"); + _depthMap_MVP.init(_shadowMapShader, "depthMapMVP"); + _depthMap_MVPinv.init(_shadowMapShader, "depthMapMVPinv"); + _depthMap_radius.init(_shadowMapShader, "depthMapRadius"); + _lightDir.init(_shadowMapShader, "lightDir"); + _bias_control.init(_shadowMapShader, "biasControl"); + _sun_app_radius.init(_shadowMapShader, "sun_app_radius"); + + sibr::Vector3f toLight = -depthMapCam.dir(); + _shadowMapShader.begin(); + _depthMap_MVP.set(depthMapCam.viewproj()); + _depthMap_MVPinv.set(depthMapCam.invViewproj()); + _depthMap_radius.set(depthMapCam.orthoRight()); + _lightDir.set(toLight); + _sun_app_radius.set(SUN_APP_DIAM/2.0f); + _shadowMapShader.end(); + } + + void ShadowMapRenderer::render(int w, int h, const sibr::InputCamera& cam, const Mesh& mesh, float bias ) + { + + //sibr::Vector1f cc(1.0); + //_depth_RT->clear(cc); + + _shadowMap_RT.reset(new sibr::RenderTargetLum(w, h)); + + glViewport(0, 0, _shadowMap_RT->w(), _shadowMap_RT->h()); + _shadowMap_RT->bind(); + glClearColor(1.0, 1.0, 1.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + _shadowMapShader.begin(); + _shadowMapShader_MVP.set(cam.viewproj()); + _bias_control.set(bias); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, _depthMap_RT->texture()); + + mesh.render(true, false, sibr::Mesh::FillRenderMode); + + _shadowMapShader.end(); + + } + +} // namespace \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/ShadowMapRenderer.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/ShadowMapRenderer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0c35ce43c92b0494da19d044f3f98e0e65f35f54 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/ShadowMapRenderer.hpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include + +# include "core/assets/InputCamera.hpp" +# include "core/graphics/Texture.hpp" +# include "core/graphics/Camera.hpp" +# include "core/graphics/RenderUtility.hpp" +# include "core/assets/Resources.hpp" +# include "core/graphics/Shader.hpp" +# include "core/graphics/Mesh.hpp" + + +namespace sibr +{ + + /** Render high quality soft shadows, designed to mimick the sun shadowing. + \note Soft shadowing require a lot of texture fetches that can impact performances. + \ingroup sibr_renderer + */ + class SIBR_EXP_RENDERER_EXPORT ShadowMapRenderer + { + + public: + + /** Constructor. + \param depthMapCam the light viewpoint + \param depthMap_RT depth map rendered from the light viewpoint + */ + ShadowMapRenderer(const sibr::InputCamera& depthMapCam, std::shared_ptr depthMap_RT) ; + + /// Destructor. + ~ShadowMapRenderer(); + + /** + Render soft sun shadows on the mesh, using the precomputed depth map. + \param w the target width + \param h the target height + \param cam the viewpoint to use + \param mesh the mesh to render + \param bias shadow acne bias + */ + void render(int w, int h,const sibr::InputCamera &cam, const Mesh& mesh, float bias= 0.0005f); + + std::shared_ptr _shadowMap_RT; ///< Result containing the soft shadows. + + std::shared_ptr _depthMap_RT; ///< Depth map rendered from the light viewpoint. + + + private: + + sibr::GLShader _shadowMapShader; ///< Shadow rendering. + sibr::GLParameter _shadowMapShader_MVP; ///< Final MVP uniform. + sibr::GLParameter _depthMap_MVP; ///< Light MVP uniform. + sibr::GLParameter _depthMap_MVPinv; ///< Light inverse MVP uniform. + sibr::GLParameter _depthMap_radius; ///< Depth map radius. + sibr::GLParameter _lightDir; ///< Light direction uniform. + sibr::GLParameter _bias_control; ///< Bias uniform. + sibr::GLParameter _sun_app_radius; ///< Sun radius (for soft shadows). + std::shared_ptr _textureDepthMap; ///< Shadow map target (unused). + + }; + +} // namespace + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/TexturedMeshRenderer.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/TexturedMeshRenderer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..005e897a1eb1713bc5276f31ab261d3e811eaa30 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/TexturedMeshRenderer.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#include + +namespace sibr { + TexturedMeshRenderer::TexturedMeshRenderer( bool flipY ) + { + if(flipY) + _shader.init("TexturedMesh", + sibr::loadFile(sibr::getShadersDirectory("core") + "/textured_mesh_flipY.vert"), + sibr::loadFile(sibr::getShadersDirectory("core") + "/textured_mesh.frag")); + else + _shader.init("TexturedMesh", + sibr::loadFile(sibr::getShadersDirectory("core") + "/textured_mesh.vert"), + sibr::loadFile(sibr::getShadersDirectory("core") + "/textured_mesh.frag")); + _paramMVP.init(_shader,"MVP"); + } + + void TexturedMeshRenderer::process(const Mesh& mesh, const Camera& eye, uint textureID, IRenderTarget& dst, bool backfaceCull) + { + dst.bind(); + _shader.begin(); + _paramMVP.set(eye.viewproj()); + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textureID); + mesh.render(true, backfaceCull); + _shader.end(); + dst.unbind(); + + } + + void TexturedMeshRenderer::process(const Mesh& mesh, const Camera& eye, const sibr::Matrix4f& model, uint textureID, IRenderTarget& dst, bool backfaceCull) + { + dst.bind(); + _shader.begin(); + _paramMVP.set(sibr::Matrix4f(eye.viewproj() * model)); + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textureID); + mesh.render(true, backfaceCull); + _shader.end(); + dst.unbind(); + + } + +} /*namespace sibr*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/TexturedMeshRenderer.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/TexturedMeshRenderer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f22f1c5dc690be3d7f9e7f23bee3505b8201543d --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/TexturedMeshRenderer.hpp @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include +# include +# include +# include + +# include + +namespace sibr { + + /** Render a textured mesh, using per-vertex texture coordinates. + \ingroup sibr_renderer + */ + class SIBR_EXP_RENDERER_EXPORT TexturedMeshRenderer + { + public: + typedef std::shared_ptr Ptr; + + public: + + /** Constructor. + \param flipY if set to true, UV coordinates will be flipped vertically. + */ + TexturedMeshRenderer(bool flipY = false ); + + /** Render the textured mesh. + \param mesh the mesh to render (should have UV attribute) + \param eye the viewpoint to use + \param textureID handle of the texture to use + \param dst destination rendertarget + \param backfaceCull should backface culling be performed + */ + void process(const Mesh& mesh, const Camera& eye, uint textureID, IRenderTarget& dst, bool backfaceCull = true); + + /** Render the textured mesh. + \param mesh the mesh to render (should have UV attribute) + \param eye the viewpoint to use + \param model additional transformation matrix + \param textureID handle of the texture to use + \param dst destination rendertarget + \param backfaceCull should backface culling be performed + */ + void process(const Mesh & mesh, const Camera & eye, const sibr::Matrix4f & model, uint textureID, IRenderTarget & dst, bool backfaceCull = true); + + protected: + + GLShader _shader; ///< The texture mesh shader. + GLParameter _paramMVP; ///< MVP uniform. + }; + +} /*namespace sibr*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/addshadow.frag b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/addshadow.frag new file mode 100644 index 0000000000000000000000000000000000000000..f3653804783f2812b3cb6a0ac3f5e23bd7fa9f89 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/addshadow.frag @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +#define SHADOWPOWER_METHOD_ESTIM 1 +#define SHADOWPOWER_METHOD_3D 2 +#define SHADOWPOWER_METHOD_ESTIM_NONLINEAR 3 + +#define SHADOWPOWER_METHOD SHADOWPOWER_METHOD_ESTIM + +layout(binding = 0) uniform sampler2D tex; +layout(binding = 1) uniform sampler2D firstPassRT; /// \todo TODO: use ping pong buffering to update it with the last add + +uniform mat4 in_inv_proj; +uniform vec2 in_image_size; + +layout(location= 0) out vec4 out_color; + +in vec2 tex_coord; + + + +//const float blurSize = 1.0 / 1000.0; + +const float constFgAdditionalOffset = -0.02; // note it should not be linear because of near/far+proj +const float constSmoothShadowDistAtten = 8.0; + +vec3 unproject(vec3 xyd, mat4 inv_proj) { + vec4 pxl = vec4(xyd,1.0)*vec4(2.0)-vec4(1.0); // [0,1] -> [-1,1] + vec4 obj = inv_proj * pxl; // unproject + return (obj.xyz/obj.w); +} + +float smoothShadowDist( float dist01 ) +{ + float v = 1.0 - max(0.0, min(1.0, dist01) ); + return exp(log(v)*constSmoothShadowDistAtten); +} + +void main(void) { + +//===========================================================================// +// // +// Adding Shadow // +// // +//===========================================================================// +{ + const float scanSizeX = (1.0 / in_image_size.x)*4.0; /// \todo TODO: should be split into H and W and use image size + const float scanSizeY = (1.0 / in_image_size.y)*4.0; /// \todo TODO: should be split into H and W and use image size + + vec4 bg = texture(firstPassRT,tex_coord); // background color + vec4 fg = texture(tex,tex_coord); // foreground color (object to add) + float bgDepth = bg.a; + float outDepth = bgDepth; + float fgDepth = fg.a+constFgAdditionalOffset; + + // By default set output values using bg + out_color = vec4(bg.rgb, 1.0); + //out_color = vec4(bg.a, 0.0, 0.0, 1.0); + //gl_FragDepth = bgDepth; + + bool fgIsEmpty = (fg.r == 0 && fg.g == 0 && fg.b == 0); + /// gl_FragDepth = 0; + + if (fgIsEmpty == false) + { + out_color = vec4(fg.rgb, (bgDepth <= fgDepth)? 0.0 : 1.0); + //fgDepth = bgDepth; + outDepth = (bgDepth <= fgDepth)? bgDepth : fgDepth; + //gl_FragDepth = fgDepth; + /// out_color = vec4(fg.a, 0.0, 0.0, 1.0); + } + else + { + // Scan for non-empty pixels for determining the power + // of the shadow. + // 'non-empty' pixels are FULL black pixels + + const int scanItCount = 8; + const int maxScanablePixels = (scanItCount*2 + 1)*(scanItCount*2 + 1); + const float maxAxisX = (scanItCount*2 + 1)*scanSizeX; + const float maxAxisY = (scanItCount*2 + 1)*scanSizeY; + const float maxScanDist = maxAxisX*maxAxisX + maxAxisY*maxAxisY; + + float nearestDist = maxScanDist*2.0;//maxScanDist + 1.0; + float nearestXs = 1.0; + float nearestYs = 1.0; + float nearestDepth = 0.0; + float averageBgDepth = 0.0; + float nonEmptyPixelFound = 0; + for (int x = -scanItCount; x <= scanItCount; x++) + { + for (int y = -scanItCount; y <= scanItCount; y++) + { + float xs = x*scanSizeX; + float ys = y*scanSizeY; + float dist = (xs*xs + ys*ys); + vec4 color = texture(tex, vec2(tex_coord.x+xs, tex_coord.y+ys)); + float sampleDepth = color.a+constFgAdditionalOffset; + + averageBgDepth += sampleDepth; + + if ( (color.r == 0 && color.g == 0 && color.b == 0) == false +//// [A] this one will cause you trouble with object in front of your shadow caster +// ) +//// [B] this one will prevent you from casting shadow in front of your object +//// but visually, you can make it fly a bit and it look like the under is in front + && sampleDepth <= bgDepth ) +//// [C] this one is the best in fidelity but requires a call to texture(...) +// && sampleDepth <= texture(firstPassRT, vec2(tex_coord.x+xs, tex_coord.y+ys)).a) + { + if (dist < nearestDist) + { + nearestXs = xs; + nearestYs = ys; + // nearestDist = dist; + // nearestDepth = sampleDepth; + } + + + //nearestXs = min(xs, nearestXs); + //nearestYs = min(ys, nearestYs); // note that stored nearestXs/Ys might stores an unexisting coordinate pair + nearestDist = min(nearestDist, dist); + nearestDepth += sampleDepth;//max(nearestDepth, sampleDepth); + ++nonEmptyPixelFound; + + averageBgDepth -= sampleDepth; // cancel this in this case + } + } + } + nearestDepth = nearestDepth/float(nonEmptyPixelFound); + averageBgDepth = averageBgDepth/float(maxScanablePixels-nonEmptyPixelFound); + + //if (nearestDist > 0) + { + + // Compute the shadow power + float shadowPower = 1.0; + + float ratioNonEmptyPixelFound = float(nonEmptyPixelFound) / float(maxScanablePixels); + // influence of the caster size + shadowPower *= smoothstep(0.0, 0.5, ratioNonEmptyPixelFound); + + //if (nonEmptyPixelFound < 100) + // shadowPower = 0.0; + + //shadowPower *= max(0.0, min(1.0, nonEmptyPixelFound/minPixelCaster )); + + // Dev Note for improving things + // There are two way to implement the influence of the shadow caster/receiver distance. + // [3d solution] + // - one is to unproject both points and measure their distance in 3d world unit + // [estim solution] + // - another one is roughly estimate the effect + +#if SHADOWPOWER_METHOD == SHADOWPOWER_METHOD_ESTIM_NONLINEAR + // [estim solution] + // influence of the distance to the object that cast this shadow (slightly improve but not enough) + //shadowPower *= smoothShadowDist(nearestDist/maxScanDist); + // influence of the depth distance + const float maxDiffDepth = 0.04;//0.15; // because it's nonlinear, it will react differently depending on Z (and your dataset clipping planes's near/far) + float diffDepth = bgDepth-nearestDepth; + diffDepth = diffDepth / maxDiffDepth; + float depthFactor = clamp(diffDepth, 0.0, 1.0); + shadowPower *= (1.0 - depthFactor); +#endif + +#if SHADOWPOWER_METHOD == SHADOWPOWER_METHOD_ESTIM + // [estim solution] + // influence of the distance to the object that cast this shadow (slightly improve but not enough) + //shadowPower *= smoothShadowDist(nearestDist/maxScanDist); + // influence of the depth distance + const float maxDist = 0.4; // in world unit + vec3 bg2dPos = vec3(tex_coord.xy, bgDepth); + vec3 bg3dPos = unproject(bg2dPos, in_inv_proj); + vec3 caster2dPos = vec3(vec2(tex_coord.x+nearestXs, tex_coord.y+nearestYs), nearestDepth); + vec3 caster3dPos = unproject(caster2dPos, in_inv_proj); + float line = abs(caster3dPos.z-bg3dPos.z); + float factorDist = 1.0 - max(0.0, min(1.0, line/maxDist) ); + shadowPower *= factorDist; +#endif + +#if SHADOWPOWER_METHOD == SHADOWPOWER_METHOD_3D + // [3d solution] + // influence of the shadow receiver distance + const float maxDist = 0.25; // in world unit + const float maxDistSqr = maxDist*maxDist; + vec3 bg2dPos = vec3(tex_coord.xy, bgDepth); + vec3 bg3dPos = unproject(bg2dPos, in_inv_proj); + vec3 caster2dPos = vec3(vec2(tex_coord.x+nearestXs, tex_coord.y+nearestYs), nearestDepth); + vec3 caster3dPos = unproject(caster2dPos, in_inv_proj); + vec3 line = caster3dPos-bg3dPos; + float distSqr = line.x*line.x + line.y*line.y + line.z*line.z; + float factorDist = 1.0 - max(0.0, min(1.0, distSqr/maxDistSqr) ); + shadowPower *= factorDist; +#endif + + + + out_color = vec4(0, 0, 0, shadowPower / 1.5); + + // //out_color = vec4(fgZ/10.0, 0, 0, 1.0); + // float nearPlane = 3.23569; + // float farPlane = 17.1543; + // //bgZ = (bg2dPos.z * bg2dPos.w - nearPlane) / (farPlane - nearPlane); + // out_color = vec4(bg2dPos.z/farPlane, 0, 0, 1.0); + //out_color = vec4(bgDepth, 0, 0, 1.0); + //gl_FragDepth = nearestDepth; + + + //gl_FragDepth = bgDepth + constFgAdditionalOffset - 1; + float newDepth = bgDepth;// + constFgAdditionalOffset; + outDepth = (newDepth <= bgDepth)? newDepth : bgDepth; + } + + // if (nearestDist < 1.0) + // { + // out_color = vec4(nearestDepth, 0.0, 0.0, 1.0); + // gl_FragDepth = 0; + // } + } + + // Simulate BLEND function (GL_ONE_MINUS_SRC_ALPHA) + //out_color = vec4(bg.xyz + out_color.xyz/out_color.a, gl_FragDepth); + out_color = vec4(bg.xyz*(1.0 - out_color.a) + out_color.xyz*out_color.a, outDepth); + //gl_FragDepth = outDepth; + //out_color = bg; +} + +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/blur.frag b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/blur.frag new file mode 100644 index 0000000000000000000000000000000000000000..4710e513a3ad7c846c4ba4b80fbac85941319ed0 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/blur.frag @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +layout(location = 0) out vec4 out_color; + +uniform sampler2D image; +uniform vec2 in_image_size; + + +in vec2 tex_coord; + + +void main(void) { + + vec4 color = texture(image, tex_coord); + + const float blurPixelStep = 1.25; + const float blurSizeX = (1.0 / in_image_size.x)*blurPixelStep; + const float blurSizeY = (1.0 / in_image_size.y)*blurPixelStep; + + const int nbVisit = 4; + ivec2 visit[nbVisit] = ivec2 []( + // cross + // ivec2( 0, -1), + // ivec2( 0, 1), + // ivec2( 1, 0), + // ivec2(-1, 0) + + // corner (better, detect more edge) + ivec2(-1, -1), + ivec2(-1, 1), + ivec2( 1, -1), + ivec2( 1, 1) + ); + + vec4 avcolor; + vec4 bgColor = vec4(color.xyz, 0.0); + for (int i = 0; i < nbVisit; ++i) + { + vec4 col = texture( image, + vec2(tex_coord.x + visit[i].x* blurSizeX, tex_coord.y + visit[i].y * blurSizeY) ); + + bgColor = (col.a > bgColor.a)? col : bgColor; + avcolor += col; + } + + avcolor /= float(nbVisit); + + float dColor = abs(avcolor.a - color.a);//length(avcolor - color); + const float maxDColor = 0.015f; + float mixFactor = 1.0 - min(1.0, dColor/maxDColor); + vec4 correction = bgColor;//mix(bgColor, avcolor, mixFactor); + + // [USEFUL FOR DEBUGGING]: show detected edge + //out_color = (dColor > maxDColor)? vec4(1.0, 0.0, 1.0, 1.0) : color; + + out_color = (dColor > maxDColor)? mix(correction, color, 0.5) : color; + + // [USEFUL FOR DEBUGGING]: change nothing + //out_color = color; + +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/colored_mesh.frag b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/colored_mesh.frag new file mode 100644 index 0000000000000000000000000000000000000000..a551ab0e7f38311e6fbe999f1ba49fa537b5e6e7 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/colored_mesh.frag @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +out vec4 out_color; + +in vec3 vertColor; + +void main(void) { + out_color = vec4(vertColor, 1.0); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/colored_mesh.vert b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/colored_mesh.vert new file mode 100644 index 0000000000000000000000000000000000000000..47592f8feba68855a8f2d188cd33266f24669106 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/colored_mesh.vert @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +uniform mat4 MVP; + +layout(location = 0) in vec3 in_vertex; +layout(location = 1) in vec3 in_color; + +out vec3 vertColor; + +void main(void) { + gl_Position = MVP * vec4(in_vertex,1.0); + + vertColor = in_color; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/copy.frag b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/copy.frag new file mode 100644 index 0000000000000000000000000000000000000000..47164cdcf774db525cd3d87ce0a9e8a5e5ab7419 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/copy.frag @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +layout(location = 0) out vec4 out_color; + +uniform sampler2D image; +uniform bool flip = false; + +in vec4 texcoord; + +void main(void) +{ + vec4 color = texture(image, flip ? vec2(texcoord.x, 1.0 - texcoord.y) : texcoord.xy); + out_color = color;//vec4(color.rgb, 1.0); + gl_FragDepth = color.w; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/copy_depth.frag b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/copy_depth.frag new file mode 100644 index 0000000000000000000000000000000000000000..564782f411cf4823cf0213c60f8743c4965a1ff7 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/copy_depth.frag @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +layout(location = 0) out vec4 out_color; + +layout(binding = 0) uniform sampler2D image; + +in vec4 texcoord; + +void main(void) +{ + vec4 color = texture(image, texcoord.xy); + out_color = vec4(vec3(color.r), 1.0); + gl_FragDepth = color.r; + //gl_FragDepth = color.r == 0? 1.0 : color.r; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/depthRenderer.fp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/depthRenderer.fp new file mode 100644 index 0000000000000000000000000000000000000000..9c555cce1b891aac8f3600687fafc80cd2891322 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/depthRenderer.fp @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +out float out_depth; + +void main(void) { + + out_depth = 2.0*gl_FragCoord.z-1.0; + //out_color = fragTexCoord.x*vec4(1.0,0.0,0.0,1.0); +} + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/depthRenderer.vp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/depthRenderer.vp new file mode 100644 index 0000000000000000000000000000000000000000..65c6db061a000407e27e401ae6aee9bc16c3c8a4 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/depthRenderer.vp @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +uniform mat4 MVP; + +layout(location = 0) in vec3 in_vertex; + + +void main(void) { + + gl_Position = MVP * vec4(in_vertex,1.0); + //fragTexCoord = vec2(0.2,0.8); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/emotive_relight.frag b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/emotive_relight.frag new file mode 100644 index 0000000000000000000000000000000000000000..160a2f1eef0ab1a5ac32042df9cc95f5d7ff09f4 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/emotive_relight.frag @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +uniform vec3 lightDir; +uniform vec3 cameraEye; + +layout(binding=0) uniform sampler2D tex; +layout(binding=1) uniform sampler2D smTex; + + +out vec4 out_color; + +in vec2 vertUV; +in float vertAO; +in vec3 VtoF_normal; +in vec3 vertPos; + +float sRGB2LinF(float inF){ + if(inF<0.04045){ + return inF/12.92; + } + else{ + return pow((inF+0.055)/(1.055),2.4); + } +} + +float lin2sRGBF(float inF){ + + if(inF<0.0031308){ + return 12.92*inF; + } + else{ + return 1.055*pow(inF,1.0/2.4)-0.055; + } + +} + +vec4 sRGB2Lin(vec4 inVec){ + return vec4(sRGB2LinF(inVec.x),sRGB2LinF(inVec.y),sRGB2LinF(inVec.z),inVec.w); +} + +vec4 lin2sRGB(vec4 inVec){ + return vec4(lin2sRGBF(inVec.x),lin2sRGBF(inVec.y),lin2sRGBF(inVec.z),inVec.w); +} + +float getFogFactor(float d) +{ + const float FogMax = 70.0; + const float FogMin = 10.0; + + if (d>=FogMax) return 1; + if (d<=FogMin) return 0; + + return 1 - (FogMax - d) / (FogMax - FogMin); +} + + +void main(void) { + vec2 uv = vertUV; + uv.y = 1.0 - uv.y; /// \todo TODO: Why Texture are flipped in y ? + + vec4 sky_color_lin = vec4(0.7,1.0,1.2,1.0)*sRGB2Lin(texture(tex, uv)); + + float shadowVal=texture(smTex,gl_FragCoord.xy/textureSize(smTex,0).xy).x; + + vec4 sun_color_lin = max(0.0,dot(VtoF_normal,lightDir))*shadowVal*sRGB2Lin(texture(tex, uv))/(vertAO+0.0001); + + float d = distance(cameraEye, vertPos); + float alpha = getFogFactor(d); + + vec4 composed_color = lin2sRGB(sun_color_lin+0.1*sky_color_lin); + + out_color = mix(composed_color, vec4(0.5,0.5,0.5,1.0), alpha); +} + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/emotive_relight.vert b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/emotive_relight.vert new file mode 100644 index 0000000000000000000000000000000000000000..10356ef2956ca91d55e2dbd1534096d3f0ae4520 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/emotive_relight.vert @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +uniform mat4 MVP; + +layout(location = 0) in vec3 in_vertex; +layout(location = 1) in vec3 in_ao; +layout(location = 2) in vec2 in_uv; +layout(location = 3) in vec3 in_normal; + +out vec2 vertUV; +out float vertAO; +out vec3 VtoF_normal; +out vec3 vertPos; + +void main(void) { + gl_Position = MVP * vec4(in_vertex,1.0); + + vertUV = in_uv; + vertAO = in_ao.x; + VtoF_normal = in_normal; + vertPos = in_vertex; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/hdrEnvMap.frag b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/hdrEnvMap.frag new file mode 100644 index 0000000000000000000000000000000000000000..d6d39fc522e992f9fdd44e243d18b7693d491696 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/hdrEnvMap.frag @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +uniform sampler2D tex; + +out vec4 out_color; + +in vec2 vertUV; + +float lin2sRGBF(float inF){ + + if(inF<0.0031308){ + return 12.92*inF; + } + else{ + return 1.055*pow(inF,1.0/2.4)-0.055; + } + +} + +vec4 lin2sRGB(vec4 inVec){ + return vec4(lin2sRGBF(inVec.x),lin2sRGBF(inVec.y),lin2sRGBF(inVec.z),inVec.w); +} + +void main(void) { + vec2 uv = vertUV; + uv.y = 1.0 - uv.y; /// \todo TODO: Why Texture are flipped in y ? + out_color = lin2sRGB(texture(tex, uv)); +} \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/hdrEnvMap.vert b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/hdrEnvMap.vert new file mode 100644 index 0000000000000000000000000000000000000000..c8a20d337d4177dd2548296c73d08e2600186d9a --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/hdrEnvMap.vert @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +uniform mat4 MVP; + +layout(location = 0) in vec3 in_vertex; +layout(location = 2) in vec2 in_uv; + +out vec2 vertUV; + +void main(void) { + gl_Position = MVP * vec4(in_vertex,1.0); + + vertUV = in_uv; +} \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/longlat.gp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/longlat.gp new file mode 100755 index 0000000000000000000000000000000000000000..d7b2afd9f96808e3299cd0aa4470e9d91bd469b4 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/longlat.gp @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 450 + +layout(triangles) in; +layout(triangle_strip, max_vertices=6) out; + +layout(location = 1) in vec3 colors_tes[]; +layout(location = 2) in vec2 coordsTex_tes[]; +layout(location = 3) in vec3 normals_tes[]; + +uniform vec3 pos; + +const float PI = 3.1415926535897932384626433832795; + +layout(location = 0) out vec4 position; +layout(location = 1) out vec3 colors_gs; +layout(location = 2) out vec2 coordsTex_gs; +layout(location = 3) out vec3 normals_gs; + +void main() +{ +int i,j; +vec3 toPoint[3]; +vec3 d[3]; +float lat[3]; +float longt[3]; + + +for(i=0; i<3; i++) +{ + toPoint[i] = gl_in[i].gl_Position.xyz-pos; + d[i] = normalize(toPoint[i]); + lat[i] = d[i].z; + longt[i] = atan(d[i].y,d[i].x); + if(longt[i]<0) + longt[i] += 2.0f*PI; +} + + +if((abs(longt[1]-longt[2])PI && abs(longt[i]-longt[(i+2)%3])>PI){ + + float longt_0[3]=longt; + float longt_1[3]=longt; + + if(longt[i]>PI){ + longt_0[i]=longt[i]-2.0f*PI; + longt_1[(i+1)%3]=longt[(i+1)%3]+2.0f*PI; + longt_1[(i+2)%3]=longt[(i+2)%3]+2.0f*PI; + } + else{ + longt_0[i]=longt[i]+2.0f*PI; + longt_1[(i+1)%3]=longt[(i+1)%3]-2.0f*PI; + longt_1[(i+2)%3]=longt[(i+2)%3]-2.0f*PI; + } + + for(j=0; j<3; j++) + { + gl_Position = vec4(longt_0[j]/PI-1.0,-lat[j],length(toPoint[j])/100.0f,1.0f); + position=gl_Position; + colors_gs = colors_tes[i]; + coordsTex_gs = coordsTex_tes[i]; + normals_gs = normals_tes[i]; + EmitVertex(); + } + EndPrimitive(); + + for(j=0; j<3; j++) + { + gl_Position = vec4(longt_1[j]/PI-1.0,-lat[j],length(toPoint[j])/100.0f,1.0f); + position=gl_Position; + colors_gs = colors_tes[i]; + coordsTex_gs = coordsTex_tes[i]; + normals_gs = normals_tes[i]; + EmitVertex(); + } + EndPrimitive(); + break; + } +} + + +} + +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/longlat.tcs b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/longlat.tcs new file mode 100755 index 0000000000000000000000000000000000000000..f4ee63b3740bd8fbd11d1e0ebe62980d489fd380 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/longlat.tcs @@ -0,0 +1,58 @@ +#version 450 core + +uniform vec3 pos; + +const float PI = 3.1415926535897932384626433832795; + +layout(vertices = 3) out; + +layout(location = 1) in vec3 vs_colors[]; +layout(location = 2) in vec2 vs_coordsTex[]; +layout(location = 3) in vec3 vs_normals[]; + +out vec3 colors_tcs []; +out vec2 coordsTex_tcs []; +out vec3 normals_tcs []; + +void main(void) { + +colors_tcs[gl_InvocationID] = vs_colors[gl_InvocationID]; +coordsTex_tcs[gl_InvocationID] = vs_coordsTex[gl_InvocationID]; +normals_tcs[gl_InvocationID] = vs_normals[gl_InvocationID]; + +if (gl_InvocationID == 0) { + int i; + vec3 toPoint[3]; + vec3 d[3]; + float lat[3]; + float longt[3]; + + for(i=0; i<3; i++) + { + toPoint[i] = gl_in[i].gl_Position.xyz-pos; + d[i] = normalize(toPoint[i]); + lat[i] = d[i].z; + longt[i] = atan(d[i].y,d[i].x); + if(longt[i]<0) + longt[i] += 2.0f*PI; + } + + float inner=0; + for(i=0; i<3; i++) + { + float level= 512*sqrt( + pow((longt[(i+1)%3]-longt[(i+2)%3])/PI,2)+ + pow((lat[(i+1)%3]-lat[(i+2)%3]),2) + ); + gl_TessLevelOuter[i] = level; + if(level>inner) + inner=level; + } + + gl_TessLevelInner[0] = inner/2; + +} + +gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position; + +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/longlat.tes b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/longlat.tes new file mode 100755 index 0000000000000000000000000000000000000000..3dd95c3ded0b8f4b22a65b960a73da5e7108660a --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/longlat.tes @@ -0,0 +1,20 @@ +#version 450 core + +layout(triangles, equal_spacing, cw) in; + +layout(location = 1) in vec3 colors_tcs[]; +layout(location = 2) in vec2 coordsTex_tcs[]; +layout(location = 3) in vec3 normals_tcs[]; + +layout(location = 1) out vec3 colors_tes; +layout(location = 2) out vec2 coordsTex_tes; +layout(location = 3) out vec3 normals_tes; + +void main(void) { + colors_tes = colors_tcs[0]; + coordsTex_tes = coordsTex_tcs[0]; + normals_tes = normals_tcs[0]; +vec4 inPos = (gl_TessCoord.x*gl_in[0].gl_Position + gl_TessCoord.y*gl_in[1].gl_Position + gl_TessCoord.z*gl_in[2].gl_Position); + + gl_Position = inPos; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/longlat.vp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/longlat.vp new file mode 100755 index 0000000000000000000000000000000000000000..fe04322efede1eb5944647390e7ff867710e2d2d --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/longlat.vp @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 450 +layout(location = 0) in vec3 inPos; +layout(location = 1) in vec3 inColors; +layout(location = 2) in vec2 inCoordsTex; +layout(location = 3) in vec3 inNormals; + +layout(location = 1) out vec3 vs_colors; +layout(location = 2) out vec2 vs_coordsTex; +layout(location = 3) out vec3 vs_normals; + +void main() +{ + vs_colors= inColors; + vs_coordsTex = inCoordsTex; + vs_normals = inNormals; + gl_Position = vec4(inPos,1.0f); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/longlatColor.fp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/longlatColor.fp new file mode 100755 index 0000000000000000000000000000000000000000..2321ce60e7659ab64b5f47221cced0d3f1b4126e --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/longlatColor.fp @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 450 +layout(location = 0) out vec4 outColor; +layout(location = 0) in vec4 position; +layout(location = 1) in vec3 colors_gs; +layout(location = 2) in vec2 texCoords_gs; +layout(location = 3) in vec3 normals_gs; + +void main() +{ + + if(100.f*position.z<0.001) + discard; + //outColor = vec4(1.f-10.f*position.z, 1.f-10.f*position.z, 1.f-10.f*position.z , 1.0f); + outColor = vec4(colors_gs.x, colors_gs.y, colors_gs.z , 1.0f); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/longlatDepth.fp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/longlatDepth.fp new file mode 100755 index 0000000000000000000000000000000000000000..75d5db24cb161e1fb64c9174d564e31390a4295d --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/longlatDepth.fp @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 450 +layout(location = 0) out vec4 outColor; +layout(location = 0) in vec4 position; +layout(location = 1) in vec3 colors_gs; +layout(location = 2) in vec2 texCoords_gs; +layout(location = 3) in vec3 normals_gs; + +void main() +{ + + if(100.f*position.z<0.001) + discard; + outColor = vec4(1.f-10.f*position.z, 1.f-10.f*position.z, 1.f-10.f*position.z , 1.0f); + //outColor = vec4(colors_gs.x, colors_gs.y, colors_gs.z , 1.0f); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/noproj.vert b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/noproj.vert new file mode 100644 index 0000000000000000000000000000000000000000..453eec2899af0843999ca18232d8c23c4eb2c1ad --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/noproj.vert @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +/** \file ibr.vp + * + * Vertex shader WITHOUT projection and modelview transformations. + */ + +#version 420 + +layout(location = 0) in vec4 in_vertex; /**< Input vertex coordinates */ +layout(location = 1) in vec4 in_texcoord; /**< Input texture coordinates */ +layout(location = 2) in vec4 in_color; /**< Input colour value */ + +out vec4 texcoord; /**< Output texture coordinates */ +out vec4 color; /**< Output color value */ + +void main(void) { + gl_Position = in_vertex; + texcoord = in_texcoord; + color = in_color; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/normalRenderer.fp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/normalRenderer.fp new file mode 100644 index 0000000000000000000000000000000000000000..21a45c9524826679b72e55a73990ca2165d4a29c --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/normalRenderer.fp @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +in vec3 GtoF_normal; +layout(location = 0) out vec4 out_color; + +void main(void) { + + vec3 colorN=(GtoF_normal+1.0)/2.0; + out_color = vec4(colorN,1.0); + //out_color = fragTexCoord.x*vec4(1.0,0.0,0.0,1.0); +} + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/normalRenderer.vp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/normalRenderer.vp new file mode 100644 index 0000000000000000000000000000000000000000..90a0aaea171d3256372d5fbb94f4d05844e8a2fd --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/normalRenderer.vp @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +uniform mat4 MVP; +uniform mat4 M; +uniform mat4 V; +uniform bool imSpaceNormals; + +layout(location = 0) in vec3 in_vertex; +layout(location = 3) in vec3 in_normal; + +out vec3 GtoF_normal; + +void main(void) { + gl_Position = MVP * vec4(in_vertex,1.0); + + if(imSpaceNormals) + GtoF_normal = normalize((inverse(transpose(V*M)) * vec4(in_normal,0.0)).xyz); + else + GtoF_normal = normalize((inverse(transpose(M)) * vec4(in_normal,0.0)).xyz); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/normalRendererGen.gp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/normalRendererGen.gp new file mode 100644 index 0000000000000000000000000000000000000000..07a981dabba9ffa1c26bec3390bc1b65cceb3a7f --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/normalRendererGen.gp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +uniform mat4 MVPinv; + +layout(triangles) in; +layout (triangle_strip) out; +layout (max_vertices = 3) out; + +out vec3 GtoF_normal; + +void main(void) { + + vec3 P0 = (MVPinv *gl_in[0].gl_Position).xyz; + vec3 P1 = (MVPinv *gl_in[1].gl_Position).xyz; + vec3 P2 = (MVPinv *gl_in[2].gl_Position).xyz; + + vec3 V0 = P0 - P1; + vec3 V1 = P2 - P1; + + vec3 N = normalize( cross(V1, V0) ); + + int i; + + for (i = 0; i < gl_in.length(); i++) + { + GtoF_normal = N; // Specs say we need to set again output values after calling EmitVertex + gl_Position = gl_in[i].gl_Position; + EmitVertex(); + } + EndPrimitive(); + +} \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/normalRendererGen.vp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/normalRendererGen.vp new file mode 100644 index 0000000000000000000000000000000000000000..e81091e6361dadd53165b967cb619f56f8f61e99 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/normalRendererGen.vp @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +uniform mat4 MVP; + +layout(location = 0) in vec3 in_vertex; + +void main(void) { + gl_Position = MVP * vec4(in_vertex,1.0); + //fragTexCoord = vec2(0.2,0.8); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/poisson_diverg.frag b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/poisson_diverg.frag new file mode 100644 index 0000000000000000000000000000000000000000..10bc19d574fd5e287d52536d480666194bb64cf1 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/poisson_diverg.frag @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +layout(binding = 0) uniform sampler2D synth; +layout(location= 0) out vec4 out_constraint; + +void main(void) { + vec4 I = texelFetch(synth, ivec2(gl_FragCoord.xy), 0); + + // hole - perform Poisson synthesis here + if (all(lessThan(I.xyz,vec3(0.01)))) + out_constraint = vec4(0); + else + out_constraint = I; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/poisson_interp.frag b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/poisson_interp.frag new file mode 100644 index 0000000000000000000000000000000000000000..dbd6b94952c9ece08b86a2db071fcd242abfa912 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/poisson_interp.frag @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +uniform float scale; + +layout(binding = 0) uniform sampler2D coarse; +layout(binding = 1) uniform sampler2D constraint; +layout(location= 0) out vec4 out_color; + +in vec4 texcoord; + + +void main(void) { + // sample color from lower multigrid level by scaling texture coordinates + vec4 color = texture(coarse,vec2(gl_FragCoord.xy/scale)/textureSize(coarse,0).xy,0); + + // sample Dirichlet constraint without texture filtering because pixel without + // Dirichlet constraint are black and texture filtering may break this check + vec4 cons = texelFetch(constraint,ivec2(gl_FragCoord),0); + + // write color of lower level to output except holes pixels in the constraint + if (any(greaterThan(cons.rgb,vec3(0.01)))) + out_color = cons; + else + out_color = color; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/poisson_jacobi.frag b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/poisson_jacobi.frag new file mode 100644 index 0000000000000000000000000000000000000000..814ad92c3e97517a82b614edf95541ac5a7fc4d6 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/poisson_jacobi.frag @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +uniform vec4 weights; +uniform float scale; + +layout(binding = 0) uniform sampler2D curr_tex; +layout(location= 0) out vec4 out_color; + +void main(void) { + ivec2 coord = ivec2(gl_FragCoord.xy*scale); + + float w_center = weights.x; + float w_edge = weights.y; + float w_corner = weights.z; + float w_c_x_inv= weights.w; + + // Solve the Laplace equation, same as Poisson equation with + // divergence equal to 0 + out_color = + -w_c_x_inv * ( + (texelFetch(curr_tex, coord, 0) * w_center + + (texelFetch(curr_tex, coord+ivec2( 0, 1), 0) + + texelFetch(curr_tex, coord+ivec2( 0,-1), 0) + + texelFetch(curr_tex, coord+ivec2( 1, 0), 0) + + texelFetch(curr_tex, coord+ivec2(-1, 0), 0)) * w_edge + + (texelFetch(curr_tex, coord+ivec2(-1,-1), 0) + + texelFetch(curr_tex, coord+ivec2(-1, 1), 0) + + texelFetch(curr_tex, coord+ivec2( 1,-1), 0) + + texelFetch(curr_tex, coord+ivec2( 1, 1), 0)) * w_corner + ) + ); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/poisson_restrict.frag b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/poisson_restrict.frag new file mode 100644 index 0000000000000000000000000000000000000000..986c0d588e1c9ed723aa24be5a7f02714474b4ba --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/poisson_restrict.frag @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +uniform float scale; + +layout(binding = 0) uniform sampler2D cons; +layout(location= 0) out vec4 out_constraint; + +void main(void) { + mat3 f = mat3( + 0.25, 0.50, 0.25, + 0.50, 1.00, 0.50, + 0.25, 0.50, 0.25); + + vec4 constr = vec4(0); + + float sum = 0; + + ivec2 coord = ivec2(gl_FragCoord.xy*scale); + for (int i=0; i<3; i++) { + for (int j=0; j<3; j++) { + vec4 c = texelFetch(cons,coord+ivec2(i-1,j-1),0); + float a = float(any(greaterThan(c.rgb, vec3(0.01)))); + constr += f[i][j] * a * c; + sum += f[i][j] * a; + } + } + out_constraint = constr / sum; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/positionReflectedDirRenderer.frag b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/positionReflectedDirRenderer.frag new file mode 100644 index 0000000000000000000000000000000000000000..8b2d513e43084e693bdce89765e057414afa51a4 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/positionReflectedDirRenderer.frag @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +in vec3 position; +in vec3 normal; + +uniform vec3 cameraPos; + +layout(location = 0) out vec3 outPosition; +layout(location = 1) out vec3 outDirection; + +void main(void) { + outPosition = position; + outDirection = reflect(normalize(position - cameraPos), normal); +} + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/positionReflectedDirRenderer.vert b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/positionReflectedDirRenderer.vert new file mode 100644 index 0000000000000000000000000000000000000000..175a2bd6707b88ce9ddf76a31dfe7be86163421a --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/positionReflectedDirRenderer.vert @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +uniform mat4 MVP; + +layout(location = 0) in vec3 in_vertex; +layout(location = 3) in vec3 in_normal; + +out vec3 position; +out vec3 normal; + +void main(void) { + gl_Position = MVP * vec4(in_vertex,1.0); + position = in_vertex; + normal = in_normal; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/positionRenderer.frag b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/positionRenderer.frag new file mode 100644 index 0000000000000000000000000000000000000000..e0eecff1f8ee93b7d3181db692313de1d54e7309 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/positionRenderer.frag @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +out vec3 out_position; + +in vec3 position; + +void main(void) { + out_position = position; +} + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/positionRenderer.vert b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/positionRenderer.vert new file mode 100644 index 0000000000000000000000000000000000000000..b16e2db726f7427da8c7a27b7bd3e477c32ec441 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/positionRenderer.vert @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +uniform mat4 MVP; + +layout(location = 0) in vec3 in_vertex; + +out vec3 position; + +void main(void) { + gl_Position = MVP * vec4(in_vertex,1.0); + position = in_vertex; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/shadowMapRenderer.fp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/shadowMapRenderer.fp new file mode 100644 index 0000000000000000000000000000000000000000..a52b4b78ef2f38f88c689274edcb2172013aa78c --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/shadowMapRenderer.fp @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 +const float PI = 3.1415926535897932384626433832795; + +vec2 poissonDisk[64] = vec2[]( +vec2(-0.613392, 0.617481), +vec2(0.170019, -0.040254), +vec2(-0.299417, 0.791925), +vec2(0.645680, 0.493210), +vec2(-0.651784, 0.717887), +vec2(0.421003, 0.027070), +vec2(-0.817194, -0.271096), +vec2(-0.705374, -0.668203), +vec2(0.977050, -0.108615), +vec2(0.063326, 0.142369), +vec2(0.203528, 0.214331), +vec2(-0.667531, 0.326090), +vec2(-0.098422, -0.295755), +vec2(-0.885922, 0.215369), +vec2(0.566637, 0.605213), +vec2(0.039766, -0.396100), +vec2(0.751946, 0.453352), +vec2(0.078707, -0.715323), +vec2(-0.075838, -0.529344), +vec2(0.724479, -0.580798), +vec2(0.222999, -0.215125), +vec2(-0.467574, -0.405438), +vec2(-0.248268, -0.814753), +vec2(0.354411, -0.887570), +vec2(0.175817, 0.382366), +vec2(0.487472, -0.063082), +vec2(-0.084078, 0.898312), +vec2(0.488876, -0.783441), +vec2(0.470016, 0.217933), +vec2(-0.696890, -0.549791), +vec2(-0.149693, 0.605762), +vec2(0.034211, 0.979980), +vec2(0.503098, -0.308878), +vec2(-0.016205, -0.872921), +vec2(0.385784, -0.393902), +vec2(-0.146886, -0.859249), +vec2(0.643361, 0.164098), +vec2(0.634388, -0.049471), +vec2(-0.688894, 0.007843), +vec2(0.464034, -0.188818), +vec2(-0.440840, 0.137486), +vec2(0.364483, 0.511704), +vec2(0.034028, 0.325968), +vec2(0.099094, -0.308023), +vec2(0.693960, -0.366253), +vec2(0.678884, -0.204688), +vec2(0.001801, 0.780328), +vec2(0.145177, -0.898984), +vec2(0.062655, -0.611866), +vec2(0.315226, -0.604297), +vec2(-0.780145, 0.486251), +vec2(-0.371868, 0.882138), +vec2(0.200476, 0.494430), +vec2(-0.494552, -0.711051), +vec2(0.612476, 0.705252), +vec2(-0.578845, -0.768792), +vec2(-0.772454, -0.090976), +vec2(0.504440, 0.372295), +vec2(0.155736, 0.065157), +vec2(0.391522, 0.849605), +vec2(-0.620106, -0.328104), +vec2(0.789239, -0.419965), +vec2(-0.545396, 0.538133), +vec2(-0.178564, -0.596057) +); + +uniform vec3 lightDir; +uniform float sun_app_radius; +uniform mat4 depthMapMVPinv; +uniform float depthMapRadius; +uniform float biasControl; + +layout(binding=0) uniform sampler2D depthMap; + +in vec4 depthMapProj; +in vec3 VtoF_normal; +in vec3 VtoF_pos; + +out float out_val; + +void main(void) { + + vec2 texc = (depthMapProj.xy + 1.0) / 2.0; + + float depthImSpace = depthMapProj.z; + + float cosTheta = clamp(dot(VtoF_normal,lightDir),0.0,1.0); + float bias = biasControl*tan(acos(cosTheta)); + bias = clamp(bias, 0.0, 5*biasControl); + + int textureWidth = textureSize(depthMap,0).x; + + // Compute the size of the shadow transition + + // The 2 account for the fact that we are treating the radius. + + int r_blocker = int(ceil(0.5*tan(sun_app_radius*PI/180.0)*textureWidth)); + float mean_blocker_val = 0.0; + float blocker_num_val = 0.0; + float sum_weight = 0.0; + + for(int i = 0; i<7 ; i++){ + + float theta_rot=i; + mat2 rotation_poisson =mat2(cos(theta_rot), sin(theta_rot), -sin(theta_rot), cos(theta_rot)); + + for(int k = 0; k <64 ; k++){ + + float pixDist = length(r_blocker*poissonDisk[k]/textureWidth); + if(pixDist<=r_blocker){ + float depthMapVal = texture(depthMap, texc + r_blocker*rotation_poisson*poissonDisk[k]/textureWidth).x; + + float bias_with_dist = bias*(pixDist+1.0); + + if( depthImSpace-bias_with_dist > depthMapVal ){ + + vec3 blocker_pos=(depthMapMVPinv*vec4(depthMapProj.x,depthMapProj.y,depthMapVal,1.0)).xyz; + + float weight = 0.01+exp(-pow(pixDist/(0.02*r_blocker),2.0)); + mean_blocker_val += weight*length(VtoF_pos-blocker_pos); + sum_weight += weight; + blocker_num_val += 1.0; + } + } + } + } + + if( dot(VtoF_normal,lightDir) <= -0.017 ){ + out_val = 0.0; + } + else if(blocker_num_val < 1.0){ + out_val = 1.0; + } + else{ + + float d_blocker_receiver = mean_blocker_val/sum_weight; + + float wShadow=2*d_blocker_receiver*tan(sun_app_radius*PI/180.0); + //float angleCompensation= dot(normalize(VtoF_normal),normalize(lightDir)); + //float wShadowAngle = wShadow/angleCompensation; + float ratioShadowTexture = wShadow/(2.0*depthMapRadius); + float pixelShadowTexture = ratioShadowTexture*textureWidth; + + const int r = int(ceil(pixelShadowTexture)); + + float num_val = 0.0; + float sum_val = 0.0; + + for(int i = 0; i<14 ; i++){ + + float theta_rot=float(i); + mat2 rotation_poisson =mat2(cos(theta_rot), sin(theta_rot), -sin(theta_rot), cos(theta_rot)); + + for(int k = 0; k <64 ; k++){ + + float depthMapVal = texture(depthMap, texc + r*rotation_poisson*poissonDisk[k]/textureWidth).x; + float pixDist = length(r*poissonDisk[k]/textureWidth); + float bias_with_dist = bias*(pixDist+1.0); + + if( depthImSpace-bias_with_dist > depthMapVal ){ + sum_val += 0.0; + } + else{ + sum_val += 1.0; + } + num_val +=1.0; + } + } + + out_val = sum_val/num_val; + } + +} + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/shadowMapRenderer.vp b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/shadowMapRenderer.vp new file mode 100644 index 0000000000000000000000000000000000000000..a816a358e21ba0602f93fa4e8072297b9e7025cb --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/shadowMapRenderer.vp @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +uniform mat4 MVP; +uniform mat4 depthMapMVP; + +layout(location = 0) in vec3 in_vertex; +layout(location = 3) in vec3 in_normal; + +out vec4 depthMapProj; +out vec3 VtoF_normal; +out vec3 VtoF_pos; + +void main(void) { + + gl_Position = MVP * vec4(in_vertex,1.0); + + depthMapProj = depthMapMVP * vec4(in_vertex,1.0); + + VtoF_normal = in_normal; + VtoF_pos = in_vertex; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/texture-invert.frag b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/texture-invert.frag new file mode 100644 index 0000000000000000000000000000000000000000..2ed2b52f131858f187f6c1dc3e44f6f81fb7dfdd --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/texture-invert.frag @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +layout(binding = 0) uniform sampler2D tex; +layout(location= 0) out vec4 out_color; + +in vec2 tex_coord; + +void main(void) { + vec2 texcoord = tex_coord ; + out_color = vec4(1, 1, 1, 1) - texture(tex,texcoord); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/texture.frag b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/texture.frag new file mode 100644 index 0000000000000000000000000000000000000000..ee57f7b8ca7c033aae5811f66d9df4732b1f1b3e --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/texture.frag @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +layout(binding = 0) uniform sampler2D tex; +layout(location= 0) out vec4 out_color; + +in vec2 tex_coord; + +void main(void) { + vec2 texcoord = tex_coord ; + out_color = texture(tex,texcoord); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/texture.vert b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/texture.vert new file mode 100644 index 0000000000000000000000000000000000000000..e58522417fee84e3254893804b61362129fbcf04 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/texture.vert @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +#define VERTICAL_FLIP (0) + +layout(location = 0) in vec2 in_vertex; +layout(location = 1) in vec2 in_texcoord; + + +out vec2 tex_coord; + +void main(void) { + gl_Position = vec4(in_vertex, 0.0, 1.0); + tex_coord.x = in_texcoord.x; + if (VERTICAL_FLIP==1) { + tex_coord.y = 1.0 - in_texcoord.y; + } + else { + tex_coord.y = in_texcoord.y; + } +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/textured_mesh.frag b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/textured_mesh.frag new file mode 100644 index 0000000000000000000000000000000000000000..84fd8d2424dcd3c6624c207bb5a2c470e4cba693 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/textured_mesh.frag @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +uniform sampler2D tex; + +out vec4 out_color; + +in vec2 vertUV; + +void main(void) { + vec2 uv = vertUV; + if(uv.x==0.0 && uv.y==0.0){ + out_color = vec4(1.0,1.0,1.0,1.0); + } + else{ + uv.y = 1.0 - uv.y; /// \todo TODO: Why Texture are flipped in y ? + out_color = texture(tex, uv); + } +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/textured_mesh.vert b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/textured_mesh.vert new file mode 100644 index 0000000000000000000000000000000000000000..8a7dccc29f4ebcb666a218c4e8b3bd432a01e2f9 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/textured_mesh.vert @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +uniform mat4 MVP; + +layout(location = 0) in vec3 in_vertex; +layout(location = 2) in vec2 in_uv; + +out vec2 vertUV; + +void main(void) { + gl_Position = MVP * vec4(in_vertex,1.0); + + vertUV = in_uv; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/textured_mesh_flipY.vert b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/textured_mesh_flipY.vert new file mode 100755 index 0000000000000000000000000000000000000000..f4a47b79cdb91b1cab2e4e8bb1ebdc976c76c803 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/shaders/textured_mesh_flipY.vert @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +uniform mat4 MVP; + +layout(location = 0) in vec3 in_vertex; +layout(location = 2) in vec2 in_uv; + +out vec2 vertUV; + +void main(void) { + gl_Position = MVP * vec4(in_vertex,1.0); + vec2 uv = in_uv; + uv.y = 1.0 - uv.y ; + vertUV = uv; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/sibr_renderer.dox b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/sibr_renderer.dox new file mode 100644 index 0000000000000000000000000000000000000000..ee1fe1e0400ee3da4edf4415dc98834b8fe0f9d7 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/renderer/sibr_renderer.dox @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +/*! + \defgroup sibr_renderer sibr_renderer + + \brief Renderer utilities. + +*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/BasicIBRScene.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/BasicIBRScene.cpp new file mode 100644 index 0000000000000000000000000000000000000000..291c574007ea50368fd68b8377278bbb21201f37 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/BasicIBRScene.cpp @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "BasicIBRScene.hpp" +#include +#include + +#include "core/scene/CalibratedCameras.hpp" +#include "core/scene/ParseData.hpp" +#include "core/scene/ProxyMesh.hpp" +#include "core/scene/InputImages.hpp" + +namespace sibr +{ + + BasicIBRScene::BasicIBRScene() { + _data.reset(new ParseData()); + _cams.reset(new CalibratedCameras()); + _imgs.reset(new InputImages()); + _proxies.reset(new ProxyMesh()); + _renderTargets.reset(new RenderTargetTextures()); + } + + BasicIBRScene::BasicIBRScene(const BasicIBRAppArgs & myArgs, bool noRTs, bool noMesh) + { + + BasicIBRScene(); + // parse metadata file + _data.reset(new ParseData()); + _currentOpts.renderTargets = !noRTs; + _currentOpts.mesh = !noMesh; + + _data->getParsedData(myArgs); + std::cout << "Number of input Images to read: " << _data->imgInfos().size() << std::endl; + + if (_data->imgInfos().size() != _data->numCameras()) + SIBR_ERR << "List Image file size do not match number of input cameras in Bundle file!" << std::endl; + + if (_data->datasetType() != IParseData::Type::EMPTY) { + createFromData(myArgs.texture_width); + } + } + + BasicIBRScene::BasicIBRScene(const BasicIBRAppArgs& myArgs, SceneOptions myOpts) + { + BasicIBRScene(); + _currentOpts = myOpts; + + // parse metadata file + _data.reset(new ParseData()); + + + _data->getParsedData(myArgs); + std::cout << "Number of input Images to read: " << _data->imgInfos().size() << std::endl; + + if (_data->imgInfos().size() != _data->numCameras()) + SIBR_ERR << "List Image file size do not match number of input cameras in Bundle file!" << std::endl; + + if (_data->datasetType() != IParseData::Type::EMPTY) { + createFromData(myArgs.texture_width); + } + } + + void BasicIBRScene::createFromCustomData(const IParseData::Ptr & data, const uint width, BasicIBRScene::SceneOptions myOpts) + { + _data = data; + _currentOpts = myOpts; + createFromData(width); + } + + + void BasicIBRScene::createRenderTargets() + { + _renderTargets->initializeDefaultRenderTargets(_cams, _imgs, _proxies); + } + + BasicIBRScene::BasicIBRScene(BasicIBRScene & scene) + { + _data = scene.data(); + _cams = scene.cameras(); + _imgs = scene.images(); + _proxies = scene.proxies(); + _renderTargets = scene.renderTargets(); + } + + void BasicIBRScene::createFromData(const uint width) + { + _cams.reset(new CalibratedCameras()); + _imgs.reset(new InputImages()); + _proxies.reset(new ProxyMesh()); + + // setup calibrated cameras + if (_currentOpts.cameras) { + + _cams->setupFromData(_data); + + std::cout << "Number of Cameras set up: " << _cams->inputCameras().size() << std::endl; + } + + // load input images + + uint mwidth = width; + if (_currentOpts.images) { + _imgs->loadFromData(_data); + std::cout << "Number of Images loaded: " << _imgs->inputImages().size() << std::endl; + + if (width == 0) {// default + if (_imgs->inputImages()[0]->w() > 1920) { + SIBR_LOG << "Limiting width to 1920 for performance; use --texture-width to override" << std::endl; + mwidth = 1920; + } + } + } + _renderTargets.reset(new RenderTargetTextures(mwidth)); + + if (_currentOpts.mesh) { + // load proxy + _proxies->loadFromData(_data); + + + std::vector inCams = _cams->inputCameras(); + float eps = 0.1f; + if (inCams.size() > 0 && (abs(inCams[0]->znear() - 0.1) < eps || abs(inCams[0]->zfar() - 1000.0) < eps || abs(inCams[0]->zfar() - 100.0) < eps) && _proxies->proxy().triangles().size() > 0) { + std::vector nearsFars; + CameraRaycaster::computeClippingPlanes(_proxies->proxy(), inCams, nearsFars); + _cams->updateNearsFars(nearsFars); + } + + //// Load the texture. + sibr::ImageRGB inputTextureImg; + + std::string texturePath, textureImageFileName; + + // Assumes that the texture is stored next to the mesh in the same directory + // This information comes from Assimp and the mtl file if available + if ((textureImageFileName = _proxies->proxy().getTextureImageFileName()) != "") { + texturePath = sibr::parentDirectory(_data->meshPath()) + "/" + textureImageFileName; + // check if full path given + if (!sibr::fileExists(texturePath) && sibr::fileExists(textureImageFileName)) + texturePath = textureImageFileName; + } + else { + texturePath = sibr::parentDirectory(_data->meshPath()) + "/mesh_u1_v1.png"; + if (sibr::fileExists(texturePath)) { + texturePath = sibr::parentDirectory(_data->meshPath()) + "/textured_u1_v1.png"; + if (!sibr::fileExists(texturePath)) + texturePath = sibr::parentDirectory(_data->meshPath()) + "/texture.png"; + } + } + + + if (_currentOpts.texture && sibr::fileExists(texturePath)) { + inputTextureImg.load(texturePath); + _inputMeshTexture.reset(new sibr::Texture2DRGB(inputTextureImg, SIBR_GPU_LINEAR_SAMPLING)); + } + + } + + if (_currentOpts.renderTargets) { + createRenderTargets(); + } + } + +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/BasicIBRScene.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/BasicIBRScene.hpp new file mode 100644 index 0000000000000000000000000000000000000000..035607b54bdafd4ac0a97223a18a4a9d29a925d8 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/BasicIBRScene.hpp @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include + +namespace sibr { + + /** + * Class used to define a basic IBR Scene + * containing multiple components required to define a scene. + * + * \ingroup sibr_scene + */ + class SIBR_SCENE_EXPORT BasicIBRScene: public IIBRScene + { + + public: + + /** + * \brief Pointer to the instance of class sibr::BasicIBRScene. + */ + SIBR_CLASS_PTR(BasicIBRScene); + + /** + * \brief Default constructor to create a BasicIBRScene. + */ + BasicIBRScene(); + + /** + * \brief Constructor to create a BasicIBRScene given command line arguments. + * The scene may be created using either dataset path, or explicitly specifying individual componenets. + * \param myArgs to provide all command line arguments containing path to specific components. + * \param noRTs to specify whether to initialize render target textures or not. + * \param noMesh skip loading the mesh + */ + BasicIBRScene(const BasicIBRAppArgs & myArgs, bool noRTs, bool noMesh = false); + + /** + * \brief Constructor to create a BasicIBRScene given command line arguments. + * The scene may be created using either dataset path, or explicitly specifying individual componenets. + * \param myArgs to provide all command line arguments containing path to specific components. + * \param myOpts to specify initialization paramters for the scene. + */ + BasicIBRScene(const BasicIBRAppArgs& myArgs, SceneOptions myOpts = SceneOptions()); + + + /** Destructor. */ + ~BasicIBRScene() {}; + + /** + * \brief Creates a BasicIBRScene given custom data argument. + * The scene will be created using the custom data (cameras/images/proxies/textures etc.) provided. + * \param data to provide data instance holding customized components. + * \param width the constrained width for GPU texture data. + * \param myOpts to specify whether to initialize specific parts of the scene (RTs, geometry,...) + */ + void createFromCustomData(const IParseData::Ptr & data, const uint width = 0, SceneOptions myOpts = SceneOptions()) override; + + /** + * \brief Function to create a scene directly using the dataset path specified in command-line. + */ + void createFromDatasetPath() {}; + + /** + * \brief Function to generate render targets using the _data (regarding cameras, images, proxies ) parsed from metadata file. + */ + void createRenderTargets() override; + + /** + * \brief Getter for the pointer holding the data related to the scene. + * + */ + const IParseData::Ptr data(void) const override; + + /** + * \brief Setter for the pointer holding the data related to the scene for scene creation. + * \param data the setup data + */ + void data(const sibr::IParseData::Ptr & data) override; + + + /** + * \brief Getter for the pointer holding cameras related to each input iamge of the scene. + * + */ + const ICalibratedCameras::Ptr cameras(void) const override; + + /** + * \brief Getter for the pointer holding the input images to the scene. + * + */ + const IInputImages::Ptr images(void) const override; + + /** + * \brief Getter for the pointer holding the proxies required by the scene. + * + */ + const IProxyMesh::Ptr proxies(void) const override; + + /** + * \brief Getter for the pointer holding the render targets textures related to the scene. + * + */ + const RenderTargetTextures::Ptr & renderTargets(void) const override; + + /** + * \brief Getter for the pointer holding the render targets textures related to the scene. + * + */ + RenderTargetTextures::Ptr & renderTargets(void) override; + + /** + * \brief Getter for the pointer holding the mesh textures related to the mesh loaded for the scene. + * + */ + Texture2DRGB::Ptr & inputMeshTextures(void) override; + + protected: + BasicIBRScene(BasicIBRScene & scene); + BasicIBRScene& operator =(const BasicIBRScene&) = delete; + + IParseData::Ptr _data; + ICalibratedCameras::Ptr _cams; + IInputImages::Ptr _imgs; + IProxyMesh::Ptr _proxies; + Texture2DRGB::Ptr _inputMeshTexture; + RenderTargetTextures::Ptr _renderTargets; + SceneOptions _currentOpts; + + /** + * \brief Creates a BasicIBRScene from the internal stored data component in the scene. + * The data could be populated either from dataset path or customized by the user externally. + * \param width the constrained width for GPU texture data. + */ + void createFromData(const uint width = 0); + + + }; + + ///// INLINE DEFINITIONS ///// + + inline const IParseData::Ptr BasicIBRScene::data(void) const + { + return _data; + } + + inline void BasicIBRScene::data(const IParseData::Ptr & data) + { + _data = data; + } + + inline const ICalibratedCameras::Ptr BasicIBRScene::cameras(void) const + { + return _cams; + } + + inline const IInputImages::Ptr BasicIBRScene::images(void) const + { + return _imgs; + } + + inline const IProxyMesh::Ptr BasicIBRScene::proxies(void) const + { + return _proxies; + } + + inline const RenderTargetTextures::Ptr & BasicIBRScene::renderTargets(void) const + { + return _renderTargets; + } + + inline RenderTargetTextures::Ptr & BasicIBRScene::renderTargets(void) + { + return _renderTargets; + } + + inline Texture2DRGB::Ptr & BasicIBRScene::inputMeshTextures(void) + { + return _inputMeshTexture; + } + +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/CMakeLists.txt b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..a3a1f5fa969dfa7071e98a11e4f403ef7cb8e7b5 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/CMakeLists.txt @@ -0,0 +1,41 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +project(sibr_scene) + +file(GLOB SOURCES "*.cpp" "*.h" "*.hpp") +source_group("Source Files" FILES ${SOURCES}) + + +## Specify target rules +add_library(${PROJECT_NAME} SHARED ${SOURCES}) + +include_directories(${Boost_INCLUDE_DIRS}) +target_link_libraries(${PROJECT_NAME} + ${Boost_LIBRARIES} + ${ASSIMP_LIBRARIES} + ${GLEW_LIBRARIES} + ${OPENGL_LIBRARIES} + ${OpenCV_LIBRARIES} + OpenMP::OpenMP_CXX + sibr_assets + sibr_graphics + sibr_raycaster +) + +add_definitions( -DSIBR_SCENE_EXPORTS -DBOOST_ALL_DYN_LINK ) + +set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER ${SIBR_FOLDER}) + +## High level macro to install in an homogen way all our ibr targets +include(install_runtime) +ibr_install_target(${PROJECT_NAME} + INSTALL_PDB ## mean install also MSVC IDE *.pdb file (DEST according to target type) +) diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/CalibratedCameras.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/CalibratedCameras.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2dbe9585e908494946a22058a0e722b1f407b93f --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/CalibratedCameras.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "CalibratedCameras.hpp" + +namespace sibr { + void CalibratedCameras::setupFromData(const sibr::IParseData::Ptr& data) + { + + + _inputCameras.resize(data->numCameras()); + _inputCameras = data->cameras(); + return; + } + + void CalibratedCameras::debugFlagCameraAsUsed(const std::vector& selectedCameras) + { + // Used for Debugging -- Display colored cameras in TopView + std::vector cameraUsed(inputCameras().size(), false); + for (uint usedID : selectedCameras) + cameraUsed[usedID] = true; + usedCameraForRendering(cameraUsed); + + } + + const void CalibratedCameras::updateNearsFars(std::vector & nearsFars) + { + if (_inputCameras.size() != nearsFars.size()) + SIBR_ERR << "InputCamera size does not match Clipping Planes size!" << std::endl; + + for (int c = 0; c < _inputCameras.size(); c++){ + _inputCameras[c]->znear(nearsFars[c].x()); + _inputCameras[c]->zfar(nearsFars[c].y()); + } + } + + + + +} \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/CalibratedCameras.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/CalibratedCameras.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9aa9e7affedcff33b8a40dd4d1420712f0bcad9c --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/CalibratedCameras.hpp @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once +# include "core/scene/ICalibratedCameras.hpp" +#include "core/scene/Config.hpp" + +namespace sibr +{ + /** + \ingroup sibr_scene + */ + class SIBR_SCENE_EXPORT CalibratedCameras : public ICalibratedCameras { + public: + + /** + * \brief Pointer to the instance of class sibr::CalibratedCameras. + */ + typedef std::shared_ptr Ptr; + + // load from a path on disk in a predefined format (or could detect from file extension) + + /** + * \brief Creates the calibrated cameras for a scene given data parsed from dataset path. + * + * \param data Holds all information required to created a set of calibrated cameras + */ + void setupFromData(const IParseData::Ptr & data) override; + + /** + * \brief Assigns the calibrated cameras for a scene to a list of cameras passed as parameter. + * + * \param cams Vector of type sibr::InputCamera to which the scene inputCameras will be set + */ + void setupCamerasFromExisting(const std::vector & cams) override; + + /** + * \brief Function to set a camera as active. + * + * \param camId Integer ID of the camera to be set active + */ + void activateCamera(uint camId) override; + + /** + * \brief Function to set a camera as inactive. + * + * \param camId Integer ID of the camera to be set inactive + */ + void deactivateCamera(uint camId) override; + + /** + * \brief Function to mark the cameras used for rendering. + * Generally used for debugging purposes + * \param selectedCameras list of camera IDs that are used for rendering + */ + void debugFlagCameraAsUsed(const std::vector& selectedCameras) override; + + /** + * \brief Function to check if the camera is used for rendering. + * + * \param camId Integer ID of the cameras to be checked if it is being used for rendering + * \return true if used for rendering + */ + bool isCameraUsedForRendering(size_t camId) const override; + + /** + * \brief Function to set the cameras used for rendering. + * + * \param usedCamera Vector to specify which cameras are used for rendering + */ + void usedCameraForRendering(const std::vector usedCamera) override; + + /** + * \brief Getter to the vector of input cameras used to create the scene + * + */ + const std::vector& inputCameras(void) const override; + + const void updateNearsFars(std::vector & nearsFars) override; + + protected: + std::vector _inputCameras; + std::vector _usedCameraFlag; + + }; + + ///// INLINE DEFINITIONS ///// + + inline void CalibratedCameras::setupCamerasFromExisting(const std::vector& cams) + { + _inputCameras = cams; + } + + inline const std::vector& CalibratedCameras::inputCameras( void ) const { + return _inputCameras; + } + + inline void CalibratedCameras::activateCamera(uint camId) + { + _inputCameras[camId]->setActive(true); + } + + inline void CalibratedCameras::deactivateCamera(uint camId) + { + _inputCameras[camId]->setActive(false); + } + + inline bool CalibratedCameras::isCameraUsedForRendering(size_t camId) const + { + return (_usedCameraFlag.empty()) ? false : _usedCameraFlag[camId]; + } + + inline void CalibratedCameras::usedCameraForRendering(const std::vector usedCamera) + { + _usedCameraFlag = usedCamera; + } +} \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/Config.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/Config.hpp new file mode 100644 index 0000000000000000000000000000000000000000..32042781dbeca7aa787a5977282c2c090d93406f --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/Config.hpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include "core/graphics/Config.hpp" +# include + + +#ifdef SIBR_OS_WINDOWS +//// Export Macro (used for creating DLLs) //// +# ifdef SIBR_STATIC_DEFINE +# define SIBR_EXPORT +# define SIBR_NO_EXPORT +# else +# ifndef SIBR_SCENE_EXPORT +# ifdef SIBR_SCENE_EXPORTS + /* We are building this library */ +# define SIBR_SCENE_EXPORT __declspec(dllexport) +# else + /* We are using this library */ +# define SIBR_SCENE_EXPORT __declspec(dllimport) +# endif +# endif +# ifndef SIBR_NO_EXPORT +# define SIBR_NO_EXPORT +# endif +# endif +# else +# define SIBR_SCENE_EXPORT +# endif + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/ICalibratedCameras.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/ICalibratedCameras.hpp new file mode 100644 index 0000000000000000000000000000000000000000..90245bb09fc31918ad5f6ade8672d89a3ee665f9 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/ICalibratedCameras.hpp @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once +# include "core/scene/IParseData.hpp" +#include "core/scene/Config.hpp" + +namespace sibr +{ + /** + \ingroup sibr_scene + */ + class SIBR_SCENE_EXPORT ICalibratedCameras { + public: + + /** + * \brief Pointer to the instance of class sibr::CalibratedCameras. + */ + typedef std::shared_ptr Ptr; + + // load from a path on disk in a predefined format (or could detect from file extension) + + /** + * \brief Creates the calibrated cameras for a scene given data parsed from dataset path. + * + * \param data Holds all information required to created a set of calibrated cameras + */ + virtual void setupFromData(const IParseData::Ptr & data) = 0; + + /** + * \brief Assigns the calibrated cameras for a scene to a list of cameras passed as parameter. + * + * \param cams Vector of type sibr::InputCamera to which the scene inputCameras will be set + */ + virtual void setupCamerasFromExisting(const std::vector & cams) = 0; + + /** + * \brief Function to set a camera as active. + * + * \param camId Integer ID of the camera to be set active + */ + virtual void activateCamera(uint camId) = 0; + + /** + * \brief Function to set a camera as inactive. + * + * \param camId Integer ID of the camera to be set inactive + */ + virtual void deactivateCamera(uint camId) = 0; + + /** + * \brief Function to mark the cameras used for rendering. + * Generally used for debugging purposes + * \param selectedCameras list of camera IDs that are used for rendering + */ + virtual void debugFlagCameraAsUsed(const std::vector& selectedCameras) = 0; + + /** + * \brief Function to check if the camera is used for rendering. + * + * \param camId Integer ID of the cameras to be checked if it is being used for rendering + * \return true if used for rendering + */ + virtual bool isCameraUsedForRendering(size_t camId) const = 0; + + /** + * \brief Function to set the cameras used for rendering. + * + * \param usedCamera Vector to specify which cameras are used for rendering + */ + virtual void usedCameraForRendering(const std::vector usedCamera) = 0; + + /** + * \brief Getter to the vector of input cameras used to create the scene + * + */ + virtual const std::vector& inputCameras(void) const = 0; + + + virtual const void updateNearsFars(std::vector & nearsFars) = 0; + + }; +} \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/IIBRScene.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/IIBRScene.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5ac9a5d8e8bb30850ce5692d56514eb462cd3120 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/IIBRScene.hpp @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include +#include "core/raycaster/CameraRaycaster.hpp" +#include "core/scene/ICalibratedCameras.hpp" +#include "core/scene/IParseData.hpp" +#include "core/scene/IProxyMesh.hpp" +#include "core/scene/IInputImages.hpp" +#include "core/scene/RenderTargetTextures.hpp" +#include "core/scene/Config.hpp" +#include "core/system/String.hpp" + +namespace sibr { + + /** + * Interface used to define how an IBR Scene is shaped + * containing multiple components required to define a scene. + * + * Members: + * - ICalibratedCameras + * - IInputImages + * - IProxyMesh + * - RenderTargetTextures + * + * \ingroup sibr_scene + */ + class SIBR_SCENE_EXPORT IIBRScene + { + + /** + * \brief Pointer to the instance of class sibr::IIBRScene. + */ + SIBR_CLASS_PTR(IIBRScene); + + public: + /** Scene initialization infos. */ + struct SceneOptions + { + bool renderTargets = true; ///< Load rendertargets? + bool mesh = true; ///< Load mesh? + bool images = true; ///< Load images? + bool cameras = true; ///< Load cameras? + bool texture = true; ///< Load texture ? + + SceneOptions() {} + }; + + /** + * \brief Creates a BasicIBRScene given custom data argument. + * The scene will be created using the custom data (cameras/images/proxies/textures etc.) provided. + * \param data to provide data instance holding customized components. + * \param width the constrained width for GPU texture data. + * \param myOpts to specify whether to initialize specific parts of the scene (RTs, geometry,...) + */ + virtual void createFromCustomData(const IParseData::Ptr & data, const uint width = 0, SceneOptions myOpts = SceneOptions()) = 0; + + /** + * \brief Function to create a scene directly using the dataset path specified in command-line. + */ + virtual void createFromDatasetPath() = 0; + + /** + * \brief Function to generate render targets using the _data (regarding cameras, images, proxies ) parsed from metadata file. + */ + virtual void createRenderTargets() = 0; + + + /** + * \brief Getter for the pointer holding the data related to the scene. + * + */ + virtual const IParseData::Ptr data(void) const = 0; + + /** + * \brief Setter for the pointer holding the data related to the scene for scene creation. + * \param data the setup data + */ + virtual void data(const sibr::IParseData::Ptr & data) = 0; + + + /** + * \brief Getter for the pointer holding cameras related to each input iamge of the scene. + * + */ + virtual const ICalibratedCameras::Ptr cameras(void) const = 0; + + /** + * \brief Getter for the pointer holding the input images to the scene. + * + */ + virtual const IInputImages::Ptr images(void) const = 0; + + /** + * \brief Getter for the pointer holding the proxies required by the scene. + * + */ + virtual const IProxyMesh::Ptr proxies(void) const = 0; + + /** + * \brief Getter for the pointer holding the render targets textures related to the scene. + * + */ + virtual const RenderTargetTextures::Ptr & renderTargets(void) const = 0; + + /** + * \brief Getter for the pointer holding the render targets textures related to the scene. + * + */ + virtual RenderTargetTextures::Ptr & renderTargets(void) = 0; + + /** + * \brief Getter for the pointer holding the mesh textures related to the mesh loaded for the scene. + * + */ + virtual Texture2DRGB::Ptr & inputMeshTextures(void) = 0; + + }; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/IInputImages.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/IInputImages.hpp new file mode 100644 index 0000000000000000000000000000000000000000..95d19fa0dfeeed9c943ba262b6a8e4fdf9f8ab2c --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/IInputImages.hpp @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include "core/scene/Config.hpp" +#include "core/scene/IParseData.hpp" + +namespace sibr +{ + /** + \ingroup sibr_scene + */ + class SIBR_SCENE_EXPORT IInputImages { + SIBR_DISALLOW_COPY(IInputImages); + public: + + + typedef std::shared_ptr Ptr; + + virtual void loadFromData(const IParseData::Ptr & data) = 0; + virtual void loadFromExisting(const std::vector & imgs) = 0; + virtual void loadFromExisting(const std::vector & imgs) = 0; + virtual void loadFromPath(const IParseData::Ptr & data, const std::string & prefix, const std::string & postfix) = 0; + + // Alpha blend and modify input images -- for fences + virtual void alphaBlendInputImages(const std::vector& back, std::vector& alphas) = 0; + + virtual const std::vector& inputImages(void) const = 0; + virtual const sibr::ImageRGB& image(uint i) = 0; + + protected: + IInputImages() {}; + + }; + +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/IParseData.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/IParseData.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ca8f2024796edf58004a8345885d6874437edf13 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/IParseData.hpp @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once +#include "picojson/picojson.hpp" +#include "core/scene/Config.hpp" +#include "core/system/CommandLineArgs.hpp" +# +#include "core/system/Matrix.hpp" +#include "core/assets/ImageListFile.hpp" +#include "core/assets/InputCamera.hpp" + + +#include +#include +#include + + +namespace sibr{ + + /** + * Interface used to store the data required for defining an IBR Scene + * + * + * Members: + * - _basePathName: Base dataset directory path. + * - _camInfos: Vector of sibr::InputCamera holding all data attached with the scene cameras. + * - _meshPath: Filepath of the mesh associated to the scene. + * - _imgInfos: Vector of sibr::ImageListFile::Infos holding filename, width, height, and id of the input images. + * - _imgPath: Path to the calibrated images directory. + * - _activeImages: Vector of bools storing active state of the camera. + * - _numCameras: Number of cameras associated with the dataset + * - _datasetType: Type if dataset being used. Currently supported: COLMAP, SIBR_BUNDLER, NVM, MESHROOM + * + * \ingroup sibr_scene + */ + + class SIBR_SCENE_EXPORT IParseData { + + public: + + /** + * \brief Denotes the type of dataset represented by a IParseData object. + * \ingroup sibr_scene + */ + enum class Type { + EMPTY, GAUSSIAN, BLENDER, SIBR, COLMAP_CAPREAL, COLMAP, COLMAP2, NVM, MESHROOM, CHUNKED, EXTERNAL + }; + + /** + * \brief Pointer to the instance of class sibr::IParseData. + */ + typedef std::shared_ptr Ptr; + + /** + * \brief Function to parse data from a dataset path. Will automatically determine the type of dataset based on the files present. + * \param myArgs Arguments containing the dataset path and other infos + * \param customPath additional data path + */ + virtual void getParsedData(const BasicIBRAppArgs & myArgs, const std::string & customPath = "") = 0; + + /** + * \brief Getter for the information regarding the input images. + * + */ + virtual const std::vector& imgInfos(void) const = 0; + + /** + * \brief Setter for the information regarding the input images. + * + */ + virtual void imgInfos(std::vector& infos) = 0; + + /** + * \brief Getter to the number of cameras defined in the bundle file. + * + */ + virtual const int numCameras(void) const = 0; + + /** + * \brief Setter to the number of cameras defined in the bundle file. + * + */ + virtual void numCameras(int numCams) = 0; + + /** + * \brief Getter for the list of active cameras/images. + * + */ + virtual const std::vector& activeImages(void) const = 0; + + /** + * \brief Setter for the list of active cameras/images. + * + */ + virtual void activeImages(std::vector& activeCams) = 0; + + /** + * \brief Getter for the base path name where the dataset is located. + * + */ + virtual const std::string& basePathName(void) const = 0; + + /** + * \brief Setter for the base path name where the dataset is located. + * + */ + virtual void basePathName(std::string & path) = 0; + + /** + * \brief Getter for the mesh path where the dataset is located. + * + */ + virtual const std::string& meshPath(void) const = 0; + + /** + * \brief Setter for the mesh path where the dataset is located. + * + */ + virtual void meshPath(std::string & path) = 0; + + /** + * \brief Getter for the dataset type. + * + */ + virtual const IParseData::Type& datasetType(void) const = 0; + + /** + * \brief Setter for the dataset type. + * + */ + virtual void datasetType(IParseData::Type dataType) = 0; + + /** + * \brief Getter for the camera infos. + * + */ + virtual const std::vector cameras(void) const = 0; + + /** + * \brief Setter for the camera infos. + * + */ + virtual void cameras(std::vector& cams) = 0; + + /** + * \brief Getter for the image path. + * + */ + virtual const std::string imgPath(void) const = 0; + + /** + * \brief Setter for the image path. + * + */ + virtual void imgPath(std::string& imPath) = 0; + + }; + +} \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/IProxyMesh.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/IProxyMesh.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c2adc02c968b6cea9f96cc69beb436155d0b26a8 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/IProxyMesh.hpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include "core/scene/Config.hpp" +#include "core/scene/IParseData.hpp" +#include "core/graphics/Mesh.hpp" + +namespace sibr { + /** + \ingroup sibr_scene + */ + class SIBR_SCENE_EXPORT IProxyMesh { + SIBR_DISALLOW_COPY(IProxyMesh); + public: + typedef std::shared_ptr Ptr; + + virtual void loadFromData(const IParseData::Ptr & data) = 0; + virtual void replaceProxy(Mesh::Ptr newProxy) = 0; + virtual void replaceProxyPtr(Mesh::Ptr newProxy) = 0; + virtual bool hasProxy(void) const = 0; + virtual const Mesh& proxy(void) const = 0; + virtual const Mesh::Ptr proxyPtr(void) const = 0; + + protected: + IProxyMesh() {}; + + }; + +} \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/InputImages.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/InputImages.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1484c8132067d39dde6bb87859fdd18d0fbf2913 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/InputImages.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "InputImages.hpp" + + +namespace sibr +{ + void InputImages::loadFromData(const IParseData::Ptr & data) + { + //InputImages out; + _inputImages.resize(data->imgInfos().size()); + + if (data->imgInfos().empty() == false) + { +// #pragma omp parallel for + for (int i = 0; i < data->imgInfos().size(); ++i) { + if (data->activeImages()[i]) { + _inputImages[i] = std::make_shared(); + _inputImages[i]->load(data->imgPath() + "/" + data->imgInfos().at(i).filename, false); + } + else { + _inputImages[i] = std::make_shared(16,16, 0); + } + } + + } + else + SIBR_WRG << "cannot load images (ImageListFile is empty. Did you use ImageListFile::load(...) before ?"; + + std::cout << std::endl; + + return; + } + + void InputImages::loadFromExisting(const std::vector & imgs) + { + _inputImages.resize(imgs.size()); + for (size_t i = 0; i < imgs.size(); ++i) { + _inputImages[i].reset(new ImageRGB(imgs[i].clone())); + } + } + + /// \todo UN-TESTED code!!!! + void InputImages::loadFromPath(const IParseData::Ptr & data, const std::string & prefix, const std::string & postfix) + { + _inputImages.resize(data->imgInfos().size()); + + #pragma omp parallel for + for (int i = 0; i < data->imgInfos().size(); ++i) { + if (data->activeImages()[i]) { + std::string imgPath = data->basePathName()+ "/images/" + prefix + sibr::imageIdToString(i) + postfix; + if (!_inputImages[i]->load(imgPath, false)) { + SIBR_WRG << "could not load input image : " << imgPath << std::endl; + } + } + } + } + + + void InputImages::alphaBlendInputImages(const std::vector& back, std::vector& alphas) + { + for (uint i = 0; i< _inputImages.size(); i++) { + // check size + if (_inputImages[i]->w() != alphas[i].w() || + _inputImages[i]->h() != alphas[i].h()) + alphas[i] = alphas[i].resized(_inputImages[i]->w(), _inputImages[i]->h()); + for (uint x = 0; x<_inputImages[i]->w(); x++) + for (uint y = 0; y<_inputImages[i]->h(); y++) { + ImageRGB::Pixel p = _inputImages[i](x, y); + ImageRGB::Pixel bp = back[i](x, y); + ImageRGB::Pixel a = alphas[i](x, y); + Vector3f alpha(float(a[0] / 255.), float(a[1] / 255.), float(a[2] / 255.)); + float al = alpha[0]; // assume grey for now + Vector3f val = Vector3f(float(p[0]), float(p[1]), float(p[2])); + Vector3f bval = Vector3f(float(bp[0]), float(bp[1]), float(bp[2])); + Vector3f out; + if (alpha[0] > 0.4) { + out = (val - bval + al*bval) / al; // foreground solving for a + + // clamp +#define NZ(x) ((x)<0.f?0.f:x) +#define UP(x) ((x)>255.f?255.f:x) + out[0] = UP(NZ(out[0])); + out[1] = UP(NZ(out[1])); + out[2] = UP(NZ(out[2])); + } + else + out = Vector3f(0, 0, 0); + + _inputImages[i](x, y) = ImageRGB::Pixel((uint)out[0], (uint)out[1], (uint)out[2]); + } + } + } +} + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/InputImages.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/InputImages.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e6b14b2448b01819ff8cb28197c72cb6a0e99dc6 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/InputImages.hpp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include "core/scene/IInputImages.hpp" +#include "core/scene/Config.hpp" + +namespace sibr +{ + /** + \ingroup sibr_scene + */ + class SIBR_SCENE_EXPORT InputImages : public IInputImages { + SIBR_DISALLOW_COPY(InputImages); + public: + + + typedef std::shared_ptr Ptr; + + InputImages(){}; + void loadFromData(const IParseData::Ptr & data) override; + virtual void loadFromExisting(const std::vector & imgs) override; + void loadFromExisting(const std::vector & imgs) override; + void loadFromPath(const IParseData::Ptr & data, const std::string & prefix, const std::string & postfix) override; + + // Alpha blend and modify input images -- for fences + void alphaBlendInputImages(const std::vector& back, std::vector& alphas) override; + + const std::vector& inputImages(void) const override; + const sibr::ImageRGB& image(uint i) override { return *_inputImages[i]; } + + ~InputImages(){}; + + protected: + + std::vector _inputImages; + + }; + + inline void InputImages::loadFromExisting(const std::vector& imgs) + { + _inputImages = imgs; + } + + inline const std::vector& InputImages::inputImages(void) const { + return _inputImages; + } + +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/ParseData.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/ParseData.cpp new file mode 100755 index 0000000000000000000000000000000000000000..f709af5a642505d559661aa0071cc72ebe8ae124 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/ParseData.cpp @@ -0,0 +1,637 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#include "ParseData.hpp" + +#include +#include +#include + +#include +#include +#include +#include +#include "core/system/String.hpp" +#include "core/graphics/Mesh.hpp" +#include "core/system/Utils.hpp" +#include + +using namespace boost::algorithm; +namespace sibr { + + + bool ParseData::parseBundlerFile(const std::string & bundler_file_path) + { + // check bundler file + std::ifstream bundle_file(bundler_file_path); + if (!bundle_file.is_open()) { + SIBR_ERR << "Bundler file does not exist at " + bundler_file_path << std::endl; + } + + // read number of images + std::string line; + safeGetline(bundle_file, line); // ignore first line - contains version + + bundle_file >> _numCameras; // read first value (number of images) + safeGetline(bundle_file, line); // ignore the rest of the line + + //_outputCamsMatrix.resize(_numCameras); + _camInfos.resize(_numCameras); + for (int i = 0; i < _numCameras; i++) { + const sibr::ImageListFile::Infos& infos = _imgInfos[i]; + + //Matrix4f &m = _outputCamsMatrix[i]; + Matrix4f m; + bundle_file >> m(0) >> m(1) >> m(2) >> m(3) >> m(4); + bundle_file >> m(5) >> m(6) >> m(7) >> m(8) >> m(9); + bundle_file >> m(10) >> m(11) >> m(12) >> m(13) >> m(14); + + _camInfos[i] = InputCamera::Ptr(new InputCamera(infos.camId, infos.width, infos.height, m, _activeImages[i])); + _camInfos[i]->name(infos.filename); + _camInfos[i]->znear(0.001f); + _camInfos[i]->zfar(1000.0f); + } + + return true; + } + + void ParseData::populateFromCamInfos() + { + _numCameras = _camInfos.size(); + _imgInfos.resize(_numCameras); + _activeImages.resize(_numCameras); + for (uint id = 0; id < _numCameras; id++) { + _imgInfos[id].camId = _camInfos[id]->id(); + _imgInfos[id].filename = _camInfos[id]->name(); + _imgInfos[id].height = _camInfos[id]->h(); + _imgInfos[id].width = _camInfos[id]->w(); + + _activeImages[id] = _camInfos[id]->isActive(); + } + } + + bool ParseData::parseSceneMetadata(const std::string& scene_metadata_path) + { + + std::string line; + std::vector splitS; + std::ifstream scene_metadata(scene_metadata_path); + if (!scene_metadata.is_open()) { + return false; + } + + uint camId = 0; + + while (safeGetline(scene_metadata, line)) + + { + if (line.compare("[list_images]") == 0 ) + { + safeGetline(scene_metadata, line); // ignore template specification line + ImageListFile::Infos infos; + int id; + while (safeGetline(scene_metadata, line)) + { +// std::cerr << line << std::endl; + split(splitS, line, is_any_of(" ")); +// std::cerr << splitS.size() << std::endl; + if (splitS.size() > 1) { + infos.filename = splitS[0]; + infos.width = stoi(splitS[1]); + infos.height = stoi(splitS[2]); + infos.camId = camId; + + //infos.filename.erase(infos.filename.find_last_of("."), std::string::npos); + id = atoi(infos.filename.c_str()); + + InputCamera::Z nearFar(100.0f, 0.1f); + + if (splitS.size() > 3) { + nearFar.near = stof(splitS[3]); + nearFar.far = stof(splitS[4]); + } + _imgInfos.push_back(infos); + + ++camId; + infos.filename.clear(); + splitS.clear(); + } + else + break; + } + } + else if (line.compare("[active_images]") == 0) { + + safeGetline(scene_metadata, line); // ignore template specification line + + _activeImages.resize(_imgInfos.size()); + + for (int i = 0; i < _imgInfos.size(); i++) + _activeImages[i] = false; + + while (safeGetline(scene_metadata, line)) + { + split(splitS, line, is_any_of(" ")); + //std::cout << splitS.size() << std::endl; + if (splitS.size() >= 1) { + for (auto& s : splitS) + if (!s.empty()) + _activeImages[stoi(s)] = true; + splitS.clear(); + break; + } + else + break; + } + } + else if (line.compare("[exclude_images]") == 0) { + + safeGetline(scene_metadata, line); // ignore template specification line + + _activeImages.resize(_imgInfos.size()); + + for (int i = 0; i < _imgInfos.size(); i++) + _activeImages[i] = true; + + while (safeGetline(scene_metadata, line)) + { + split(splitS, line, is_any_of(" ")); + if (splitS.size() >= 1) { + for (auto& s : splitS) + if (!s.empty()) + _activeImages[stoi(s)] = false; + splitS.clear(); + break; + } + else + break; + } + } + else if (line == "[proxy]") { + // Read the relative path of the mesh to load. + safeGetline(scene_metadata, line); + + _meshPath = _basePathName + "/" + line; + } + } + + if (_activeImages.empty()) { + _activeImages.resize(_imgInfos.size()); + for (int i = 0; i < _imgInfos.size(); i++) { + _activeImages[i] = true; + } + } + + + + scene_metadata.close(); + + return true; + } + + void ParseData::getParsedBundlerData(const std::string & dataset_path, const std::string & customPath, const std::string & scene_metadata_filename) + { + _basePathName = dataset_path + customPath; + /*std::cout << scene_metadata_filename << std::endl;*/ + if (!parseSceneMetadata(_basePathName + "/" + scene_metadata_filename)) { + SIBR_ERR << "Scene Metadata file does not exist at /" + _basePathName + "/." << std::endl; + } + + if (!parseBundlerFile(_basePathName + "/cameras/bundle.out")) { + SIBR_ERR << "Bundle file does not exist at /" + _basePathName + "/cameras/." << std::endl; + } + + _imgPath = _basePathName + "/images/"; + + // Default mesh path if none found in the metadata file. + if (_meshPath.empty()) { + _meshPath = _basePathName + "/meshes/recon.obj"; + _meshPath = (sibr::fileExists(_meshPath)) ? _meshPath : _basePathName + "/meshes/recon.ply"; + } + + } + + void ParseData::getParsedMeshroomData(const std::string & dataset_path, const std::string & customPath) + { + _basePathName = dataset_path; + + std::string meshRoomCachePath = sibr::listSubdirectories(_basePathName + "/StructureFromMotion/")[0]; + + _camInfos = sibr::InputCamera::loadMeshroom(_basePathName + "/StructureFromMotion/" + meshRoomCachePath); + + if (_camInfos.empty()) { + SIBR_ERR << "Could not load Meshroom sfm file at /" + _basePathName + "/StructureFromMotion/"<< meshRoomCachePath << std::endl; + } + + _imgPath = _basePathName + "/PrepareDenseScene/" + sibr::listSubdirectories(_basePathName + "/PrepareDenseScene/")[0]; + + populateFromCamInfos(); + + _meshPath = _basePathName + "/Texturing/" + sibr::listSubdirectories(_basePathName + "/Texturing/")[0] + "/texturedMesh.obj"; + } + + void ParseData::getParsedBlenderData(const std::string& dataset_path) + { + _camInfos = InputCamera::loadTransform(dataset_path + "/transforms_test.json", 800, 800, "png", 0.01f, 1000.0f); + auto testInfos = InputCamera::loadTransform(dataset_path + "/transforms_train.json", 800, 800, "png", 0.01f, 1000.0f, _camInfos.size()); + _camInfos.insert(_camInfos.end(), testInfos.begin(), testInfos.end()); + + _basePathName = dataset_path; + + if (_camInfos.empty()) { + SIBR_ERR << "Colmap camera calibration file does not exist at /" + _basePathName + "/sparse/." << std::endl; + } + + _imgPath = dataset_path; + + populateFromCamInfos(); + + _meshPath = dataset_path; + } + + void ParseData::getParsedGaussianData(const std::string& dataset_path) + { + _camInfos = InputCamera::loadJSON(dataset_path + "/cameras.json"); + _meshPath = dataset_path + "/input.ply"; + + _basePathName = dataset_path; + + _imgPath = "."; + + populateFromCamInfos(); + + _meshPath = dataset_path + "/input.ply"; + } + + void ParseData::getParsedColmap2Data(const std::string& dataset_path, const int fovXfovY_flag, const bool capreal_flag) + { + _basePathName = dataset_path + "/sparse/0/"; + + _camInfos = sibr::InputCamera::loadColmapBin(_basePathName, 0.01f, 1000.0f, fovXfovY_flag); + + if (_camInfos.empty()) { + _camInfos = sibr::InputCamera::loadColmap(_basePathName, 0.01f, 1000.0f, fovXfovY_flag); + } + + if (_camInfos.empty()) { + SIBR_ERR << "Colmap camera calibration file does not exist at /" + _basePathName + "/sparse/." << std::endl; + } + + _imgPath = dataset_path + "/images/"; + + populateFromCamInfos(); + + _meshPath = dataset_path + "/sparse/0/points3d.bin"; + + if (!std::ifstream(_meshPath).good()) + _meshPath = dataset_path + "/sparse/0/points3d.txt"; + } + + void colmapSave(const std::string& filename, const std::vector& xformPath, float scale) { + // save as colmap images.txt file + sibr::Matrix3f converter; + converter << 1, 0, 0, + 0, -1, 0, + 0, 0, -1; + + std::ofstream outputColmapPath, outputColmapPathCams; + std::string colmapPathCams = parentDirectory(filename) + std::string("/cameras.txt"); + + std::cerr << std::endl; + std::cerr << std::endl; + std::cerr << "Writing colmap path to " << parentDirectory(filename) << std::endl; + + outputColmapPath.open(filename); + if (!outputColmapPath.good()) + SIBR_ERR << "Cant open output file " << filename << std::endl; + outputColmapPathCams.open(colmapPathCams); + + outputColmapPathCams << "# Camera list with one line of data per camera:" << std::endl; + outputColmapPathCams << "# CAMERA_ID, MODEL, WIDTH, HEIGHT, PARAMS[]" << std::endl; + outputColmapPathCams << "# Number of cameras: " << xformPath.size() << std::endl; + + SIBR_WRG << "No focal x given making it equal to focaly * aspect ratio; use result at own risk. Should have a colmap dataset as input" << std::endl; + + for (int i = 0; i < xformPath.size(); i++) { + float focalx = xformPath[i]->focal() * xformPath[i]->aspect(); // use aspect ratio + outputColmapPathCams << i + 1 << " PINHOLE " << xformPath[i]->w() * scale << " " << xformPath[i]->h() * scale + << " " << xformPath[i]->focal() * scale << " " << focalx * scale + << " " << xformPath[i]->w() * scale * 0.5 << " " << xformPath[i]->h() * scale * 0.5 << std::endl; + } + + + outputColmapPath << "# Image list with two lines of data per image:" << std::endl; + outputColmapPath << "# IMAGE_ID, QW, QX, QY, QZ, TX, TY, TZ, CAMERA_ID, NAME" << std::endl; + outputColmapPath << "# POINTS2D[] as (X, Y, POINT3D_ID)" << std::endl; + for (int i = 0; i < xformPath.size(); i++) { + sibr::Matrix3f tmp = xformPath[i]->rotation().toRotationMatrix() * converter; + sibr::Matrix3f Qinv = tmp.transpose(); + sibr::Quaternionf q = quatFromMatrix(Qinv); + sibr::Vector3f t = -Qinv * xformPath[i]->position(); + + outputColmapPath << (i+1) << " " << q.w() << " " << -q.x() << " " << -q.y() << " " << -q.z() << " " << + t.x() << " " << t.y() << " " << t.z() << " " << (i+1) << " " << xformPath[i]->name() << std::endl; + outputColmapPath << std::endl; // empty line, no points + } + outputColmapPath.close(); + outputColmapPathCams.close(); + } + + void ParseData::getParsedChunkedData(const std::string& dataset_path) + { + _basePathName = sibr::parentDirectory(sibr::parentDirectory(dataset_path));; + + auto test = sibr::getFileName(dataset_path); + std::replace(test.begin(), test.end(), '_', ' '); + std::stringstream ss(test); + int x, y; + ss >> x >> y; + x = 0; + y = 0; + + _imgPath = _basePathName + "/cameras/"; + + auto camdirs = sibr::listSubdirectories(_imgPath); + + for (int i = 0; i < camdirs.size(); i++) + { + auto cam = std::make_shared(0, 0, 0, 0, 0, 0, _camInfos.size()); + cam->loadFromBinary(_imgPath + camdirs[i] + "/incam.bin"); + + auto quat = cam->transform().rotation(); + auto mat = sibr::matFromQuat(quat); + + if (mat(2, 2) > 0.9 || cam->position().x() < (x) * 100.9 || cam->position().x() > (x+1) * 100.9 || cam->position().y() < y * 100.9 || cam->position().y() > (y + 1) * 100.9) + continue; + + cam->name(camdirs[i] + ".png"); + _camInfos.push_back(cam); + } + + populateFromCamInfos(); + + colmapSave(_basePathName + "/sparse/images.txt", _camInfos, 1.0f); + + _meshPath = dataset_path + "/mesh.ply"; + } + + + void ParseData::getParsedColmapData(const std::string & dataset_path, const int fovXfovY_flag, const bool capreal_flag) + { + _basePathName = dataset_path + "/colmap/stereo"; + + _camInfos = sibr::InputCamera::loadColmap(_basePathName + "/sparse", 0.01f, 1000.0f, fovXfovY_flag); + + if (_camInfos.empty()) { + SIBR_ERR << "Colmap camera calibration file does not exist at /" + _basePathName + "/sparse/." << std::endl; + } + + _imgPath = _basePathName + "/images/"; + + std::string blackListFile = dataset_path + "/colmap/database.blacklist"; + + if (sibr::fileExists(blackListFile)) { + std::string line; + std::vector splitS; + std::ifstream blackListFileF(blackListFile); + if (blackListFileF.is_open()) { + while (safeGetline(blackListFileF, line)) { + + split(splitS, line, is_any_of(" ")); + //std::cout << splitS.size() << std::endl; + if (splitS.size() > 0) { + for (uint cam_id = 0; cam_id < _camInfos.size(); cam_id++) { + if (find_any(splitS, _camInfos[cam_id]->name())) { + _camInfos[cam_id]->setActive(false); + } + } + splitS.clear(); + } + else + break; + } + } + } + + populateFromCamInfos(); + + if(capreal_flag) { + _meshPath = dataset_path + "/capreal/mesh.obj"; + _meshPath = (sibr::fileExists(_meshPath)) ? _meshPath : dataset_path + "/capreal/mesh.ply"; + } + else { + _meshPath = dataset_path + "/colmap/stereo/meshed-delaunay.ply"; + } + + } + + void ParseData::getParsedNVMData(const std::string & dataset_path, const std::string & customPath, const std::string & nvm_path) + { + _basePathName = dataset_path + customPath + nvm_path; + + _camInfos = sibr::InputCamera::loadNVM(_basePathName + "/scene.nvm", 0.001f, 1000.0f); + if (_camInfos.empty()) { + SIBR_ERR << "Error reading NVM dataset at /" + _basePathName << std::endl; + } + + _imgPath = _basePathName; + + populateFromCamInfos(); + + _meshPath = dataset_path + "/capreal/mesh.obj"; + _meshPath = (sibr::fileExists(_meshPath)) ? _meshPath : dataset_path + "/capreal/mesh.ply"; + } + + void ParseData::getParsedData(const BasicIBRAppArgs & myArgs, const std::string & customPath) + { + std::string datasetTypeStr = myArgs.dataset_type.get(); + + boost::algorithm::to_lower(datasetTypeStr); + + std::string bundler = myArgs.dataset_path.get() + customPath + "/cameras/bundle.out"; + std::string colmap = myArgs.dataset_path.get() + "/colmap/stereo/sparse/images.txt"; + std::string colmap_2 = myArgs.dataset_path.get() + "/sparse/0/images.bin"; + std::string caprealobj = myArgs.dataset_path.get() + "/capreal/mesh.obj"; + std::string caprealply = myArgs.dataset_path.get() + "/capreal/mesh.ply"; + std::string nvmscene = myArgs.dataset_path.get() + customPath + "/nvm/scene.nvm"; + std::string meshroom = myArgs.dataset_path.get() + "/../../StructureFromMotion/"; + std::string meshroom_sibr = myArgs.dataset_path.get() + "/StructureFromMotion/"; + std::string chunked = myArgs.dataset_path.get() + "/chunk.dat"; + std::string blender = myArgs.dataset_path.get() + "/transforms_train.json"; + std::string gaussian = myArgs.dataset_path.get() + "/cameras.json"; + + if(datasetTypeStr == "sibr") { + if (!sibr::fileExists(bundler)) + SIBR_ERR << "Cannot use dataset_type " + myArgs.dataset_type.get() + " at /" + myArgs.dataset_path.get() + "." << std::endl + << "Reason : bundler folder (" << bundler << ") does not exist" << std::endl; + + _datasetType = Type::SIBR; + } + else if (datasetTypeStr == "colmap_capreal") { + if (!sibr::fileExists(colmap)) + SIBR_ERR << "Cannot use dataset_type " + myArgs.dataset_type.get() + " at /" + myArgs.dataset_path.get() + "." << std::endl + << "Reason : colmap folder (" << colmap << ") does not exist" << std::endl; + + if (!(sibr::fileExists(caprealobj) || sibr::fileExists(caprealply))) + SIBR_ERR << "Cannot use dataset_type " + myArgs.dataset_type.get() + " at /" + myArgs.dataset_path.get() + "." << std::endl + << "Reason : capreal mesh (" << caprealobj << ", " << caprealply << ") does not exist" << std::endl; + + _datasetType = Type::COLMAP_CAPREAL; + } + else if (datasetTypeStr == "colmap") { + if (!sibr::fileExists(colmap)) + SIBR_ERR << "Cannot use dataset_type " + myArgs.dataset_type.get() + " at /" + myArgs.dataset_path.get() + "." << std::endl + << "Reason : colmap folder (" << colmap << ") does not exist" << std::endl; + + _datasetType = Type::COLMAP; + } + else if (datasetTypeStr == "nvm") { + if (!sibr::fileExists(nvmscene)) + SIBR_ERR << "Cannot use dataset_type " + myArgs.dataset_type.get() + " at /" + myArgs.dataset_path.get() + "." << std::endl + << "Reason : nvmscene folder (" << nvmscene << ") does not exist" << std::endl; + + _datasetType = Type::NVM; + } + else if (datasetTypeStr == "meshroom") { + if (!(sibr::directoryExists(meshroom) || sibr::directoryExists(meshroom_sibr))) + SIBR_ERR << "Cannot use dataset_type " + myArgs.dataset_type.get() + " at /" + myArgs.dataset_path.get() + "." << std::endl + << "Reason : meshroom folder (" << meshroom << ", " << meshroom_sibr << ") does not exist" << std::endl; + + _datasetType = Type::MESHROOM; + } + else if (datasetTypeStr == "blender") + { + if (!sibr::fileExists(blender)) + SIBR_ERR << "Cannot use dataset_type " + myArgs.dataset_type.get() + " at /" + myArgs.dataset_path.get() + "." << std::endl + << "Reason : blender transform (" << blender << ") does not exist" << std::endl; + + _datasetType = Type::BLENDER; + } + else if (datasetTypeStr == "gaussian") + { + if (!sibr::fileExists(gaussian)) + SIBR_ERR << "Cannot use dataset_type " + myArgs.dataset_type.get() + " at /" + myArgs.dataset_path.get() + "." << std::endl + << "Reason : Gaussian transform (" << blender << ") does not exist" << std::endl; + + _datasetType = Type::BLENDER; + } + else { + if (sibr::fileExists(bundler)) { + _datasetType = Type::SIBR; + } + else if (sibr::fileExists(gaussian)) + { + _datasetType = Type::GAUSSIAN; + } + else if (sibr::fileExists(colmap) && (sibr::fileExists(caprealobj) || sibr::fileExists(caprealply))) { + _datasetType = Type::COLMAP_CAPREAL; + } + else if (sibr::fileExists(colmap)) { + _datasetType = Type::COLMAP; + } + else if (sibr::fileExists(nvmscene)) { + _datasetType = Type::NVM; + } + else if (sibr::directoryExists(meshroom) || sibr::directoryExists(meshroom_sibr)) { + _datasetType = Type::MESHROOM; + } + else if (sibr::fileExists(colmap_2)) + _datasetType = Type::COLMAP2; + + else if (sibr::fileExists(chunked)) + { + _datasetType = Type::CHUNKED; + } + else if (sibr::fileExists(blender)) + { + _datasetType = Type::BLENDER; + } + else { + SIBR_ERR << "Cannot determine type of dataset at /" + myArgs.dataset_path.get() + customPath << std::endl; + } + } + + switch(_datasetType) { + case Type::GAUSSIAN: getParsedGaussianData(myArgs.dataset_path); break; + case Type::BLENDER: getParsedBlenderData(myArgs.dataset_path); break; + case Type::SIBR : getParsedBundlerData(myArgs.dataset_path, customPath, myArgs.scene_metadata_filename); break; + case Type::COLMAP_CAPREAL : getParsedColmapData(myArgs.dataset_path, myArgs.colmap_fovXfovY_flag, true); break; + case Type::COLMAP : getParsedColmapData(myArgs.dataset_path, myArgs.colmap_fovXfovY_flag, false); break; + case Type::COLMAP2 : getParsedColmap2Data(myArgs.dataset_path, myArgs.colmap_fovXfovY_flag, false); break; + case Type::CHUNKED: getParsedChunkedData(myArgs.dataset_path); break; + case Type::NVM : getParsedNVMData(myArgs.dataset_path, customPath, "/nvm/"); break; + case Type::MESHROOM : if (sibr::directoryExists(meshroom)) getParsedMeshroomData(myArgs.dataset_path.get() + "/../../"); + else if (sibr::directoryExists(meshroom_sibr)) getParsedMeshroomData(myArgs.dataset_path); break; + } + + // What happens if multiple are present? + // Ans: Priority --> SIBR > COLMAP > NVM + + // Subtract minCAMID from all + uint minCamID = UINT_MAX; + for (const auto& cam : _camInfos) + minCamID = std::min(minCamID, cam->id()); + for (auto& cam : _camInfos) + cam->_id -= minCamID; + for (auto& img : _imgInfos) + img.camId -= minCamID; + + // Find max cam ID and check present image IDs + int maxId = 0; + std::vector presentIDs; + + presentIDs.resize(_numCameras); + + for (int c = 0; c < _numCameras; c++) { + maxId = (maxId > int(_imgInfos[c].camId)) ? maxId : int(_imgInfos[c].camId); + if (_imgInfos[c].camId >= presentIDs.size()) + { + //SIBR_ERR << "Incorrect Camera IDs " << std::endl; + continue; + } + try + { + presentIDs[_imgInfos[c].camId] = true; + } + catch (const std::exception&) + { + SIBR_ERR << "Incorrect Camera IDs " << std::endl; + } + } + + // Check if max cam ID matches max number of cams + // If not find the missing IDs + std::vector missingIDs; + int curid; + int j, pos; + if (maxId >= _numCameras) { + for (int i = 0; i < _numCameras; i++) { + if (!presentIDs[i]) { missingIDs.push_back(i); } + } + + // Now, shift the imgInfo IDs to adjust max Cam IDs + for (int k = 0; k < _numCameras; k++) { + curid = _imgInfos[k].camId; + pos = -1; + for (j = 0; j < missingIDs.size(); j++) { + if (curid > missingIDs[j]) { pos = j; } + else { break; } + } + + _imgInfos[k].camId = _imgInfos[k].camId - (pos + 1); + } + } + + } + +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/ParseData.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/ParseData.hpp new file mode 100644 index 0000000000000000000000000000000000000000..09ac8b53294da4805539f8dc63dee419be1b3235 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/ParseData.hpp @@ -0,0 +1,309 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include "core/scene/IParseData.hpp" + + +namespace sibr{ + + /** + * Class used to store the data required for defining an IBR Scene + * + * + * Members: + * - _basePathName: Base dataset directory path. + * - _camInfos: Vector of sibr::InputCamera holding all data attached with the scene cameras. + * - _meshPath: Filepath of the mesh associated to the scene. + * - _imgInfos: Vector of sibr::ImageListFile::Infos holding filename, width, height, and id of the input images. + * - _imgPath: Path to the calibrated images directory. + * - _activeImages: Vector of bools storing active state of the camera. + * - _numCameras: Number of cameras associated with the dataset + * - _datasetType: Type if dataset being used. Currently supported: COLMAP, SIBR_BUNDLER, NVM, MESHROOM + * + * \ingroup sibr_scene + */ + + class SIBR_SCENE_EXPORT ParseData: public IParseData { + + public: + + /** + * \brief Pointer to the instance of class sibr::ParseData. + */ + typedef std::shared_ptr Ptr; + + /** + * \brief Function to parse data from a template dataset path. + * \param dataset_path Path to the folder containing data + * \param customPath Path to algorithm specific data + * \param scene_metadata_filename Specify the filename of the Scene Metadata file to load specific scene + */ + void getParsedBundlerData(const std::string & dataset_path, const std::string & customPath, const std::string & scene_metadata_filename); + + /** + * \brief Function to parse data from a template dataset path. + * \param dataset_path Path to the folder containing data + * \param customPath Path to algorithm specific data + */ + void getParsedMeshroomData(const std::string & dataset_path, const std::string & customPath = ""); + + + /** + * \brief Function to parse data from a colmap dataset path. + * + * The function takes in a colmap dataset folder path and populates ParseData members with data. + * This function can be used for direct compatibility with colmap data in SIBR. + * The function automatically computes the intrinsic and extrinsic parameters of the camera, input images filename, widht and height etc. + * Colmap uses LHS coordinate system while SIBR uses RHS coordinate system. The function applies appropriate transformation to handle this case. + * + * For further compatibility with FrIBR, which enforces a Y-up RHS coordinate system, we need to apply an extra conversion to the rotation matrix, to 'flip back' from y-down to y-up. + * \note Note: when applying the above mentioned conversion, the mesh needs to be converted by the same converter matrix + * \param dataset_path Path to the folder containing data + * \param fovXfovY_flag activate two dimensional fov parameters + * \param capreal_flag use capreal data + */ + void getParsedColmapData(const std::string & dataset_path, const int fovXfovY_flag, const bool capreal_flag = true); + + + void getParsedColmap2Data(const std::string & dataset_path, const int fovXfovY_flag, const bool capreal_flag = true); + + void getParsedGaussianData(const std::string& dataset_path); + + void getParsedBlenderData(const std::string& dataset_path); + + void getParsedChunkedData(const std::string& dataset_path); + + /** + * \brief Function to parse data from a template dataset path. + * \param dataset_path Path to the folder containing data + * \param customPath Path to algorithm specific data + * \param nvm_path Specify the filename of the NVM path. + */ + void getParsedNVMData(const std::string & dataset_path, const std::string & customPath, const std::string & nvm_path); + + /** + * \brief Function to parse data from a dataset path. Will automatically determine the type of dataset based on the files present. + * \param myArgs Arguments containing the dataset path and other infos + * \param customPath additional data path + */ + void getParsedData(const BasicIBRAppArgs & myArgs, const std::string & customPath = "") override; + + /** + * \brief Getter for the information regarding the input images. + * + */ + const std::vector& imgInfos(void) const override; + + /** + * \brief Setter for the information regarding the input images. + * + */ + void imgInfos(std::vector& infos) override; + + /** + * \brief Getter to the number of cameras defined in the bundle file. + * + */ + const int numCameras(void) const override; + + /** + * \brief Setter to the number of cameras defined in the bundle file. + * + */ + void numCameras(int numCams) override; + + /** + * \brief Getter for the list of active cameras/images. + * + */ + const std::vector& activeImages(void) const override; + + /** + * \brief Setter for the list of active cameras/images. + * + */ + void activeImages(std::vector& activeCams) override; + + /** + * \brief Getter for the base path name where the dataset is located. + * + */ + const std::string& basePathName(void) const override; + + /** + * \brief Setter for the base path name where the dataset is located. + * + */ + void basePathName(std::string & path) override; + + /** + * \brief Getter for the mesh path where the dataset is located. + * + */ + const std::string& meshPath(void) const override; + + /** + * \brief Setter for the mesh path where the dataset is located. + * + */ + void meshPath(std::string & path) override; + + /** + * \brief Getter for the dataset type. + * + */ + const IParseData::Type& datasetType(void) const override; + + /** + * \brief Setter for the dataset type. + * + */ + void datasetType(IParseData::Type dataType) override; + + /** + * \brief Getter for the camera infos. + * + */ + const std::vector cameras(void) const override; + + /** + * \brief Setter for the camera infos. + * + */ + void cameras(std::vector& cams) override; + + /** + * \brief Getter for the image path. + * + */ + const std::string imgPath(void) const override; + + /** + * \brief Setter for the image path. + * + */ + void imgPath(std::string& imPath) override; + + /** + * \brief Function to parse the scene metadata file to read image data. + * + */ + virtual bool parseSceneMetadata(const std::string & scene_metadata_path); + + protected: + + /** + * \brief Function to parse the camera calibration files to read camera properties (camera matrix etc.). + * + */ + bool parseBundlerFile(const std::string & bundler_file_path); + + + /** + * \brief Function to populate scene info from camera infos to appropriate location. + * + */ + void populateFromCamInfos(); + + std::vector _camInfos; + std::string _basePathName; + std::string _meshPath; + std::vector _imgInfos; + std::string _imgPath = ""; + std::vector _activeImages; + int _numCameras; + Type _datasetType = Type::EMPTY; + + }; + + + ///// INLINE DEFINITIONS ///// + + inline const std::vector& ParseData::imgInfos(void) const { + return _imgInfos; + } + + inline void ParseData::imgInfos(std::vector& infos) + { + _imgInfos = infos; + } + + inline const int ParseData::numCameras( void ) const { + return _numCameras; + } + + inline void ParseData::numCameras(int numCams) + { + _numCameras = numCams; + } + + inline const std::vector& ParseData::activeImages(void) const { + return _activeImages; + } + + inline void ParseData::activeImages(std::vector& activeCams) + { + _activeImages = activeCams; + } + + inline const std::string & ParseData::basePathName(void) const + { + return _basePathName; + } + + inline void ParseData::basePathName(std::string& path) + { + _basePathName = path; + } + + inline const std::string & ParseData::meshPath(void) const + { + return _meshPath; + } + + inline void ParseData::meshPath(std::string& path) + { + _meshPath = path; + } + + inline void ParseData::datasetType(IParseData::Type dataType) { + _datasetType = dataType; + } + + inline const std::vector ParseData::cameras(void) const + { + return _camInfos; + } + + inline void ParseData::cameras(std::vector& cams) + { + _camInfos = cams; + } + + inline const std::string ParseData::imgPath(void) const + { + return _imgPath; + } + + inline void ParseData::imgPath(std::string& imPath) + { + _imgPath = imPath; + } + + inline const ParseData::Type & ParseData::datasetType(void) const + { + return _datasetType; + } + +} \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/ProxyMesh.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/ProxyMesh.cpp new file mode 100644 index 0000000000000000000000000000000000000000..19c18121747b2a1191335fb71860f1976bc9b475 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/ProxyMesh.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "ProxyMesh.hpp" + + +namespace sibr { + + void ProxyMesh::loadFromData(const IParseData::Ptr & data) + { + _proxy.reset(new Mesh()); + // GD HACK + if (boost::filesystem::extension(data->meshPath()) == ".bin") { + if (!_proxy->loadSfM(data->meshPath(), data->basePathName())) { + SIBR_WRG << "proxy model not found at " << data->meshPath() << std::endl; + } + } + else if (!_proxy->load(data->meshPath(), data->basePathName()) && !_proxy->load(removeExtension(data->meshPath()) + ".ply") && !_proxy->load(removeExtension(data->meshPath()) + ".obj")) { + if (!_proxy->loadSfM(data->meshPath(), data->basePathName())) { + SIBR_WRG << "proxy model not found at " << data->meshPath() << std::endl; + } + } + if (!_proxy->hasNormals()) { + _proxy->generateNormals(); + } + } + + void ProxyMesh::replaceProxy(Mesh::Ptr newProxy) + { + _proxy.reset(new Mesh()); + _proxy->vertices(newProxy->vertices()); + _proxy->normals(newProxy->normals()); + _proxy->colors(newProxy->colors()); + _proxy->triangles(newProxy->triangles()); + _proxy->texCoords(newProxy->texCoords()); + + // Used by inputImageRT init() and debug rendering + if (!_proxy->hasNormals()) + { + _proxy->generateNormals(); + } + + } + + void ProxyMesh::replaceProxyPtr(Mesh::Ptr newProxy) + { + _proxy = newProxy; + } + + +} + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/ProxyMesh.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/ProxyMesh.hpp new file mode 100644 index 0000000000000000000000000000000000000000..fbdcf2c815bf85ad703df6dd8c37a732db76f108 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/ProxyMesh.hpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include "core/scene/IProxyMesh.hpp" + +namespace sibr { + /** + \ingroup sibr_scene + */ + class SIBR_SCENE_EXPORT ProxyMesh : public IProxyMesh { + SIBR_DISALLOW_COPY(ProxyMesh); + public: + typedef std::shared_ptr Ptr; + + ProxyMesh() {}; + ~ProxyMesh() {}; + void loadFromData(const IParseData::Ptr & data) override; + void replaceProxy(Mesh::Ptr newProxy) override; + void replaceProxyPtr(Mesh::Ptr newProxy) override; + bool hasProxy(void) const; + const Mesh& proxy(void) const; + const Mesh::Ptr proxyPtr(void) const; + + protected: + + Mesh::Ptr _proxy; + + }; + + inline bool sibr::ProxyMesh::hasProxy(void) const + { + return _proxy && !_proxy->vertices().empty(); + } + + inline const Mesh& ProxyMesh::proxy(void) const + { + return *_proxy; + } + + inline const Mesh::Ptr ProxyMesh::proxyPtr(void) const + { + return _proxy; + } + +}; diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/RenderTargetTextures.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/RenderTargetTextures.cpp new file mode 100644 index 0000000000000000000000000000000000000000..79f66ebbdb9cdaa38c3dc48446f4d613cb0761bd --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/RenderTargetTextures.cpp @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "RenderTargetTextures.hpp" + +namespace sibr { + + void RTTextureSize::initSize(uint w, uint h, bool force_aspect_ratio) + { + + std::cerr << "RTTextureSize::initSize NEW FORCE ASPECT " << force_aspect_ratio << " : " << w << "x" << h << " " << std::endl; + + float aspect; + if (_width == 0) { // use full resolution + _width = w; + _height = h; + } else if (!force_aspect_ratio) { // use constrained resolution + + if (w >= h) { + aspect = float(w) / float(h); + _height = uint(floor(float(_width) / aspect)); + } + else { + _height = _width; + aspect = float(w) / float(h); + _width = uint(floor(float(_height) * aspect)); + } + + } + else { + if (w >= h) _height = w, _width = h; + else _width = w, _height = h; + } + + SIBR_LOG << "Rendering resolution: (" << _width << "," << _height << ")" << std::endl; + _isInit = true; + } + + bool RTTextureSize::isInit() const + { + return _isInit; + } + + const std::vector& RGBDInputTextures::inputImagesRT() const + { + return _inputRGBARenderTextures; + } + + void RGBDInputTextures::initializeImageRenderTargets(ICalibratedCameras::Ptr cams, IInputImages::Ptr imgs) + { + SIBR_LOG << "Initializing input image RTs " << std::endl; + + if (!isInit()) { + initSize(cams->inputCameras()[_initActiveCam]->w(), cams->inputCameras()[_initActiveCam]->h()); + } + + _inputRGBARenderTextures.resize(imgs->inputImages().size()); + + GLShader textureShader; + textureShader.init("Texture", + loadFile(Resources::Instance()->getResourceFilePathName("texture.vp")), + loadFile(Resources::Instance()->getResourceFilePathName("texture.fp"))); + uint interpFlag = (SIBR_SCENE_LINEAR_SAMPLING & SIBR_SCENE_LINEAR_SAMPLING) ? SIBR_GPU_LINEAR_SAMPLING : 0; // LINEAR_SAMPLING Set to default + + for (uint i = 0; i < imgs->inputImages().size(); i++) { + if (cams->inputCameras()[i]->isActive()) { + std::cerr << "." ; + ImageRGB img = std::move(imgs->inputImages()[i]->clone()); + img.flipH(); + + std::shared_ptr rawInputImage(new Texture2DRGB(img, interpFlag)); + + glViewport(0, 0, _width, _height); + _inputRGBARenderTextures[i].reset(new RenderTargetRGBA32F(_width, _height, interpFlag)); + _inputRGBARenderTextures[i]->clear(); + _inputRGBARenderTextures[i]->bind(); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, rawInputImage->handle()); + + glDisable(GL_DEPTH_TEST); + textureShader.begin(); + RenderUtility::renderScreenQuad(); + textureShader.end(); + _inputRGBARenderTextures[i]->unbind(); + } + } + std::cerr << std::endl; + } + + void RGBDInputTextures::initializeDepthRenderTargets(ICalibratedCameras::Ptr cams, IProxyMesh::Ptr proxies, bool facecull) + { + if (!isInit()) { + initSize(cams->inputCameras()[_initActiveCam]->w(), cams->inputCameras()[_initActiveCam]->h()); + } + + GLParameter size; + GLParameter proj; + + GLShader depthShader; + depthShader.init("Depth", + loadFile(Resources::Instance()->getResourceFilePathName("depth.vp")), + loadFile(Resources::Instance()->getResourceFilePathName("depth.fp"))); + + proj.init(depthShader, "proj"); // [SP]: ?? + size.init(depthShader, "size"); // [SP]: ?? + for (uint i = 0; i < cams->inputCameras().size(); i++) { + if (cams->inputCameras()[i]->isActive()) { + _inputRGBARenderTextures[i]->bind(); + glEnable(GL_DEPTH_TEST); + glClear(GL_DEPTH_BUFFER_BIT); + glDepthMask(GL_TRUE); + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); + + if (!proxies->proxy().triangles().empty()) + { + + const uint w = _inputRGBARenderTextures[i]->w(); + const uint h = _inputRGBARenderTextures[i]->h(); + + depthShader.begin(); + size.set((float)w, (float)h); + proj.set(cams->inputCameras()[i]->viewproj()); + proxies->proxy().render(true, facecull); + + depthShader.end(); + } + _inputRGBARenderTextures[i]->unbind(); + } + } + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + } + + void DepthInputTextureArray::initDepthTextureArrays(ICalibratedCameras::Ptr cams, IProxyMesh::Ptr proxies, bool facecull, int flags) + { + + if (!isInit()) { + initSize(cams->inputCameras()[_initActiveCam]->w(), cams->inputCameras()[_initActiveCam]->h()); + } + + if (!proxies->hasProxy()) { + SIBR_WRG << " Cannot init DepthTextureArrays without proxy." << std::endl; + return; + } + + SIBR_LOG << "Depth vertex shader location: " << Resources::Instance()->getResourceFilePathName("depthonly.vp") << std::endl; + SIBR_LOG << "Depth fragment shader location: " << Resources::Instance()->getResourceFilePathName("depthonly.fp") << std::endl; + + GLShader depthOnlyShader; + depthOnlyShader.init("DepthOnly", + loadFile(Resources::Instance()->getResourceFilePathName("depthonly.vp")), + loadFile(Resources::Instance()->getResourceFilePathName("depthonly.fp"))); + + const uint interpFlag = (flags & SIBR_SCENE_LINEAR_SAMPLING) ? SIBR_GPU_LINEAR_SAMPLING : 0; + + RenderTargetLum32F depthRT(_width, _height, interpFlag); + + GLParameter proj; + proj.init(depthOnlyShader, "proj"); + + + const uint numCams = (uint)cams->inputCameras().size(); + _inputDepthMapArrayPtr.reset(new Texture2DArrayLum32F(_width, _height, numCams, flags)); + + for (uint i = 0; i < numCams; i++) { + glViewport(0, 0, _width, _height); + + depthRT.bind(); + glEnable(GL_DEPTH_TEST); + glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + glDepthMask(GL_TRUE); + + depthOnlyShader.begin(); + proj.set(cams->inputCameras()[i]->viewproj()); + proxies->proxy().render(true, facecull); + depthOnlyShader.end(); + + depthRT.unbind(); + + glCopyImageSubData( + depthRT.handle(), GL_TEXTURE_2D, 0, 0, 0, 0, + _inputDepthMapArrayPtr->handle(), GL_TEXTURE_2D_ARRAY, 0, 0, 0, i, + _width, _height, 1); + CHECK_GL_ERROR; + } + CHECK_GL_ERROR; + } + + const Texture2DArrayLum32F::Ptr & DepthInputTextureArray::getInputDepthMapArrayPtr() const + { + return _inputDepthMapArrayPtr; + } + + void RGBInputTextureArray::initRGBTextureArrays(IInputImages::Ptr imgs, int flags, bool force_aspect_ratio) + { + if (!isInit()) { + std::cerr << "RGBInputTextureArray::initRGBTextureArrays NEW FORCE ASPECT " << force_aspect_ratio << std::endl; + initSize(imgs->inputImages()[_initActiveCam]->w(), imgs->inputImages()[_initActiveCam]->h(), force_aspect_ratio); + } + + _inputRGBArrayPtr.reset(new Texture2DArrayRGB(imgs->inputImages(), _width, _height, flags)); + } + + const Texture2DArrayRGB::Ptr & RGBInputTextureArray::getInputRGBTextureArrayPtr() const + { + return _inputRGBArrayPtr; + } + + void RenderTargetTextures::initializeDefaultRenderTargets(ICalibratedCameras::Ptr cams, IInputImages::Ptr imgs, IProxyMesh::Ptr proxies) + { + if (!isInit()) { + initRenderTargetRes(cams); + + } + initializeImageRenderTargets(cams, imgs); + initializeDepthRenderTargets(cams, proxies, true); + } + + void RenderTargetTextures::initRenderTargetRes(ICalibratedCameras::Ptr cams) + { + // Find the first active camera and use it's reolution to init Rendertargets + for (int i = 0; i < cams->inputCameras().size(); i++) { + if (cams->inputCameras()[i]->isActive()) { + _initActiveCam = i; + return; + } + } + SIBR_ERR << "No cameras active! Fail to initialize RenderTarget!!" << std::endl; + } + + void RenderTargetTextures::initRGBandDepthTextureArrays(ICalibratedCameras::Ptr cams, IInputImages::Ptr imgs, IProxyMesh::Ptr proxies, int textureFlags, int texture_width, bool faceCull, bool force_aspect_ratio) + { + _width = texture_width; + initRGBandDepthTextureArrays(cams, imgs, proxies, textureFlags, faceCull, force_aspect_ratio); + } + + void RenderTargetTextures::initRGBandDepthTextureArrays(ICalibratedCameras::Ptr cams, IInputImages::Ptr imgs, IProxyMesh::Ptr proxies, int textureFlags, unsigned int width, unsigned int height, bool faceCull) + { + initSize(width, height, true); + initRGBTextureArrays(imgs, textureFlags, true); + initDepthTextureArrays(cams, proxies, faceCull); + } + + void RenderTargetTextures::initRGBandDepthTextureArrays(ICalibratedCameras::Ptr cams, IInputImages::Ptr imgs, IProxyMesh::Ptr proxies, int textureFlags, bool faceCull, bool force_aspect_ratio) + { + if (!isInit()) { + initRenderTargetRes(cams); + } + initRGBTextureArrays(imgs, textureFlags, force_aspect_ratio); + initDepthTextureArrays(cams, proxies, faceCull); + } +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/RenderTargetTextures.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/RenderTargetTextures.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e4329ea379b3ea0073cf77d82412825b1d8f4921 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/RenderTargetTextures.hpp @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include "core/graphics/Texture.hpp" +#include "core/scene/ICalibratedCameras.hpp" +#include "core/scene/IInputImages.hpp" +#include "core/scene/IProxyMesh.hpp" +#include "core/assets/Resources.hpp" +# include "core/graphics/Shader.hpp" +#include "core/graphics/Utils.hpp" +#include "core/scene/Config.hpp" + + +# define SIBR_SCENE_LINEAR_SAMPLING 4 + + +namespace sibr{ + + /** + \ingroup sibr_scene + */ + class SIBR_SCENE_EXPORT RTTextureSize { + + public: + RTTextureSize(uint w = 0) : _width(w) {} + + void initSize(uint w, uint h, bool force_aspect_ratio = false); + + bool isInit() const; + + protected: + uint _width = 0; //constrained width provided by the command line args, defaults to 0 + uint _height = 0; //associated height, computed in initSize + bool _isInit = false; + int _initActiveCam = 0; + + }; + + /** + \ingroup sibr_scene + */ + class SIBR_SCENE_EXPORT RGBDInputTextures : public virtual RTTextureSize { + SIBR_CLASS_PTR(RGBDInputTextures) + public: + const std::vector & inputImagesRT() const; + + virtual void initializeImageRenderTargets(ICalibratedCameras::Ptr cams, IInputImages::Ptr imgs); + virtual void initializeDepthRenderTargets(ICalibratedCameras::Ptr cams, IProxyMesh::Ptr proxies, bool facecull); + + protected: + std::vector _inputRGBARenderTextures; + + }; + + /** + \ingroup sibr_scene + */ + class SIBR_SCENE_EXPORT DepthInputTextureArray : public virtual RTTextureSize { + SIBR_CLASS_PTR(DepthInputTextureArray) + public: + virtual void initDepthTextureArrays(ICalibratedCameras::Ptr cams, IProxyMesh::Ptr proxies, bool facecull, int flags = SIBR_GPU_LINEAR_SAMPLING); + const Texture2DArrayLum32F::Ptr & getInputDepthMapArrayPtr() const; + + protected: + Texture2DArrayLum32F::Ptr _inputDepthMapArrayPtr; + + }; + /** + \ingroup sibr_scene + */ + class SIBR_SCENE_EXPORT RGBInputTextureArray : public virtual RTTextureSize { + + SIBR_CLASS_PTR(RGBInputTextureArray) + + public: + virtual void initRGBTextureArrays(IInputImages::Ptr imgs, int flags = 0, bool force_aspect_ratio=false); + const Texture2DArrayRGB::Ptr & getInputRGBTextureArrayPtr() const; + + protected: + Texture2DArrayRGB::Ptr _inputRGBArrayPtr; + + }; + + /** + \ingroup sibr_scene + */ + class SIBR_SCENE_EXPORT RenderTargetTextures : + public virtual RGBDInputTextures, + public virtual DepthInputTextureArray, + public virtual RGBInputTextureArray + { + + public: + SIBR_CLASS_PTR(RenderTargetTextures) + + RenderTargetTextures(uint w = 0) : RTTextureSize(w) {} + + virtual void initRGBandDepthTextureArrays(ICalibratedCameras::Ptr cams, IInputImages::Ptr imgs, IProxyMesh::Ptr proxies, int textureFlags, unsigned int w, unsigned int h, bool faceCull = true); + // TODO: remove this, not needed + virtual void initRGBandDepthTextureArrays(ICalibratedCameras::Ptr cams, IInputImages::Ptr imgs, IProxyMesh::Ptr proxies, int textureFlags, int texture_width, bool faceCull = true, bool force_aspect_ratio = false); + virtual void initRGBandDepthTextureArrays(ICalibratedCameras::Ptr cams, IInputImages::Ptr imgs, IProxyMesh::Ptr proxies, int textureFlags, bool faceCull = true, bool force_aspect_ratio=false); + virtual void initializeDefaultRenderTargets(ICalibratedCameras::Ptr cams, IInputImages::Ptr imgs, IProxyMesh::Ptr proxies); + + protected: + void initRenderTargetRes(ICalibratedCameras::Ptr cams); + + }; + + +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/sibr_scene.dox b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/sibr_scene.dox new file mode 100644 index 0000000000000000000000000000000000000000..919aa241a1cee892922ed754c9569e859f4ae3b2 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/scene/sibr_scene.dox @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +/*! + \defgroup sibr_scene sibr_scene + + \brief IBR Scene components. + +*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Array2d.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Array2d.hpp new file mode 100644 index 0000000000000000000000000000000000000000..beb3aba1db753206d8a5c0c6741e1109e6253902 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Array2d.hpp @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include +#include + +namespace sibr +{ + template class Array2d; + + + /// + /// Used to store custom data on a map using pixel position + /// (2d unsigned pos). + /// Internally, this simply use a one dimensional std::vector. + /// This class abstract convert operation from 2d to 1d for + /// making code easy to read. + /// \ingroup sibr_system + /// + template + class Array2d + { + public: + // We use 'reference' defined by std::vector (and STL) and they are + // a bit special. For example, I suppose that some compiler should + // be able to replace a heave 'const bool&' by a simple 'bool' (in + // this case a copy is far more cheaper). And what about 'bool&' ? + typedef typename std::vector::const_reference const_reference; + typedef typename std::vector::reference reference; + + /// Build from the given size. + /// Note you can't resize your Array2d (just create a new one + /// if you need). + Array2d( uint width=0, uint height=0 ); + /// Build from the given size and using the given default value. + /// Note you can't resize your Array2d (just create a new one + /// if you need). + Array2d( uint width, uint height, const_reference defaultValue ); + + /// Destructor. + ~Array2d( ); + + /// Return the width of this Array2d + uint width( void ) const; + /// Return the height of this Array2d + uint height( void ) const; + /// Return the width of this Array2d + uint w(void) const; + /// Return the height of this Array2d + uint h(void) const; + + /// Return TRUE if is empty + bool empty( void ) const; + + /// Return data about a pixel at given coordinates + const_reference operator ()( uint x, uint y ) const; + /// Access data about a pixel at given coordinates + reference operator ()( uint x, uint y ); + + /// Return data about a pixel at given coordinates + const_reference operator ()(const sibr::Vector2i & coords) const; + /// Access data about a pixel at given coordinates + reference operator ()(const sibr::Vector2i & coords); + + /// Return data about a pixel at given index + const_reference operator []( size_t i ) const; + /// Access data about a pixel at given index + reference operator []( size_t i ); + + /// Return the total size of the one dimensional array + size_t size( void ) const; + + /// Return data accessible in a one array form + /// \deprecated Use Array2d::vector( void ) instead. + const std::vector& operator () ( void ) const; + std::vector& operator () ( void ); + + /// Return the internally used std::vector (so you + /// can use STL algos). + const std::vector& vector( void ) const; + std::vector& vector( void ); + + /// Return a pointer to the first byte a stored + /// data. + void* data( void ) const; + void* data( void ); + + + + /// Return the element index for the given coordinates + inline uint index( uint x, uint y ) const; + + /// Return FALSE if x,y are out of range. (DON'T print error) + inline bool inRange( uint x, uint y ) const; + inline bool isInRange( uint x, uint y) const; + + + protected: + /// Return FALSE if x,y are out of range. (print error) + bool checkSizeFor( uint x, uint y ) const; + + uint _width; ///< Width of the pixel map + uint _height; ///< Height of the pixel map + std::vector _data; ///< data of the pixel map + }; + + + ///// DEFINITION ///// + + template + Array2d::Array2d( uint width, uint height ) + : _width(width), _height(height), _data(_width*_height) { + } + + template + Array2d::Array2d( uint width, uint height, const_reference defaultValue ) + : _width(width), _height(height), _data(_width*_height, defaultValue) { + } + + template + Array2d::~Array2d( ) + { + _data.clear(); + } + + template + uint Array2d::width( void ) const { + return _width; + } + + template + uint Array2d::height( void ) const { + return _height; + } + + template + uint Array2d::w(void) const { + return _width; + } + + template + uint Array2d::h(void) const { + return _height; + } + + + template + typename Array2d::const_reference Array2d::operator ()( uint x, uint y ) const { + checkSizeFor(x, y); + return _data.at(index(x, y)); + } + template + typename Array2d::reference Array2d::operator ()( uint x, uint y) { + checkSizeFor(x, y); + return _data[index(x, y)]; + } + + template + typename Array2d::const_reference Array2d::operator ()(const sibr::Vector2i & coords) const { + return _data[index(coords[0], coords[1])]; + } + template + typename Array2d::reference Array2d::operator ()(const sibr::Vector2i & coords) { + return _data[index(coords[0], coords[1])]; + } + + template + const std::vector& Array2d::operator () ( void ) const { + return _data; + } + template + std::vector& Array2d::operator () ( void ) { + return _data; + } + + + template + const std::vector& Array2d::vector( void ) const { + return _data; + } + template + std::vector& Array2d::vector( void ) { + return _data; + } + + template + void* Array2d::data( void ) const { + return vector().empty()? nullptr : &vector()[0]; + } + template + void* Array2d::data( void ) { + return vector().empty()? nullptr : &vector()[0]; + } + + template + bool Array2d::empty( void ) const { + return vector().empty(); + } + + + template + typename Array2d::const_reference Array2d::operator []( size_t i ) const { + return _data.at(i); + } + + template + typename Array2d::reference Array2d::operator []( size_t i ) { + return _data[i]; + } + + template + size_t Array2d::size( void ) const { + return _data.size(); + } + + + template + uint Array2d::index( uint x, uint y ) const { + return y*_width + x; + } + + template + bool Array2d::inRange( uint x, uint y ) const { + return (x < _width && y < _height); + } + + template + bool Array2d::isInRange(uint x, uint y) const { + return (x < _width && y < _height); + } + + template + bool Array2d::checkSizeFor( uint x, uint y ) const { + if (inRange(x, y)) + return true; + //else + SIBR_ERR << "invalid pixelmap range at " << x << ", " << y + << "(current size: " << _width << ", " << _height << "). " + << std::endl; + + assert(false);// else it will crash because of std::vector + return false; + } + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/system/ByteStream.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/ByteStream.cpp new file mode 100644 index 0000000000000000000000000000000000000000..825bfb6c48f7b018449f7c5193883ee46f21338d --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/ByteStream.cpp @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#include +#include +#include + +#ifndef SIBR_OS_WINDOWS +# include +#endif + +#include "core/system/ByteStream.hpp" + + +namespace sibr +{ + void ByteStream::memoryDump( void ) const + { + const unsigned char* data = reinterpret_cast(&_buffer[0]); + std::cout << "Readable size: " << readableSize() << std::endl; + std::cout << "Real size: " << bufferSize() << std::endl; + std::cout << std::hex << std::setfill('0') << std::setw(2); + for (unsigned i = 0; i < _buffer.size(); ++i) + { + const int blocksize = 2; + for (unsigned j = 0; i < _buffer.size() && j < blocksize; ++j, ++i) + std::cout << uint(data[i]); + std::cout << ' '; + for (unsigned j = 0; i < _buffer.size() && j < blocksize; ++j, ++i) + std::cout << uint(data[i]); + std::cout << ' '; + for (unsigned j = 0; i < _buffer.size() && j < blocksize; ++j, ++i) + std::cout << uint(data[i]); + std::cout << ' '; + for (unsigned j = 0; i < _buffer.size() && j < blocksize; ++j, ++i) + std::cout << uint(data[i]); + std::cout << ' '; + std::cout << std::endl; + } + std::cout << std::dec << std::setw(0); + } + + uint64 ByteStream::htonll(uint64 n) + { + if (ByteStream::systemIsBigEndian()) + return n; + // Else we are on a little endian system + uint32 out = 0; + out |= (n & 0xFF00000000000000) >> 56; + out |= (n & 0x00FF000000000000) >> 40; + out |= (n & 0x0000FF0000000000) >> 24; + out |= (n & 0x000000FF00000000) >> 8; + out |= (n & 0x00000000FF000000) << 8; + out |= (n & 0x0000000000FF0000) << 24; + out |= (n & 0x000000000000FF00) << 40; + out |= (n & 0x00000000000000FF) << 56; + return out; + } + + uint32 ByteStream::htonl( uint32 n ) + { + if (ByteStream::systemIsBigEndian()) + return n; + // Else we are on a little endian system + uint32 out = 0; + + out |= (n & 0xFF000000) >> 24; + out |= (n & 0x00FF0000) >> 8; + out |= (n & 0x0000FF00) << 8; + out |= (n & 0x000000FF) << 24; + return out; + } + + uint16 ByteStream::htons( uint16 n ) + { + if (ByteStream::systemIsBigEndian()) + return n; + // Else we are on a little endian system + uint16 out = 0; + + out |= (n & 0xFF00) >> 8; + out |= (n & 0x00FF) << 8; + return out; + } + + bool ByteStream::systemIsBigEndian( void ) + { + static int16 isBigEndian = -1; + if (isBigEndian == -1) + { + /// \todo TODO: check the compiler is not too smart and that it does not + /// optimize this at compile-time with a const. + int16 word = 0x0001; + char *b = (char *) &word; + isBigEndian = (b[0]? 0 /*little endian*/ : 1 /*big endian*/); + } + return isBigEndian != 0; + } + + bool ByteStream::load( const std::string& filename ) + { + std::ifstream file(filename.c_str(), std::ios::in | std::ios::binary); + + if (file) + { + file.seekg(0, file.end); + auto len = file.tellg(); + file.seekg(0, file.beg); + + _buffer.resize(len); + file.read(reinterpret_cast(&_buffer[0]), len); + + file.close(); + return true; + } + else + SIBR_WRG << "cannot load ByteStream from file '" << filename << "'." << std::endl; + return false; + } + + void ByteStream::saveToFile( const std::string& filename ) + { + if (bufferSize() == 0) + return; + + std::ofstream file(filename.c_str(), std::ios::out | std::ios::binary | std::ios::trunc); + + if (file) + { + file.write((char*)&_buffer[0], _buffer.size() * sizeof(_buffer[0])); + file.close(); + } + else + SIBR_LOG << "ERROR: cannot write to the file '" << filename << "'" << std::endl; + } + + void ByteStream::push(const void* data, uint size) + { + assert(data != nullptr && size > 0); + + size_t curpos = _buffer.size(); + _buffer.resize(curpos + size); + memcpy(&_buffer[curpos], data, size); + } + + + ByteStream& ByteStream::operator <<( bool b ) + { + return ByteStream::operator << (static_cast(b)); + } + + ByteStream& ByteStream::operator <<( int8 i ) + { + push(&i, sizeof(i)); + return *this; + } + + ByteStream& ByteStream::operator <<( int16 i ) + { + int16 netorder = htons(i); + push(&netorder, sizeof(netorder)); + return *this; + } + + ByteStream& ByteStream::operator <<( int32 i ) + { + int32 netorder = htonl(i); + push(&netorder, sizeof(netorder)); + return *this; + } + + ByteStream& ByteStream::operator <<( int64 i ) + { + int64 netorder = htonll(i); + push(&netorder, sizeof(netorder)); + return *this; + } + + ByteStream& ByteStream::operator <<( uint8 i ) + { + push(&i, sizeof(i)); + return *this; + } + + ByteStream& ByteStream::operator <<( uint16 i ) + { + uint16 netorder = htons(i); + push(&netorder, sizeof(netorder)); + return *this; + } + + ByteStream& ByteStream::operator <<( uint32 i ) + { + uint32 netorder = htonl(i); + push(&netorder, sizeof(netorder)); + return *this; + } + + ByteStream& ByteStream::operator <<(uint64 i) + { + uint64 netorder = htonll(i); + push(&netorder, sizeof(netorder)); + return *this; + } + + ByteStream& ByteStream::operator <<( const std::string& str ) + { + uint32 size = static_cast(str.size()); + operator << (size); + push(str.data(), sizeof(char)*size); + return *this; + } + + ByteStream& ByteStream::operator <<( float f ) + { + int32* p = (int32*)&f; + return ByteStream:: operator<<( *p ); + } + + ByteStream& ByteStream::operator <<(double d) + { + int64* p = (int64*)&d; + return ByteStream:: operator<<(*p); + } + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/system/ByteStream.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/ByteStream.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5211c713b8cd9a58e7c3ea72144ebee0b3005c3e --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/ByteStream.hpp @@ -0,0 +1,457 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include +# include +# include "core/system/Config.hpp" + + +namespace sibr +{ + /// Be sure to use STL objects from client's dll version by exporting this declaration (see warning C4251) + //template class SIBR_EXPORT std::vector; + + /** + Used to manipulate stream of bytes. + \note This ByteStream stores integer using the network byte order (which is big endian). + \ingroup sibr_system + */ + class SIBR_SYSTEM_EXPORT ByteStream + { + public: + + /** Stream endianness, always default to BigEndian. */ + enum Endianness + { + BigEndian = 0, // always default + LittleEndian + }; + + public: + typedef std::vector bytes; ///< type used for storing bytes + + /// Constructor + ByteStream( void ) : _readPos(0), _valid(true) /*,_endianness(BigEndian)*/ { } + + /** Load all bytes from a file using the given filename + * \param filename the filename + * \return success boolean + * */ + bool load( const std::string& filename ); + + /** Save all bytes to a file using the given filename + *\param filename file apth + **/ + void saveToFile( const std::string& filename ); + + /** Append data to the current buffer + *\param data pointer to the data + *\param size size in bytes + **/ + void push(const void* data, uint size); + + /** \return true if the stream is opened and valid. */ + operator bool( void ) const { return _valid; } + + /** Write a bool to the stream. + *\param b input value + *\return the stream (for chaining). + **/ + ByteStream& operator <<( bool b ); + + /** Write an 8bits-integer to the stream. + *\param i input value + *\return the stream (for chaining). + **/ + ByteStream& operator <<( int8 i ); + + /** Write a 16bits-integer to the stream. + *\param i input value + *\return the stream (for chaining). + **/ + ByteStream& operator <<( int16 i ); + + /** Write a 32bits-integer to the stream. + *\param i input value + *\return the stream (for chaining). + **/ + ByteStream& operator <<( int32 i ); + + /** Write a 64bits-integer to the stream. + *\param i input value + *\return the stream (for chaining). + **/ + ByteStream& operator <<( int64 i ); + + /** Write an 8bits-unsigned-integer to the stream. + *\param i input value + *\return the stream (for chaining). + **/ + ByteStream& operator <<( uint8 i ); + + /** Write a 16bits-unsigned-integer to the stream. + *\param i input value + *\return the stream (for chaining). + **/ + ByteStream& operator <<( uint16 i ); + + /** Write a 32bits-unsigned-integer to the stream. + *\param i input value + *\return the stream (for chaining). + **/ + ByteStream& operator <<( uint32 i ); + + /** Write a 64bits-unsigned-integer to the stream. + *\param i input value + *\return the stream (for chaining). + **/ + ByteStream& operator <<( uint64 i ); + + /** Write a string to the stream. + *\param str input value + *\return the stream (for chaining). + **/ + ByteStream& operator <<( const std::string& str ); + + /** Write a float to the stream. + *\param f input value + *\return the stream (for chaining). + *\note Use the same endianness as for integers (not specified in IEEE 754). + **/ + ByteStream& operator <<( float f ); + + /** Write a double to the stream. + *\param d input value + *\return the stream (for chaining). + **/ + ByteStream& operator <<(double d); + + /** Read a bool from the stream. + *\param b output value + *\return the stream (for chaining). + **/ + inline ByteStream& operator >>( bool & b ); + + /** Read an 8bits-integer from the stream. + *\param i output value + *\return the stream (for chaining). + **/ + inline ByteStream& operator >>( int8& i ); + + /** Read a 16bits-integer from the stream. + *\param i output value + *\return the stream (for chaining). + **/ + inline ByteStream& operator >>( int16& i ); + + /** Read a 32bits-integer from the stream. + *\param i output value + *\return the stream (for chaining). + **/ + inline ByteStream& operator >>( int32& i ); + + /** Read a 64bits-integer from the stream. + *\param i output value + *\return the stream (for chaining). + **/ + inline ByteStream& operator >>( int64& i ); + + /** Read an 8bits-unsigned-integer from the stream. + *\param i output value + *\return the stream (for chaining). + **/ + inline ByteStream& operator >>( uint8& i ); + + /** Read a 16bits-unsigned-integer from the stream. + *\param i output value + *\return the stream (for chaining). + **/ + inline ByteStream& operator >>( uint16& i ); + + /** Read a 32bits-unsigned-integer from the stream. + *\param i output value + *\return the stream (for chaining). + **/ + inline ByteStream& operator >>( uint32& i ); + + /** Read a 64bits-unsigned-integer from the stream. + *\param i output value + *\return the stream (for chaining). + **/ + inline ByteStream& operator >>( uint64 & i ); + + /** Read a string from the stream. + *\param str output value + *\return the stream (for chaining). + **/ + inline ByteStream& operator >>( std::string& str ); + + /** Read a float from the stream. + *\param f output value + *\return the stream (for chaining). + *\note Use the same endianness as for integers (not specified in IEEE 754). + **/ + inline ByteStream& operator >>( float& f ); + + /** Read a double from the stream. + *\param d output value + *\return the stream (for chaining). + **/ + inline ByteStream& operator >>(double& d); + + /** \return the number of bytes that have not been read yet.*/ + inline size_t readableSize( void ) const; + /** \return the total number of bytes in the buffer used by the stream*/ + inline size_t bufferSize( void ) const; + /** \return a pointer to the buffer */ + inline const uint8* buffer( void ) const { return &_buffer[0]; } + + // We don't want to include network-related libs (and all their stuffs), so we use a custom implementation of htonl/htons, ntohl/ntohs. + + /** Convert an uint32 from host to network byte order (which is big endian) + *\param n host order value + *\return network order value + **/ + static uint64 htonll(uint64 n); + + /** Convert an uint32 from host to network byte order (which is big endian) + *\param n host order value + *\return network order value + **/ + static uint32 htonl( uint32 n ); + + /** Convert an uint16 from host to network byte order (which is big endian) + *\param n host order value + *\return network order value + **/ + static uint16 htons( uint16 n ); + + /** Convert an uint32 from network to host byte order + *\param n network order value + *\return host order value + **/ + inline static uint64 ntohll(uint64 n); + + /** Convert an uint32 from network to host byte order + *\param n network order value + *\return host order value + **/ + inline static uint32 ntohl( uint32 n ); + + /** Convert an uint16 from network to host byte order + *\param n network order value + *\return host order value + **/ + inline static uint16 ntohs( uint16 n ); + + /** \return true if the current system runs using Big Endian **/ + static bool systemIsBigEndian( void ); + + // (Not used for now: future features to change how are stored float) + // void setEndianness( Endianness e ); + // Endianness getEndianness( void ); + + /** Dump the buffer contents to stdout. (used for debugging purposes) + **/ + void memoryDump( void ) const; + + private: + /** Test if we can read n bytes in the buffer. + *\param n the number of bytes to check + *\return false if it fails (and set valid flag to false). + **/ + inline bool testSize( uint n ); + + bytes _buffer; ///< the whole stream + uint32 _readPos; ///< Current position in the buffer when reading. + bool _valid; ///< tells if no error occured when reading + // Endianness _endianness; + + }; + + ///// INLINE FUNCTIONS ///// + size_t ByteStream::readableSize( void ) const { + return bufferSize() - _readPos; + } + size_t ByteStream::bufferSize( void ) const { + return _buffer.size(); + } + + uint64 ByteStream::ntohll(uint64 n) { + return htonll(n); + } + uint32 ByteStream::ntohl( uint32 n ) { + return htonl(n); + } + uint16 ByteStream::ntohs( uint16 n ) { + return htons(n); + } + bool ByteStream::testSize( uint n ) { + return (_valid = (_valid && (readableSize() >= n))); + } + + ByteStream& ByteStream::operator >>( bool& b ) { + uint8 i; + ByteStream::operator >>(i); + b = (i != 0); + return *this; + } + ByteStream& ByteStream::operator >>( int8& i ) { + if (testSize(sizeof(i))) + { + i = *reinterpret_cast(&_buffer[_readPos]); + _readPos += sizeof(i); + } + return *this; + } + ByteStream& ByteStream::operator >>( int16& i ) { + if (testSize(sizeof(i))) + { + i = ntohs(*reinterpret_cast(&_buffer[_readPos])); + _readPos += sizeof(i); + } + return *this; + } + + ByteStream& ByteStream::operator >>( int32& i ) { + if (testSize(sizeof(i))) + { + i = ntohl(*reinterpret_cast(&_buffer[_readPos])); + _readPos += sizeof(i); + } + return *this; + } + ByteStream& ByteStream::operator >>(int64& i) { + if (testSize(sizeof(i))) + { + i = ntohll(*reinterpret_cast(&_buffer[_readPos])); + _readPos += sizeof(i); + } + return *this; + } + + ByteStream& ByteStream::operator >>( uint8& i ) { + if (testSize(sizeof(i))) + { + i = *reinterpret_cast(&_buffer[_readPos]); + _readPos += sizeof(i); + } + return *this; + } + ByteStream& ByteStream::operator >>( uint16& i ) { + if (testSize(sizeof(i))) + { + i = ntohs(*reinterpret_cast(&_buffer[_readPos])); + _readPos += sizeof(i); + } + return *this; + } + ByteStream& ByteStream::operator >>( uint32& i ) { + if (testSize(sizeof(i))) + { + i = ntohl(*reinterpret_cast(&_buffer[_readPos])); + _readPos += sizeof(i); + } + return *this; + } + ByteStream& ByteStream::operator >>(uint64& i) { + if (testSize(sizeof(i))) + { + i = ntohll(*reinterpret_cast(&_buffer[_readPos])); + _readPos += sizeof(i); + } + return *this; + } + ByteStream& ByteStream::operator >>( std::string& str ) { + uint32 size; + operator >> (size); + str.resize(size); + + if (testSize(sizeof(char)*size)) + { + str.insert(str.begin(), + reinterpret_cast(&_buffer[_readPos]), + reinterpret_cast(&_buffer[_readPos + size])); + _readPos += sizeof(char)*size; + } + return *this; + } + ByteStream& ByteStream::operator >>( float& f ) { + int32 p; + ByteStream::operator>> (p); + char* ptr = (char*)&p; + float *fptr = (float*)ptr; + if (_valid) + f = *fptr; + return *this; + } + ByteStream& ByteStream::operator >>( double& d ) { + int64 p; + ByteStream::operator>> (p); + char* ptr = (char*)&p; + double *fptr = (double*)ptr; + if (_valid) + d = *fptr; + return *this; + } + + // Function used to test this class (might be still useful to test future improvement) + /* + static void unitTestByteStream( void ) + { + SIBR_LOG << "[work in progress] - testing ByteStream" << std::endl; + + struct SomeData { + bool b; + int8 s8; + uint8 u8; + int16 s16; + uint16 u16; + int32 s32; + uint32 u32; + float f; + + void dump( void ) { + SIBR_DEBUG(b); + SIBR_DEBUG(s8); + SIBR_DEBUG(u8); + SIBR_DEBUG(s16); + SIBR_DEBUG(u16); + SIBR_DEBUG(s32); + SIBR_DEBUG(u32); + SIBR_DEBUG(f); + } + }; + + SomeData di = {true, -30, 120, -12000, 23000, -1234567, 2345678, 2.8f}; + std::cout << "Dumping DataIN:" << std::endl; + di.dump(); + + sibr::ByteStream bytes; + + bytes << di.b << di.s8 << di.u8 << di.s16 << di.u16 << di.s32 << di.u32 << di.f; + SomeData dout = {false, 0, 0, 0, 0, 0, 0, 0.f}; + std::cout << "Dumping DataOUT:" << std::endl; + dout.dump(); + + bytes.memoryDump(); + + + bytes >> dout.b >> dout.s8 >> dout.u8 >> dout.s16 >> dout.u16 >> dout.s32 >> dout.u32 >> dout.f; + std::cout << "Dumping DataOUT:" << std::endl; + dout.dump(); + } + */ + + } // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/system/CMakeLists.txt b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..9e0a4afb78089449c9bbd9ef2d50f5b0d0633743 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/CMakeLists.txt @@ -0,0 +1,48 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +project(sibr_system) + +file(GLOB SOURCES "*.cpp" "*.h" "*.hpp") +source_group("Source Files" FILES ${SOURCES}) + +## Specify target rules +add_library(${PROJECT_NAME} SHARED ${SOURCES}) + +include_directories( + ${Boost_INCLUDE_DIRS} + ${picojson_INCLUDE_DIRS} + ${rapidxml_INCLUDE_DIRS} +) +if (WIN32) +target_link_libraries(${PROJECT_NAME} + ${Boost_LIBRARIES} + picojson + rapidxml + nfd +) +else() +target_link_libraries(${PROJECT_NAME} + ${Boost_LIBRARIES} + picojson + rapidxml + nativefiledialog +) +endif() + +add_definitions( -DSIBR_SYSTEM_EXPORTS -DBOOST_ALL_DYN_LINK ) + +set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER ${SIBR_FOLDER}) + +## High level macro to install in an homogen way all our ibr targets +include(install_runtime) +ibr_install_target(${PROJECT_NAME} + INSTALL_PDB ## mean install also MSVC IDE *.pdb file (DEST according to target type) +) diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/system/CommandLineArgs.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/CommandLineArgs.cpp new file mode 100644 index 0000000000000000000000000000000000000000..31ef823585bbf8567a88745e117a580747049420 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/CommandLineArgs.cpp @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#include "core/system/CommandLineArgs.hpp" +#include "core/system/Utils.hpp" + + +namespace sibr +{ + CommandLineArgs CommandLineArgs::global = CommandLineArgs(); + + const CommandLineArgs & getCommandLineArgs() + { + return CommandLineArgs::getGlobal(); + } + + CommandLineArgs & CommandLineArgs::getGlobal() + { + static bool first = true; + if (!global.init && first) { + SIBR_WRG << "CommandLineArgs::parseMainArgs(ac, av) was not called rigth after main(ac, av) \n default value (empty command line) will be used" << std::endl; + first = false; + } + return global; + } + + void CommandLineArgs::parseMainArgs(const int argc, const char * const * argv) + { + static const std::vector acceptable_prefixes = { "--", "-" }; + + global.args.clear(); + + global.args["app_path"] = { std::string(argv[0])}; + + std::string current_arg; + for (int i = 1; i < argc; ++i) { + std::string arg = std::string(argv[i]); + bool new_arg = false; + for (const auto & prefix : acceptable_prefixes) { + if (arg.substr(0, prefix.size()) == prefix) { + current_arg = arg.substr(prefix.size()); + new_arg = true; + break; + } + } + if (current_arg.empty()) { + continue; + } + if (new_arg) { + if (global.args.count(current_arg) > 0) { + SIBR_WRG << "Collision for argument : " << arg << std::endl; + } else { + global.args[current_arg] = {}; + } + } else { + global.args[current_arg].push_back(arg); + } + } + + global.init = true; + } + + bool CommandLineArgs::contains(const std::string & key) const + { + return args.count(key) > 0; + } + + int CommandLineArgs::numArguments(const std::string & key) const + { + if (contains(key)) { + return (int)args.at(key).size(); + } else { + return -1; + } + } + + + void CommandLineArgs::displayHelp() const { + // Find the maximum length. + size_t maxLength = 0; + for (const auto & command : commands) { + maxLength = std::max(maxLength, command.first.size()); + } + + const Path path = args.at("app_path")[0]; + SIBR_LOG << "Help for " << path.filename().string() << ":" << std::endl; + for(const auto & command : commands) { + // Pad to align everything. +#ifdef WIN32 // green + std::string req = "[required]"; + std::string sec = command.second, xx; + bool tgreen = false; + if(sec.substr(sec.size()-req.size(), req.size()+1) == req) { + setupConsole(); + printf("\x1b[32m"); + tgreen = true; + } +#endif + std::cout << "\t" << "--" << command.first; + std::cout << std::string(int(maxLength) - command.first.size() + 1, ' '); + std::cout << command.second << std::endl; + +#ifdef WIN32 + if( tgreen ) + restoreConsole(); +#endif + } + std::cout << std::endl; + } + + void CommandLineArgs::registerCommand(const std::string & key, const std::string & description, const std::string & defaultValue) { + // Register the command. + std::string defaultDesc = description.empty() ? "" : " "; + defaultDesc.append("(default: " + defaultValue + ")"); + commands[key] = description + defaultDesc; + } + + void CommandLineArgs::registerRequiredCommand(const std::string & key, const std::string & description) { + // Register the command. + std::string defaultDesc = description.empty() ? "" : " "; + defaultDesc.append("[required]"); + commands[key] = description + defaultDesc; + } + + + AppArgs::AppArgs() + { + Path path = CommandLineArgs::getGlobal().getRequired("app_path"); + appName = path.filename().string(); + appPath = path.parent_path().string(); + } + + void AppArgs::displayHelpIfRequired() const { + if(showHelp.get()) { + getCommandLineArgs().displayHelp(); + } + } + +} // namespace sirb + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/system/CommandLineArgs.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/CommandLineArgs.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b83e9a14870064e8e517269b4afa18d3d9df8b4b --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/CommandLineArgs.hpp @@ -0,0 +1,540 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include +# include +# include + +# include "Config.hpp" +# include + +namespace sibr +{ + /** + \addtogroup sibr_system + @{ + */ + + /// Used to wrap a toggle argument in the command line. + struct Switch {}; + + /// uint contexpr helper, defining the number of command line tokens required to init T + template + constexpr uint NumberOfArg = 1; + /// uint contexpr helper, defining the number of command line tokens required to init T + template<> + constexpr uint NumberOfArg = 0; + /// uint contexpr helper, defining the number of command line tokens required to init T + template<> + constexpr uint NumberOfArg = 0; + /// uint contexpr helper, defining the number of command line tokens required to init T + template + constexpr uint NumberOfArg> = N * NumberOfArg; + + /// Helper to extract values from a vector of strings. + template struct ValueGetter { + + /** Extract the N-th element from a vector of string representations. + \param values a list of strings representing elements + \param n the index of the element to query + \return the element corresponding to the N-th string. + */ + static T get(const std::vector & values, uint n); + + /** Convert an element to its string representation. + \param value the element to convert + \return the string representation + */ + static std::string toString(const T & value); + }; + + /** Available rendering modes for IBR views. */ + enum RenderingModes { + RENDERMODE_MONO, + RENDERMODE_STEREO_ANAGLYPH, + RENDERMODE_STEREO_QUADBUFFER + }; + + + + /** @} */ + + /* Parse and store the command line arguments specified by the user. + * Only a static instance exists, that must be init with parseMainArgs(argc,argv) right after main(argc,argv) + * Parses -key or --key with any number of value. + * \ingroup sibr_system + */ + class SIBR_SYSTEM_EXPORT CommandLineArgs { + + public: + + /** Populate arguments list, should be called once at launch. + * \param argc argument count + * \param argv argument list + * */ + static void parseMainArgs(const int argc, const char* const* argv); + + /** Get the Nth parsed element following -key or --key as a T + * If not available (key not found or not enough token), return default_val argument + * \param key the argument keyword + * \param default_val the default value to use if not present + * */ + template + T get(const std::string & key, const T & default_val) const { + T out; + if (getInternal(key, out)) { + return out; + } else { + return default_val; + } + } + + /** Get the Nth parsed element following -key or --key as a T + * If not available (key not found or not enough token), an error is raised. + * \param key the argument keyword + * */ + template + T getRequired(const std::string & key) const { + T out; + if (!getInternal(key, out)) { + SIBR_ERR; + } + return out; + } + + /** Register a command for the help message. + * \param key the command + * \param description a string describing the use of the command + * \param defaultValue string representation of the default value + */ + void registerCommand(const std::string & key, const std::string & description, const std::string & defaultValue); + + /** Register a mandatory command for the help message. + * \param key the command + * \param description a string describing the use of the command + */ + void registerRequiredCommand(const std::string & key, const std::string & description); + + /** Check if a given argument was specified by the user. + *\param key the argument to look for + *\return whether the argument was specified + */ + bool contains(const std::string & key) const; + + /** Count how many parameters were specified by the suer for a given argument. + *\param key the argument to look for + *\return the number of parameters + */ + int numArguments(const std::string & key) const; + + /** Global instance getter. */ + static CommandLineArgs & getGlobal(); + + /** Display an help message to stdout. */ + void displayHelp() const; + + protected: + + /// Default constructor. + CommandLineArgs() = default; + + /** Get the Nth parsed element following -key or --key as a T + * If not available (key not found or not enough token), an error is raised. + * */ + template + bool getInternal(const std::string & key, T & val) const { + if (contains(key) && (N + 1)*NumberOfArg <= args.at(key).size()) { + val = ValueGetter::get(args.at(key), N); + + return true; + } else { + return false; + } + } + + std::map> args; ///< List of arguments input by the user and their parameters. + std::map commands; ///< List of registered commands to display the help. + bool init = false; ///< Have the arguments been parsed. + + static CommandLineArgs global;///< Singleton (because there is only one command line). + }; + + /** Getter for the command line args manager singleton. + * \ingroup sibr_system + */ + SIBR_SYSTEM_EXPORT const CommandLineArgs & getCommandLineArgs(); + + /** Internal argument based interface. + * \ingroup sibr_system*/ + template + class ArgBase { + public: + + /// \return a reference to the argument value + operator const T &() const { return _value; } + + /// \return a reference to the argument value + const T & get() const { return _value; } + + /** Copy operator. + \param t the value to copy + \return a reference to the argument value + */ + T & operator=(const T & t) { _value = t; return _value; } + + protected: + + T _value; ///< the argument value. + }; + + /** Template Arg class, will init itself in the defaut ctor using the command line args (ie. --key value) + * Should be declared as some class/struct member using Arg myArg = { "key", some_default_value }; + * is implicitly convertible to the template type + * \note As multiple implicit conversion is not possible in cpp, you might have to use the .get() method to access the inner T value + * \ingroup sibr_system + * */ + template + class Arg : public ArgBase { + public: + /** Constructor + *\param key the command argument + *\param default_value the default value + *\param description help message description + */ + Arg(const std::string & key, const T & default_value, const std::string & description = "") { + this->_value = CommandLineArgs::getGlobal().get(key, default_value); + // \todo We could display default values if we had a common stringization method. + CommandLineArgs::getGlobal().registerCommand(key, description, ValueGetter::toString(default_value)); + } + using ArgBase::operator=; + }; + + /// Specialization of Arg for Switch, default value get flipped if arg is present + /// \ingroup sibr_system + template<> + class Arg : public ArgBase { + public: + /** Constructor + *\param key the command argument + *\param default_value the default boolean value + *\param description help message description + */ + Arg(const std::string & key, const bool & default_value, const std::string & description = "") { + const bool arg_is_present = CommandLineArgs::getGlobal().get(key, false); + if (arg_is_present) { + _value = !default_value; + } else { + _value = default_value; + } + const std::string defaultDesc = (default_value ? "enabled" : "disabled"); + CommandLineArgs::getGlobal().registerCommand(key, description, defaultDesc); + } + + using ArgBase::operator=; + }; + using ArgSwitch = Arg; + + /// Specialization of Arg for bool, value is true if key is present and false otherwise + /// \ingroup sibr_system + template<> + class Arg : public ArgBase { + public: + /** Constructor + *\param key the command argument + *\param description help message description + *\note Will default to false + */ + Arg(const std::string & key, const std::string & description = "") { + const bool arg_is_present = CommandLineArgs::getGlobal().get(key, false); + _value = arg_is_present; + CommandLineArgs::getGlobal().registerCommand(key, description, "disabled"); + } + + using ArgBase::operator=; + }; + + /// Represent a mandatory argument + /// \ingroup sibr_system + template + class RequiredArgBase { + public: + /** Constructor + *\param _key the command argument + *\param description help message description + */ + RequiredArgBase(const std::string & _key, const std::string & description = "") : key(_key) { + if (CommandLineArgs::getGlobal().contains(key)) { + _value = CommandLineArgs::getGlobal().get(key, _value); + wasInit = true; + } + CommandLineArgs::getGlobal().registerRequiredCommand(key, description); + } + + /// \return a reference to the argument value + operator const T &() const { checkInit(); return _value; } + + /// \return a reference to the argument value + const T & get() const { checkInit(); return _value; } + + /** Copy operator. + \param t the value to copy + \return a reference to the argument value + */ + T & operator=(const T & t) { _value = t; wasInit = true; return _value; } + + /// \return true if the argument was given + const bool & isInit() const { return wasInit; } + + protected: + + /** Check if the argument was init.If not, as it is a required argument we display the help message and raise an error.*/ + void checkInit() const { + if (!wasInit) { + CommandLineArgs::getGlobal().displayHelp(); + SIBR_ERR << "Argument \"" << key << "\" is required." << std::endl; + } + } + + std::string key; ///< Argument key. + T _value; ///< Argument value. + bool wasInit = false; ///< Was the argument initialized. + }; + + /// Similar to Arg, except this one will crash if attempt to use the value while not initialized + /// initialization can be done using the command line or manually + /// \ingroup sibr_system + template + class RequiredArg : public RequiredArgBase { + using RequiredArgBase::RequiredArgBase; + }; + + /// Specialization required for std::string as const string & key constructor and const T & constructor are ambiguous. + /// TT : no const T & ctor anymore but operator const char*() const operator added + /// \ingroup sibr_system + template<> + class RequiredArg : public RequiredArgBase { + + public: + using RequiredArgBase::RequiredArgBase; + std::string & operator=(const std::string & t) { _value = t; wasInit = true; return _value; } + + operator const char*() const { checkInit(); return _value.c_str(); } + }; + + /// Hierarchy of Args classes that can be seens as modules, and can be combined using virtual inheritance, with no duplication of code so derived Args has no extra work to do + /// Assuming CommandLineArgs::parseMainArgs() was called once, Args arguments will be automatically initialized with the value from the command line by the constructor + /// Existing Args structs should cover most of the existing IBR apps + /// To add a new argument like --my-arg 5 on top of existing arguments and + /// to add a new required argument like --important-param "on" on top of existing arguments, do the following: + /// + /// struct SIBR_SYSTEM_EXPORT MyArgs : virtual ExistingArg1, virtual ExistingArgs2, ... { + /// Arg myParameter = { "my-arg", some_default_value }; + /// RequiredArg myRequiredParameter = { "important-param" }; + /// } + /// \ingroup sibr_system + struct SIBR_SYSTEM_EXPORT AppArgs { + /// Constructor + AppArgs(); + + std::string appName; + std::string appPath; + Arg custom_app_path = { "appPath", "./", "define a custom app path" }; + Arg showHelp = {"help", "display this help message"}; + + /// Helper to print the help message if the help argument was passed. + void displayHelpIfRequired() const; + + // offline path rendering options + Arg noExit = {"noExit", "dont exit after rendering path "}; + Arg pathFile = { "pathFile", "", "filename of path to render offline; app renders path and exits" }; // app needs to handle this; if it does default behavior is to render the path and exit + Arg outPath = { "outPath", "pathOutput", "Path of directory to store path output default relative the input path directory " }; // app needs to handle this; if it does default behavior is to render the path and exit + + }; + + /// Arguments related to a window. + /// \ingroup sibr_system + struct SIBR_SYSTEM_EXPORT WindowArgs { + Arg win_width = { "width", 720, "initial window width" }; + Arg win_height = { "height", 480, "initial window height" }; + Arg vsync = { "vsync", 1, "enable vertical sync" }; + Arg fullscreen = { "fullscreen", "set the window to fullscreen" }; + Arg hdpi = { "hd", "rescale UI elements for high-density screens" }; + Arg no_gui = { "nogui", "do not use ImGui" }; + Arg gl_debug = { "gldebug", "enable OpenGL error callback" }; + Arg offscreen = { "offscreen", "do not open window" }; + }; + + /// Combination of window and application arguments. + /// \ingroup sibr_system + struct SIBR_SYSTEM_EXPORT WindowAppArgs : + virtual AppArgs, virtual WindowArgs { + }; + + /// Common rendering settings. + /// \ingroup sibr_system + struct SIBR_SYSTEM_EXPORT RenderingArgs { + Arg scene_metadata_filename = { "scene", "scene_metadata.txt", "scene metadata file" }; + Arg rendering_size = { "rendering-size", { 0, 0 }, "size at which rendering is performed" }; + Arg texture_width = { "texture-width", 0 , "size of the input data in memory"}; + Arg texture_ratio = { "texture-ratio", 1.0f }; + Arg rendering_mode = { "rendering-mode", RENDERMODE_MONO, "select mono (0) or stereo (1) rendering mode" }; + Arg focal_pt = { "focal-pt", {0.0f, 0.0f, 0.0f} }; + Arg colmap_fovXfovY_flag = { "colmap_fovXfovY_flag", false }; + Arg force_aspect_ratio = { "force-aspect-ratio", false }; + }; + + /// Dataset related arguments. + /// \ingroup sibr_system + struct SIBR_SYSTEM_EXPORT BasicDatasetArgs { + RequiredArg dataset_path = { "path", "path to the dataset root" }; + Arg dataset_type = { "dataset_type", "", "type of dataset" }; + }; + + /// "Default" set of arguments. + /// \ingroup sibr_system + struct SIBR_SYSTEM_EXPORT BasicIBRAppArgs : + virtual WindowAppArgs, virtual BasicDatasetArgs, virtual RenderingArgs { + }; + + /// Specialization of value getter for strings. + /// \ingroup sibr_system + template<> + struct ValueGetter { + static std::string get(const std::vector & values, uint n) { + return values[n]; + } + static std::string toString(const std::string & value) { + return "\"" + value + "\""; + } + }; + + /// Specialization of value getter for booleans. + /// \ingroup sibr_system + template<> + struct ValueGetter { + static bool get(const std::vector & values, uint n) { + return true; + } + static std::string toString(const bool & value) { + return value ? "true" : "false"; + } + }; + + /// Specialization of value getter for doubles. + /// \ingroup sibr_system + template<> + struct ValueGetter { + static double get(const std::vector & values, uint n) { + return std::stod(values[n]); + } + static std::string toString(const double & value) { + return std::to_string(value); + } + }; + + /// Specialization of value getter for floats. + /// \ingroup sibr_system + template<> + struct ValueGetter { + static float get(const std::vector & values, uint n) { + return std::stof(values[n]); + } + static std::string toString(const float & value) { + return std::to_string(value); + } + }; + + /// Specialization of value getter for integers. + /// \ingroup sibr_system + template<> + struct ValueGetter { + static int get(const std::vector & values, uint n) { + return std::stoi(values[n]); + } + static std::string toString(const int & value) { + return std::to_string(value); + } + }; + + /// Specialization of value getter for chars. + /// \ingroup sibr_system + template<> + struct ValueGetter { + static char get(const std::vector & values, uint n) { + return static_cast(std::stoi(values[n])); + } + static std::string toString(const char & value) { + return std::to_string(value); + } + }; + + /// Specialization of value getter for unsigned integers. + /// \ingroup sibr_system + template<> + struct ValueGetter { + static uint get(const std::vector & values, uint n) { + return static_cast(std::stoi(values[n])); + } + static std::string toString(const uint & value) { + return std::to_string(value); + } + }; + + /// Specialization of value getter for arrays. + /// \ingroup sibr_system + template + struct ValueGetter> { + static std::array get(const std::vector & values, uint n) { + std::array out; + for (uint i = 0; i < N; ++i) { + out[i] = ValueGetter::get(values, n*N*NumberOfArg + i); + } + return out; + } + static std::string toString(const std::array & value) { + std::string res = "("; + for (uint i = 0; i < N; ++i) { + res.append(ValueGetter::toString(value[i])); + if (i != N - 1) { + res.append(","); + } + } + return res + ")"; + } + }; + + /// Specialization of value getter for sibr::Vectors & eigen matrices. + /// \ingroup sibr_system + template + struct ValueGetter> { + static Eigen::Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> get(const std::vector & values, uint n) { + Eigen::Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> out; + for (uint i = 0; i < _Rows*_Cols; ++i) { + out[i] = ValueGetter<_Scalar>::get(values, n*_Rows*_Cols*NumberOfArg<_Scalar> + i); + } + return out; + } + static std::string toString(const Eigen::Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> & value) { + std::string res = "("; + for (uint i = 0; i < _Rows*_Cols; ++i) { + res.append(ValueGetter<_Scalar>::toString(value[i])); + if(i != _Rows*_Cols-1) { + res.append(","); + } + } + return res + ")"; + } + }; + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Config.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Config.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3dfd2c80a4e4f35248044b024fb08aba3340ece2 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Config.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#include +#include "core/system/Config.hpp" + +std::mutex gLogMutex; + +namespace sibr +{ + + LogExit::LogExit(void) : + lock(gLogMutex) + { } + + void LogExit::operator <<=( const std::ostream& /*stream*/ ) + { + // do exit, only profit a the rules of 'operator precedence' + // to be executed after operator << when writing to the stream + // itself. + // So that this class is evaluated after writing the output and + // it will exit (see dtor) + //exit(EXIT_FAILURE); + throw std::runtime_error("See log for message errors"); + } + + DebugScopeProfiler::~DebugScopeProfiler( void ) + { + double t = double(clock() - _t0) / CLOCKS_PER_SEC; + SIBR_LOG << "[PROFILER] Scope '" << _name << + "' completed in " << t << "sec." << std::endl; + } + + DebugScopeProfiler::DebugScopeProfiler( const std::string& name ) + : _name(name) + { + _t0 = clock(); + } + +} // namespace sirb \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Config.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Config.hpp new file mode 100644 index 0000000000000000000000000000000000000000..941a0f2dd62b5a1e143eac9dfb6bbbeb0f13d113 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Config.hpp @@ -0,0 +1,304 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +//// Default includes //// +# ifndef _USE_MATH_DEFINES +# define _USE_MATH_DEFINES // for C++ +# endif +# include +# include +# include +# include +# include +# include +# include +# include +# include +#include + +//// Determine the operating system //// +# if defined(_WIN32) +# define SIBR_OS_WINDOWS +// Windows define macro for 'far' and 'near'... +// http://stackoverflow.com/questions/118774/is-there-a-clean-way-to-prevent-windows-h-from-creating-a-near-far-macro +// We could use other names than far and near but because we work in +// computer graphics, I am sure that future guys will also try to +// declare variables called far/near and loose time until finding +// this is all because windows. + +// Edit: I wanted to do something about it (a warning message) but it +// slow the compilation time (~5sec on my machine), so I let this code +// but disabled by default. +# if SIBR_UNDEF_WINDOWMACROS +// The strategy here is to undef macros AFTER including +// headers that use them. +# pragma warning(push, 0) + +// Note including this file increase the compilation time +// of the core libs by 5 additional seconds. +# include +# include +# include +# include +# include +# pragma warning(pop) +# undef far +# undef near +# endif // SIBR_UNDEF_WINDOWMACROS +# elif defined(__unix__) +# define SIBR_OS_UNIX +# elif defined(__APPLE__) && defined(__MACH__) +# define SIBR_OS_MAC +# else +# error This operating system might be not supported. +# endif + +//# undef NDEBUG /// \todo By undefining NDEBUG, I enable the assert system definition. (TODO RELEASE: remove this) +// (it certainly not a good pratice but it reveal previous assert already in the code) + +# ifdef SIBR_OS_WINDOWS + +# pragma warning(disable:4503) // decorated name length exceeded, name was truncated +// The two following lines disable warning concerning 'inconsistent dll linkage'. +// MSVC doesn't like exporting STL containers because their implementation (their 'dll') +// can be different from one Windows to another. Unix garantees to provide a universal +// implementation and doesn't have this problem. +// My point of view is: +// - Make the code compliants with Windows' dlls will make us: +// 1) lose lots of time (if we need to wrap STL containers each time we use them...) +// 2) break the beauty of the code (we want to keep simple code). +// - Once we will release this code (for a large public), we should: +// 1) Either explicitely export EVERY template/stl containers we use. +// 2) Or provide msvc's dll (redistribuable) that contains the same stl implementation +# pragma warning(disable:4251) +# pragma warning(disable:4273) + +//// Export Macro (used for creating DLLs) //// +# ifdef SIBR_STATIC_DEFINE +# define SIBR_EXPORT +# define SIBR_NO_EXPORT +# else +# ifndef SIBR_SYSTEM_EXPORT +# ifdef SIBR_SYSTEM_EXPORTS + /* We are building this library */ +# define SIBR_SYSTEM_EXPORT __declspec(dllexport) +# else + /* We are using this library */ +# define SIBR_SYSTEM_EXPORT __declspec(dllimport) +# endif +# endif +# ifndef SIBR_NO_EXPORT +# define SIBR_NO_EXPORT +# endif +# endif +# else +# define SIBR_SYSTEM_EXPORT +# endif + +//// Deprecator Macro (used to flag as 'deprecated' some functionalities) //// +#ifndef SIBR_DEPRECATED +# define SIBR_DEPRECATED __declspec(deprecated) +#endif + +//// Int To String Macro (used to convert int into string at compile-time) //// +# define SIBR_MACROINTTOSTR_IMPL(x) #x // small trick to get __LINE__ into a string +# define SIBR_MACROINTTOSTR(x) SIBR_MACROINTTOSTR_IMPL(x) +//// Concatenate Macro (used to concatenate two things, whatever it is. //// +//// See SIBR_PROFILESCOPE for an example of use). //// +# define SIBR_CATMACRO_IMPL(x, y) x ## y +# define SIBR_CATMACRO(x, y) SIBR_CATMACRO_IMPL(x, y) + +//# if SIBR_OS_WINDOWS +# define __FUNCTION_STR__ __FUNCTION__ +//# else +//# define __FUNCTION_STR__ SIBR_MACROINTTOSTR(__FUNCTION__) +//# endif + +// Macro used for +// Use: #pragma message WARN("My message") +# if _MSC_VER +# define FILE_LINE_LINK __FILE__ "(" SIBR_MACROINTTOSTR(__LINE__) ") : " +# define PRAGMAWARN(exp) (FILE_LINE_LINK "WARNING: " exp) +# else//__GNUC__ - may need other defines for different compilers +# define PRAGMAWARN(exp) ("WARNING: " exp) +# endif + +//// Math Macro //// +# define SIBR_PI 3.14159265358979323846 +# define SIBR_2PI (SIBR_PI * 2.0) + +# define SIBR_PI_DIV_180 0.01745329251 +# define SIBR_180_DIV_PI 57.2957795131 + +# define SIBR_RADTODEG(x) ((x) * (float)SIBR_180_DIV_PI) // ( (x) * (180.0f / PI) ) +# define SIBR_DEGTORAD(x) ((x) * (float)SIBR_PI_DIV_180) // ( (x) * (PI / 180.0f) ) + +//// Class Attribute Macro //// +# define SIBR_DISALLOW_COPY( classname ) \ + private: \ + classname( const classname& ); \ + classname& operator =( const classname& ); + +# define SIBR_CLASS_PTR( classname ) \ + public: \ + typedef std::shared_ptr Ptr; \ + typedef std::unique_ptr UPtr; + +namespace sibr +{ + /** Ensure that all logs are output before exiting when an error or exception is raised. + \ingroup sibr_system + */ + struct SIBR_SYSTEM_EXPORT LogExit + { + /// Constructor. + LogExit( void ); + + /** Throw an exception and trigger exit. + \param stream the log stream. + */ + void operator <<=( const std::ostream& stream ); + + std::lock_guard lock; ///< Sync lock. + }; +} + + +#ifdef NDEBUG +# define SIBR_MAXIMIZE_INLINE +#endif + +# ifdef SIBR_MAXIMIZE_INLINE +# define SIBR_OPT_INLINE inline +# else +# define SIBR_OPT_INLINE +# endif + + +//// Log Macro //// +# define SIBR_LOG std::cout << "[SIBR] -- INFOS --:\t" // Must be replaced by a true log system +# define SIBR_WRG std::cout << "[SIBR] !! WARNING !!:\tFILE " << __FILE__ << "\n\t\t\tLINE " << __LINE__ << ", FUNC " << __FUNCTION_STR__ << "\n\t\t\t" +# define SIBR_ERR ::sibr::LogExit() <<= \ + std::cerr << "[SIBR] ## ERROR ##:\tFILE " << __FILE__ << "\n\t\t\tLINE " << __LINE__ << ", FUNC " << __FUNCTION_STR__ << "\n\t\t\t" // Could be augmented for exiting + +// One drawback of using the standard assert is that you MUST catch the exception +// it throws in order to display its message and know the error. Not everyone thinks +// to do this (or want to add try/catch block in their code). Thus the solution here +// is to, first display the message (btw we inform on the precise location where it +// happens using __FILE__ and __LINE__) and then throw an exception (using the std +// assert) so that we can retrieve the callstack easily for debugging). + + +#ifdef NDEBUG +# define SIBR_ASSERT(condition) ((void)0) +# define SIBR_ASSERT_LOGIC(condition) (condition) // This assertion can contain code logic (this code will also be included at release) +#else +# define SIBR_ASSERT(condition) do { if(!(condition)) { SIBR_WRG << "ASSERT FAILED: " #condition << std::endl; assert(condition); } } while(0) +# define SIBR_ASSERT_LOGIC(condition) do { if(!(condition)) { SIBR_WRG << "ASSERT FAILED: " #condition << std::endl; assert(condition); } } while(0) +#endif + +// Small variants for adding function name +# define SIBR_FLOG SIBR_LOG "[" << __FUNCTION_STR__ << "]" +// Some code parts are written to manage additional or future features. They might remain untested +// until they are required (avoiding losing time to test code that could be useless at the end). +# define SIBR_UNTESTED \ + SIBR_LOG << "!Warning! Using an untested code flagged as potentially " \ + "unstable. (if something goes wrong, check over here - " __FILE__ ":" << __LINE__ << ")" << std::endl; +# define SIBR_DEBUG(var) std::cout << __FILE__ ":\n" "[Debug] " #var " = "<< (var) << std::endl // No access to debug mode for now (so I made this tmp tool) + +// Note Visual studio is bugged with multiple statements macro (I avoided them): +// http://stackoverflow.com/questions/22212737/strange-syntax-error-reported-in-a-range-based-for-loop + +//// TYPEDEF //// +typedef int8_t int8; +typedef int16_t int16; +typedef int32_t int32; +typedef int64_t int64; +typedef unsigned uint; +typedef uint8_t uint8; +typedef uint16_t uint16; +typedef uint32_t uint32; +typedef uint64_t uint64; + +using Path = boost::filesystem::path; + +// This stuff should be in a file gathering all debug tools +//# if !defined(NDEBUG) +# include +namespace sibr +{ + /// Used for quickly measuring time for completing a scope. + /// \ingroup sibr_system + struct SIBR_SYSTEM_EXPORT DebugScopeProfiler + { + /** Constructor. + \param name the display name of the profiling session + */ + DebugScopeProfiler( const std::string& name ); + + /// Destructor. + ~DebugScopeProfiler( void ); + + private: + clock_t _t0; ///< Timing. + std::string _name; ///< Name. + }; + +# define SIBR_PROFILESCOPE_EXPAND(x, y) sibr::DebugScopeProfiler x(y); + // its a bit weird (because of macro's tricks) but that just create an instance of DebugScopeProfiler (with a generated var name) +# define SIBR_PROFILESCOPE \ + SIBR_PROFILESCOPE_EXPAND(SIBR_CATMACRO(debugScopeProfiler,__COUNTER__), std::string(__FUNCTION_STR__) + std::string(" (File: " __FILE__ ":" SIBR_MACROINTTOSTR(__LINE__) ")") ); +# define SIBR_PROFILESCOPE_NAME(name) \ + SIBR_PROFILESCOPE_EXPAND(SIBR_CATMACRO(debugScopeProfiler,__COUNTER__), name ); +} // namespace sibr +//# endif + +//// Define the init behavior //// +# define SIBR_INITZERO +// Initializing with a default value (zero) can be slightly slower but +// make the code safe. In the current case, we don't have performance +// problems (of this level). +# if defined(SIBR_INITZERO) +# ifndef EIGEN_INITIALIZE_MATRICES_BY_ZERO +# define EIGEN_INITIALIZE_MATRICES_BY_ZERO +# endif +# endif + +// I didn't use the Plugin system for Eigen's MatrixBase +// because I wanted also custom ctor +// EDIT: +// Now that libslmini leaved out, we don't need this ctor +// anymore. +# define EIGEN_MATRIXBASE_PLUGIN "core/system/MatrixBasePlugin.hpp" +# define EIGEN_MATRIX_PLUGIN "core/system/MatrixPlugin.hpp" +# include +# include + +# define SIBR_USE_CHOLMOD_EIGEN + + + +namespace sibr +{ + /** Rounding operation. + \param x the value to round + \return the rounded value + \todo Compare behaviour with std::round + \ingroup sibr_system + */ + inline float round(float x) { + return x >= 0.0f ? floorf(x + 0.5f) : ceilf(x - 0.5f); + } + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/system/LoadingProgress.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/LoadingProgress.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4bc8287ffffbb967c3e28e7b47529ea4ac690f4b --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/LoadingProgress.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#include "core/system/LoadingProgress.hpp" + +namespace sibr +{ + + LoadingProgress::LoadingProgress( size_t maxIteration, + const std::string& status, float interval ) + : _currentStep(0), _maxProgress(maxIteration), _status(status), _interval(interval) + { + _lastReport = clock::now(); + } + + void LoadingProgress::walk( size_t step ) + { + std::lock_guard l(_mutex); + + _currentStep += step; + if (std::chrono::duration(clock::now()-_lastReport).count() >= _interval + || _currentStep >= _maxProgress) + { + report(); + _lastReport = clock::now(); + } + + } + + float LoadingProgress::current( void ) const + { + if (_maxProgress <= 0) + return 1.f; + return (float)_currentStep/(float)_maxProgress; + } + + void LoadingProgress::report( void ) const + { + if (_status.empty()) + SIBR_LOG << "Progression [ "<< current()*100.f <<"% ]" << std::endl; + else + SIBR_LOG << "Progression [ "<< current()*100.f <<"% ] - " << _status << std::endl; + } + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/system/LoadingProgress.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/LoadingProgress.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1fba6045b2c0ca6e68c9a537e8101ed6849c83f9 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/LoadingProgress.hpp @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include +# include +# include +# include "core/system//Config.hpp" + + +namespace sibr +{ + /// + /// Simple utility class for reporting on the standard output + /// a loading progess. (So users know your heavy computations + /// didn't crash) + /// + /// Instructions: + /// 1) Instantiate just before a loop (for or while), providing + /// the max number of iterations. + /// 2) Call walk() once in a the loop. + /// \ingroup sibr_system + /// + class SIBR_SYSTEM_EXPORT LoadingProgress + { + public: + typedef std::chrono::steady_clock clock; + typedef clock::time_point time_point; + typedef std::function ExternalCallback; + + /** Create a progress bar. + \param maxIteration total number of iterations + \param status a message that will be inserted in next reports + \param interval an interval of time between each report. + */ + LoadingProgress( size_t maxIteration, + const std::string& status="", float interval=1.f ); + + /// Make the loading progress by the given number of steps. + /// \param step number of steps + void walk( size_t step = 1); + /// \return the current progress in a range [0.0, 1.0] + float current( void ) const; + + /// \return the time interval used + inline float interval( void ) const; + /// Change the frequency of each report + /// \param interval the new step interval to use + inline void interval( float interval ); + + /// \return the status message used + inline const std::string& status( void ) const; + /// Insert a message in printed reports + /// \param message the message to insert + inline void status( const std::string& message ); + + private: + /// Print a report + void report( void ) const; + + size_t _currentStep; ///< current number of iterations + size_t _maxProgress; ///< number of iterations before reaching 100% + std::string _status; ///< inserted into a report (you can update it) + float _interval; ///< time interval before next report (sec) + time_point _lastReport; ///< time point saved during the last report + std::mutex _mutex; ///< used ot thread-safe this class (not heavly tested!) + }; + + ///// DEFINITIONS ///// + + float LoadingProgress::interval( void ) const { + return _interval; + } + void LoadingProgress::interval( float interval ) { + _interval = interval; + } + + + const std::string& LoadingProgress::status( void ) const { + return _status; + } + void LoadingProgress::status( const std::string& message ) { + _status = message; + } + + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/system/MD5.h b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/MD5.h new file mode 100644 index 0000000000000000000000000000000000000000..97955cd66c717baa996166bcf7834aef9a80df6b --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/MD5.h @@ -0,0 +1,353 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +/* + ********************************************************************** + ** md5.h -- Header file for implementation of MD5 ** + ** RSA Data Security, Inc. MD5 Message Digest Algorithm ** + ** Created: 2/17/90 RLR ** + ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version ** + ** Revised (for MD5): RLR 4/27/91 ** + ** -- G modified to have y&~z instead of y&z ** + ** -- FF, GG, HH modified to add in last register done ** + ** -- Access pattern: round 2 works mod 5, round 3 works mod 3 ** + ** -- distinct additive constant for each step ** + ** -- round 4 added, working mod 7 ** + ********************************************************************** + */ + +/* + ********************************************************************** + ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** + ** ** + ** License to copy and use this software is granted provided that ** + ** it is identified as the "RSA Data Security, Inc. MD5 Message ** + ** Digest Algorithm" in all material mentioning or referencing this ** + ** software or this function. ** + ** ** + ** License is also granted to make and use derivative works ** + ** provided that such works are identified as "derived from the RSA ** + ** Data Security, Inc. MD5 Message Digest Algorithm" in all ** + ** material mentioning or referencing the derived work. ** + ** ** + ** RSA Data Security, Inc. makes no representations concerning ** + ** either the merchantability of this software or the suitability ** + ** of this software for any particular purpose. It is provided "as ** + ** is" without express or implied warranty of any kind. ** + ** ** + ** These notices must be retained in any copies of any part of this ** + ** documentation and/or software. ** + ********************************************************************** + */ + +#ifndef SIBR_SYSTEM_MD5 +#define SIBR_SYSTEM_MD5 + +#include + +/* typedef a 32 bit type */ +typedef unsigned long int UINT4; + +/* Data structure for MD5 (Message Digest) computation */ +typedef struct { + UINT4 i[2]; /* number of _bits_ handled mod 2^64 */ + UINT4 buf[4]; /* scratch buffer */ + unsigned char in[64]; /* input buffer */ + unsigned char digest[16]; /* actual digest after MD5Final call */ +} MD5_CTX; + +void MD5Init (MD5_CTX *mdContext); +void MD5Update (MD5_CTX *mdContext, unsigned char *inBuf, size_t inLen); +void MD5Final (MD5_CTX *mdContext); + + +/* + Compute MD5 for a binary blob + Writes 16 bytes (4 uints) to pDigest + */ +void MD5Buffer( void* buffer, size_t bufLen, unsigned int* pDigest ) +{ + int i; + MD5_CTX mdContext; + + // compute MD5 + MD5Init(&mdContext); + MD5Update(&mdContext, (unsigned char*)buffer, bufLen); + MD5Final(&mdContext); + + // copy digest over + for( i = 0; i < 4; ++i ) + pDigest[i] = *(((unsigned int*)mdContext.digest)+i); +} + +/* + ********************************************************************** + ** md5.c ** + ** RSA Data Security, Inc. MD5 Message Digest Algorithm ** + ** Created: 2/17/90 RLR ** + ** Revised: 1/91 SRD,AJ,BSK,JT Reference C Version ** + ********************************************************************** + */ + +/* + ********************************************************************** + ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** + ** ** + ** License to copy and use this software is granted provided that ** + ** it is identified as the "RSA Data Security, Inc. MD5 Message ** + ** Digest Algorithm" in all material mentioning or referencing this ** + ** software or this function. ** + ** ** + ** License is also granted to make and use derivative works ** + ** provided that such works are identified as "derived from the RSA ** + ** Data Security, Inc. MD5 Message Digest Algorithm" in all ** + ** material mentioning or referencing the derived work. ** + ** ** + ** RSA Data Security, Inc. makes no representations concerning ** + ** either the merchantability of this software or the suitability ** + ** of this software for any particular purpose. It is provided "as ** + ** is" without express or implied warranty of any kind. ** + ** ** + ** These notices must be retained in any copies of any part of this ** + ** documentation and/or software. ** + ********************************************************************** + */ + +/* forward declaration */ +static void Transform (UINT4 *buf, UINT4 *in); + +static unsigned char PADDING[64] = { + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* F, G and H are basic MD5 functions: selection, majority, parity */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */ +/* Rotation is separate from addition to prevent recomputation */ +#define FF(a, b, c, d, x, s, ac) \ + {(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) \ + {(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) \ + {(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) \ + {(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +void MD5Init (MD5_CTX *mdContext) +{ + mdContext->i[0] = mdContext->i[1] = (UINT4)0; + + /* Load magic initialization constants. + */ + mdContext->buf[0] = (UINT4)0x67452301; + mdContext->buf[1] = (UINT4)0xefcdab89; + mdContext->buf[2] = (UINT4)0x98badcfe; + mdContext->buf[3] = (UINT4)0x10325476; +} + +void MD5Update (MD5_CTX *mdContext, unsigned char *inBuf, size_t inLen) +{ + UINT4 in[16]; + int mdi; + unsigned int i, ii; + + /* compute number of bytes mod 64 */ + mdi = (int)((mdContext->i[0] >> 3) & 0x3F); + + /* update number of bits */ + if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0]) + mdContext->i[1]++; + mdContext->i[0] += ((UINT4)inLen << 3); + mdContext->i[1] += ((UINT4)inLen >> 29); + + while (inLen--) { + /* add new character to buffer, increment mdi */ + mdContext->in[mdi++] = *inBuf++; + + /* transform if necessary */ + if (mdi == 0x40) { + for (i = 0, ii = 0; i < 16; i++, ii += 4) + in[i] = (((UINT4)mdContext->in[ii+3]) << 24) | + (((UINT4)mdContext->in[ii+2]) << 16) | + (((UINT4)mdContext->in[ii+1]) << 8) | + ((UINT4)mdContext->in[ii]); + Transform (mdContext->buf, in); + mdi = 0; + } + } +} + +void MD5Final (MD5_CTX *mdContext) +{ + UINT4 in[16]; + int mdi; + unsigned int i, ii; + unsigned int padLen; + + /* save number of bits */ + in[14] = mdContext->i[0]; + in[15] = mdContext->i[1]; + + /* compute number of bytes mod 64 */ + mdi = (int)((mdContext->i[0] >> 3) & 0x3F); + + /* pad out to 56 mod 64 */ + padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi); + MD5Update (mdContext, PADDING, padLen); + + /* append length in bits and transform */ + for (i = 0, ii = 0; i < 14; i++, ii += 4) + in[i] = (((UINT4)mdContext->in[ii+3]) << 24) | + (((UINT4)mdContext->in[ii+2]) << 16) | + (((UINT4)mdContext->in[ii+1]) << 8) | + ((UINT4)mdContext->in[ii]); + Transform (mdContext->buf, in); + + /* store buffer in digest */ + for (i = 0, ii = 0; i < 4; i++, ii += 4) { + mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF); + mdContext->digest[ii+1] = + (unsigned char)((mdContext->buf[i] >> 8) & 0xFF); + mdContext->digest[ii+2] = + (unsigned char)((mdContext->buf[i] >> 16) & 0xFF); + mdContext->digest[ii+3] = + (unsigned char)((mdContext->buf[i] >> 24) & 0xFF); + } +} + +/* Basic MD5 step. Transform buf based on in. + */ +static void Transform (UINT4 *buf, UINT4 *in) +{ + UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; + + /* Round 1 */ +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 + FF ( a, b, c, d, in[ 0], S11, 3614090360); /* 1 */ + FF ( d, a, b, c, in[ 1], S12, 3905402710); /* 2 */ + FF ( c, d, a, b, in[ 2], S13, 606105819); /* 3 */ + FF ( b, c, d, a, in[ 3], S14, 3250441966); /* 4 */ + FF ( a, b, c, d, in[ 4], S11, 4118548399); /* 5 */ + FF ( d, a, b, c, in[ 5], S12, 1200080426); /* 6 */ + FF ( c, d, a, b, in[ 6], S13, 2821735955); /* 7 */ + FF ( b, c, d, a, in[ 7], S14, 4249261313); /* 8 */ + FF ( a, b, c, d, in[ 8], S11, 1770035416); /* 9 */ + FF ( d, a, b, c, in[ 9], S12, 2336552879); /* 10 */ + FF ( c, d, a, b, in[10], S13, 4294925233); /* 11 */ + FF ( b, c, d, a, in[11], S14, 2304563134); /* 12 */ + FF ( a, b, c, d, in[12], S11, 1804603682); /* 13 */ + FF ( d, a, b, c, in[13], S12, 4254626195); /* 14 */ + FF ( c, d, a, b, in[14], S13, 2792965006); /* 15 */ + FF ( b, c, d, a, in[15], S14, 1236535329); /* 16 */ + + /* Round 2 */ +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 + GG ( a, b, c, d, in[ 1], S21, 4129170786); /* 17 */ + GG ( d, a, b, c, in[ 6], S22, 3225465664); /* 18 */ + GG ( c, d, a, b, in[11], S23, 643717713); /* 19 */ + GG ( b, c, d, a, in[ 0], S24, 3921069994); /* 20 */ + GG ( a, b, c, d, in[ 5], S21, 3593408605); /* 21 */ + GG ( d, a, b, c, in[10], S22, 38016083); /* 22 */ + GG ( c, d, a, b, in[15], S23, 3634488961); /* 23 */ + GG ( b, c, d, a, in[ 4], S24, 3889429448); /* 24 */ + GG ( a, b, c, d, in[ 9], S21, 568446438); /* 25 */ + GG ( d, a, b, c, in[14], S22, 3275163606); /* 26 */ + GG ( c, d, a, b, in[ 3], S23, 4107603335); /* 27 */ + GG ( b, c, d, a, in[ 8], S24, 1163531501); /* 28 */ + GG ( a, b, c, d, in[13], S21, 2850285829); /* 29 */ + GG ( d, a, b, c, in[ 2], S22, 4243563512); /* 30 */ + GG ( c, d, a, b, in[ 7], S23, 1735328473); /* 31 */ + GG ( b, c, d, a, in[12], S24, 2368359562); /* 32 */ + + /* Round 3 */ +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 + HH ( a, b, c, d, in[ 5], S31, 4294588738); /* 33 */ + HH ( d, a, b, c, in[ 8], S32, 2272392833); /* 34 */ + HH ( c, d, a, b, in[11], S33, 1839030562); /* 35 */ + HH ( b, c, d, a, in[14], S34, 4259657740); /* 36 */ + HH ( a, b, c, d, in[ 1], S31, 2763975236); /* 37 */ + HH ( d, a, b, c, in[ 4], S32, 1272893353); /* 38 */ + HH ( c, d, a, b, in[ 7], S33, 4139469664); /* 39 */ + HH ( b, c, d, a, in[10], S34, 3200236656); /* 40 */ + HH ( a, b, c, d, in[13], S31, 681279174); /* 41 */ + HH ( d, a, b, c, in[ 0], S32, 3936430074); /* 42 */ + HH ( c, d, a, b, in[ 3], S33, 3572445317); /* 43 */ + HH ( b, c, d, a, in[ 6], S34, 76029189); /* 44 */ + HH ( a, b, c, d, in[ 9], S31, 3654602809); /* 45 */ + HH ( d, a, b, c, in[12], S32, 3873151461); /* 46 */ + HH ( c, d, a, b, in[15], S33, 530742520); /* 47 */ + HH ( b, c, d, a, in[ 2], S34, 3299628645); /* 48 */ + + /* Round 4 */ +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + II ( a, b, c, d, in[ 0], S41, 4096336452); /* 49 */ + II ( d, a, b, c, in[ 7], S42, 1126891415); /* 50 */ + II ( c, d, a, b, in[14], S43, 2878612391); /* 51 */ + II ( b, c, d, a, in[ 5], S44, 4237533241); /* 52 */ + II ( a, b, c, d, in[12], S41, 1700485571); /* 53 */ + II ( d, a, b, c, in[ 3], S42, 2399980690); /* 54 */ + II ( c, d, a, b, in[10], S43, 4293915773); /* 55 */ + II ( b, c, d, a, in[ 1], S44, 2240044497); /* 56 */ + II ( a, b, c, d, in[ 8], S41, 1873313359); /* 57 */ + II ( d, a, b, c, in[15], S42, 4264355552); /* 58 */ + II ( c, d, a, b, in[ 6], S43, 2734768916); /* 59 */ + II ( b, c, d, a, in[13], S44, 1309151649); /* 60 */ + II ( a, b, c, d, in[ 4], S41, 4149444226); /* 61 */ + II ( d, a, b, c, in[11], S42, 3174756917); /* 62 */ + II ( c, d, a, b, in[ 2], S43, 718787259); /* 63 */ + II ( b, c, d, a, in[ 9], S44, 3951481745); /* 64 */ + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +#endif diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Matrix.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Matrix.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1e21e962b6f6e18c801d5b82310f158d9edd070f --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Matrix.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#include "core/system/Transform3.hpp" + +namespace sibr +{ + Matrix4f perspective( float fovRadian, float ratio, float zn, float zf, const sibr::Vector2f & p) + { + const float yScale = float(1.0)/std::tan(fovRadian/2.0f); + const float xScale = yScale/ratio; + + Matrix4f m; + const float dx = 2.0f * p.x() - 1.0f; + const float dy = 2.0f * p.y() - 1.0f; + m << + xScale, 0, dx, 0, + 0, yScale, dy, 0, + 0, 0, (zn+zf)/(zn-zf), 2*zn*zf/(zn-zf), + 0, 0, -1, 0; + + return m; + } + + Matrix4f perspectiveOffCenter( + float left, float right, float bottom, float top, float mynear, float myfar ) + { + float x = (2.0f * mynear) / (right - left); + float y = (2.0f * mynear) / (top - bottom); + float a = (right + left) / (right - left); + + float b = (top + bottom) / (top - bottom); + float c = -(myfar + mynear) / (myfar - mynear); + float d = -(2.0f * myfar * mynear) / (myfar - mynear); + float e = -1.0f; + + Matrix4f m; + + m << + x, 0, 0, 0, + 0, y, 0, 0, + a, b, c, e, + 0, 0, d, 0; + + return m; + } + + Matrix4f perspectiveStereo( + float fovRadian, float aspect, float zn, float zf, float focalDistance, float eyeDistance, bool isLeftEye ) + { + + float left, right; + float a = float(1.0f)/std::tan(fovRadian/2.0f); + float b = zf / focalDistance; + + if (isLeftEye) // left camera + { + left = - aspect * a + (eyeDistance) * b; + right = aspect * a + (eyeDistance) * b; + } + else // right camera + { + left = - aspect * a - (eyeDistance) * b; + right = aspect * a - (eyeDistance) * b; + } + + return perspectiveOffCenter(left, right, -a, a, zn, zf); + } + + Matrix4f orthographic(float right, float top, float mynear, float myfar) + { + + Matrix4f m; + + m << + 1.0f/right, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f/top, 0.0f, 0.0f, + 0.0f, 0.0f, -2.0f/(myfar-mynear), -(myfar + mynear) / (myfar - mynear), + 0.0f, 0.0f, 0.0f, 1.0f; + + return m; + } + + Matrix4f lookAt( + const Vector3f& eye, + const Vector3f& center, + const Vector3f& up ) + { + const sibr::Vector3f f = (center - eye).normalized(); + sibr::Vector3f u = up.normalized(); + const sibr::Vector3f s = f.cross(u).normalized(); + u = s.cross(f); + + Eigen::Matrix res; + res << s.x(),s.y(),s.z(),-s.dot(eye), + u.x(),u.y(),u.z(),-u.dot(eye), + -f.x(),-f.y(),-f.z(),f.dot(eye), + 0,0,0,1; + + return res; + } + + void operator<< (std::ofstream& outfile, const Matrix4f& m) + { + outfile << m(0,0) << " " << m(0,1) << " " << m(0,2) << " " << m(0,3) + << " " << m(1,0) << " " << m(1,1) << " " << m(1,2) << " " << m(1,3) + << " " << m(2,0) << " " << m(2,1) << " " << m(2,2) << " " << m(2,3) + << " " << m(3,0) << " " << m(3,1) << " " << m(3,2) << " " << m(3,3) ; + + } + + void operator>>( std::ifstream& infile, Matrix4f& out) + { + float m[16]; + infile >> m[0] >> m[1] >> m[2] >> m[3] + >> m[4] >> m[5] >> m[6] >> m[7] + >> m[8] >> m[9] >> m[10] >> m[11] + >> m[12] >> m[13] >> m[14] >> m[15]; + + out << m[0] , m[1] , m[2] , m[3] + , m[4] , m[5] , m[6] , m[7] + , m[8] , m[9] , m[10] , m[11] + , m[12] , m[13] , m[14] , m[15]; + } + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Matrix.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Matrix.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c37776050190be59e967ca5bc571a0b5b2ee61ab --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Matrix.hpp @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +/****************************************************************************** + + Design Decision -- Eigen Integration: + + At the very beginning, we used vector/matrices from libminisl. Then we + began to switch to Eigen's tools (because already used in lots of our code). + Thus during the migration phase, we used custom class inheriting from + Eigen::Matrix. + However I encountered issues when executing the code under linux. It + appears it was because of SSE instructions (special pipeline on CPU allowing + to perform some vector operations in parallel). This SSE instruction required + 128-bit aligned memory. There are articles about this on Eigen website: + eigen.tuxfamily.org/dox/group__DenseMatrixManipulation__Alignement.html + + But to summerize: keeping the alignment is difficult because you have to + overload new operator in each class containing an Eigen::Matrix. Too unsafe, + thus I disable this (Eigen::DontAlign) but missing assignment operators did + that this consideration was ignored in some cases. + E.g.: sibr::Matrix A, B, C; + // ... // set A and B + C = A*B; // A*B return a temporary class of Eigen but C didn't have the + // assignment operator for this class [...] it wrongly considered it has an + // not-aligned matrix and data was corrupted. + + Now SIBR uses a plugin system to extend Eigen classes: + eigen.tuxfamily.org/dox/TopicCustomizingEigen.html + + It's both safer and faster. (but it was not possible during the migration + phase because I needed the child type to perfom automatic convertion with + remaining libminisl tools). + +******************************************************************************/ + +#pragma once + +# include +# include "core/system/Config.hpp" +# include "core/system/Vector.hpp" + + +namespace sibr +{ + /** + \addtogroup sibr_system + @{ + */ + typedef Eigen::Matrix Matrix4u; + typedef Eigen::Matrix Matrix4i; + typedef Eigen::Matrix Matrix4f; + typedef Eigen::Matrix Matrix4d; + typedef Eigen::Matrix Matrix3u; + typedef Eigen::Matrix Matrix3i; + typedef Eigen::Matrix Matrix3f; + typedef Eigen::Matrix Matrix3d; + + /** Convert a quaternion to a rotation matrix. + * \param q the quaternion to convert + * \return the corresponding matrix + */ + template + Eigen::Matrix matFromQuat( const Eigen::Quaternion& q ) { + Eigen::Matrix s = q.toRotationMatrix(); + + Eigen::Matrix mat; + mat << + s(0,0), s(0,1), s(0,2), 0, + s(1,0), s(1,1), s(1,2), 0, + s(2,0), s(2,1), s(2,2), 0, + 0, 0, 0, 1; + return mat; + } + + /** Convert a translation to a rotation matrix. + * \param vec the translation to convert + * \return the corresponding matrix + */ + template + Eigen::Matrix matFromTranslation( const Eigen::Matrix& vec ) { + + Eigen::Matrix mat; + mat.setIdentity(); + + mat(0,3) = vec.x(); + mat(1,3) = vec.y(); + mat(2,3) = vec.z(); + return mat; + } + + /** Generate a perspective matrix. + * \param fovRadian vertical field of view in radians + * \param ratio aspect ratio + * \param zn near plane + * \param zf far plane + * \param p the principal point, expressed in [0,1] + * \return the projection matrix */ + Matrix4f SIBR_SYSTEM_EXPORT perspective( float fovRadian, float ratio, float zn, float zf, const ::sibr::Vector2f & p = {0.5f, 0.5f}); + + /** Generate an off-center perspective matrix. + * Defined by giving the top/left/right/bottom extent in world units. + * \param left left extent + * \param right right extent + * \param bottom bottom extent + * \param top top extent + * \param mynear near plane + * \param myfar dar plane + * \return the projection matrix */ + Matrix4f SIBR_SYSTEM_EXPORT perspectiveOffCenter( + float left, float right, float bottom, float top, float mynear, float myfar ); + + /** Generate a perspective matrix for stereo rendering. + * \param fovRadian vertical field of view in radians + * \param aspect aspect ratio + * \param zn near plane + * \param zf far plane + * \param focalDistance the focal distance + * \param eyeDistance the inter-eye distance + * \param isLeftEye if true computes the left eye matrix, else the right eye + * \return the projection matrix */ + Matrix4f SIBR_SYSTEM_EXPORT perspectiveStereo( float fovRadian, float aspect, float zn, float zf, float focalDistance, + float eyeDistance, bool isLeftEye ); + + /** Generate an orthographic matrix. + * Defined by giving the top/right extent in world units. + * \param right right extent + * \param top top extent + * \param mynear near plane + * \param myfar dar plane + * \return the projection matrix */ + Matrix4f SIBR_SYSTEM_EXPORT orthographic(float right, float top, float mynear, float myfar); + + /** Generate a view matrix using the look at parameters. + * \param eye camera position + * \param center point the camera is looking at + * \param up up vector + * \return the projection matrix */ + Matrix4f SIBR_SYSTEM_EXPORT lookAt( const Vector3f& eye, const Vector3f& center, const Vector3f& up ); + + /** Output a Matrix4f to a file stream. + *\param outfile the output file + *\param m the matrix + */ + void SIBR_SYSTEM_EXPORT operator<< (std::ofstream& outfile, const Matrix4f& m); + + /** Read a Matrix4f from a file stream. + *\param infile the input file + *\param out the matrix + */ + void SIBR_SYSTEM_EXPORT operator>>( std::ifstream& infile, Matrix4f& out); + + /** }@ */ +} // namespace sibr + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/system/MatrixBasePlugin.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/MatrixBasePlugin.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5b36c57c66922648184e98afcf00c79afc4d3fa3 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/MatrixBasePlugin.hpp @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +// This file is used to extend Eigen's MatrixBase class using +// the following tricks: +// https://eigen.tuxfamily.org/dox-3.2/TopicCustomizingEigen.html + +public: + +/** Helper to evaluate a transposed matrix without overwriting risks. + \return a copy of the matrix, transposed +*/ +inline MatrixBase transposed( void ) { return this->transpose().eval(); } + +/** Get the first two components, filling with a default value if some are missing. + \param fill the default value to use + \return the selected components. +*/ +Matrix xy( float fill=0.f ) const { + return Matrix( this->operator[](0), size()<2? fill:this->operator[](1)); +} + +/** Get the first two components swapped, filling with a default value if some are missing. + \param fill the default value to use + \return the selected components. +*/ +Matrix yx(float fill = 0.f) const { + return Matrix(this->operator[](1), size()<2 ? fill : this->operator[](0)); +} + +/** Get the last two components swapped, filling with a default value if some are missing. + \param fill the default value to use + \return the selected components. +*/ +Matrix wz(float fill = 0.f) const { + return Matrix(size()<4 ? fill : this->operator[](3), size()<3 ? fill : this->operator[](2)); +} + +/** Get the first three components, filling with a default value if some are missing. + \param fill the default value to use + \return the selected components. +*/ +Matrix xyz( float fill=0.f ) const { + return Matrix( this->operator[](0), size()<2? fill:this->operator[](1), size()<3? fill:this->operator[](2)); +} + +/** Get the first four components, filling with a default value if some are missing. + \param fill the default value to use + \return the selected components. +*/ +Matrix xyzw( float fill=0.f ) const { + return Matrix( this->operator[](0), size()<2? fill:this->operator[](1), size()<3? fill:this->operator[](2), size()<4? fill:this->operator[](3)); +} + +/** Get the first three components swapped (YXZ), filling with a default value if some are missing. + \param fill the default value to use + \return the selected components. +*/ +Matrix yxz(float fill = 0.f) const { + return Matrix(size()<2 ? fill : this->operator[](1), this->operator[](0), size()<3 ? fill : this->operator[](2)); +} + +/** Get the first three components swapped (YZX), filling with a default value if some are missing. + \param fill the default value to use + \return the selected components. +*/ +Matrix yzx(float fill = 0.f) const { + return Matrix(size()<2 ? fill : this->operator[](1), size()<3 ? fill : this->operator[](2), this->operator[](0)); +} + +/** Check if a vector is exactly zero for all components +\return true if all components are exactly zero. +*/ +bool isNull( void ) const { + return (array() == 0).all(); +} + +typedef Scalar Type; + +//enum { NumComp = Derived::RowsAtCompileTime }; + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/system/MatrixPlugin.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/MatrixPlugin.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0035522264d303cfebdeec21e01fb8bc29494d51 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/MatrixPlugin.hpp @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +// This file is used to extend Eigen's MatrixBase class using +// the following tricks: +// https://eigen.tuxfamily.org/dox-3.2/TopicCustomizingEigen.html + +public: + +typedef Scalar Type; +enum { NumComp = RowsAtCompileTime }; + +//Matrix( const Scalar* data ) { for(int i=0; ioperator [] (i) = data[i]; } + +/** +Matrix( float x, float y=0.f, float z=0.f, float w=0.f ) { + float data[] = {x, y, z, w}; + for(int i=0; ioperator [] (i) = data[i]; +} +**/ + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Quaternion.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Quaternion.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a9d38357cb5f6850602b96bcdf9f7fb1b8e106ab --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Quaternion.cpp @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#include "core/system/Transform3.hpp" + +namespace sibr +{ + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Quaternion.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Quaternion.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ef0b44cc4f677de3ca6e7b258b3f6ffcdebd76af --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Quaternion.hpp @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include +# include +# include "core/system/Config.hpp" +# include "core/system/Matrix.hpp" +# include "core/system/Vector.hpp" + +namespace sibr +{ + /** + \addtogroup sibr_system + @{ + */ + + /** Build a quaternion from a rotation matrix + *\param m the rotation matrix + *\return the quaternion + *\todo Seems to be different from sibr::Quaternion(rotationmatrix) + */ + template + Eigen::Quaternion quatFromMatrix(const Eigen::Matrix& m) { + Eigen::Quaternion q; + float trace = m(0, 0) + m(1, 1) + m(2, 2) + 1.f; + if (trace > 0) + { + float s = 0.5f / sqrtf(trace); + q.x() = (m(1, 2) - m(2, 1)) * s; + q.y() = (m(2, 0) - m(0, 2)) * s; + q.z() = (m(0, 1) - m(1, 0)) * s; + q.w() = 0.25f / s; + } + else + { + if ((m(0, 0) > m(1, 1)) && (m(0, 0) > m(2, 2))) + { + float s = sqrtf(1.f + m(0, 0) - m(1, 1) - m(2, 2)) * 2.f; + q.x() = 0.5f / s; + q.y() = (m(1, 0) + m(0, 1)) / s; + q.z() = (m(2, 0) + m(0, 2)) / s; + q.w() = (m(2, 1) + m(1, 2)) / s; + } + else if (m(1, 1) > m(2, 2)) + { + float s = sqrtf(1.f - m(0, 0) + m(1, 1) - m(2, 2)) * 2.f; + q.x() = (m(1, 0) + m(0, 1)) / s; + q.y() = 0.5f / s; + q.z() = (m(2, 1) + m(1, 2)) / s; + q.w() = (m(2, 0) + m(0, 2)) / s; + } + else + { + float s = sqrtf(1.f - m(0, 0) - m(1, 1) + m(2, 2)) * 2.f; + q.x() = (m(2, 0) + m(0, 2)) / s; + q.y() = (m(2, 1) + m(1, 2)) / s; + q.z() = 0.5f / s; + q.w() = (m(1, 0) + m(0, 1)) / s; + } + } + return q; + } + + /** Build a quaternion from a rotation matrix + *\param m the rotation matrix + *\return the quaternion + */ + template + Eigen::Quaternion quatFromMatrix( const Eigen::Matrix& m ) { + Eigen::Quaternion q; + float trace = m(0, 0) + m(1, 1) + m(2, 2) + 1.f; + if (trace > 0) + { + float s = 0.5f / sqrtf(trace); + q.x() = (m(1, 2) - m(2, 1)) * s; + q.y() = (m(2, 0) - m(0, 2)) * s; + q.z() = (m(0, 1) - m(1, 0)) * s; + q.w() = 0.25f / s; + } + else + { + if ((m(0, 0) > m(1, 1)) && (m(0, 0) > m(2, 2))) + { + float s = sqrtf(1.f + m(0, 0) - m(1, 1) - m(2, 2)) * 2.f; + q.x() = 0.5f / s; + q.y() = (m(1, 0) + m(0, 1)) / s; + q.z() = (m(2, 0) + m(0, 2)) / s; + q.w() = (m(2, 1) + m(1, 2)) / s; + } + else if (m(1, 1) > m(2, 2)) + { + float s = sqrtf(1.f - m(0, 0) + m(1, 1) - m(2, 2)) * 2.f; + q.x() = (m(1, 0) + m(0, 1)) / s; + q.y() = 0.5f / s; + q.z() = (m(2, 1) + m(1, 2)) / s; + q.w() = (m(2, 0) + m(0, 2)) / s; + } + else + { + float s = sqrtf(1.f - m(0, 0) - m(1, 1) + m(2, 2)) * 2.f; + q.x() = (m(2, 0) + m(0, 2)) / s; + q.y() = (m(2, 1) + m(1, 2)) / s; + q.z() = 0.5f / s; + q.w() = (m(1, 0) + m(0, 1)) / s; + } + } + return q; + } + + /** Build a quaternion from rotation euler angles. + *\param deg the rotation angles + *\return the quaternion + *\todo Explicit the angles order (yaw, pitch, roll?) + */ + template + Eigen::Quaternion quatFromEulerAngles( const Eigen::Matrix& deg ) { + Vector3f v(SIBR_DEGTORAD(deg.x()), SIBR_DEGTORAD(deg.y()), SIBR_DEGTORAD(deg.z())); + Vector3f halfAngles( v.x() * 0.5f, v.y() * 0.5f, v.z() * 0.5f ); + + const float cx = cosf (halfAngles.x()); + const float sx = sinf (halfAngles.x()); + const float cy = cosf (halfAngles.y()); + const float sy = sinf (halfAngles.y()); + const float cz = cosf (halfAngles.z()); + const float sz = sinf (halfAngles.z()); + + const float cxcz = cx*cz; + const float cxsz = cx*sz; + const float sxcz = sx*cz; + const float sxsz = sx*sz; + + Eigen::Quaternion dst; + dst.vec().x() = (cy * sxcz) - (sy * cxsz); + dst.vec().y() = (cy * sxsz) + (sy * cxcz); + dst.vec().z() = (cy * cxsz) - (sy * sxcz); + dst.w() = (cy * cxcz) + (sy * sxsz); + return dst; + } + + /** Rotate a vector using a quaternion. + *\param rotation the quaternion + *\param vec the vector + *\return the rotated vector. + */ + template + Eigen::Matrix quatRotateVec( + const Eigen::Quaternion& rotation, const Eigen::Matrix& vec ) { + return rotation._transformVector(vec); + } + + /** Quaternion product. + * \param q1 first quaternion + * \param q2 second quaternion + * \return the result quaternion + */ + template + inline static Eigen::Quaternion dot( const Eigen::Quaternion& q1, const Eigen::Quaternion& q2 ) { + return q1.vec().dot(q2.vec()) + q1.w()*q2.w(); + } + + /** Compute the delta angle between two quaternions. + *\param q1 first quaternion + *\param q2 second quaternion + *\return the angle in radians + *\note Will return the smallest angle possible + */ + template + inline static float angleRadian( const Eigen::Quaternion& q1, const Eigen::Quaternion& q2 ) { + const float mid = 3.14159f; + const float angle = q1.angularDistance(q2); + return angle > mid? mid-angle : angle; // be sure to return the shortest angle + } + + /** Linear quaternion interpolation + *\param q1 first quaternion + *\param q2 second quaternion + *\param t interpolation factor + *\return the interpolated quaternion + */ + template + inline static Eigen::Quaternion lerp( const Eigen::Quaternion& q1, const Eigen::Quaternion& q2, float t ) { + return (q1*(1-t) + q2*t).normalized(); + } + + /** Spherical quaternion interpolation + *\param q1 first quaternion + *\param q2 second quaternion + *\param t interpolation factor + *\return the interpolated quaternion + */ + template + static Eigen::Quaternion slerp( const Eigen::Quaternion& q1, const Eigen::Quaternion& q2, float t ) { + Eigen::Quaternion q3; + float dot = q1.dot(q2);// Eigen::Quaternion::dot(q1, q2); + // dot = cos(theta) + // if (dot < 0), q1 and q2 are more than 90 degrees apart, + // so we can invert one to reduce spinning + if (dot < 0) + { + dot = -dot; + q3 = -q2; + } else q3 = q2; + if (dot < 0.95f) + { + float angle = acosf(dot); + return (q1*sinf(angle*(1-t)) + q3*sinf(angle*t))/sinf(angle); + } else // if the angle is small, use linear interpolation + return lerp(q1,q3,t); + } + + typedef Eigen::Quaternion Quaternionu; + typedef Eigen::Quaternion Quaternioni; + typedef Eigen::Quaternion Quaternionf; + typedef Eigen::Quaternion Quaterniond; + + /** }@ */ + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Rect.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Rect.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6bf742ab019d0898f93997d0a92057a9c6394cb2 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Rect.hpp @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include "core/system/Config.hpp" +# include "core/system/Vector.hpp" + +namespace sibr +{ + /** Represents a simple aligned axis rectangle + + I use left, top, right, bottom and not x1, x2, y1, y2 + or x, y, w, h for being free of coordinate systems. + (so you can use this class with an origin starting in + the top left corner or the bottom right corner; this + should be the same). + + Note this class is currently what I call a constclass: + once built you cannot modify it. + * \ingroup sibr_system + */ + template + class Rect + { + public: + typedef Eigen::Matrix Vec; + + public: + + /// Default constructor (null everything) + Rect( void ); + + /** Constructor + \param left x-coordinate of the left border + \param top y-coordinate of the top border + \param right x-coordinate of the right border + \param bottom y-coordinate of the bottom border + */ + Rect( T left, T top, T right, T bottom ); + + /// \return the position of the left side + inline T left( void ) const; + /// \return the position of the right side + inline T right( void ) const; + /// \return the position of the top side + inline T top( void ) const; + /// \return the position of the bottom side + inline T bottom( void ) const; + + /// \return the width + inline T width( void ) const; + /// \return the height + inline T height( void ) const; + + /// \return the top left rectangle corner location. + inline Eigen::Matrix cornerLeftTop( void ) const; + /// \return the bottom left rectangle corner location. + inline Eigen::Matrix cornerLeftBottom( void ) const; + /// \return the bottom right rectangle corner location. + inline Eigen::Matrix cornerRightBottom( void ) const; + /// \return the top right rectangle corner location. + inline Eigen::Matrix cornerRightTop( void ) const; + + private: + T _left; ///< x-coordinate of the left border + T _top; ///< y-coordinate of the top border + T _right; ///< x-coordinate of the right border + T _bottom; ///< y-coordinate of the bottom border + }; + + ///// EXPORT DEFAULT TYPES ///// + + typedef Rect Rectf; + typedef Rect Recti; + + ///// DEFINITION ///// + + template + Rect::Rect( void ) + : _left(T(0)), _top(T(0)), _right(T(0)), _bottom(T(0)) { + } + template + Rect::Rect( T left, T top, T right, T bottom ) + : _left(left), _top(top), _right(right), _bottom(bottom) { + } + + template + T Rect::left( void ) const { + return _left; + } + template + T Rect::right( void ) const { + return _right; + } + template + T Rect::top( void ) const { + return _top; + } + template + T Rect::bottom( void ) const { + return _bottom; + } + + template + T Rect::width( void ) const { + T v = _right - _left; + return (v<0.f)? -v : v; + } + template + T Rect::height( void ) const { + T v = _top - _bottom; + return (v<0.f)? -v : v; + } + + template + Eigen::Matrix Rect::cornerLeftTop( void ) const { + return Eigen::Matrix(left(),top()); + } + template + Eigen::Matrix Rect::cornerLeftBottom( void ) const { + return Eigen::Matrix(left(),bottom()); + } + template + Eigen::Matrix Rect::cornerRightBottom( void ) const { + return Eigen::Matrix(right(),bottom()); + } + template + Eigen::Matrix Rect::cornerRightTop( void ) const { + return Eigen::Matrix(right(),top()); + } + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/system/SimpleTimer.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/SimpleTimer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ae0b439f76e0e57ccb40922c41c6105ed87ff539 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/SimpleTimer.hpp @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include "core/system/Config.hpp" +#include +#include + +namespace sibr +{ + /** + * Timer to monitor performance of a section of code. + * \ingroup sibr_system + */ + class Timer + { + public: + typedef std::chrono::time_point time_point; + typedef std::chrono::nanoseconds nano; + typedef std::chrono::microseconds micro; + typedef std::chrono::milliseconds milli; + typedef std::chrono::seconds s; + + const double timeResolution = (double)std::chrono::high_resolution_clock::period::num + / std::chrono::high_resolution_clock::period::den; ///< Timer resolution. + + /** Constructor. Create a timer. + \param start_now start to measure time at creation + */ + Timer(bool start_now = false ) : hasStarted(false) + { + if (start_now) { + tic(); + } + } + + /** Copy constructor + \param timer another timer + */ + Timer(const Timer & timer) { + hasStarted = timer.hasStarted; + current_tic = timer.current_tic; + } + + /** Start measuring elapsed time. + * \warning This will clear existing recorded times. + */ + void tic() + { + tocs.resize(0); + hasStarted = true; + current_tic = std::chrono::high_resolution_clock::now(); + } + + /** Save currently elapsed time. + * \note You can call toc multiple times in a row. + */ + void toc() + { + auto toc = std::chrono::high_resolution_clock::now(); + tocs.push_back(toc); + } + + /** Get the time elapsed since the last tic, with a precisiond etemrined by the tempalte argument. + \return the measured time (default: in ms) + */ + template + double deltaTimeFromLastTic() const + { + if (!hasStarted) { return std::numeric_limits::max(); } + auto toc = std::chrono::high_resolution_clock::now(); + + double deltaTime = 1; + if (!getDeltaTime(current_tic, toc, deltaTime)) { + std::cout << "[SIBR - Timer] : below time reslution " << std::endl; + } + + return deltaTime; + } + + /** Print a list of all the recorded tocs, with the precision specified as a template argument (by default in ms). + \param toc_now should a toc be generated right now. + */ + template + void display(bool toc_now = false) + { + if (toc_now) { + toc(); + } + const int n = (int)tocs.size(); + if (!hasStarted || n == 0) { + std::cout << "[SIBR - Timer] : no tic or no toc" << std::endl; + } + else { + double deltaTime; + for (auto & toc : tocs) { + if (getDeltaTime(current_tic,toc,deltaTime) ) { + std::cout << "[SIBR - Timer] : " << deltaTime << std::endl; + } + else { + std::cout << "[SIBR - Timer] : below time reslution " << std::endl; + } + } + } + } + + /** Get the time elapsed between two points in time, using the precision specified as a template argument (default to ms). + \param tic first time point + \param toc second time point + \param deltaTime will contain the computed duration + \return false if the elapsed time was below the timer precision. + */ + template + bool getDeltaTime(const time_point & tic, const time_point & toc, double & deltaTime) const { + double timediff_nanoSeconds = (double)std::chrono::duration_cast(toc - tic).count(); + if (timediff_nanoSeconds < Timer::timeResolution) { + return false; + } + else { + deltaTime = (double)std::chrono::duration_cast(toc - tic).count(); + return true; + } + } + + private: + time_point current_tic; ///< Initial tic. + std::vector tocs; ///< Recorded time points. + bool hasStarted; ///< Is the timer currently running. + }; + + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/system/String.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/String.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9f4d7311397436278f5a79c892a9b4f142ab5a65 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/String.cpp @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#include "core/system/String.hpp" +#include +#include +#include + +namespace sibr +{ + std::string strSearchAndReplace( const std::string& src, const std::string& search, const std::string& replaceby ) + { + size_t pos = src.find(search); + if (pos != std::string::npos) + { + std::string out; + out = src.substr(0, pos) + replaceby + src.substr(pos+search.size(), src.size()-pos+search.size()); + return out; + } + return src; + } + + std::string removeExtension(const std::string & str) + { + return str.substr(0, str.find_last_of('.')); + } + + std::string getExtension(const std::string & str) + { + const std::string::size_type dotPos = str.find_last_of('.'); + if(dotPos == std::string::npos) { + return ""; + } + return str.substr(dotPos+1); + } + + std::string parentDirectory(const std::string & str) + { + const char kPathSeparator = +#ifdef _WIN32 + '\\'; +#else + '/'; +#endif + const std::string::size_type pos = str.find_last_of("/\\"); + // If no separator, return empty path. + if(pos == std::string::npos) { + return str + kPathSeparator + ".."; + } + // If the separator is not trailing, we are done. + if(pos < str.size()-1) { + return str.substr(0, pos); + } + // Else we have to look for the previous one. + const std::string::size_type pos1 = str.find_last_of("/\\", pos-1); + return str.substr(0, pos1); + } + + SIBR_SYSTEM_EXPORT std::string getFileName(const std::string & str) + { + const std::string::size_type pos = str.find_last_of("/\\"); + if (pos == std::string::npos) { + return str; + } + return str.substr(pos+1); + } + + bool strContainsOnlyDigits(const std::string& str) + { + for (char c : str) + if (c < '0' || c > '9') + return false; + return true; + } + + std::vector split(const std::string& str, char delim) + { + std::stringstream ss(str); + std::string to; + std::vector out; + + if (str.empty()) + return out; + + while (std::getline(ss, to, delim)) + out.push_back(to); + return out; + } + + /// Wrapper around sibr::sprintf that returns a string + std::string sprint(const char *msg, ...) + { +#define TEMP_STR_SIZE 4096 + va_list args; + va_start(args, msg); + char s_StrSingle[TEMP_STR_SIZE]; +#ifdef WIN32 + vsprintf_s(s_StrSingle, TEMP_STR_SIZE, msg, args); +#else + vsnprintf(s_StrSingle, TEMP_STR_SIZE, msg, args); +#endif + va_end(args); + return std::string(s_StrSingle); +#undef TEMP_STR_SIZE + } + + int sprintf(char* buffer, size_t size, const char* format, ...) + { + va_list args; + int ret = 0; + va_start(args, format); +#ifdef WIN32 + ret = vsprintf_s(buffer, size, format, args); +#else + ret = vsnprintf(buffer, size, format, args); +#endif + va_end(args); + return ret; + } + + SIBR_SYSTEM_EXPORT std::string to_lower(const std::string& str) + { + std::string out; + out.reserve(str.length()); + + for (size_t i = 0; i < str.length(); ++i) + out.push_back(tolower(str[i])); + + return out; + } + + + SIBR_SYSTEM_EXPORT bool find_any(const std::vector& needles, const std::string& haystack) + { + for (std::string needle : needles) + { + if (haystack.find(needle) != std::string::npos) + return true; + } + + return false; + } + + std::string timestamp(const std::string & format) { + auto now = std::time(nullptr); +#ifdef SIBR_OS_WINDOWS + tm ltm = { 0,0,0,0,0,0,0,0,0 }; + localtime_s(<m, &now); +#else + tm ltm = *(std::localtime(&now)); +#endif + std::stringstream buffer; + buffer << std::put_time(<m, format.c_str()); + return buffer.str(); + } + +} // namespace sirb + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/system/String.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/String.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0e22bb75d620553590d2478ca8c48af47411d771 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/String.hpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include "core/system/Config.hpp" + +namespace sibr +{ + + /** + * \addtogroup sibr_system + * @{ + */ + + /** + * Replaces all occurences of a substring with another substring. + * \param src the string to perform replacements in + * \param search the substring to replace + * \param replaceby the new substring to substitute + * \return the string with the substitutions performed. + */ + SIBR_SYSTEM_EXPORT std::string strSearchAndReplace( const std::string& src, const std::string& search, const std::string& replaceby ); + + /** + * Process a string (a filename or path) to remove any extension if it exists. + * \param str the string to remove the extension from + * \return the string without extension + */ + SIBR_SYSTEM_EXPORT std::string removeExtension(const std::string& str); + + /** + * Process a string (a filename or path) to extract the file extension if it exists. + * \param str the string to get the extension from + * \return the extension string (without the leading dot) + */ + SIBR_SYSTEM_EXPORT std::string getExtension(const std::string& str); + + /** + * Process a string (a path) to return the parent directory. + * \param str the string to process + * \return the string with the last component removed + * \note Will return the empty string if no separator was found. + */ + SIBR_SYSTEM_EXPORT std::string parentDirectory(const std::string& str); + + /** + * Process a string (a path) to return the file name. + * \param str the string to process + * \return the string with all but the last component removed + * \note Will return the full string if no separator was found. + */ + SIBR_SYSTEM_EXPORT std::string getFileName(const std::string& str); + + /** + * Check if a string only contains digits. + * \param str the string to check + * \return true if it only contains digits + */ + SIBR_SYSTEM_EXPORT bool strContainsOnlyDigits(const std::string& str); + + /** Split string into sub-strings delimited by a given character. + * \param str the input string + * \param delim the delimiting characters + * \return a list of split substrings + */ + SIBR_SYSTEM_EXPORT std::vector split(const std::string& str, char delim = '\n'); + + /** Wrapper around sibr::sprintf that returns a string + * \param msg the string with C placeholders + * \param ... the values for each placeholder + * \return the string with the formatted values inserted + */ + SIBR_SYSTEM_EXPORT std::string sprint(const char *msg, ...); + + /** Write a formatted string with inserted values to a buffer. + * \param buffer the destination string + * \param size the size of the format string + * \param format the string with C placeholders + * \param ... the values for each placeholder + * \return a status code similar to sprintf + */ + SIBR_SYSTEM_EXPORT int sprintf(char* buffer, size_t size, const char* format, ...); + + /** Convert the input string to lowert case. + * \param str the input string + * \return the input string in lower case + */ + SIBR_SYSTEM_EXPORT std::string to_lower(const std::string& str); + + /** Find if a list of substring is present in a given string. + * \param needles the list of substring + * \param haystack the search string + * \return true if any substring is present in the search string, else false + */ + SIBR_SYSTEM_EXPORT bool find_any(const std::vector& needles, const std::string& haystack); + + /** Write the current timestamp to a string. + * \param format the formatting to use for the timestamp (see default value for an example) + * \return a string containing the timestamp + */ + SIBR_SYSTEM_EXPORT std::string timestamp(const std::string & format = "%Y_%m_%d_%H_%M_%S"); + + + /*** @} */ + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/system/ThreadIdWorker.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/ThreadIdWorker.cpp new file mode 100644 index 0000000000000000000000000000000000000000..55c19f14c6ca6a9f610cda8f470e360118269228 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/ThreadIdWorker.cpp @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#include "core/system/ThreadIdWorker.hpp" + +namespace sibr +{ + /*static*/ std::mutex ThreadIdWorker::g_mutex; + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/system/ThreadIdWorker.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/ThreadIdWorker.hpp new file mode 100644 index 0000000000000000000000000000000000000000..afb76a65f2442ba30fac7bfc6eb19d843bcdfb94 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/ThreadIdWorker.hpp @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include +# include +# include +# include + +# include "core/system/Config.hpp" + +namespace sibr +{ + /** Class used to work concurrently on multiple tasks/instructions. + The only shared object is a queue (TaskIds) that + contains ids of remaining tasks to perform. + + Typically, you use this id to access a const array + (input) and write results to another array using once + again this id. The output array is already resized + at the begin so that you can freely modify its + element without hurting other threads. + + Code Example: + + std::vector workers(MASKPATCH_NBTHREADS); + + // Launch all threads + for (ThreadIdWorker& t: workers) + t = std::move(ThreadIdWorker(taskId, workFunc)); + + // Wait for all threads + for (ThreadIdWorker& t: workers) + if (t.joinable()) + t.join(); + + \ingroup sibr_system + */ + class /*SIBR_SYSTEM_EXPORT*/ ThreadIdWorker : public std::thread + { + public: + typedef std::queue TaskIds; + public: + /// Build an empty worker (placeholder) + ThreadIdWorker( void ); + + /** Move constructor + *\param other worker to move + */ + ThreadIdWorker( ThreadIdWorker&& other ) noexcept; + + /** Constructor. Will call the passed function for each given task ID. + \param ids a list of task ids + \param func a function receiving a task ID as parameter returning either FALSE for signaling the worker to stop or TRUE for keep going. + */ + ThreadIdWorker( TaskIds& ids, std::function func ); + + /** Move operator. + *\param other worker to assign + *\return the current worker + */ + ThreadIdWorker& operator =( ThreadIdWorker&& other ) noexcept; + + /// Deleted copy operator. + ThreadIdWorker(const ThreadIdWorker&) = delete; + + private: + + /** Will pull the next task or automatically stop. + \param ids a list of task ids + \param func a function receiving a task ID as parameter + */ + void taskPuller( TaskIds& ids, std::function func ); + + SIBR_SYSTEM_EXPORT static std::mutex g_mutex; ///< used to protect the common shared TaskIds list + }; + + ///// INLINES ///// + inline ThreadIdWorker::ThreadIdWorker( void ) { + } + + inline ThreadIdWorker::ThreadIdWorker( ThreadIdWorker&& other ) noexcept : + std::thread(std::move((std::thread&)other)) { + } + + inline ThreadIdWorker::ThreadIdWorker( TaskIds& ids, std::function func ) + : std::thread( [this, &ids, &func]() { taskPuller(ids, std::move(func)); } ) { + } + + inline ThreadIdWorker& ThreadIdWorker::operator =( ThreadIdWorker&& other ) noexcept { + ((std::thread*)this)->operator=(std::move(other)); return *this; + } + + inline void ThreadIdWorker::taskPuller( TaskIds& ids, std::function func ) { + uint id = 0; + bool stop = false; + while (!stop) + { + { // Pop next id + std::lock_guard lock(g_mutex); + stop = ids.empty(); + + if (!stop) + { + id = ids.front(); + ids.pop(); + } + } + + if (!stop) + stop = !func(id); + } + } + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Transform3.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Transform3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d774d621e668b8bad3a399670f60fb162edb2b36 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Transform3.hpp @@ -0,0 +1,404 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include "core/system/ByteStream.hpp" +# include "core/system/Config.hpp" +# include "core/system/Matrix.hpp" +# include "core/system/Vector.hpp" +# include "core/system/Quaternion.hpp" + + +namespace sibr +{ + /** + * Represent a 3D transformation composed of a rotation and translation. + * \ingroup sibr_system + */ + template + class Transform3 + { + public: + typedef Eigen::Matrix Vector3; + typedef Eigen::Quaternion Quaternion; + + public: + + /** Constructor: identity transform. */ + Transform3( void ) : _position(0, 0, 0), _scale(1., 1., 1.) { + _rotation.setIdentity(); + } + + /** Set the transformation parameters. + *\param translation the translation vector + *\param rotation the rotation quaternion + */ + void set( const Vector3& translation, const Quaternion& rotation ) { + _position = translation; + _rotation = rotation; + } + + /** Apply a translation. + *\param x x shift + *\param y y shift + *\param z z shift + **/ + void translate( float x, float y, float z ); + + /** Apply a translation that is itself rotated by another transformation. + *\param x x shift + *\param y y shift + *\param z z shift + *\param ref additional rotation trnasofrmation to apply to the translation vector. + **/ + void translate( float x, float y, float z, const Transform3& ref); + + /** Apply a translation. + *\param v translation vector + **/ + void translate( const Vector3& v ); + + /** Apply a translation that is itself rotated by another transformation. + *\param v translation vector + *\param ref additional rotation trnasofrmation to apply to the translation vector. + **/ + void translate( const Vector3& v, const Transform3& ref ); + + + void scale(const float& s); + /** Set the position. + *\param x x position + *\param y y position + *\param z z position + **/ + void position( float x, float y, float z ); + + /** Set the position. + *\param v position + **/ + void position( const Vector3& v ); + + /** \return the position */ + const Vector3& position( void ) const; + + + /** Apply a rotation. + *\param rotation quaternion rotation + */ + void rotate( const Quaternion& rotation ); + + /** Apply a rotation using Euler angles. + *\param x yaw + *\param y pitch + *\param z roll + *\todo Clarify the angles order. + *\sa quatFromEulerAngles + */ + void rotate( float x, float y, float z ); + + /** Apply a rotation using Euler angles and composite with an additional transformation. + *\param x yaw + *\param y pitch + *\param z roll + *\param ref additional rotation + *\todo Clarify the angles order. + *\sa quatFromEulerAngles + */ + void rotate( float x, float y, float z, + const Transform3& ref); + + /** Apply a rotation using Euler angles. + *\param v angles + *\todo Clarify the angles order. + *\sa quatFromEulerAngles + */ + void rotate( const Vector3& v ); + + /** Apply a rotation using Euler angles and composite with an additional transformation. + *\param v angles + *\param ref additional rotation + *\todo Clarify the angles order. + *\sa quatFromEulerAngles + */ + void rotate( const Vector3& v, const Transform3& ref ); + + /** Set the rotation from Euler angles. + *\param x yaw + *\param y pitch + *\param z roll + *\todo Clarify the angles order. + *\sa quatFromEulerAngles + */ + void rotation( float x, float y, float z ); + + /** Set the rotation from Euler angles. + *\param v angles + *\todo Clarify the angles order. + *\sa quatFromEulerAngles + */ + void rotation( const Vector3& v ); + + /** Set the rotation. + *\param q quaternion rotation + */ + void rotation( const Quaternion& q ); + + /// \return the rotation + const Quaternion& rotation( void ) const; + + /// \return the transformation matrix + Matrix4f matrix( void ) const; + /// \return the inverse of the transformation matrix + Matrix4f invMatrix( void ) const; + + /** Interpolate between two transformations. + *\param from source transformation + *\param to destination transformation + *\param dist01 interpolation factor + *\return the interpolated transformation + */ + static Transform3 interpolate( const Transform3& from, const Transform3& to, float dist01 ) { + dist01 = std::max(0.f, std::min(1.f, dist01)); // clamp + + Transform3 out; + out.position((1.0f-dist01)*from.position() + dist01*to.position()); + out.rotation(from.rotation().slerp(dist01, to.rotation())); + return out; + } + + /** Linearly extrapolate based on two transformations, by reapplying the delta between the two transformations to the current one + * and interpolating between the current and the new estimate. + *\param previous source transformation + *\param current current transformation + *\param dist01 extrapolation factor + *\return the extrapolated transformation + *\note dist01 should still be in 0,1 + */ + static Transform3 extrapolate(const Transform3& previous, const Transform3& current, float dist01) { + + Vector3f deltaPosition = current.position() - previous.position(); + Quaternion deltaRotation = previous.rotation().inverse() * current.rotation(); + + Transform3 t = current; + t.rotate(deltaRotation); + t.translate(deltaPosition); + return interpolate(current, t, dist01); + } + + /** Compute a trnasformation made by compsoiting a parent and child transformations. + * \param parentTr the parent + * \param childTr the child + * \return the composite transformation + */ + static Transform3 computeFinal( const Transform3& parentTr, const Transform3& childTr ) { + Transform3 finalTr; + finalTr.position(parentTr.position() + parentTr.rotation() * childTr.position()); + finalTr.rotation(parentTr.rotation() * childTr.rotation()); + return finalTr; + } + + /** Equality operator with a 1e-3 tolerance. + *\param other transformation to test equality with + *\return true if other is equal + */ + bool operator==(const Transform3 & other) const { + static const float eps = 1e-3f; + return (_position-other._position).norm()/ _position.norm() < eps && std::abs(_rotation.dot(other._rotation)) > ( 1 - eps); + } + + /** Difference operator. + *\param other transformation to test difference with + *\return true if other is different + **/ + bool operator!=(const Transform3 & other) const { + return !(*this == other); + } + + private: + Vector3 _position; + Quaternion _rotation; + Vector3 _scale; + }; + + /// Helper def. + typedef Transform3 Transform3f; + + /** Write transformation to a byte stream. + *\param stream the byte stream + *\param t the transform + *\return the stream for compositing + \ingroup sibr_system + */ + template + ByteStream& operator << (ByteStream& stream, const Transform3& t ) { + typename Transform3::Vector3 v = t.position(); + typename Transform3::Quaternion q = t.rotation(); + return stream + << v.x() << v.y() << v.z() + << q.x() << q.y() << q.z() << q.w(); + } + + /** Read transformation from a byte stream. + *\param stream the byte stream + *\param t the transform + *\return the stream for compositing + \ingroup sibr_system + */ + template + ByteStream& operator >> (ByteStream& stream, Transform3& t ) { + typename Transform3::Vector3 v; + typename Transform3::Quaternion q; + stream + >> v.x() >> v.y() >> v.z() + >> q.x() >> q.y() >> q.z() >> q.w(); + t.position(v); + t.rotation(q); + return stream; + } + + //==================================================================// + // Inlines + //==================================================================// + + template + void Transform3::translate( float x, float y, float z ) { + _position.x() += x; _position.y() += y; _position.z() += z; + } + + template + void Transform3::translate( float x, float y, float z, + const Transform3& ref) { + translate( Vector3( x, y, z ), ref ); + } + + template + void Transform3::translate( const Vector3& v ) { + _position.x() += v.x(); _position.y() += v.y(); _position.z() += v.z(); + } + + template + void Transform3::translate( const Vector3& v, const Transform3& ref ) { + translate( ref.rotation().operator*(v) ); + } + + template + inline void Transform3::scale(const float& s) + { + _scale = Vector3(s, s, s); + } + + template + void Transform3::position( float x, float y, float z ) { + _position.x() = x; _position.y() = y; _position.z() = z; + } + + template + void Transform3::position( const Vector3& v ) { + _position.x() = v.x(); _position.y() = v.y(); _position.z() = v.z(); + } + + template + const typename Transform3::Vector3& Transform3::position( void ) const { + return _position; + } + + + template + void Transform3::rotate( const Quaternion& rotation ) { + _rotation = rotation * _rotation; + _rotation.normalize(); + } + + template + void Transform3::rotate( float x, float y, float z ) { + Quaternion q = quatFromEulerAngles(Vector3(x, y, z)); + q.normalize(); + rotate(q); + } + + template + void Transform3::rotate( const Vector3& v ) { + rotate( v.x(), v.y(), v.z() ); + } + + template + void Transform3::rotate( const Vector3& v, const Transform3& ref ) { + rotate( v.x(), v.y(), v.z(), ref ); + } + + template + void Transform3::rotation( float x, float y, float z ) { + _rotation = quatFromEulerAngles(Vector3(x, y, z)); + } + + template + void Transform3::rotation( const Vector3& v ) { + rotation( v.x(), v.y(), v.z() ); + } + + template + void Transform3::rotation( const Quaternion& q ) { + _rotation = q; + } + + template + const typename Transform3::Quaternion& Transform3::rotation( void ) const { + return _rotation; + } + + template + Matrix4f Transform3::matrix( void ) const { + Matrix4f trans = matFromQuat(_rotation); + Matrix4f scaleMat = Matrix4f::Identity(); + scaleMat(0, 0) = _scale.x(); + scaleMat(1, 1) = _scale.y(); + scaleMat(2, 2) = _scale.z(); + + trans = matFromTranslation(_position) * trans * scaleMat; // Opti (direct) + + return trans; + } + + template + Matrix4f Transform3::invMatrix( void ) const { + // This is wrapped so we can (in the future) add a policy class + // to enable caching this inv matrix + return matrix().inverse(); + } + + template + void Transform3::rotate( float x, float y, float z, + const Transform3& ref) + { + Quaternion q = quatFromEulerAngles(Vector3(x, y, z)); + q.normalize(); + + if ( &ref == this ) // Local Rotation + { + _rotation = _rotation * q; + _rotation.normalize(); + } + else + { + Quaternion refConj = ref.rotation(); + refConj.conjugate(); + + // 1) Apply global rotation of ref on 'q' (ref * q) + // 2) Apply local rotation of ref.conj (~inv) on 'q' (q*ref.conj) + // 3) The rotation is converted and can be applied using rotate + rotate((ref.rotation() * q) * refConj); + } + } + + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Utils.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Utils.cpp new file mode 100755 index 0000000000000000000000000000000000000000..06670fd654e21a3819a51a3077e9774ea0ac4379 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Utils.cpp @@ -0,0 +1,498 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#include +#include +#include +#include +#include "core/system/Utils.hpp" + +#ifdef SIBR_OS_WINDOWS + #include + #include + #include + #include + // Some old MinGW/CYGWIN distributions don't define this: + #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING + #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 + #endif +#else + #include + #include + #include + #include + #include + #include +#endif + +namespace sibr +{ +#ifdef SIBR_OS_WINDOWS + static HANDLE stdoutHandle; + static DWORD outModeInit; + + void setupConsole(void) { + DWORD outMode = 0; + stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE); + + if(stdoutHandle == INVALID_HANDLE_VALUE) { + exit(GetLastError()); + } + + if(!GetConsoleMode(stdoutHandle, &outMode)) { + exit(GetLastError()); + } + + outModeInit = outMode; + + // Enable ANSI escape codes + outMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + + if(!SetConsoleMode(stdoutHandle, outMode)) { + exit(GetLastError()); + } + } + + void restoreConsole(void) { + // Reset colors + printf("\x1b[0m"); + + // Reset console mode + if(!SetConsoleMode(stdoutHandle, outModeInit)) { + exit(GetLastError()); + } + } +#endif + + + std::string loadFile(const std::string& fname) + { + std::ifstream file(fname.c_str(), std::ios::binary); + if (!file || !file.is_open()) { + SIBR_ERR << "File not found: " << fname << std::endl; + return ""; + } + file.seekg(0, std::ios::end); + + std::streampos length = file.tellg(); + file.seekg(0, std::ios::beg); + + std::vector buffer(length); + file.read(&buffer[0], length); + file.close(); + + return std::string(buffer.begin(), buffer.end()); + } + + void makeDirectory(const std::string& path) + { + boost::filesystem::path p(path); + if (boost::filesystem::exists(p) == false) + boost::filesystem::create_directories(p); + } + + std::vector listFiles(const std::string & path, const bool listHidden, const bool includeSubdirectories, const std::vector & allowedExtensions) + { + if (!directoryExists(path)) { + return {}; + } + + std::vector files; + bool shouldCheckExtension = !allowedExtensions.empty(); + + try { + boost::filesystem::directory_iterator end_iter; + for (boost::filesystem::directory_iterator dir_itr(path); dir_itr != end_iter; ++dir_itr) { + + const std::string itemName = dir_itr->path().filename().string(); + if (includeSubdirectories && boost::filesystem::is_directory(dir_itr->status())) { + if (listHidden || (itemName.size() > 0 && itemName.at(0) != '.')) { + files.push_back(itemName); + } + } + else if (boost::filesystem::is_regular_file(dir_itr->status())) { + bool shouldKeep = !shouldCheckExtension; + if (shouldCheckExtension) { + for (const auto & allowedExtension : allowedExtensions) { + if (dir_itr->path().extension() == ("." + allowedExtension) || dir_itr->path().extension() == allowedExtension) { + shouldKeep = true; + break; + } + } + } + + if (shouldKeep && (listHidden || (itemName.size() > 0 && itemName.at(0) != '.'))) { + files.push_back(itemName); + } + } + } + } + catch (const boost::filesystem::filesystem_error&) { + std::cout << "Can't access or find directory." << std::endl; + } + + std::sort(files.begin(), files.end()); + + return files; + } + + std::vector listSubdirectories(const std::string & path, const bool listHidden) + { + if (!directoryExists(path)) { + return {}; + } + + std::vector dirs; + + + try { + boost::filesystem::directory_iterator end_iter; + for (boost::filesystem::directory_iterator dir_itr(path); dir_itr != end_iter; ++dir_itr) { + + const std::string itemName = dir_itr->path().filename().string(); + if (boost::filesystem::is_directory(dir_itr->status())) { + if (listHidden || (itemName.size() > 0 && itemName.at(0) != '.')) { + dirs.push_back(itemName); + } + } + } + } + catch (const boost::filesystem::filesystem_error& ) { + std::cout << "Can't access or find directory." << std::endl; + } + + std::sort(dirs.begin(), dirs.end()); + + return dirs; + } + + + bool copyDirectory(const std::string& src, const std::string& dst) + { + boost::filesystem::path source = src; + boost::filesystem::path destination = dst; + namespace fs = boost::filesystem; + try + { + // Check whether the function call is valid + if (!fs::exists(source) || !fs::is_directory(source)) + { + std::cerr << "Source directory " << source.string() + << " does not exist or is not a directory." << '\n' + ; + return false; + } + if (fs::exists(destination)) + { + std::cerr << "Destination directory " << destination.string() + << " already exists." << '\n' + ; + return false; + } + // Create the destination directory + if (!fs::create_directory(destination)) + { + std::cerr << "Unable to create destination directory" + << destination.string() << '\n' + ; + return false; + } + } + catch (fs::filesystem_error const & e) + { + std::cerr << e.what() << '\n'; + return false; + } + // Iterate through the source directory + for (fs::directory_iterator file(source); file != fs::directory_iterator(); ++file) + { + try + { + fs::path current(file->path()); + if (fs::is_directory(current)) + { + // Found directory: Recursion + if (!copyDirectory(current.string(), (destination / current.filename()).string())) + { + return false; + } + } + else + { + // Found file: Copy + fs::copy_file( + current, + destination / current.filename() + ); + } + } + catch (fs::filesystem_error const & e) + { + std::cerr << e.what() << '\n'; + } + } + return true; + } + + bool copyFile(const std::string & src, const std::string & dst, const bool overwrite) + { + boost::filesystem::path source = src; + boost::filesystem::path destination = dst; + namespace fs = boost::filesystem; + try { + // Check whether the function call is valid + if (!fs::exists(source) || !fs::is_regular_file(source)) + { + std::cerr << "Source file " << source.string() + << " does not exist or is not a regular file." << '\n' + ; + return false; + } + + // If the destination is a directory, we copy the file into this directory, with the same name. + if (fs::is_directory(destination)) { + destination = destination / source.filename(); + } + + if (fs::exists(destination) && !overwrite) + { + std::cerr << "Destination file " << destination.string() + << " already exists." << '\n' + ; + return false; + } + if(overwrite) { + fs::copy_file(source, destination, boost::filesystem::copy_option::overwrite_if_exists); + } else { + fs::copy_file(source, destination); + } + + } + catch (fs::filesystem_error const & e) + { + std::cerr << e.what() << '\n'; + return false; + } + + return true; + } + + void emptyDirectory(const std::string& path) { + boost::filesystem::path p(path); + for (boost::filesystem::directory_iterator end_dir_it, it(p); it != end_dir_it; ++it) { + boost::filesystem::remove_all(it->path()); + } + } + + bool fileExists(const std::string& path) + { + boost::filesystem::path p(path); + return boost::filesystem::exists(p) && boost::filesystem::is_regular_file(path); + } + + bool directoryExists(const std::string& path) + { + boost::filesystem::path p(path); + return boost::filesystem::exists(p) && boost::filesystem::is_directory(path); + } + + size_t getAvailableMem() { +#define DIV 1024 + +#ifdef SIBR_OS_WINDOWS + MEMORYSTATUSEX statex; + statex.dwLength = sizeof(statex); + GlobalMemoryStatusEx(&statex); + return static_cast(statex.ullAvailPhys) / DIV; +#else + long pages = sysconf(_SC_PHYS_PAGES); + long page_size = sysconf(_SC_PAGE_SIZE); + return static_cast(pages * page_size) / DIV; +#endif + } + + SIBR_SYSTEM_EXPORT std::string getInstallDirectory() + { + char exePath[4095]; + +#ifdef SIBR_OS_WINDOWS + unsigned int len = GetModuleFileNameA(GetModuleHandleA(0x0), exePath, MAX_PATH); + + std::string installDirectory = parentDirectory(parentDirectory(exePath)); +#else + unsigned int len=0; + + char result[PATH_MAX]; + ssize_t c = readlink("/proc/self/exe", result, PATH_MAX); + len = c; + result[len]='\0'; + const char* path; + if( c != -1 ) + path = dirname(result); + else + SIBR_ERR << "Cant find executable path "<< std::endl; + + + std::string installDirectory(parentDirectory(path)); +#endif + + if (len == 0 && + !directoryExists(installDirectory + "/bin")) // memory not sufficient or general error occured + { + SIBR_ERR << "Can't find install folder! Please specify as command-line option using --appPath option!" << std::endl; + } + return installDirectory; + } + + SIBR_SYSTEM_EXPORT std::string getBinDirectory() + { + return getInstallSubDirectory("bin"); + } + + SIBR_SYSTEM_EXPORT std::string getShadersDirectory(const std::string & subfolder) + { + return getInstallSubDirectory("shaders" + ((subfolder != "") ? "/" + subfolder : "")); + } + + SIBR_SYSTEM_EXPORT std::string getScriptsDirectory() + { + return getInstallSubDirectory("scripts"); + } + + SIBR_SYSTEM_EXPORT std::string getResourcesDirectory() + { + return getInstallSubDirectory("resources"); + } + + SIBR_SYSTEM_EXPORT std::string getAppDataDirectory() + { + std::string appDataDirectory = ""; +#ifdef SIBR_OS_WINDOWS + PWSTR path_tmp; + + /* Attempt to get user's AppData folder + * + * Microsoft Docs: + * https://docs.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetknownfolderpath + * https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid + */ + auto get_folder_path_ret = SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, nullptr, &path_tmp); + + /* Error check */ + if (get_folder_path_ret != S_OK) { + CoTaskMemFree(path_tmp); + SIBR_ERR << "Could not access AppData folder."; + } + + std::wstring path_wtmp(path_tmp); + appDataDirectory += std::string( path_wtmp.begin(), path_wtmp.end() ); + appDataDirectory += "\\sibr"; + CoTaskMemFree(path_tmp); +#else + struct passwd *pw = getpwuid(getuid()); + appDataDirectory += pw->pw_dir + std::string("/.sibr"); +#endif + + makeDirectory(appDataDirectory); + + return appDataDirectory; + } + + SIBR_SYSTEM_EXPORT std::string getInstallSubDirectory(const std::string & subfolder) + { + std::string installDirectory = getInstallDirectory(); + std::string installSubDirectory = installDirectory + "/" + subfolder; + + if(!directoryExists(installSubDirectory)) + { + // try subdirs GD LINUX issue + installSubDirectory = installDirectory + "/install/" + subfolder; + if(!directoryExists(installSubDirectory)) + SIBR_ERR << "Can't find subfolder " << subfolder << " in " << installDirectory << ". Please specify correct app folder as command-line option using --appPath option!" << std::endl; + } + + return installSubDirectory; + } + + bool showFilePicker(std::string & selectedElement, + + const FilePickerMode mode, const std::string & directoryPath, const std::string & extensionsAllowed) { + + nfdchar_t *outPath = NULL; + nfdresult_t result = NFD_CANCEL; + + if (mode == Directory) { + result = NFD_PickFolder(directoryPath.c_str(), &outPath); + } else if (mode == Save) { + result = NFD_SaveDialog(extensionsAllowed.empty() ? NULL : extensionsAllowed.c_str(), directoryPath.c_str(), &outPath); + } else { + result = NFD_OpenDialog(extensionsAllowed.empty() ? NULL : extensionsAllowed.c_str(), directoryPath.c_str(), &outPath); + } + + + if (result == NFD_OKAY) { + selectedElement = std::string(outPath); + free(outPath); + return true; + } else if (result == NFD_CANCEL) { + // User canceled, do nothing. + } else { + // Programmatic error. + SIBR_WRG << "Unable to present file dialog." << std::endl; + std::cout << std::string(NFD_GetError()) << std::endl; + } + free(outPath); + + return false; + + } + + SIBR_SYSTEM_EXPORT std::istream& safeGetline(std::istream& is, std::string& t) + { +#ifdef SIBR_OS_WINDOWS + return std::getline(is, t); +#else + t.clear(); + + // The characters in the stream are read one-by-one using a std::streambuf. + // That is faster than reading them one-by-one using the std::istream. + // Code that uses streambuf this way must be guarded by a sentry object. + // The sentry object performs various tasks, + // such as thread synchronization and updating the stream state. + + std::istream::sentry se(is, true); + std::streambuf* sb = is.rdbuf(); + + for(;;) { + int c = sb->sbumpc(); + switch (c) { + case '\n': + return is; + case '\r': + if(sb->sgetc() == '\n') + sb->sbumpc(); + return is; + case std::streambuf::traits_type::eof(): + // Also handle the case when the last line has no line ending + is.setstate(std::ios::eofbit); + // this helps ignore the last line if it's empty (otherwise it's a different behavior from std::get_line) + if (t.empty()) is.setstate(std::ios::badbit); + return is; + default: + t += (char)c; + } + } +#endif + } + +} // namespace sirb diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Utils.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Utils.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4ec59f7d851cdb9f746358169174875ad74a7f10 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Utils.hpp @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include +# include "core/system/Config.hpp" +# include "core/system/String.hpp" + +namespace sibr +{ + /** + * \addtogroup sibr_system + * @{ + */ + +#ifdef SIBR_OS_WINDOWS + /** setup console to allow color printing in console + */ + SIBR_SYSTEM_EXPORT void setupConsole(void) ; + /** restore console to no colors + */ + SIBR_SYSTEM_EXPORT void restoreConsole(void) ; + +#endif + + /** Load the whole file into a std::string + * \param filename the file path + * \return the loaded content */ + SIBR_SYSTEM_EXPORT std::string loadFile( const std::string& filename ); + + /** Create directory (if it doesn't exist already) + * \param path the directory path + */ + SIBR_SYSTEM_EXPORT void makeDirectory( const std::string& path ); + + /** List content of directory, sorted alphabetically. + * \param path directory path + * \param listHidden should hidden files be listed + * \param includeSubdirectories should subdirectories be explored + * \param allowedExtensions a list of allowed extensions to filter the list with (for instance {"png", "bmp"}) + * \return a list of file names/subpaths + * \note To get each element full path, use path + "/" + itemPath + */ + SIBR_SYSTEM_EXPORT std::vector listFiles(const std::string & path, const bool listHidden = false, const bool includeSubdirectories = false, const std::vector & allowedExtensions = {}); + + /** List content of directory, sorted alphabetically, including subdirectories. + * \param path directory path + * \param listHidden should hidden directories be listed + * \return a list of directory names/subpaths + * \note To get each element full path, use path + "/" + itemPath + */ + SIBR_SYSTEM_EXPORT std::vector listSubdirectories(const std::string& path, const bool listHidden = false); + + /** Copy directory. + * \param src source path + * \param dst destination path + * \return success boolean + */ + SIBR_SYSTEM_EXPORT bool copyDirectory(const std::string& src, const std::string& dst); + + /** Copy file. + * \param src source path + * \param dst destination path + * \param overwrite if the file already exists, should it be overwritten + * \return success boolean + */ + SIBR_SYSTEM_EXPORT bool copyFile(const std::string& src, const std::string& dst, const bool overwrite = false); + + /** Empty a directory (if it exist already) + * \param path the directory path + */ + SIBR_SYSTEM_EXPORT void emptyDirectory(const std::string& path); + + /** Test if a file exists. + *\param path the file path + *\return true if file exists + */ + SIBR_SYSTEM_EXPORT bool fileExists( const std::string& path ); + + /** Test if a directory exists. + *\param path the directory path + *\return true if directory exists + */ + SIBR_SYSTEM_EXPORT bool directoryExists( const std::string& path ); + + /** \return the available memory on windows system in Ko*/ + SIBR_SYSTEM_EXPORT size_t getAvailableMem(); + + /** \return the binary directory on windows system*/ + SIBR_SYSTEM_EXPORT std::string getInstallDirectory(); + + /** \return the binary directory on windows system*/ + SIBR_SYSTEM_EXPORT std::string getBinDirectory(); + + /** + * \param subfolder optional subfolder for subproject + * \return the binary directory on windows system + */ + SIBR_SYSTEM_EXPORT std::string getShadersDirectory(const std::string & subfolder = ""); + + /** \return the scripts directory on windows system*/ + SIBR_SYSTEM_EXPORT std::string getScriptsDirectory(); + + /** \return the resources directory on windows system*/ + SIBR_SYSTEM_EXPORT std::string getResourcesDirectory(); + + /** \return the user specific application directory */ + SIBR_SYSTEM_EXPORT std::string getAppDataDirectory(); + + /** + * \param subfolder the subfolder to get + * \return the provided subfolder path on windows system + */ + SIBR_SYSTEM_EXPORT std::string getInstallSubDirectory(const std::string & subfolder); + + /** Selection mode for the file picker. */ + enum FilePickerMode { + Default, Save, Directory + }; + + /** + * Present a native OS file picker. + * \param selectedElement will contain the path to the element selected by the user if any. + * \param mode the mode to use, pick from Save, Directory, Default. + * \param directoryPath the initial directory to present to the user. + * \param extensionsAllowed a list of file extensions to allow: "obj,ply" for instance. + * \return true if an element was selected, else false. + * \warning '.' relative path is unsupported for directoryPath. + */ + SIBR_SYSTEM_EXPORT bool showFilePicker(std::string & selectedElement, + const FilePickerMode mode, const std::string & directoryPath = "", const std::string & extensionsAllowed = ""); + + /** Measure and print the timing of a task. + *\param s description + *\param f function to run + *\param args arguments for the function + */ + template + void taskTiming(const std::string & s, FunType && f, ArgsType && ... args) { + const auto start = std::chrono::high_resolution_clock::now(); + f(args...); + const auto end = std::chrono::high_resolution_clock::now(); + std::cout << s << " : " << std::chrono::duration_cast(end - start).count() << " ms" << std::endl; + }; + + SIBR_SYSTEM_EXPORT std::istream& safeGetline(std::istream& is, std::string& t); + + /*** @} */ +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Vector.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Vector.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1986be7ef24246d0d9afe0f4486b4892343b3bbd --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Vector.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#include "core/system/Vector.hpp" +# include "core/system/Quaternion.hpp" + +namespace sibr +{ + + Vector3f toColorFloat(Vector3ub & colorUB ) { + return colorUB.cast().unaryExpr( [] (unsigned char c) { return (float)c/255.0f; } ); + } + + Vector3ub toColorUB( Vector3f & colorFloat ) { + return colorFloat.unaryExpr( [] (float f) { return std::floor(f*255.0f); } ).cast(); + } + + Eigen::Matrix alignRotationMatrix(const sibr::Vector3f & from, const sibr::Vector3f & to) + { + sibr::Quaternionf q = sibr::Quaternionf::FromTwoVectors(from, to); + q.normalize(); + Eigen::Matrix3f R = q.toRotationMatrix(); + sibr::Matrix4f R4; + R4.setIdentity(); + R4.block<3, 3>(0, 0) = R; + return R4; + } + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Vector.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Vector.hpp new file mode 100644 index 0000000000000000000000000000000000000000..fac26c44404ab048e127ada5657a9ede085abb59 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/Vector.hpp @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include "core/system/Config.hpp" + + + +namespace Eigen +{ + /** + * \addtogroup sibr_system + * @{ + */ + + // The following operators work with Eigen structs, so + // they must be declared in the namespace Eigen (or + // you would have to do sibr::operator < (left, right) + // instead of simple left < right) + + /** Lexicographic comparison (from left to right). + *\param left first element + *\param right second element + *\return true if left is lexicographically smaller than right. + */ + template + bool operator<(const Eigen::Matrix& left, const Eigen::Matrix& right) { + + for (int c = 0; c < N; c++) { + if (left[c] < right[c]) return true; + else if (left[c] > right[c]) return false; + } + return false; //case where they are equal + + } + + // stream + + /** Output matrix to a stream. + *\param s stream + *\param t matrix + *\return the stream for chaining + */ + template + std::ostream& operator<<( std::ostream& s, const Eigen::Matrix& t ) { + s << '('; + for (uint i=0; i + std::istream& operator>>( std::istream& s, Eigen::Matrix& t ) { + char tmp = 0; + s >> tmp; // ( + for (int i = 0; i < N; ++i) + { + s >> t [i]; + s >> tmp; //, or ) + } + + return s; + } + + /** @} */ +} + +namespace sibr +{ + + /** + * \addtogroup sibr_system + * @{ + */ + + template + using Vector = Eigen::Matrix; + + /** Fractional part of each component. + *\param A vector + *\return the fractional matrix + **/ + template + Eigen::Matrix frac( const Eigen::Matrix& A ) { + Eigen::Matrix out = A; + for (int i = 0; i < N; ++i) + out[i] = out[i] - floor(out[i]); + return out; + } + + /** Distance between two vectors + *\param A first vector + *\param B second vector + *\return norm(A-B) + */ + template + inline T distance( const Eigen::Matrix& A, const Eigen::Matrix& B ) { + return (A-B).norm(); + } + + /** Return the length of a vector. + *\param A vector + *\return norm(A) + */ + template + inline T length( const Eigen::Matrix& A ) { + return A.norm(); + } + + /** Return the squared length of a vector. + *\param A vector + *\return norm(A)^2 + */ + template + inline T sqLength( const Eigen::Matrix& A ) { + return A.squaredNorm(); + } + + /** Compute the dot product of two vectors + *\param A first vector + *\param B second vector + *\return A.B + */ + template + inline T dot( const Eigen::Matrix& A, const Eigen::Matrix& B ) { + return A.dot(B); + } + + /** Compute the cross product of two vectors + *\param A first vector + *\param B second vector + *\return AxB + */ + template + inline Eigen::Matrix cross( const Eigen::Matrix& A, const Eigen::Matrix& B ) { + return A.cross(B); + } + + /** Clamp each component of a vector between two values. + * \param A vector + * \param min min values vector + * \param max max values vector + * \return min(max(A, min), max) + */ + template + inline Vector clamp(const Vector& A, const Vector & min, const Vector & max) { + return A.cwiseMax(min).cwiseMin(max); + } + + /** Compute the cotangent of the angle between two vectors. + *\param A first vector + *\param B second vector + *\return the cotangent + */ + template + inline T cotan(const Eigen::Matrix& A, const Eigen::Matrix& B) { + return A.dot(B) / A.cross(B).norm(); + } + + /** Convert an unsigned char color in [0,255] to a float color in [0,1]. + *\param colorUB the color vector + *\return the [0,1] float vector + */ + SIBR_SYSTEM_EXPORT Eigen::Matrix toColorFloat( Vector & colorUB ); + + /** Convert a float color in [0,1] to an unsigned char color in [0,255]. + *\param colorFloat the color vector + *\return the [0,255] float vector + */ + SIBR_SYSTEM_EXPORT Eigen::Matrix toColorUB( Vector & colorFloat ); + + // Typedefs. + + typedef Eigen::Matrix Vector1f; + typedef Eigen::Matrix Vector1i; + + typedef Eigen::Matrix Vector2u; + typedef Eigen::Matrix Vector2ub; + typedef Eigen::Matrix Vector2i; + typedef Eigen::Matrix Vector2f; + typedef Eigen::Matrix Vector2d; + + typedef Eigen::Matrix Vector3u; + typedef Eigen::Matrix Vector3ub; + typedef Eigen::Matrix Vector3s; + typedef Eigen::Matrix Vector3i; + typedef Eigen::Matrix Vector3f; + typedef Eigen::Matrix Vector3d; + + typedef Eigen::Matrix Vector4u; + typedef Eigen::Matrix Vector4ub; + typedef Eigen::Matrix Vector4i; + typedef Eigen::Matrix Vector4f; + typedef Eigen::Matrix Vector4d; + + /** + Return a 4x4 3D rotation matrix that aligns the first vector onto the second one. + \param from source vector, current direction + \param to destination vector, target direction + \return the rotation matrix + */ + SIBR_SYSTEM_EXPORT Eigen::Matrix alignRotationMatrix(const sibr::Vector3f & from, const sibr::Vector3f & to); + + /** @} */ +} // namespace sibr + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/system/VectorUtils.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/VectorUtils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cba9c4ebddaf509d95add5fc2c20b79db41f146d --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/VectorUtils.cpp @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "VectorUtils.hpp" \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/system/VectorUtils.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/VectorUtils.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e41261bb8c5b474703ba87c8a0e498f116407546 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/VectorUtils.hpp @@ -0,0 +1,350 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include +# include "core/system/Config.hpp" +#include + +namespace sibr +{ + /** + * \addtogroup sibr_system + * @{ + */ + + /** Sum elements from a vector. + *\param vec vector + *\param f validity function (f(i) == true if the i-th element should be taken into account. + *\return the accumulated sum + **/ + template T_out sum( + const std::vector & vec , + const std::function & f = [](T_in val) { return true; } + ) { + double sum = 0; + for (T_in val : vec) { + if( f(val) ){ + sum += (double)val; + } + } + return (T_out)sum; + } + + /** Weighted sum of elements in a vector. + *\param vec vector + *\param weights per-element weight + *\param f validity function (f(i) == true if the i-th element should be taken into account. + *\return the weighted sum + **/ + template std::vector weighted_normalization( + const std::vector & vec, + const std::vector & weights, + const std::function & f = [](T_in val) { return true; } + ) { + double sum = 0; + int size = (int)std::min(vec.size(), weights.size()); + for (int i = 0; i < size; ++i) { + T_in val = vec[i]; + if (f(val)) { + sum += (double)val*(double)weights[i]; + } + } + + std::vector out(size); + for (int i = 0; i < size; ++i) { + if ((sum == 0) || !f(vec[i])) { + out[i] = (T_out)vec[i]; + } else { + out[i] = (T_out)( ( (double)vec[i] * (double)weights[i] )/sum ); + } + } + + return out; + } + + /** Apply a function to each element of a vector (not in place) + *\param vec vector + *\param f function to apply + *\return vector containing the processed results + */ + template std::vector applyLambda( + const std::vector & vec, + const std::function & f + ) { + std::vector out(vec.size()); + for (int i = 0; i < vec.size(); ++i) { + out[i] = f(vec[i]); + } + return out; + } + + /** Apply a function to each pair of elements from two vectors of same size (not in place). + *\param vec1 first vector + *\param vec2 second vector + *\param f function to apply + *\return vector containing the processed results + */ + template std::vector applyLambda( + const std::vector & vec1, + const std::vector & vec2, + const std::function & f + ) { + int size = (int)std::min(vec1.size(), vec2.size()); + std::vector out(size); + for (int i = 0; i < size; ++i) { + out[i] = f(vec1[i],vec2[i]); + } + return out; + } + + /** Compute the variance of elements in a vector. + *\param vec vector + *\param f validity function (f(i) == true if the i-th element should be taken into account. + *\return the variance + **/ + template T_out var( + const std::vector & vec, + const std::function & f = [](T_in val) { return true; } + ) { + double sum = 0; + double sum2 = 0; + int n = 0; + + for (T_in val : vec) { + if ( f(val) ) { + sum += (double)val; + sum2 += (double)val*(double)val; + ++n; + } + } + + if (n < 2) { + return (T_out)(-1); + } + else { + return (T_out)((sum2 - sum*sum / (double)n) / double(n - 1)); + } + + } + + /** Normalize all elements in a vector based on the min and max values in it (not in place). + *\param vec vector + *\param f validity function (f(i) == true if the i-th element should be taken into account. + *\return a vector containing the normalized values + **/ + template std::vector normalizedMinMax( + const std::vector & vec, + const std::function & f = [](T_in val) { return true; } + ) { + T_in min = 0, max = 0; + bool first = true; + for (T_in val : vec) { + if (f(val)) { + if (first || val > max) { + max = val; + } + if (first || val < min) { + min = val; + } + first = false; + } + } + if (min == max) { + return std::vector(); + } + + std::vector out(vec.size()); + const double normFactor = 1.0 / (double)(max - min); + for (int i = 0; i < (int)vec.size(); ++i) { + out[i] = f(vec[i]) ? (T_out)((double)(vec[i] - min)*normFactor) : (T_out)vec[i]; + } + return out; + } + + /** Apply a power-sum normalization. + *\param vec vector + *\param f validity function (f(i) == true if the i-th element should be taken into account. + *\return a vector containing the normalized values + */ + template std::vector normalizedZeroOne( + const std::vector & vec, + const std::function & f = [](T_in val) { return true; } + ) { + double sumP = 0; + + for (T_in val : vec) { + if (f(val)) { + sumP += std::pow((double)val, Power); + } + + } + + if (sumP == 0) { + return std::vector(); + } + + std::vector out(vec.size()); + for (int i = 0; i <(int)vec.size(); ++i) { + out[i] = f(vec[i]) ? (T_out)(vec[i] / sumP) : (T_out)vec[i]; + } + return out; + + } + + /*** @} */ + + /** + * Multi dimensional vector. + * \ingroup sibr_system + */ + template< typename T, unsigned int N > + class MultiVector : public std::vector< MultiVector > + { + static_assert(N >= 1, " MultiVector : the number of dimensions N must be >= 1 "); + + friend class MultiVector; + + typedef MultiVector SubVector; + + public: + + /// Constructor. + MultiVector() {} + + /** Constructor. + *\param n number of elements on each axis + *\param t default value + */ + MultiVector(int n, const T & t = T() ) + : std::vector< SubVector >(n, SubVector(n, t)) { } + + /** Constructor. + *\param dims number of elements on each axis + *\param t default value + */ + MultiVector(const std::vector & dims, const T & t = T() ) + : std::vector< SubVector >(dims.at(dims.size()-N), SubVector(dims, t)) { } + + /** Getter + *\param ids N-d coordinates + *\return a reference to the corresponding value. + */ + T & multiAt(const std::vector & ids) { + return this.at(ids.at(ids.size() - N)).multiAt(ids); + } + + /** Getter + *\param ids N-d coordinates + *\return a const reference to the corresponding value. + */ + const T & multiAt(const std::vector & ids) const { + return this.at(ids.at(ids.size() - N)).multiAt(ids); + } + + /** Get the size along each dimension. + *\return the N-d size + **/ + std::vector dims() const + { + std::vector v; + dimsRecur(v); + return v; + } + + /**Print the size along each dimension. + */ + void dimsDisplay() const { + std::vector d(dims()); + std::cout << " [ "; + for (int i = 0; i < N; ++i) { + std::cout << d[i] << (i != N - 1 ? " x " : ""); + } + std::cout << " ] " << std::endl; + } + + protected: + + /** Helper to get the dimensions. + *\param v will contain the size along each axis + */ + void dimsRecur(std::vector & v) const + { + v.push_back((int)this.size()); + this.at(0).dimsRecur(v); + } + }; + + /** Base multi-dimensional vector class (a 1D vector). + \ingroup sibr_system + */ + template + class MultiVector : public std::vector + { + friend class MultiVector; + + public: + + /// Constructor. + MultiVector() {} + + /** Constructor. + *\param n number of elements + *\param t default value + */ + MultiVector(int n, const T & t = T() ) + : std::vector(n, t) { } + + /** Constructor. + *\param dims number of elements on each axis (only the last one will be considered here). + *\param t default value + */ + MultiVector(const std::vector & dims, const T & t = T()) + : std::vector(dims.at(dims.size()-1), t) { } + + /** Getter + *\param ids N-d coordinates + *\return a reference to the corresponding value. + */ + T & multiAt(const std::vector & ids) { + return this.at(ids.at(ids.size() - 1)); + } + + /** Getter + *\param ids N-d coordinates + *\return a const reference to the corresponding value. + */ + const T & multiAt(const std::vector & ids) const { + return this.at(ids.at(ids.size() - 1)); + } + + /**Print the size along each dimension. + */ + void dimsDisplay() const { + std::cout << " [ " << this.size() << " ] " << std::endl; + } + + protected: + + /** Helper to get the dimensions. + *\param v will contain the size along each axis + */ + void dimsRecur(std::vector & v) const + { + v.push_back((int)this.size()); + } + + }; + + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/system/XMLTree.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/XMLTree.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3d1e36efb8806c988867d8bf92ee3c7a19002d0e --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/XMLTree.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "XMLTree.h" +#include "rapidxml/rapidxml_print.hpp" +#include +#include +#include + + +namespace sibr { + XMLTree::XMLTree(const std::string & path) + { + std::cout << "Parsing xml file < " << path << " > : "; + std::ifstream file(path.c_str()); + if (file) { + std::stringstream buffer; + buffer << file.rdbuf(); + file.close(); + xmlString = std::move(std::string(buffer.str())); + this->parse<0>(&xmlString[0]); + std::cout << "success " << std::endl; + } + else { + std::cout << "error, cant open file " << std::endl; + } + } + + + XMLTree::~XMLTree(void) + { + } + + + bool XMLTree::save(const std::string & path) const { + std::ofstream file(path); + if(!file.is_open()) { + SIBR_WRG << "Unable to save XML to path \"" << path << "\"." << std::endl; + return false; + } + + file << *this; + file.close(); + return true; + } + +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/system/XMLTree.h b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/XMLTree.h new file mode 100644 index 0000000000000000000000000000000000000000..c7825908b4f05fe6a1cffc2e246e928485fff519 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/XMLTree.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include +#include +#include "Config.hpp" + +namespace sibr { + + /** Wrapper of rapidxml xml_document<> class so that the string associated to the xml file stays in memory. + Needed to access nodes by their names. + * \ingroup sibr_system + */ + class SIBR_SYSTEM_EXPORT XMLTree : public rapidxml::xml_document<> + { + public: + /** Construct an XML structure from the content of a file. + \param path the file path + */ + XMLTree(const std::string & path); + + /** Destructor. */ + ~XMLTree(void); + + /** Save the XML structure to a file as a string representation. + \param path output path + \return a success flag + */ + bool save(const std::string & path) const; + + private: + std::string xmlString; //< Internal copy of the laoded string. + }; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/system/sibr_system.dox b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/sibr_system.dox new file mode 100644 index 0000000000000000000000000000000000000000..8e915b3d1b2de1a39f894368f44ebd2c00272d3b --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/system/sibr_system.dox @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +/*! + \defgroup sibr_system sibr_system + + \brief System utilities. + +*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/video/CMakeLists.txt b/submodules/gaussian-splatting/SIBR_viewers/src/core/video/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..5bf35cb92aa1406a44ccd4b03c626c2209677326 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/video/CMakeLists.txt @@ -0,0 +1,38 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +project(sibr_video) + +file(GLOB SOURCES "*.cpp" "*.h" "*.hpp") +source_group("Source Files" FILES ${SOURCES}) + + +## Specify target rules +add_library(${PROJECT_NAME} SHARED ${SOURCES}) + +include_directories(${Boost_INCLUDE_DIRS}) +target_link_libraries(${PROJECT_NAME} + ${FFMPEG_LIBRARIES} + OpenMP::OpenMP_CXX + sibr_graphics +) + + + +add_definitions( -DSIBR_VIDEO_EXPORTS -DBOOST_ALL_DYN_LINK ) + +set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER ${SIBR_FOLDER}) + + +## High level macro to install in an homogen way all our ibr targets +include(install_runtime) +ibr_install_target(${PROJECT_NAME} + INSTALL_PDB ## mean install also MSVC IDE *.pdb file (DEST according to target type) +) diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/video/Config.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/video/Config.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b14cb76bdd88963a04b240cb77bc661197650816 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/video/Config.hpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include "core/graphics/Config.hpp" + +//// Export Macro (used for creating DLLs) //// +# ifdef SIBR_OS_WINDOWS +# ifdef SIBR_STATIC_VIDEO_DEFINE +# define SIBR_VIDEO_EXPORT +# define SIBR_NO_VIDEO_EXPORT +# else +# ifndef SIBR_VIDEO_EXPORT +# ifdef SIBR_VIDEO_EXPORTS + /* We are building this library */ +# define SIBR_VIDEO_EXPORT __declspec(dllexport) +# else + /* We are using this library */ +# define SIBR_VIDEO_EXPORT __declspec(dllimport) +# endif +# endif +# ifndef SIBR_NO_EXPORT +# define SIBR_NO_EXPORT +# endif +# endif +# else +# define SIBR_VIDEO_EXPORT +# endif diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/video/FFmpegVideoEncoder.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/video/FFmpegVideoEncoder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d908531272dd273962d299ce741a2eaae661f600 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/video/FFmpegVideoEncoder.cpp @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "FFmpegVideoEncoder.hpp" + +#ifndef HEADLESS +extern "C" +{ +#include +#include +#include +} +#endif + +#define QQ(rat) (rat.num/(double)rat.den) + +// Disable ffmpeg deprecation warning. +#pragma warning(disable : 4996) + +namespace sibr { + + bool FFVideoEncoder::ffmpegInitDone = false; + + FFVideoEncoder::FFVideoEncoder( + const std::string & _filepath, + double _fps, + const sibr::Vector2i & size, + bool forceResize + ) : filepath(_filepath), fps(_fps), _forceResize(forceResize) + { +#ifndef HEADLESS + /** Init FFMPEG, registering available codec plugins. */ + if (!ffmpegInitDone) { + SIBR_LOG << "[FFMPEG] Registering all." << std::endl; + // Ignore next line warning. +#pragma warning(suppress : 4996) + av_register_all(); + ffmpegInitDone = true; + } + + sibr::Vector2i sizeFix = size; + bool hadToFix = false; + if(sizeFix[0]%2 != 0) { + sizeFix[0] -= 1; + hadToFix = true; + } + if (sizeFix[1] % 2 != 0) { + sizeFix[1] -= 1; + hadToFix = true; + } + if(hadToFix) { + SIBR_WRG << "Non-even video dimensions, resized to " << sizeFix[0] << "x" << sizeFix[1] << "." << std::endl; + _forceResize = true; + } + + init(sizeFix); +#endif + } + + bool FFVideoEncoder::isFine() const + { + return initWasFine; + } + + void FFVideoEncoder::close() + { +#ifndef HEADLESS + if (av_write_trailer(pFormatCtx) < 0) { + SIBR_WRG << "[FFMPEG] Can not av_write_trailer " << std::endl; + } + + if (video_st) { + avcodec_close(video_st->codec); + av_free(frameYUV); + } + avio_close(pFormatCtx->pb); + avformat_free_context(pFormatCtx); + + needFree = false; +#endif + } + + FFVideoEncoder::~FFVideoEncoder() + { + if (needFree) { + close(); + } + + } + + void FFVideoEncoder::init(const sibr::Vector2i & size) + { +#ifndef HEADLESS + w = size[0]; + h = size[1]; + + auto out_file = filepath.c_str(); + + + pFormatCtx = avformat_alloc_context(); + + fmt = av_guess_format(NULL, out_file, NULL); + pFormatCtx->oformat = fmt; + + const bool isH264 = pFormatCtx->oformat->video_codec == AV_CODEC_ID_H264; + if(isH264){ + SIBR_LOG << "[FFMPEG] Found H264 codec." << std::endl; + } else { + SIBR_LOG << "[FFMPEG] Found codec with ID " << pFormatCtx->oformat->video_codec << " (not H264)." << std::endl; + } + + if (avio_open(&pFormatCtx->pb, out_file, AVIO_FLAG_READ_WRITE) < 0) { + SIBR_WRG << "[FFMPEG] Could not open file " << filepath << std::endl; + return; + } + + pCodec = avcodec_find_encoder(pFormatCtx->oformat->video_codec); + if (!pCodec) { + SIBR_WRG << "[FFMPEG] Could not find codec." << std::endl; + return; + } + + video_st = avformat_new_stream(pFormatCtx, pCodec); + + if (video_st == NULL) { + SIBR_WRG << "[FFMPEG] Could not create stream." << std::endl; + return; + } + + pCodecCtx = video_st->codec; + pCodecCtx->codec_id = fmt->video_codec; + pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO; + pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P; + pCodecCtx->width = w; + pCodecCtx->height = h; + pCodecCtx->gop_size = 10; + pCodecCtx->time_base.num = 1; + pCodecCtx->time_base.den = (int)std::round(fps); + + // Required for the header to be well-formed and compatible with Powerpoint/MediaPlayer/... + if (pFormatCtx->oformat->flags & AVFMT_GLOBALHEADER) { + pCodecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; + } + + //H.264 specific options. + AVDictionary *param = 0; + if (pCodecCtx->codec_id == AV_CODEC_ID_H264) { + av_dict_set(¶m, "preset", "slow", 0); + av_dict_set(¶m, "tune", "zerolatency", 0); + } + + av_dump_format(pFormatCtx, 0, out_file, 1); + + int res = avcodec_open2(pCodecCtx, pCodec, ¶m); + if(res < 0){ + SIBR_WRG << "[FFMPEG] Failed to open encoder, error: " << res << std::endl; + return; + } + // Write the file header. + avformat_write_header(pFormatCtx, NULL); + + // Prepare the scratch frame. + frameYUV = av_frame_alloc(); + frameYUV->format = (int)pCodecCtx->pix_fmt; + frameYUV->width = w; + frameYUV->height = h; + frameYUV->linesize[0] = w; + frameYUV->linesize[1] = w / 2; + frameYUV->linesize[2] = w / 2; + + yuSize[0] = frameYUV->linesize[0] * h; + yuSize[1] = frameYUV->linesize[1] * h / 2; + + pkt = av_packet_alloc(); + + initWasFine = true; + needFree = true; +#endif + } + + + bool FFVideoEncoder::operator<<(cv::Mat frame) + { +#ifndef HEADLESS + if (!video_st) { + return false; + } + cv::Mat local; + if (frame.cols != w || frame.rows != h) { + if(_forceResize) { + cv::resize(frame, local, cv::Size(w,h)); + } else { + SIBR_WRG << "[FFMPEG] Frame doesn't have the same dimensions as the video." << std::endl; + return false; + } + } else { + local = frame; + } + + cv::cvtColor(local, cvFrameYUV, cv::COLOR_BGR2YUV_I420); + frameYUV->data[0] = cvFrameYUV.data; + frameYUV->data[1] = frameYUV->data[0] + yuSize[0]; + frameYUV->data[2] = frameYUV->data[1] + yuSize[1]; + + //frameYUV->pts = (1.0 / std::round(fps)) *frameCount * 90; + frameYUV->pts = (int)(frameCount*(video_st->time_base.den) / ((video_st->time_base.num) * std::round(fps))); + ++frameCount; + + return encode(frameYUV); +#else + SIBR_ERR << "Not supported in headless" << std::endl; + return false; +#endif + } + + bool FFVideoEncoder::operator<<(const sibr::ImageRGB & frame){ + return (*this)<<(frame.toOpenCVBGR()); + } + +#ifndef HEADLESS + bool FFVideoEncoder::encode(AVFrame * frame) + { + int got_picture = 0; + + int ret = avcodec_encode_video2(pCodecCtx, pkt, frameYUV, &got_picture); + if (ret < 0) { + SIBR_WRG << "[FFMPEG] Failed to encode frame." << std::endl; + return false; + } + if (got_picture == 1) { + pkt->stream_index = video_st->index; + ret = av_write_frame(pFormatCtx, pkt); + av_packet_unref(pkt); + } + + return true; + } +#endif + +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/video/FFmpegVideoEncoder.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/video/FFmpegVideoEncoder.hpp new file mode 100644 index 0000000000000000000000000000000000000000..18f92a1849748cf6c449cd7f3ba08a21dcb46d13 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/video/FFmpegVideoEncoder.hpp @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + + +#include +#include +#include "Video.hpp" +#include "Config.hpp" + +// Forward libav declarations. +struct AVFrame; +struct AVFormatContext; +struct AVOutputFormat; +struct AVStream; +struct AVCodecContext; +struct AVCodec; +struct AVPacket; + +namespace sibr { + + + /** Video encoder using ffmpeg. + Adapted from https://github.com/leixiaohua1020/simplest_ffmpeg_video_encoder/blob/master/simplest_ffmpeg_video_encoder/simplest_ffmpeg_video_encoder.cpp + \ingroup sibr_video + */ + class SIBR_VIDEO_EXPORT FFVideoEncoder { + + public: + + /** Constructor. + \param _filepath destination file, the extension will be used to infer the container type. + \param fps target video framerate + \param size target video size, should be even else a resize will happen + \param forceResize resize frames that are not at the target dimensions instead of ignoring them + */ + FFVideoEncoder( + const std::string & _filepath, + double fps, + const sibr::Vector2i & size, + bool forceResize = false + ); + + /** \return true if the encoder was properly setup. */ + bool isFine() const; + + /** Close the file. */ + void close(); + + /** Encode a frame. + \param frame the frame to encode + \return a success flag + */ + bool operator << (cv::Mat frame); + + /** Encode a frame. + \param frame the frame to encode + \return a success flag + */ + bool operator << (const sibr::ImageRGB & frame); + + /// Destructor. + ~FFVideoEncoder(); + + protected: + + /** Setup the encoder. + \param size the video target size, prfer using power of two. + */ + void init(const sibr::Vector2i & size); + + /** Encode a frame to the file. + \param frame the frame to encode + \return a success flag. + */ +//#define HEADLESS +#ifndef HEADLESS + bool encode(AVFrame *frame); +#endif + + bool initWasFine = false; ///< Was the encoder init properly. + bool needFree = false; ///< Is the file open. + std::string filepath; ///< Destination path. + int w, h; ///< Dimensions. + int frameCount = 0; ///< Current frame. + double fps; ///< Framerate. + bool _forceResize = false; ///< Resize frames. + +#ifndef HEADLESS + AVFrame * frameYUV = NULL; ///< Working frame. +#endif + cv::Mat cvFrameYUV; ///< Working frame data. + sibr::Vector2i yuSize; ///< Working size. + +#ifndef HEADLESS + AVFormatContext* pFormatCtx; ///< Format context. + AVOutputFormat* fmt; ///< Output format. + AVStream* video_st; ///< Output stream. + AVCodecContext* pCodecCtx; ///< Codec context. + AVCodec* pCodec; ///< Codec. + AVPacket * pkt; ///< Encoding packet. + +#endif + static bool ffmpegInitDone; ///< FFMPEG initialization status. + + }; + +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/video/MultipleVideoDecoder.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/video/MultipleVideoDecoder.hpp new file mode 100644 index 0000000000000000000000000000000000000000..bdd87c8dbd688dc7dc544b690f6252849ca7e70d --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/video/MultipleVideoDecoder.hpp @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include "Config.hpp" + +#include + +namespace sibr +{ + + /** Double-buffered texture, used to load/display video frames for instance. + * \ingroup sibr_video + */ + template + struct PingPongTexture { + using TexPtr = std::shared_ptr>; + + /** \return the current loading texture. */ + TexPtr & getLoadingTex(); + + /** \return the current display texture. */ + TexPtr & getDisplayTex(); + + /** Update the content of the loading texture and swap the two textures. + \param frame the new data + */ + template + void update(const ImgType & frame); + + /** Load the frame into the loading texture. + \param frame the new data + */ + template + void updateGPU(const ImgType & frame); + + int displayTex = 1, loadingTex = 1; /// Textures indices. + TexPtr ping, pong; ///< Textures. + bool first = true; ///< First update. + }; + + + /** Batch decoding of multiple videos at the same time, stored in a texture array. + * \ingroup sibr_video + */ + template + struct MultipleVideoDecoder { + using TexArray = sibr::Texture2DArray; + using TexArrayPtr = typename TexArray::Ptr; + + /** Update a set of video players to the next frame. + \param videos the video players to udpate + \note Internally calls both updateCPU and updateGPU. + */ + void update(const std::vector & videos) { + updateCPU(videos); + updateGPU(videos); + + loadingTexArray = (loadingTexArray + 1) % 2; + + if (first) { + first = false; + } else { + displayTexArray = (displayTexArray + 1) % 2; + } + } + + /** Load the next frame on the CPU for a set of video players. + \param videos the video players to udpate + */ + void updateCPU(const std::vector & videos) { + size_t numVids = videos.size(); + + for (size_t i = 0; i < numVids; ++i) { + videos[i]->updateCPU(); + } + + } + + /** Upload the next frame to the GPU for a set of video players. + \param videos the video players to udpate + */ + void updateGPU(const std::vector & videos) { + size_t numVids = videos.size(); + std::vector frames(numVids); + for (size_t i = 0; i < numVids; ++i) { + if (std::is_same_v && N == 3) { + frames[i] = videos[i]->getCurrentFrame(); + } else { + std::vector cs; + cv::split(videos[i]->getCurrentFrame(), cs); + frames[i] = cs[0]; + } + } + + if (getLoadingTexArray().get()) { + getLoadingTexArray()->updateFromImages(frames); + } else { + getLoadingTexArray() = TexArrayPtr(new TexArray(frames)); + } + } + + /** \return the current loading texture array. */ + TexArrayPtr & getLoadingTexArray() { return loadingTexArray ? ping : pong; } + + /** \return the current display texture array. */ + const TexArrayPtr & getDisplayTexArray() const { return displayTexArray ? ping : pong; } + + bool first = true; ///< First frame. + int loadingTexArray = 1, displayTexArray = 1; ///< Texture indices. + TexArrayPtr ping, pong; ///< Textures. + }; + + + /** Batch decoding of multiple videos at the same time, stored in a texture array. + * Support updating an arbitrary subset. + * \ingroup sibr_video + */ + template + struct MultipleVideoDecoderArray : public MultipleVideoDecoder { + using TexArray = sibr::Texture2DArray; + using TexArrayPtr = typename TexArray::Ptr; + + /** Update a set of video players to the next frame. + \param videos the video players list + \param slices the indices of the videos to update + \note Internally calls both updateCPU and updateGPU. + */ + void update(const std::vector & videos, const std::vector & slices) { + updateCPU(videos, slices); + updateGPU(videos, slices); + + loadingTexArray = (loadingTexArray + 1) % 2; + + if (first) { + first = false; + } else { + displayTexArray = (displayTexArray + 1) % 2; + } + } + + /** Load the next frame on the CPU for a set of video players. + \param videos the video players list + \param slices the indices of the videos to update + */ + void updateCPU(const std::vector & videos, const std::vector & slices) { +#pragma omp parallel for num_threads(4) + for (int i = 0; i < (int)slices.size(); ++i) { + videos[slices[i]]->updateCPU(); + } + } + + /** Upload the next frame to the GPU for a set of video players. + \param videos the video players list + \param slices the indices of the videos to update + */ + void updateGPU(const std::vector & videos, const std::vector & slices) { + int numVids = (int)videos.size(); + int numSlices = (int)slices.size(); + + std::vector frames(numVids); + for (int s = 0; s < numSlices; ++s) { + if (std::is_same_v && N == 3) { + frames[slices[s]] = videos[slices[s]]->getCurrentFrame(); + } else { + std::vector cs; + cv::split(videos[slices[s]]->getCurrentFrame(), cs); + frames[slices[s]] = cs[0]; + } + } + + if (!getLoadingTexArray().get()) { + getLoadingTexArray() = TexArrayPtr(new TexArray((uint)videos.size(), SIBR_GPU_LINEAR_SAMPLING)); + } + + CHECK_GL_ERROR; + getLoadingTexArray()->updateSlices(frames, slices); + } + + }; + + + // --- TYPEDEFS ---------------- + + using PingPong4u = PingPongTexture<4>; + using PingPong3u = PingPongTexture<3>; + using PingPong1u = PingPongTexture<1>; + using MultipleVideoDecoder1u = MultipleVideoDecoder; + using MultipleVideoDecoder3u = MultipleVideoDecoder; + using MultipleVideoDecoderArray1u = MultipleVideoDecoderArray; + using MultipleVideoDecoderArray3u = MultipleVideoDecoderArray; + + // --- IMPLEMENTATION ---------------- + + template + std::shared_ptr> & PingPongTexture::getLoadingTex() + { + return loadingTex ? ping : pong; + } + + template + std::shared_ptr> & PingPongTexture::getDisplayTex() + { + return displayTex ? ping : pong; + } + + template template + void PingPongTexture::update(const ImgType & frame) + { + if (first) { + updateGPU(frame); + loadingTex = (loadingTex + 1) % 2; + first = false; + return; + } + + updateGPU(frame); + + displayTex = (displayTex + 1) % 2; + loadingTex = (loadingTex + 1) % 2; + } + + template template + void PingPongTexture::updateGPU(const ImgType & frame) + { + if (getLoadingTex()) { + getLoadingTex()->update(frame); + } else { + getLoadingTex() = TexPtr(new sibr::Texture2D(frame, SIBR_GPU_LINEAR_SAMPLING)); + } + } + + } // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/video/Video.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/video/Video.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d276b905ab4e5d0ce3b2ef3d46cd0ff598a5d199 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/video/Video.cpp @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "Video.hpp" +#include +// #include "VideoUtils.hpp" + +namespace sibr +{ + bool Video::load(const std::string & path) + { + cap = cv::VideoCapture(path); + filepath = path; + loaded = cap.isOpened(); + if (loaded) { + nFrames = (int)cap.get(cv::VideoCaptureProperties::CAP_PROP_FRAME_COUNT); + frameRate = (double)cap.get(cv::VideoCaptureProperties::CAP_PROP_FPS); + resolution[0] = (int)cap.get(cv::VideoCaptureProperties::CAP_PROP_FRAME_WIDTH); + resolution[1] = (int)cap.get(cv::VideoCaptureProperties::CAP_PROP_FRAME_HEIGHT); + codec = (int)cap.get(cv::VideoCaptureProperties::CAP_PROP_FOURCC); + SIBR_LOG << "[Video] " << path << " loaded." << std::endl; + } + return loaded; + } + + const sibr::Vector2i & Video::getResolution() { + checkLoad(); + return resolution; + } + + cv::Size Video::getResolutionCV() { + checkLoad(); + return cv::Size(resolution[0], resolution[1]); + } + + int Video::getCurrentFrameNumber() { + checkLoad(); + return (int)cap.get(cv::VideoCaptureProperties::CAP_PROP_POS_FRAMES); + } + + void Video::setCurrentFrame(int i){ + checkLoad(); + cap.set(cv::VideoCaptureProperties::CAP_PROP_POS_FRAMES, i); + } + + int Video::getNumFrames() { + checkLoad(); + return nFrames; + } + + double Video::getFrameRate() { + checkLoad(); + return frameRate; + } + + const Path & Video::getFilepath() const { + return filepath; + } + + bool Video::isLoaded() { + return loaded; + } + + int Video::getCodec() { + checkLoad(); + return codec; + } + + void Video::release() + { + cap = cv::VideoCapture(); + loaded = false; + } + + cv::Mat Video::getVolume(float time_skiped_begin, float time_skiped_end) + { + const int starting_frame = (int)(time_skiped_begin * getFrameRate()); + const int finishing_frame = getNumFrames() - (int)(time_skiped_end*getFrameRate()) - 1; + return getVolume(starting_frame, finishing_frame); + } + + cv::Mat Video::getVolume(int starting_frame, int ending_frame) + { + checkLoad(); + + const int w = getResolution()[0]; + const int h = getResolution()[1]; + const int nc = 3; + + const int npixels = w * h; + const int N = npixels * nc; + const int L = ending_frame - starting_frame + 1; + + cv::Mat volume(L, N, CV_8UC1); + setCurrentFrame(starting_frame); + for (int i = 0; i < L; ++i) { + cv::Mat mat = volume.row(i).reshape(3, h); + cap >> mat; + } + setCurrentFrame(0); + + return volume; + } + + cv::Mat Video::next() + { + checkLoad(); + cv::Mat frame; + cap >> frame; + return frame; + } + + cv::VideoCapture & Video::getCVvideo() + { + checkLoad(); + return cap; + } + + bool Video::exists() const + { + return sibr::fileExists(getFilepath().string()); + } + + void Video::checkLoad() + { + if (!loaded) { + if (!load(filepath.string())) { + SIBR_ERR << "[Video] Could not open video " << filepath << std::endl; + } + } + } + + + //------------------------------------------------------------ + + VideoPlayer::VideoPlayer(const std::string & filepath, const std::function & f) : + Video(filepath), transformation(f) + { + } + + bool VideoPlayer::load(const std::string & path) { + VideoPlayer other; + if (other.Video::load(path)) { + *this = other; + return true; + } + return false; + } + + const std::shared_ptr & VideoPlayer::getDisplayTex() const + { + return displayTex ? ping : pong; + } + + void VideoPlayer::update() + { + checkLoad(); + + if (first) { + loadNext(); + loadingTex = (loadingTex + 1) % 2; + first = false; + return; + } + + if (mode != PLAY) { + return; + } + + loadNext(); + + displayTex = (displayTex + 1) % 2; + loadingTex = (loadingTex + 1) % 2; + } + + void VideoPlayer::onGui(float ratio_display) + { + checkLoad(); + + if (mode == PAUSE){ + if (ImGui::Button("Play")) { + mode = PLAY; + } + } else if (mode == PLAY) { + if (ImGui::Button("Pause")) { + mode = PAUSE; + } + } + ImGui::SameLine(); + ImGui::Checkbox("Repeat when finished", &repeat_when_end); + + current_frame_slider = getCurrentFrameNumber(); + ImGui::Separator(); + ImGui::PushScaledItemWidth(500); + if (ImGui::SliderInt("timeline", ¤t_frame_slider, 1, getNumFrames())) { + setCurrentFrame(current_frame_slider); + loadingTex = displayTex; + first = true; + } + ImGui::PopItemWidth(); + + ImGui::Separator(); + + if (getDisplayTex() && getDisplayTex()->handle() ) { + std::string infos = "size : " + std::to_string((int)getDisplayTex()->w()) + " " + std::to_string((int)getDisplayTex()->h()) + ", framerate : " + std::to_string(getFrameRate()); + ImGui::Text(infos.c_str()); + sibr::Vector2f displayTexSize(getDisplayTex()->w(), getDisplayTex()->h()); + sibr::Vector2i viewResolution = (ratio_display*displayTexSize).cast(); + + sibr::ImageWithCallback(getDisplayTex()->handle(), viewResolution, callBackData, zoomData.topLeft(), zoomData.bottomRight()); + + updateZoom(displayTexSize); + } + + } + + bool VideoPlayer::updateCPU() + { + + checkLoad(); + + bool alreayEmpty = tmpFrame.empty(); + tmpFrame = next(); + if (!tmpFrame.empty()) { + tmpFrame = transformation(tmpFrame); + return true; + } else { + if (alreayEmpty) { + SIBR_WRG << "[Video] Could not load next frames." << std::endl; + return false; + } + if (repeat_when_end) { + setCurrentFrame(0); + return updateCPU(); + } else { + mode = PAUSE; + } + return false; + } + } + + void VideoPlayer::updateGPU() + { + if (getLoadingTex().get()) { + getLoadingTex()->update(tmpFrame); + } else { + getLoadingTex() = std::shared_ptr(new sibr::Texture2DRGB(tmpFrame)); + } + } + + void VideoPlayer::loadNext() + { + if (updateCPU()) { + updateGPU(); + } + } + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/video/Video.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/video/Video.hpp new file mode 100644 index 0000000000000000000000000000000000000000..918ab8d4909b776daecb7a5cfb11f52a44c12640 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/video/Video.hpp @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include "Config.hpp" + +#include +#include +#include + +// must install ffdshow +#define CV_WRITER_CODEC cv::VideoWriter::fourcc('F','F','D','S') + + +namespace sibr +{ + + /** Video loaded from a file using OpenCV VideoCapture and FFMPEG. + * \ingroup sibr_video + */ + class SIBR_VIDEO_EXPORT Video + { + SIBR_CLASS_PTR(Video); + + public: + + /** Constructor. + \param path the path to the video file + \note No loading will be performed at construction. Call load. + */ + Video(const std::string & path = "") : filepath(path) {} + + /** Load from a given file on disk. + \param path path to the video + \return a success flag + */ + virtual bool load(const std::string & path); + + /** \return the video resolution. */ + const sibr::Vector2i & getResolution(); + + /** \return the video resolution. */ + cv::Size getResolutionCV(); + + /** \return the current frame ID. */ + int getCurrentFrameNumber(); + + /** Seek a specific frame. + \param i the frame ID to seek + */ + void setCurrentFrame(int i); + + /** \return the total number of frames. */ + int getNumFrames(); + + /** \return the video framerate. */ + double getFrameRate(); + + /** \return the path to the video file on disk. */ + const Path & getFilepath() const; + + /** \return true if the video has been loaded. */ + bool isLoaded(); + + /** \return the ID of the codec used to decode the video. */ + int getCodec(); + + /** Stop reading from the file. */ + virtual void release(); + + /** Read a section of the video and store it in a cv::Mat, where + each row contains a frame, stored as RGBRGBRGB... linearly. + \param time_skiped_begin time to skip at the beginning of the video, in seconds + \param time_skiped_end time to skip at the end of the video, in seconds + \return the frames data stored as described above. + */ + cv::Mat getVolume(float time_skiped_begin = 0, float time_skiped_end = 0); + + /** Read a section of the video and store otin a cv::Mat, where + each row contains a frame, stored as RGBRGBRGB... linearly. + \param starting_frame index of the first frame to extract + \param ending_frame index of the last frame to extract + \return the frames data stored as described above. + */ + cv::Mat getVolume(int starting_frame, int ending_frame); + + /** \return the next frame. */ + cv::Mat next(); + + /** \return the underlying VideoCapture object. */ + cv::VideoCapture & getCVvideo(); + + /** \return true if the video exists on disk. */ + bool exists() const; + + protected: + + /** Check if the video is loaded. */ + virtual void checkLoad(); + + cv::VideoCapture cap; ///< Internal capture object. + + Path filepath; ///< The path to the video. + sibr::Vector2i resolution; ///< Video resolution. + int nFrames = 0; ///< Number of frames in the video. + double frameRate = 0.0; ///< Video frame rate. + int codec = 0; ///< Codec used to read the video. + bool loaded = false; ///< Video loading status. + }; + + + /** Load and display a video in a view, with playback options. + * \ingroup sibr_video + */ + class SIBR_VIDEO_EXPORT VideoPlayer : public Video, public ZoomInterraction + { + + SIBR_CLASS_PTR(VideoPlayer); + + public: + + /** Replay mode. */ + enum Mode { PAUSE, PLAY, SHOULD_CLOSE }; + + using Transformation = std::function; ///< Image processing function. + + /** Constructor. + \param filepath the path to the video file + \param f a function to apply to each frame + \note No loading will be performed at construction. Call load. + */ + VideoPlayer(const std::string & filepath = "", const std::function& f = [](cv::Mat m) { return m; }); + + /** Load a video from disk. + \param path the path to the video on disk + \return a success flag + */ + bool load(const std::string & path) override; + + /** Set a transformation function to apply to each frame. + \param f the new transformation + */ + void setTransformation(const Transformation & f) { transformation = f; } + + /** Set the playback mode. + \param _mode the new mode + */ + void setMode(Mode _mode) { mode = _mode; } + + /** \return the current display texture on the GPU. */ + const std::shared_ptr & getDisplayTex() const; + + /** Load the next frame, call once per rendering frame. + \note Internally calls updateCPU and updateGPU. + */ + void update(); + + /** Display playback GUI. + \param ratio_display a scaling factor that determine the size of the video on screen based on the video intrinsic size. + */ + void onGui(float ratio_display); + + /** Load the next frame to the CPU. + \return a success flag + */ + bool updateCPU(); + + /** Load the next frame to the GPU. + \note You should call updateCPU first. + */ + void updateGPU(); + + /** \return a reference to the current frame on the CPU. */ + const cv::Mat & getCurrentFrame() const { return tmpFrame; } + + protected: + + /** \return the current loading texture on the GPU. */ + std::shared_ptr & getLoadingTex() { return loadingTex ? ping : pong; } + + /// Load the next frame, on the CPU then the GPU. + void loadNext(); + + Mode mode = PAUSE; ///< Play mode. + bool first = true; ///< Are we at the first frame. + bool repeat_when_end = true; ///< Loop when reaching the end. + int displayTex = 1; ///< Index of the display texture. + int loadingTex = 1; ///< Index of the loading texture. + std::shared_ptr ping,pong; ///< Double buffer textures. + cv::Mat tmpFrame; ///< Scratch frame. + Transformation transformation; ///< Transformation to apply to each frame. + int current_frame_slider; ///< Slider position. + }; + + + } // namespace sibr + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/video/VideoUtils.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/video/VideoUtils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..44deeb1566d52c6b49e0a24ba33b41cb3accd4f0 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/video/VideoUtils.cpp @@ -0,0 +1,1863 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "VideoUtils.hpp" + +#include +#include + + +#include +#include +namespace sibr { + + std::vector cvSplitChannels(cv::Mat mat) { + std::vector out; + cv::split(mat, out); + return out; + } + + Volume3u loadVideoVolume(const std::string & filepath) { + Video video(filepath); + if (video.exists()) { + return loadVideoVolume(video); + } else { + SIBR_WRG << filepath << " does not exists" << std::endl; + return Volume3u(); + } + } + + Volume3u loadVideoVolume(sibr::Video & video) + { + int currentFrame = video.getCurrentFrameNumber(); + video.setCurrentFrame(0); + Volume3u volume(video.getNumFrames(), video.getResolution()[0], video.getResolution()[1]); + for (int t = 0; t < video.getNumFrames(); ++t) { + cv::Mat mat = volume.frame(t); + video.getCVvideo() >> mat; + } + video.setCurrentFrame(currentFrame); + return volume; + } + + SIBR_VIDEO_EXPORT uint optimal_num_levels(uint length) + { + uint num_levels = 1; + while (length != 1) { + length = (length + 1) / 2; + ++num_levels; + } + return num_levels; + } + + SIBR_VIDEO_EXPORT std::vector gaussianPyramid(const sibr::Volume3u & vid, uint num_levels) + { + if (num_levels == 0) { + num_levels = optimal_num_levels(vid.l); + } + + std::vector out(1, vid); + for (int i = 1; i < (int)num_levels; ++i) { + out.push_back(out.back().pyrDown()); + } + return out; + } + + SIBR_VIDEO_EXPORT std::vector gaussianPyramidTemporal(const sibr::Volume3u & vid, uint num_levels) + { + if (num_levels == 0) { + num_levels = optimal_num_levels(vid.l); + } + + std::vector out(1, vid); + for (int i = 1; i < (int)num_levels; ++i) { + out.push_back(out.back().pyrDownTemporal()); + } + return out; + } + + std::vector laplacianPyramid(const sibr::Volume3u & vid, uint num_levels) + { + if (num_levels == 0) { + num_levels = optimal_num_levels(vid.l); + } + + std::vector out; + + sibr::Volume3f current_v = vid.convertTo(), down, up; + for (int i = 0; i < (int)num_levels - 1; ++i) { + down = current_v.pyrDown(); + up = down.pyrUp(current_v.l, current_v.w, current_v.h); + //current_v.play(30, { 1200,800 }); + //up.play(30, { 1200,800 }); + current_v.substract(up); + current_v.shift(128); + out.push_back(current_v.convertTo()); + std::swap(current_v, down); + } + out.push_back(current_v.convertTo()); + return out; + } + + std::vector laplacianPyramidTemporalDouble(const sibr::Volume3u & vid, uint num_levels) + { + if (num_levels == 0) { + num_levels = 1; + int length = vid.l; + while (length != 1) { + length = (length + 1) / 2; + length = (length + 1) / 2; + ++num_levels; + } + } + + std::cout << " num lvls : " << num_levels << std::endl; + + std::vector out; + sibr::Volume3f current_v = vid.convertTo(), down, up; + for (int i = 0; i < (int)num_levels - 1; ++i) { + down = current_v.pyrDownTemporal().pyrDownTemporal(); + up = down.pyrUpTemporal((current_v.l + 1) / 2).pyrUpTemporal(current_v.l); + current_v.substract(up); + current_v.shift(128); + out.push_back(current_v.convertTo()); + std::cout << i << " : " << current_v.l << std::endl; + std::swap(current_v, down); + } + out.push_back(current_v.convertTo()); + return out; + } + + SIBR_VIDEO_EXPORT sibr::Volume3u collapseLaplacianPyramid(const std::vector& pyr, double shift) + { + sibr::Volume3f v = pyr.back().convertTo(); + for (int i = (int)pyr.size() - 2; i >= 0; --i) { + v = v.pyrUp(pyr[i].l, pyr[i].w, pyr[i].h); + v.add(pyr[i]); + if (shift != 0) { + v.shift(shift); + } + } + return v.convertTo(); + } + + SIBR_VIDEO_EXPORT sibr::Volume3u laplacianBlending(const sibr::Volume3u & vA, const sibr::Volume3u & vB, std::vector& pyrM) + { + auto pyrA = laplacianPyramid(vA); + auto pyrB = laplacianPyramid(vB); + + for (int i = (int)pyrA.size() - 1; i >= 0; --i) { + pyrA[i] = pyrA[i].applyMask(pyrM[i]); + pyrM[i].toggle(); + pyrB[i] = pyrB[i].applyMask(pyrM[i]); + pyrA[i].add(pyrB[i]); + } + + return collapseLaplacianPyramid(pyrA, -128); + } + + + int VideoUtils::codec_ffdshow = cv::VideoWriter::fourcc('F', 'F', 'D', 'S'); + int VideoUtils::codec_OpenH264 = cv::VideoWriter::fourcc('H', '2', '6', '4'); + int VideoUtils::codec_OpenH264_fallback = 0x31637661; + + // from https://stackoverflow.com/questions/7693561/opencv-displaying-a-2-channel-image-optical-flow + cv::Mat VideoUtils::getFlowViz(const cv::Mat & flow) { + + cv::Mat xy[2]; //X,Y + cv::split(flow, xy); + + //calculate angle and magnitude + cv::Mat magnitude, angle; + cv::cartToPolar(xy[0], xy[1], magnitude, angle, true); + + //translate magnitude to range [0;1] + double mag_max; + cv::minMaxLoc(magnitude, 0, &mag_max); + magnitude.convertTo(magnitude, -1, 1.0 / mag_max); + + //build hsv image + cv::Mat _hsv[3], hsv; + _hsv[0] = angle; + _hsv[1] = magnitude; + _hsv[2] = cv::Mat::ones(angle.size(), CV_32F); + cv::merge(_hsv, 3, hsv); + + //convert to BGR and show + cv::Mat bgr;//CV_32FC3 matrix + cv::cvtColor(hsv, bgr, cv::COLOR_HSV2BGR); + + return bgr; + } + + cv::Mat VideoUtils::cropFromSize(const cv::Mat & mat, const sibr::Vector2i & size) + { + sibr::Vector2i currentSize(mat.cols, mat.rows); + sibr::Vector2i targetSize = size.cwiseMin(currentSize); + sibr::Vector2i topLeft = ((currentSize - targetSize).cast() / 2.0).cast(); + sibr::Vector2i bottomRight = ((currentSize + targetSize).cast() / 2.0).cast(); + cv::Rect roi(cv::Point(topLeft[0], topLeft[1]), cv::Point(bottomRight[0], bottomRight[1])); + + //std::cout << "--------------" << std::endl; + //std::cout << currentSize << std::endl; + //std::cout << targetSize << std::endl; + //std::cout << roi << std::endl; + + return mat(roi).clone(); + } + + void VideoUtils::getMeanVariance(cv::VideoCapture & cap, cv::Mat & outMean, cv::Mat & outVariance, const sibr::Vector2i & finalSize) + { + cap.set(cv::VideoCaptureProperties::CAP_PROP_POS_FRAMES, 0); + bool first = true; + cv::Mat mean, meanSq, out; + float sum = 0; + int f_id = 0, current_seg = -1; + bool doResize = (finalSize[0] != cap.get(cv::CAP_PROP_FRAME_WIDTH) || finalSize[1] != cap.get(cv::CAP_PROP_FRAME_HEIGHT)); + while (true) { + std::cout << "." << std::flush; + cv::Mat frame, frame_float; + cap >> frame; + ++f_id; + if (frame.empty()) { + break; + } + + if (doResize) { + cv::resize(frame, frame, cv::Size(finalSize[0], finalSize[1])); + } + + frame.convertTo(frame_float, CV_32FC3); + if (first) { + mean = frame_float; + meanSq = frame_float.mul(frame_float); + first = false; + } else { + mean += frame_float; + meanSq += frame_float.mul(frame_float); + } + sum += 1; + } + if (first) { + return; + } + + mean /= sum; + cv::Mat var = cv::min(255.0f*255.0f, cv::max(0.0f, meanSq / sum - mean.mul(mean))); + cv::sqrt(var, var); + var *= 5.0; + mean.convertTo(outMean, CV_8UC3); + var.convertTo(outVariance, CV_8UC3); + + } + + void VideoUtils::getMeanVariance2(cv::VideoCapture & cap, cv::Mat & outMean, cv::Mat & outVariance, const sibr::Vector2i & finalSize, float starting_point_s) + { + int starting_frame = (int)(starting_point_s*cap.get(cv::CAP_PROP_FPS)); + + cap.set(cv::VideoCaptureProperties::CAP_PROP_POS_FRAMES, starting_frame); + bool first = true; + cv::Mat mean, meanSq, out; + float sum = 0; + int f_id = 0, current_seg = -1; + bool doResize = (finalSize[0] != cap.get(cv::CAP_PROP_FRAME_WIDTH) || finalSize[1] != cap.get(cv::CAP_PROP_FRAME_HEIGHT)); + while (true) { + std::cout << "." << std::flush; + cv::Mat frame, frame_float; + cap >> frame; + ++f_id; + if (frame.empty()) { + break; + } + + if (doResize) { + cv::resize(frame, frame, cv::Size(finalSize[0], finalSize[1])); + } + + cv::GaussianBlur(frame, frame, cv::Size(3, 3), 0); + + frame.convertTo(frame_float, CV_32FC3); + if (first) { + mean = frame_float; + meanSq = frame_float.mul(frame_float); + first = false; + } else { + mean += frame_float; + meanSq += frame_float.mul(frame_float); + } + sum += 1; + } + if (first) { + return; + } + + mean /= sum; + cv::Mat var = cv::min(255.0f*255.0f, cv::max(0.0f, meanSq / sum - mean.mul(mean))); + cv::sqrt(var, var); + var *= 5.0; + mean.convertTo(outMean, CV_8UC3); + var.convertTo(outVariance, CV_8UC3); + } + + cv::Mat VideoUtils::getMedian(sibr::Video & vid, float time_skiped_begin, float time_skiped_end) { + + cv::Mat volume = vid.getVolume(time_skiped_begin, time_skiped_end); + + //std::cout << "tranpose "; + //volume = volume.t(); + //std::cout << t.deltaTimeFromLastTic<>() << std::endl; + + //cv::Mat volumeSorted; + + //std::cout << "sort "; + //cv::sort(volume, volume, CV_SORT_EVERY_COLUMN); + //std::cout << t.deltaTimeFromLastTic<>() << std::endl; + + cv::Mat median(vid.getResolutionCV(), CV_8UC3); + + const int L = volume.rows; + +#pragma omp parallel for + for (int i = 0; i < median.rows; ++i) { + + for (int j = 0; j < median.cols; ++j) { + cv::Vec3b medianColor; + for (int c = 0; c < 3; ++c) { + std::vector values(L); + for (int t = 0; t < L; ++t) { + values[t] = volume.at(t, 3 * (i*median.cols + j) + c); + } + //std::sort(values.begin(), values.end()); + //medianColor[c] = values[values.size() / 2]; + std::nth_element(values.begin(), values.begin() + L / 2, values.end()); + medianColor[c] = values[L / 2]; + } + median.at(i, j) = medianColor; + } + + + } + + return median; + } + + cv::Mat3b VideoUtils::getMedian(const std::string & path, float time_percentage_crop) + { + + sibr::Video vid(path); + Volume3u vol = loadVideoVolume(vid); + cv::Mat3b median(vid.getResolutionCV(), CV_8UC3); + + int crop = (int)(vol.l*std::min(time_percentage_crop, 0.4f)); + int start = crop, end = vol.l - crop; + + +#pragma omp parallel for + for (int i = 0; i < median.rows; ++i) { + cv::Mat line = vol.video_line(i); + std::vector values; + for (int j = 0; j < median.cols; ++j) { + for (int c = 0; c < 3; ++c) { + line.col(3 * j + c).rowRange(start, end).copyTo(values); + std::nth_element(values.begin(), values.begin() + values.size() / 2, values.end()); + median(i, j)[c] = values[values.size() / 2]; + } + } + } + + return median; + } + + cv::Mat VideoUtils::getBackgroundImage(sibr::Video & vid, int numBins, float time_skip_begin, float time_skip_end) { + cv::Mat volume = vid.getVolume(time_skip_begin, time_skip_end); + volume = volume.t(); + return getBackgroundImage(volume, vid.getResolution()[0], vid.getResolution()[1], numBins); + } + + cv::Mat VideoUtils::getBackgroundImage(const cv::Mat volume, int w, int h, int numBins) + { + cv::Mat bg = cv::Mat(h, w, CV_8UC3); + const int L = volume.cols; + +#pragma omp parallel for + for (int i = 0; i < bg.rows; ++i) { + for (int j = 0; j < bg.cols; ++j) { + + std::vector values(L); + + for (int c = 0; c < 3; ++c) { + for (int t = 0; t < L; ++t) { + values[t][c] = volume.at(3 * (i*bg.cols + j) + c, t); + } + } + + TimeHistogram histo = TimeHistogram(0, 255, numBins); + histo.addValues(values); + + auto mode = histo.getBinMiddle(histo.getHMode()); + for (int c = 0; c < 3; ++c) { + bg.at(i, j)[c] = mode[c]; + } + } + } + return bg; + } + + void VideoUtils::getBackGroundVideo(sibr::Video & vid, PyramidLayer & out_mask, PyramidLayer & out_video, cv::Mat & out_img, + const sibr::ImageRGB & meanImg, int threshold, int numBins, float time_skip_begin, float time_skip_end) + { + cv::Mat volume = vid.getVolume(time_skip_begin, time_skip_end).t(); + + const int w = vid.getResolution()[0], h = vid.getResolution()[1], L = volume.cols; + out_mask.w = w; + out_mask.l = L; + out_mask.h = h; + + out_video = out_mask; + + out_mask.volume = cv::Mat(L, 3 * w*h, CV_8UC1); + out_video.volume = cv::Mat(L, 3 * w*h, CV_8UC1); + out_img = cv::Mat(h, w, CV_8UC3); + + const bool useMeanImg = !(meanImg.size()[0] == 0); + + std::cout << w << " " << h << " " << L << " use mean img " << useMeanImg << std::endl; +#pragma omp parallel for + for (int i = 0; i < h; ++i) { + for (int j = 0; j < w; ++j) { + + std::vector values(L); + for (int c = 0; c < 3; ++c) { + for (int t = 0; t < L; ++t) { + values[t][c] = volume.at(3 * (i*w + j) + c, t); + } + } + + TimeHistogram histo = TimeHistogram(0, 255, numBins); + histo.addValues(values); + //histo.computeSortedBins(); + + auto mode = histo.getHMode(); + auto mode_color = histo.getBinMiddle(histo.getHMode()); + + out_img.at(i, j) = sibr::toOpenCV(mode_color); + + sibr::Vector3ub stdDev; + + if (useMeanImg) { + const int radius = 4; + const int diam = 2 * radius + 1; + const int num = diam * diam; + sibr::Vector3f sumColor(0, 0, 0), sumColorSq(0, 0, 0); + for (int di = -radius; di <= radius; ++di) { + int ii = sibr::clamp(i + di, 0, h - 1); + for (int dj = -radius; dj <= radius; ++dj) { + int jj = sibr::clamp(j + dj, 0, w - 1); + sumColor += meanImg(jj, ii).cast(); + sumColorSq += meanImg(jj, ii).cast().cwiseProduct(meanImg(jj, ii).cast()); + } + } + sumColor /= (float)(num); + sumColorSq = sumColorSq / (float)num - sumColor.cwiseProduct(sumColor); + stdDev = sumColorSq.cwiseSqrt().cast(); + threshold = 15 * stdDev.norm(); + } + + for (int t = 0; t < L; ++t) { + const auto & color = values[t]; + auto bin = histo.whatBin(color); + + //float cdf = histo.sorted_bins[bin]; + //float outlier_prop = 1.0f - cdf; + //auto viz_color = sibr::jetColor(outlier_prop); + + for (int c = 0; c < 3; ++c) { + //out_mask.volume.at(t, 3 * (i*w + j) + c) = (cdf < 0.75f ? 0 : 255); + //out_video.volume.at(t, 3 * (i*w + j) + c) = viz_color[c]; + + if ((color.cast() - mode_color.cast()).norm() < threshold) { + out_mask.volume.at(t, 3 * (i*w + j) + c) = 0; + } else { + out_mask.volume.at(t, 3 * (i*w + j) + c) = 255; + } + } + } + + } + } + + volume = volume.t(); + out_video.volume = volume.mul((1.0 / 255)*out_mask.volume); + } + + sibr::Volume1u VideoUtils::getBackgroundVolume(const sibr::Volume3u & volume, int threshold, int numBins) + { + const int L = volume.l; + sibr::Volume1u out_mask = sibr::Volume1u(L, volume.w, volume.h, 0); + +#pragma omp parallel for + for (int i = 0; i < volume.h; ++i) { + for (int j = 0; j < volume.w; ++j) { + std::vector values(L); + for (int c = 0; c < 3; ++c) { + for (int t = 0; t < L; ++t) { + values[t][c] = volume.valueAt(t, i, j, c); + } + } + + TimeHistogram histo = TimeHistogram(0, 255, numBins); + histo.addValues(values); + + auto mode_color = histo.getBinMiddle(histo.getHMode()); + + for (int t = 0; t < L; ++t) { + const auto & color = values[t]; + + if ((color.cast() - mode_color.cast()).norm() > threshold) { + out_mask.pixelAt(t, i, j) = 255; + } + } + + } + } + + return out_mask; + } + + sibr::Volume1f VideoUtils::getBackgroundVolumeF(const sibr::Volume3u & volume, int numBins) + { + const int L = volume.l; + sibr::Volume1f out_mask = sibr::Volume1f(L, volume.w, volume.h); + +#pragma omp parallel for + for (int i = 0; i < volume.h; ++i) { + for (int j = 0; j < volume.w; ++j) { + std::vector values(L); + for (int c = 0; c < 3; ++c) { + for (int t = 0; t < L; ++t) { + values[t][c] = volume.valueAt(t, i, j, c); + } + } + + TimeHistogram histo = TimeHistogram(0, 255, numBins); + histo.addValues(values); + + auto mode_color = histo.getBinMiddle(histo.getHMode()); + + for (int t = 0; t < L; ++t) { + const auto & color = values[t]; + out_mask.pixelAt(t, i, j) = (float)(color.cast() - mode_color.cast()).norm(); + } + + } + } + + return out_mask; + } + + void VideoUtils::computeSaveSimpleFlow(sibr::Video & vid, bool show) + { + int layers = 5; + int block_size = 3; + int max_flow = 5; + + sibr::Volume3u vol = sibr::loadVideoVolume(vid); + Path path = vid.getFilepath(); + std::string folder = path.parent_path().string() + "/flow/"; + sibr::makeDirectory(folder); + + std::string filepath = folder + "/" + path.stem().string() + "_sflow_" + std::to_string(layers) + "_" + + std::to_string(block_size) + + "_" + std::to_string(max_flow) + ".mp4"; + + sibr::FFVideoEncoder encoder(filepath, 30, { 2 * vol.w,2 * vol.h }); + for (int t = 0; t < vol.l - 1; ++t) { + cv::Mat flow; + cv::optflow::calcOpticalFlowSF(vol.frame(t), vol.frame(t + 1), flow, layers, block_size, max_flow); + cv::Mat viz = vol.frame(t).clone(); + int r = 10; + for (int i = 0; i < vol.h; i += r) { + for (int j = 0; j < vol.w; j += r) { + auto f = flow.at(i, j); + if (isfinite(f[0]) && isfinite(f[1])) { + if (cv::norm(f) > 0.5) { + cv::line(viz, cv::Point(j, i), cv::Point(int(j + f[1]), int(i + f[0])), { 255,0,255 }, 2); + } + } else { + cv::circle(viz, cv::Point(j, i), 3, { 0,0,0 }, 2); + } + + + } + } + cv::resize(viz, viz, cv::Size(2 * viz.cols, 2 * viz.rows), 0, 0, cv::INTER_NEAREST); + + if (show) { + cv::imshow("flow", viz); + if (cv::waitKey() == 27) { + break; + } + } else { + encoder << viz; + } + std::cout << "." << std::flush; + } + std::cout << "done " << std::endl; + } + + void VideoUtils::computeSaveVideoMaskF(Video & vid, int threshold, bool viz) + { + sibr::Volume3u volume = sibr::loadVideoVolume(vid); + sibr::Volume1f mask = sibr::VideoUtils::getBackgroundVolumeF(volume, 150); + + sibr::Volume1f bilateral_mask(volume.l, volume.w, volume.h); + sibr::Volume1f bilateral_mask_median(volume.l, volume.w, volume.h); + sibr::Volume1u median_bilateral_mask_binary(volume.l, volume.w, volume.h); + + const int radius_bila = 21; + const double eps = 10; + +#pragma omp parallel for + for (int t = 0; t < volume.l; ++t) { + cv::ximgproc::guidedFilter(volume.frame(t), mask.frame(t), bilateral_mask.frame(t), radius_bila, eps); + //cv::medianBlur(mask.frame(t), median_mask.frame(t), 7); + cv::medianBlur(bilateral_mask.frame(t), bilateral_mask_median.frame(t), 5); + median_bilateral_mask_binary.frame(t) = bilateral_mask_median.frame(t) > threshold; + } + + sibr::Volume3u video_masked_bilateral_bin = volume.applyMaskBinary(median_bilateral_mask_binary); + + if (viz) { + bilateral_mask.play(); + bilateral_mask_median.play(); + median_bilateral_mask_binary.play(); + video_masked_bilateral_bin.play(); + } + + Path filepath = vid.getFilepath(); + const std::string folder = filepath.parent_path().string() + "/masks/bilateral/"; + sibr::makeDirectory(folder); + + const std::string basename = folder + filepath.stem().string() + "_bila_" + std::to_string(radius_bila) + "_" + std::to_string((int)(10 * eps)); + const std::string extension = ".mp4"; + + bilateral_mask.saveToVideoFile(basename + "_raw" + extension); + bilateral_mask_median.saveToVideoFile(basename + "_median" + extension); + median_bilateral_mask_binary.saveToVideoFile(basename + "_median_binary" + extension); + video_masked_bilateral_bin.saveToVideoFile(basename + "_video" + extension); + } + + void VideoUtils::computeSaveVideoMaskBlur(Video & vid, int time_window) + { + const Path & filepath = vid.getFilepath(); + const std::string in_filename = filepath.parent_path().string() + "/masks/bilateral/" + filepath.stem().string() + "_bila_21_100_median_binary.mp4"; + const std::string out_folder = filepath.parent_path().string() + "/masks/bilateral_tblur/"; + sibr::makeDirectory(out_folder); + const std::string out_filename = out_folder + "/" + filepath.stem().string() + "_mask_tblur.mp4"; + + sibr::Volume3u volume = sibr::loadVideoVolume(in_filename); + std::cout << "volume.mat.isContinuous() : " << volume.mat.isContinuous() << std::endl; + sibr::Volume3u out = sibr::Volume3u(volume.l, volume.w, volume.h, 0); + + int time_win = 10; + + //#pragma omp parallel for + for (int i = 0; i < out.h; ++i) { + for (int j = 0; j < out.w; ++j) { + for (int t = 0; t < out.l; ++t) { + for (int u = std::max(0, t - time_win); u < std::min(out.l - 1, t + time_win); ++u) { + if (volume.valueAt(u, i, j, 0) > 128) { + out.pixelAt(t, i, j) = cv::Vec3b(255, 255, 255); + break; + } + } + } + } + } + out.saveToVideoFile(out_filename); + } + + cv::Mat VideoUtils::getTemporalSpatialRatio(sibr::Video & vid, PyramidLayer & out_ratio, const sibr::ImageRGB & spatial_ratio, int numBins, float time_skip_begin, float time_skip_end) + { + cv::Mat volume = vid.getVolume(time_skip_begin, time_skip_end).t(); + + const int w = vid.getResolution()[0], h = vid.getResolution()[1], L = volume.cols; + out_ratio.w = w; + out_ratio.l = L; + out_ratio.h = h; + + out_ratio.volume = cv::Mat(L, 3 * w*h, CV_8UC1); + +#pragma omp parallel for + for (int i = 0; i < h; ++i) { + for (int j = 0; j < w; ++j) { + + std::vector values(L); + for (int c = 0; c < 3; ++c) { + for (int t = 0; t < L; ++t) { + values[t][c] = volume.at(3 * (i*w + j) + c, t); + } + } + + TimeHistogram histo = TimeHistogram(0, 255, numBins); + histo.addValues(values); + //histo.computeSortedBins(); + + auto mode = histo.getHMode(); + auto mode_color = histo.getBinMiddle(histo.getHMode()); + + for (int t = 0; t < L; ++t) { + const auto & color = values[t]; + auto bin = histo.whatBin(color); + + sibr::Vector3f norm_temporal = (color.cast() - mode_color.cast()).cwiseAbs().cast(); + sibr::Vector3f norm_spatial = spatial_ratio(j, i).cwiseAbs().cast().array() + 10; + sibr::Vector3f ratios = norm_temporal.cwiseQuotient(norm_spatial); + + + for (int c = 0; c < 3; ++c) { + out_ratio.volume.at(t, 3 * (i*w + j) + c) = sibr::clamp((uchar)(128 * ratios[c]), 0, 255); + //if (ratios.maxCoeff() > 0.5) { + // out_ratio.volume.at(t, 3 * (i*w + j) + c) = 255; + //} else { + // out_ratio.volume.at(t, 3 * (i*w + j) + c) = 0; + //} + //out_ratio.volume.at(t, 3 * (i*w + j) + c) = sibr::clamp((uchar)(64*ratios[c]),0,255); + } + } + + } + } + + return volume.t(); + } + + cv::Mat VideoUtils::getLaplacian(cv::Mat mat, int size, bool smooth, bool absolute) + { + cv::Mat grey, laplacian, abs; + if (smooth) { + cv::GaussianBlur(mat, mat, cv::Size(size, size), 0, 0, cv::BORDER_DEFAULT); + } + grey = getGrey(mat); + cv::Laplacian(grey, laplacian, CV_16S, size); + if (absolute) { + cv::convertScaleAbs(laplacian, abs); + return abs; + } + return laplacian; + } + + cv::Mat VideoUtils::getCanny(cv::Mat mat) + { + cv::Mat grey, canny; + grey = getGrey(mat); + cv::Canny(grey, canny, 50, 150); + return canny; + } + + int VideoUtils::rotationAngleFromMetadata(const std::string & videoPath) + { + namespace bfs = boost::filesystem; + + Path vidPath = bfs::canonical(videoPath); + std::string parentAbs = bfs::canonical(vidPath.parent_path()).string(); + std::string tmpFilePath = parentAbs + "/" + vidPath.stem().string() + "_tmp.txt"; + + std::string cmd = "ffprobe -i \"" + vidPath.string() + "\" > \"" + tmpFilePath + "\" 2>&1"; + //std::cout << cmd << std::endl; + + int cmd_status = std::system(cmd.c_str()); + if (cmd_status != EXIT_SUCCESS) { + SIBR_WRG << "getMetaData failed to call : " << cmd << std::endl; + } + + std::ifstream file(tmpFilePath); + if (!file.is_open()) { + SIBR_WRG << "getMetaData failed to open " << tmpFilePath << std::endl; + } + std::string line, tmp; + std::stringstream linestream; + + int angle = 0; + while (safeGetline(file, line)) { + if (line.find("rotate") != std::string::npos) { + linestream << line; + linestream >> tmp >> tmp >> angle; + break; + } + } + file.close(); + + if (!boost::filesystem::remove(tmpFilePath)) { + SIBR_WRG << "getMetaData failed to remove " << tmpFilePath << std::endl; + } + + return angle; + } + + void VideoUtils::ECCtransform(cv::Mat matA, cv::Mat matB, cv::Mat & correctedB, cv::Mat & diff, int cvMotion) + { + cv::Mat greyA, greyB, warpBA; + cv::cvtColor(matA, greyA, cv::COLOR_BGR2GRAY); + cv::cvtColor(matB, greyB, cv::COLOR_BGR2GRAY); + try { + cv::findTransformECC(greyA, greyB, warpBA, cvMotion); + } + catch (const std::exception & e) { std::cout << e.what(); return; } + + if (cvMotion == cv::MOTION_HOMOGRAPHY) { + cv::warpPerspective(matB, correctedB, warpBA, matB.size()); + } else if (cvMotion == cv::MOTION_AFFINE) { + cv::warpAffine(matB, correctedB, warpBA, matB.size()); + } + + cv::absdiff(matA, correctedB, diff); + } + + void VideoUtils::smallAlignmentVideo(sibr::Video & vid, const std::string & outputVidPath, bool viz) + { + struct Match { + cv::Point2f in, out; + float error; + }; + + //cv::VideoWriter out(outputVidPath, codec_OpenH264, vid.getFrameRate(), cv::Size(vid.getResolution()[0], vid.getResolution()[1])); + sibr::FFVideoEncoder out(outputVidPath, vid.getFrameRate(), vid.getResolution()); + + if (!out.isFine()) { + SIBR_WRG << " cant write video " << outputVidPath << std::endl; + } + vid.setCurrentFrame(0); + cv::Mat initFrame = vid.next(); + cv::Mat initGray = VideoUtils::getGrey(initFrame); + + std::vector features, nextFeatures; + std::vector status; + std::vector errors; + + cv::Mat totalHomography = cv::Mat::eye(3, 3, CV_32FC1); + + const double magic_expon = 1.6; + const double ratio = 0.5; + const double ransac_repro_error = 3.0; + const double features_to_track_quality = 0.1; + const double features_min_dist = 0.1; //10 + int nPixels = vid.getResolution().prod(); + + int numFeatures = (int)pow(nPixels, 1.0 / magic_expon); + std::cout << " num features " << numFeatures << std::endl; + + cv::goodFeaturesToTrack(initGray, features, numFeatures, features_to_track_quality, 10); + + cv::Mat nextFrame, gray; + + for (;;) { + nextFrame = vid.next(); + if (nextFrame.empty()) { + break; + } + gray = VideoUtils::getGrey(nextFrame); + + cv::calcOpticalFlowPyrLK(initGray, gray, features, nextFeatures, status, errors, cv::Size(15, 15), 0); + + std::vector matchs; + for (int i = 0; i < (int)status.size(); ++i) { + if (status[i] == 1) { + matchs.push_back({ features[i] ,nextFeatures[i] ,errors[i] }); + } + } + //std::cout << matchs.size() / (double)status.size() << std::endl; + + std::sort(matchs.begin(), matchs.end(), [](const Match & a, const Match & b) { return a.error < b.error; }); + + int numBestMatch = (int)(ratio*matchs.size()); + std::vector inputFeatures(numBestMatch), outputFeatures(numBestMatch); + + for (int i = 0; i < numBestMatch; ++i) { + inputFeatures[i] = matchs[i].in; + outputFeatures[i] = matchs[i].out; + } + + if (viz) { + cv::Mat corresp_viz = nextFrame.clone(); + for (int i = 0; i < numBestMatch; ++i) { + cv::circle(corresp_viz, matchs[i].in, 5, cv::Scalar(0, 255, 0), 2); + cv::circle(corresp_viz, matchs[i].out, 5, cv::Scalar(255, 0, 0), 2); + } + cv::imshow("viz", corresp_viz); + if (cv::waitKey() == 27) { + viz = false; + cv::destroyAllWindows(); + } + } + + cv::Mat homography = cv::findHomography(inputFeatures, outputFeatures, cv::RANSAC, ransac_repro_error); + + cv::Mat correctedFrame; + cv::warpPerspective(nextFrame, correctedFrame, homography.inv(), nextFrame.size()); + + out << correctedFrame; + std::cout << "." << std::flush; + } + + if (viz) { + cv::destroyAllWindows(); + } + + out.close(); + std::cout << " done " << std::endl; + } + + void VideoUtils::smallAlignmentVideo2(sibr::Video & vid, const std::string & outputVidPath, bool viz) + { + struct Match { + cv::Point2f in, out; + float error; + }; + + //cv::VideoWriter out(outputVidPath, codec_OpenH264, vid.getFrameRate(), cv::Size(vid.getResolution()[0], vid.getResolution()[1])); + sibr::FFVideoEncoder out(outputVidPath, vid.getFrameRate(), vid.getResolution()); + + if (!out.isFine()) { + SIBR_WRG << " cant write video " << outputVidPath << std::endl; + } + vid.setCurrentFrame(0); + cv::Mat initFrame = vid.next(); + cv::Mat initGray = VideoUtils::getGrey(initFrame); + + std::vector features, nextFeatures; + std::vector status; + std::vector errors; + + cv::Mat completeHomography = cv::Mat::eye(3, 3, CV_64FC1); + + const double magic_expon = 2.0; + const double ratio = 0.5; + const double ransac_repro_error = 0.5; + const double features_to_track_quality = 0.1; + const double features_min_dist = 10; //10 + const double max_displacement = 2; + int nPixels = vid.getResolution().prod(); + + int numFeatures = (int)pow(nPixels, 1.0 / magic_expon); + std::cout << " num features " << numFeatures << std::endl; + + cv::Mat nextFrame, gray; + + for (;;) { + nextFrame = vid.next(); + if (nextFrame.empty()) { + break; + } + gray = VideoUtils::getGrey(nextFrame); + + cv::GaussianBlur(gray, gray, cv::Size(3, 3), 0); + + cv::goodFeaturesToTrack(initGray, features, numFeatures, features_to_track_quality, features_min_dist); + + cv::calcOpticalFlowPyrLK(initGray, gray, features, nextFeatures, status, errors, cv::Size(5, 5), 0); + + std::vector matchs; + for (int i = 0; i < (int)status.size(); ++i) { + auto v = features[i] - nextFeatures[i]; + + if (status[i] == 1 && cv::norm(cv::Vec2f(v.x, v.y), cv::NORM_INF) < max_displacement) { + matchs.push_back({ features[i] ,nextFeatures[i] ,errors[i] }); + } + } + //std::cout << matchs.size() / (double)status.size() << std::endl; + + std::sort(matchs.begin(), matchs.end(), [](const Match & a, const Match & b) { return a.error < b.error; }); + + int numBestMatch = (int)(ratio*matchs.size()); + std::vector inputFeatures(numBestMatch), outputFeatures(numBestMatch); + + for (int i = 0; i < numBestMatch; ++i) { + inputFeatures[i] = matchs[i].in; + outputFeatures[i] = matchs[i].out; + } + + if (viz) { + cv::Mat corresp_viz = nextFrame.clone(); + for (int i = 0; i < numBestMatch; ++i) { + cv::circle(corresp_viz, matchs[i].in, 5, cv::Scalar(0, 255, 0), 2); + cv::circle(corresp_viz, matchs[i].out, 5, cv::Scalar(255, 0, 0), 2); + } + cv::imshow("viz", corresp_viz); + if (cv::waitKey() == 27) { + viz = false; + cv::destroyAllWindows(); + } + } + + cv::Mat homography = cv::findHomography(inputFeatures, outputFeatures, cv::RANSAC, ransac_repro_error); + + completeHomography *= homography; + + cv::Mat correctedFrame; + cv::warpPerspective(nextFrame, correctedFrame, completeHomography.inv(), nextFrame.size()); + + initGray = gray; + + out << correctedFrame; + std::cout << "." << std::flush; + } + + if (viz) { + cv::destroyAllWindows(); + } + + out.close(); + std::cout << " done " << std::endl; + } + + cv::Mat VideoUtils::applyFlow(const cv::Mat & prev, const cv::Mat & flow) { + cv::Mat out, realFlow = flow; + for (int i = 0; i < prev.rows; ++i) { + for (int j = 0; j < prev.cols; ++j) { + realFlow.at(i, j) += cv::Vec2f(j + 0.5f, i + 0.5f); + } + } + cv::remap(prev, out, realFlow, cv::Mat(), cv::INTER_LINEAR); + return out; + } + + void VideoUtils::simpleFlow(cv::VideoCapture & cap, float ratio, + std::function f, + std::function end_function + ) { + cap.set(cv::VideoCaptureProperties::CAP_PROP_POS_FRAMES, 0); + cv::Mat prev, flow; + int flow_id = 0; + while (true) { + + cv::Mat next; + cap >> next; + if (next.empty()) { + break; + } + cv::resize(next, next, cv::Size((int)(ratio*next.size().width), (int)(ratio*next.size().height))); + + if (!prev.empty()) { + cv::optflow::calcOpticalFlowSF(prev, next, flow, 3, 2, 4); + + if (!f(prev, next, flow, flow_id)) { + break; + } + + ++flow_id; + } + + prev = next; + } + + end_function(); + } + + void VideoUtils::simpleFlowViz(cv::VideoCapture & cap, float ratio) + { + simpleFlow(cap, ratio, [](cv::Mat prev, cv::Mat next, cv::Mat flow, int flow_id) { + cv::Mat viz = getFlowViz(flow); + cv::resize(viz, viz, cv::Size(2000, 1500)); + cv::Mat diff = VideoUtils::applyFlow(prev, flow); + + cv::imshow("simpleflow", viz); + cv::imshow("frame", next); + cv::imshow("applyFlow", diff); + int key = cv::waitKey(1); + if (key == 27) { + return false; + } + + return true; + }, []() { + cv::destroyAllWindows(); + } + ); + } + + void VideoUtils::simpleFlowSave(cv::VideoCapture & cap, float ratio, std::function naming_f) + { + std::cout << " saving flow " << std::flush; + simpleFlow(cap, ratio, [&](cv::Mat prev, cv::Mat next, cv::Mat flow, int flow_id) { + std::cout << "." << std::flush; + cv::Mat viz = getFlowViz(flow); + viz.convertTo(viz, CV_8UC3, 255.0); + return cv::imwrite(naming_f(flow_id), viz); + }); + std::cout << "done" << std::endl; + } + + void VideoUtils::deepFlow(cv::VideoCapture & cap, float ratio, + std::function f, + std::function end_function) + { + cap.set(cv::VideoCaptureProperties::CAP_PROP_POS_FRAMES, 0); + + auto deepFlow = cv::optflow::createOptFlow_DeepFlow(); + cv::Mat flow, next, nextGrey, prevGrey; + int flow_id = 0; + while (true) { + cap >> next; + if (next.empty()) { + break; + } + + auto size = cv::Size((int)(ratio*next.size().width), (int)(ratio*next.size().height)); + cv::resize(next, next, size); + nextGrey = getGrey(next); + + if (!prevGrey.empty()) { + deepFlow->calc(prevGrey, nextGrey, flow); + + if (!f(prevGrey, nextGrey, flow, flow_id)) { + break; + } + ++flow_id; + } + + prevGrey = nextGrey.clone(); + } + + end_function(); + + } + + void VideoUtils::deepFlowViz(cv::VideoCapture & cap, float ratio) + { + deepFlow(cap, ratio, [](cv::Mat prev, cv::Mat next, cv::Mat flow, int flow_id) { + cv::Mat viz = getFlowViz(flow); + cv::Mat diff = applyFlow(prev, flow); + cv::imshow("simpleflow", viz); + cv::imshow("frame", prev); + cv::imshow("applyFlow", diff); + int key = cv::waitKey(1); + if (key == 27) { + return false; + } + return true; + }, []() { + cv::destroyAllWindows(); + } + ); + } + + cv::Mat VideoUtils::getGrey(const cv::Mat & mat) + { + cv::Mat out; + cv::cvtColor(mat, out, cv::COLOR_BGR2GRAY); + return out; + } + + void PyramidLayer::show(int s) const + { + int slice_y = 0; + + struct Data { + PyramidLayer A; + }; + Data data = { *this }; + + auto cb = [](int pos, void* userdata) -> void { + Data & d = *(Data*)userdata; + cv::Mat sliceA = sibr::slice(d.A, 0, pos); + cv::resize(sliceA, sliceA, cv::Size(800, 800), 0, 0, cv::INTER_NEAREST); + cv::imshow("sliceA", sliceA); + }; + + + int t = 0; + while (true) { + + cv::Mat slice; + cv::Mat shifted = (volume.row(t) + 0 * 128.0f); + shifted.reshape(3, h).convertTo(slice, CV_8UC3); + cv::imshow("shpw", slice); + cv::createTrackbar("sy", "shpw", &slice_y, w - 1, cb, &data); + if (cv::waitKey(s) == 27) { + break; + } + ++t; + if (t == l) { + std::cout << "." << std::flush; + t = 0; + } + } + } + + cv::Mat PyramidLayer::getRGB(int frame, bool centered) { + cv::Mat out; + if (centered) { + cv::Mat shifted = (volume.row(frame) + 128.0f); + shifted.reshape(3, h).convertTo(out, CV_8UC3); + } else { + volume.row(frame).reshape(3, h).convertTo(out, CV_8UC3); + } + + return out; + } + + void PyramidLayer::saveToVideoFile(const std::string & filename, double framerate) + { + sibr::FFVideoEncoder output(filename, framerate, { w,h }); + for (int f = 0; f < l; ++f) { + cv::Mat frame; + volume.row(f).reshape(3, h).convertTo(frame, CV_8UC3); + output << frame; + } + output.close(); + + } + + void PyramidLayer::show(PyramidLayer A, PyramidLayer B, int s) { + int t = 0; + while (true) { + cv::Mat sliceA = A.getRGB(t); + cv::Mat sliceB = B.getRGB(t); + cv::Mat top; + cv::hconcat(sliceA, sliceB, top); + cv::imshow("show duo", top); + if (cv::waitKey(s) == 27) { + break; + } + ++t; + if (t == A.l) { + std::cout << "." << std::flush; + t = 0; + } + } + } + + void PyramidLayer::show(PyramidLayer A, PyramidLayer B, PyramidLayer C, int s) { + int slice_x = 0; + int slice_y = 0; + int t = 0; + + struct Data { + PyramidLayer A, B, C; + }; + Data data = { A,B,C }; + + auto cb = [](int pos, void* userdata) -> void { + Data & d = *(Data*)userdata; + cv::Mat sliceA = sibr::slice(d.A, 0, pos); + cv::Mat sliceB = sibr::slice(d.B, 0, pos); + cv::Mat sliceC = sibr::slice(d.C, 0, pos); + cv::resize(sliceA, sliceA, cv::Size(800, 800), 0, 0, cv::INTER_NEAREST); + cv::resize(sliceB, sliceB, cv::Size(800, 800), 0, 0, cv::INTER_NEAREST); + cv::resize(sliceC, sliceC, cv::Size(800, 800), 0, 0, cv::INTER_NEAREST); + + cv::imshow("sliceA", sliceA); + cv::imshow("sliceB", sliceB); + cv::imshow("sliceC", sliceC); + }; + + while (true) { + cv::imshow("show A", A.getRGB(t)); + cv::imshow("show B", B.getRGB(t)); + cv::imshow("show C", C.getRGB(t)); + + cv::createTrackbar("sy", "show C", &slice_y, A.w - 1, cb, &data); + + int k = cv::waitKey(s); + if (k == 27) { + break; + } else if (k == 'c') { + t = t > 0 ? t - 1 : A.l - 1; + } else { + ++t; + if (t == A.l) { + std::cout << "." << std::flush; + t = 0; + } + } + } + } + + void PyramidLayer::show(PyramidLayer A, PyramidLayer B, PyramidLayer C, PyramidLayer D, int s, bool centered) { + int slice_y = 0; + int t = 0; + struct Data { + PyramidLayer A, B, C, D; + bool center; + }; + Data data = { A,B,C,D, centered }; + + auto cb = [](int pos, void* userdata) -> void { + Data & d = *(Data*)userdata; + cv::Mat sliceA = sibr::slice(d.A, 0, pos, true, d.center); + cv::Mat sliceB = sibr::slice(d.B, 0, pos, true, d.center); + cv::Mat sliceC = sibr::slice(d.C, 0, pos, true, d.center); + cv::Mat sliceD = sibr::slice(d.D, 0, pos, true, d.center); + cv::resize(sliceA, sliceA, cv::Size(800, 800), 0, 0, cv::INTER_NEAREST); + cv::resize(sliceB, sliceB, cv::Size(800, 800), 0, 0, cv::INTER_NEAREST); + cv::resize(sliceC, sliceC, cv::Size(800, 800), 0, 0, cv::INTER_NEAREST); + cv::resize(sliceD, sliceD, cv::Size(800, 800), 0, 0, cv::INTER_NEAREST); + cv::imshow("sliceA", sliceA); + cv::imshow("sliceB", sliceB); + cv::imshow("sliceC", sliceC); + cv::imshow("sliceD", sliceD); + }; + + while (true) { + cv::imshow("show A", A.getRGB(t, data.center)); + cv::imshow("show B", B.getRGB(t, data.center)); + cv::imshow("show C", C.getRGB(t, data.center)); + cv::imshow("show D", D.getRGB(t, data.center)); + cv::createTrackbar("sy", "show C", &slice_y, A.w - 1, cb, &data); + + int k = cv::waitKey(s); + if (k == 27) { + std::cout << "clear" << std::endl; + cv::destroyAllWindows(); + break; + } else if (k == 'c') { + t = t > 0 ? t - 1 : A.l - 1; + } else if (k == 'm') { + data.center = !data.center; + } else { + ++t; + if (t == A.l) { + std::cout << "." << std::flush; + t = 0; + } + } + } + } + + void PyramidLayer::showDiff(PyramidLayer A, PyramidLayer B, int s) + { + int t = 0; + while (true) { + cv::Mat sliceA = A.getRGB(t); + cv::Mat sliceB = B.getRGB(t); + cv::Mat diff; + cv::absdiff(sliceA, sliceB, diff); + cv::Mat top; + //cv::hconcat(sliceB, 5 * diff, top); + //cv::hconcat(sliceA, top, top); + cv::imshow("show a", sliceA); + cv::imshow("show B", sliceB); + + cv::imshow("show diff", diff); + int k = cv::waitKey(s); + if (k == 27) { + break; + } else if (k == 'c') { + t = t > 0 ? t - 1 : A.l - 1; + } else { + ++t; + if (t == A.l) { + std::cout << "." << std::flush; + t = 0; + } + } + } + } + + PyramidLayer PyramidLayer::operator+(const PyramidLayer & other) + { + //assert(w == other.w && h == other.w && l = other.l); + + PyramidLayer out; + out.w = w; + out.h = h; + out.l = l; + out.volume = volume + other.volume; + return out; + } + + PyramidLayer PyramidLayer::operator-(const PyramidLayer & other) + { + //assert(w == other.w && h == other.w && l = other.l); + + PyramidLayer out; + out.w = w; + out.h = h; + out.l = l; + out.volume = volume - other.volume; + return out; + } + + PyramidLayer blur(const PyramidLayer & layer, const PyramidParameters & params) + { + PyramidLayer out(layer.w, layer.h, layer.l); + +#pragma omp parallel for + for (int t = 0; t < layer.l; ++t) { + cv::Mat sliceIn = layer.volume.row(t).reshape(3, layer.h); + cv::Mat sliceOut = out.volume.row(t).reshape(3, out.h); + if (params.splacialDS) { + cv::GaussianBlur(sliceIn, sliceOut, cv::Size(2 * params.spatial_radius + 1, 2 * params.spatial_radius + 1), 0); + } else { + sliceIn.copyTo(sliceOut); + } + } + + temporalBlur(out, params); + + return out; + } + + // PyramidLayer temporalBlur(const PyramidLayer & layer, const PyramidParameters & params, float scaling) + // { + // //cv::Mat kernel = cv::Mat::ones(cv::Size(2 * params.temporal_radius + 1, 1), CV_32FC1); + // //kernel = kernel / cv::norm(kernel, cv::NORM_L1); + // + // const cv::Mat kernel = (scaling / 16.0f)*(cv::Mat_(1, 5) << 1, 4, 6, 4, 1); + // + // //layer.show(0); + // + // cv::Mat vol = layer.volume.t(); + // + // //std::cout << vol.row(3 * (0 * layer.w + 0) + 0) << std::endl; + // //std::cout << vol.row(3 * (0 * layer.w + 0) + 1) << std::endl; + // //std::cout << vol.row(3 * (0 * layer.w + 0) + 2) << std::endl; + // + // cv::filter2D(vol, vol, -1, kernel, { 2,0 }, 0, cv::BORDER_DEFAULT); + // + ////#pragma omp parallel for + //// for (int i = 0; i < layer.h; ++i) { + //// for (int j = 0; j < layer.w; ++j) { + //// for (int c = 0; c < 3; ++c) { + //// cv::Mat slice = vol.row(3 * (i*layer.w + j) + c); + //// cv::filter2D(slice, slice, -1, kernel, { 2,0 }, 0, cv::BORDER_DEFAULT); // cv::Point(-1,-1) BORDER_ISOLATED cv::BORDER_REPLICATE + //// } + //// } + //// } + // + // //std::cout << vol.row(3 * (0 * layer.w + 0) + 0) << std::endl; + // //std::cout << vol.row(3 * (0 * layer.w + 0) + 1) << std::endl; + // //std::cout << vol.row(3 * (0 * layer.w + 0) + 2) << std::endl; + // + // PyramidLayer out(vol.t(), layer.w, layer.h); + // //out.cout(); + // //out.show(0); + // + // return out; + // } + + PyramidLayer temporalBlur(const PyramidLayer & layer, const PyramidParameters & params, float scaling) + { + const cv::Mat kernel = (scaling / 16.0f)*(cv::Mat_(5, 1) << 1, 4, 6, 4, 1); + cv::Mat vol = layer.volume.clone(); + cv::filter2D(vol, vol, -1, kernel, { -1,-1 }, 0.0, cv::BORDER_DEFAULT); + return PyramidLayer(vol, layer.w, layer.h); + } + + void temporalBlurInPlace(PyramidLayer & layer, const PyramidParameters & params, float scaling) + { + const cv::Mat kernel = (scaling / 16.0f)*(cv::Mat_(5, 1) << 1, 4, 6, 4, 1); + cv::filter2D(layer.volume, layer.volume, -1, kernel, { -1,-1 }, 0.0, cv::BORDER_DEFAULT); + } + + PyramidLayer decimate(const PyramidLayer & layer, const PyramidParameters & params) + { + + PyramidLayer out((layer.w + 1) / 2, (layer.h + 1) / 2, (layer.l + 1) / 2); + +#pragma omp parallel for + for (int t = 0; t < out.l; ++t) { + cv::Mat sliceCurrent = layer.volume.row(2 * t).reshape(3, layer.h); + cv::Mat sliceDecimated = out.volume.row(t).reshape(3, out.h); + + cv::pyrDown(sliceCurrent, sliceDecimated); + //cv::resize(sliceCurrent, sliceDecimated, sliceDecimated.size(), 0, 0, CV_INTER_NN); + + } + + return out; + + } + + PyramidLayer upscale(const PyramidLayer & layerUp, const PyramidLayer & layerDown, const PyramidParameters & params) + { + //std::cout << layerUp.w << " " << layerUp.h << " " << layerUp.l << std::endl; + //std::cout << layerDown.w << " " << layerDown.h << " " << layerDown.l << std::endl; + + PyramidLayer out(layerUp.w, layerUp.h, layerUp.l); + //#pragma omp parallel for + for (int t = 0; t < layerDown.l; ++t) { + //if (2 * t + 1 >= layerUp.l) { + // continue; + //} + //cv::Mat sliceUp = out.volume.row(2 * t + 1).reshape(3, layerUp.h); + cv::Mat sliceUp = out.volume.row(2 * t).reshape(3, layerUp.h); + cv::Mat sliceDown = layerDown.volume.row(t).reshape(3, layerDown.h); + + if (params.splacialDS) { + cv::pyrUp(sliceDown, sliceUp, sliceUp.size()); + } else { + sliceDown.copyTo(sliceUp); + } + + + // if (2 * t + 1 < layerUp.l) { + // sliceUp.copyTo(out.volume.row(2 * t + 1).reshape(3, layerUp.h)); + // } + } + temporalBlurInPlace(out, params, 2.0f); + return out; + } + + PyramidLayer downscale(const PyramidLayer & layer, const PyramidParameters & params) + { + + PyramidLayer blured = temporalBlur(layer, params); + //std::cout << " temporal blur " << std::endl; + //blured.show(); + //std::cout << " temporal blur end" << std::endl; + + PyramidLayer out; + + if (params.splacialDS) { + out = PyramidLayer((layer.w + 1) / 2, (layer.h + 1) / 2, (layer.l + 1) / 2); + } else { + out = PyramidLayer(layer.w, layer.h, (layer.l + 1) / 2); + } + + //#pragma omp parallel for + for (int t = 0; t < out.l; ++t) { + //if (2 * t + 1 >= layer.l) { + // continue; + //} + //cv::Mat sliceCurrent = blured.volume.row(2 * t + 1).reshape(3, layer.h); + cv::Mat sliceCurrent = blured.volume.row(2 * t).reshape(3, layer.h); + cv::Mat sliceDecimated = out.volume.row(t).reshape(3, out.h); + + if (params.splacialDS) { + cv::pyrDown(sliceCurrent, sliceDecimated); + } else { + sliceCurrent.copyTo(sliceDecimated); + } + + } + + //PyramidLayer blur (layer.w, layer.h, (layer.l + 1) / 2); + + //for (int i = 0; i < blur.volume.rows; ++i) { + // cv::pyrDown(layer.volume.row(i), blur.volume.row(i), blur.volume.row(i).size()); + //} + + //PyramidLayer out; + //if (params.splacialDS) { + // out = PyramidLayer((layer.w + 1) / 2, (layer.h + 1) / 2, blur.l); + //} else { + // out = PyramidLayer(layer.w, layer.h, blur.l); + //} + + //for (int t = 0; t < out.l; ++t) { + // if (2 * t + 1 >= layer.l) { + // continue; + // } + // cv::Mat sliceCurrent = blur.volume.row(2 * t + 1).reshape(3, layer.h); + // cv::Mat sliceDecimated = out.volume.row(t).reshape(3, out.h); + + // if (params.splacialDS) { + // cv::pyrDown(sliceCurrent, sliceDecimated); + // } else { + // sliceCurrent.copyTo(sliceDecimated); + // } + //} + + return out; + } + + SIBR_VIDEO_EXPORT cv::Mat slice(const PyramidLayer & layer, int i, int j, bool vertical, bool center) + { + cv::Mat out; + if (vertical) { + out = cv::Mat(layer.l, layer.h, CV_8UC3); + + for (int t = 0; t < layer.l; ++t) { + for (int i = 0; i < layer.h; ++i) { + for (int c = 0; c < 3; ++c) { + out.at(t, i)[c] = (uchar)sibr::clamp((int)layer.volume.at(t, 3 * (i*layer.w + j) + c) + (center ? 128 : 0), 0, 255); + } + } + } + } + + //cv::vconcat(out, out, out); + out = out.t(); + return out; + } + + PyramidLayer VideoLaplacianPyramid::collapse() const + { + PyramidLayer out = layers.back(); + for (int i = (int)layers.size() - 2; i >= 0; --i) { + PyramidLayer up = upscale(layers[i], out, params); + out = up + layers[i]; + } + return out; + } + + VideoGaussianPyramid buildVideoGaussianPyramid(const cv::Mat & volume, int w, int h, int nLevels, const PyramidParameters & params, bool show) + { + VideoGaussianPyramid out; + out.params = params; + PyramidLayer currentLayer(volume, w, h); + out.layers.push_back(currentLayer); + + for (int i = 1; i < nLevels; ++i) { + PyramidLayer down = downscale(currentLayer, params); + out.layers.push_back(down); + currentLayer = down; + if (show) { + currentLayer.show(); + } + } + + return out; + } + + VideoGaussianPyramid buildVideoGaussianPyramid(sibr::Video & vid, int nLevels, const PyramidParameters & params, bool show) + { + return buildVideoGaussianPyramid(vid.getVolume(), vid.getResolution()[0], vid.getResolution()[1], nLevels, params, show); + } + + SIBR_VIDEO_EXPORT VideoLaplacianPyramid buildVideoLaplacianPyramid(PyramidLayer vid, int nLevels, const PyramidParameters & params, bool show) + { + VideoLaplacianPyramid out; + out.params = params; + + PyramidLayer currentLayer = vid; + currentLayer.volume.convertTo(currentLayer.volume, CV_32FC1); + + for (int i = 0; i < nLevels - 1; ++i) { + PyramidLayer down = downscale(currentLayer, params); + PyramidLayer up = upscale(currentLayer, down, params); + if (show) { + up.show(); + } + out.layers.push_back(currentLayer - up); + currentLayer = down; + } + + out.layers.push_back(currentLayer); + + return out; + } + + VideoLaplacianPyramid buildVideoLaplacianPyramid(sibr::Video & vid, int nLevels, const PyramidParameters & params, bool show) { + PyramidLayer layer(vid.getVolume(), vid.getResolution()[0], vid.getResolution()[1]); + return buildVideoLaplacianPyramid(layer, nLevels, params, show); + } + + VideoLaplacianPyramid buildVideoLaplacianPyramidFullyReduced(PyramidLayer vid, int nLevels, const PyramidParameters & params, bool show) + { + VideoLaplacianPyramid standardPyramid = buildVideoLaplacianPyramid(vid, nLevels, params, show); + + VideoLaplacianPyramid out; + out.params = params; + + out.layers.push_back(standardPyramid.layers[0]); + + for (int i = 1; i < nLevels; ++i) { + + PyramidLayer diff = standardPyramid.layers[i].clone(); + for (int k = i - 1; k >= 0; --k) { + diff = upscale(standardPyramid.layers[k], diff, params); + } + std::cout << " layer " << i << " : "; + diff.cout(); + out.layers.push_back(diff); + } + + return out; + } + + SIBR_VIDEO_EXPORT void convertReducedVideoPyramidTo128(VideoLaplacianPyramid & vid) + { + int nLayers = (int)vid.layers.size(); + for (int l = 0; l < nLayers - 1; ++l) { + vid.layers[l].volume += 128.0; + } + } + + PyramidLayer videoLaplacianBlending(sibr::Video & vidA, sibr::Video & vidB, PyramidLayer mask_volume) + { + int num_lvls = 6; + auto pyrA = sibr::buildVideoLaplacianPyramid(vidA, num_lvls); + auto pyrB = sibr::buildVideoLaplacianPyramid(vidB, num_lvls); + auto pyrM = sibr::buildVideoGaussianPyramid(mask_volume.volume, mask_volume.w, mask_volume.h, num_lvls); + + VideoLaplacianPyramid out; + for (int l = 0; l < num_lvls; ++l) { + sibr::PyramidLayer layer; + layer.w = pyrA.layers[l].w; + layer.h = pyrA.layers[l].h; + layer.l = pyrA.layers[l].l; + + cv::Mat A_lvl = pyrA.layers[l].volume; + cv::Mat B_lvl = pyrB.layers[l].volume; + cv::Mat M_lvl = pyrM.layers[l].volume; + + layer.volume = A_lvl.mul(M_lvl) + B_lvl.mul(1.0f - M_lvl); + out.layers.push_back(layer); + } + + return out.collapse(); + } + + PyramidLayer videoLaplacianBlending(PyramidLayer vidA, PyramidLayer vidB, PyramidLayer mask_volume, PyramidParameters params, bool show) + { + int num_lvls = params.num_levels; + + auto pyrA = sibr::buildVideoLaplacianPyramid(vidA, num_lvls, params, show); + auto pyrB = sibr::buildVideoLaplacianPyramid(vidB, num_lvls, params, show); + auto pyrM = sibr::buildVideoGaussianPyramid(mask_volume.volume, mask_volume.w, mask_volume.h, num_lvls, params, show); + + VideoLaplacianPyramid out; + out.params = params; + for (int l = 0; l < num_lvls; ++l) { + + std::cout << l << std::endl; + + sibr::PyramidLayer layer; + layer.w = pyrA.layers[l].w; + layer.h = pyrA.layers[l].h; + layer.l = pyrA.layers[l].l; + + cv::Mat A_lvl = pyrA.layers[l].volume; + cv::Mat B_lvl = pyrB.layers[l].volume; + cv::Mat M_lvl = pyrM.layers[l].volume; + + + cv::Mat rev_Mask = 255 - M_lvl; + sibr::PyramidLayer test(rev_Mask, pyrM.layers[l].w, pyrM.layers[l].h); + + //pyrA.layers[l].show(); + //pyrB.layers[l].show(); + //pyrM.layers[l].show(); + + //test.show(); + + cv::Mat normalized_mask = (1 / 255.0)*M_lvl; + cv::Mat normalized_mask_r = (1 / 255.0)*test.volume; + + layer.volume = A_lvl.mul(normalized_mask) + B_lvl.mul(normalized_mask_r); + //layer.show(); + + out.layers.push_back(layer); + } + + return out.collapse(); + } + + std::vector videoLaplacianBlendingContrib(PyramidLayer vidA, PyramidLayer vidB, PyramidLayer mask_volume, PyramidParameters params) + { + int num_lvls = params.num_levels; + + auto pyrA = sibr::buildVideoLaplacianPyramid(vidA, num_lvls, params); + auto pyrB = sibr::buildVideoLaplacianPyramid(vidB, num_lvls, params); + auto pyrM = sibr::buildVideoGaussianPyramid(mask_volume.volume, mask_volume.w, mask_volume.h, num_lvls, params); + + std::vector out(num_lvls); + + VideoLaplacianPyramid l_out; + l_out.params = params; + l_out.layers.resize(num_lvls); + +#pragma omp parallel for + for (int l = 0; l < num_lvls; ++l) { + + FullContribData data; + ContribData & data_s = data.scaled; + ContribData & data_ns = data.notScaled; + + sibr::PyramidLayer layer; + + layer.w = pyrA.layers[l].w; + layer.h = pyrA.layers[l].h; + layer.l = pyrA.layers[l].l; + + cv::Mat A_lvl = pyrA.layers[l].volume; + cv::Mat B_lvl = pyrB.layers[l].volume; + cv::Mat M_lvl = pyrM.layers[l].volume; + + cv::Mat rev_Mask = 255 - M_lvl; + sibr::PyramidLayer test(rev_Mask, pyrM.layers[l].w, pyrM.layers[l].h); + + cv::Mat normalized_mask = (1 / 255.0)*M_lvl; + cv::Mat normalized_mask_r = (1 / 255.0)*test.volume; + + layer.volume = A_lvl.mul(normalized_mask) + B_lvl.mul(normalized_mask_r); + l_out.layers[l] = layer; + + PyramidLayer mask = pyrM.layers[l]; + PyramidLayer partA = pyrA.layers[l]; + PyramidLayer partB = pyrB.layers[l]; + + data_ns.contrib = layer; + data_ns.mask = mask; + data_ns.partA = partA; + data_ns.partB = partB; + + for (int j = l - 1; j >= 0; --j) { + layer = upscale(pyrA.layers[j], layer, params); + mask = upscale(pyrA.layers[j], mask, params); + partA = upscale(pyrA.layers[j], partA, params); + partB = upscale(pyrA.layers[j], partB, params); + } + + data_s.contrib = layer; + data_s.mask = mask; + data_s.partA = partA; + data_s.partB = partB; + + out[l] = data; + } + + out[0].result = l_out.collapse(); + + return out; + } + + void videoLaplacianBlendingDebug(PyramidLayer vidA, PyramidLayer vidB, PyramidLayer mask_volume, PyramidParameters params) + { + int num_lvls = params.num_levels; + + auto pyrA = sibr::buildVideoLaplacianPyramid(vidA, num_lvls, params); + auto pyrB = sibr::buildVideoLaplacianPyramid(vidB, num_lvls, params); + auto pyrM = sibr::buildVideoGaussianPyramid(mask_volume.volume, mask_volume.w, mask_volume.h, num_lvls, params); + + VideoLaplacianPyramid out; + + //struct LayerData { + // int i; + //} data; + + + for (int l = 0; l < num_lvls; ++l) { + sibr::PyramidLayer layer; + layer.w = pyrA.layers[l].w; + layer.h = pyrA.layers[l].h; + layer.l = pyrA.layers[l].l; + + cv::Mat A_lvl = pyrA.layers[l].volume; + cv::Mat B_lvl = pyrB.layers[l].volume; + cv::Mat M_lvl = pyrM.layers[l].volume; + + layer.volume = A_lvl.mul(M_lvl) + B_lvl.mul(1.0f - M_lvl); + out.layers.push_back(layer); + } + + auto final_res = out.collapse(); + + } + + //int TimeHistogram::getModeId() const { + // return std::distance(bins.begin(), std::max_element(bins.begin(), bins.end())); + //} + +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/video/VideoUtils.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/video/VideoUtils.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e79dac1f66b746a7b399225916895b7f2f02d893 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/video/VideoUtils.hpp @@ -0,0 +1,1138 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include "Config.hpp" +#include +#include +#include "FFmpegVideoEncoder.hpp" + +namespace sibr { + + SIBR_VIDEO_EXPORT std::vector cvSplitChannels(cv::Mat mat); + + template + struct CV_Assign { + static void assignValue(uint c, const T & val, cv::Vec & vec) { + vec[c] = val; + } + }; + template + struct CV_Assign { + static void assignValue(uint c, const T & val, T & vec) { + vec = val; + } + }; + + template + cv::Mat cvConvertMatTo(cv::Mat mat, double scale = 1.0) { + if (mat.type() == getOpenCVtype) { + return mat; + } + + cv::Mat m, out; + const int nc = mat.channels(); + if (nc == N) { + m = mat; + } else { + std::vector in_channels = cvSplitChannels(mat), out_channels(N); + for (int i = 0; i < N; ++i) { + in_channels[i < nc ? i : (nc - 1)].copyTo(out_channels[i]); + } + cv::merge(out_channels, m); + } + + m.convertTo(out, getOpenCVtype, scale); + return out; + } + + template + class VideoVolume; + + using Volume3f = VideoVolume; + using Volume1f = VideoVolume; + using Volume4u = VideoVolume; + using Volume3u = VideoVolume; + using Volume1u = VideoVolume; + + /** + * \addtogroup sibr_video + * @{ + */ + template + class VideoVolume { + public: + using CVpixel = std::conditional_t>; + static const uint cv_type = getOpenCVtype; + + // data + int w = 0, h = 0, l = 0; + cv::Mat_ mat; + + // medthods + VideoVolume() {} + + VideoVolume(int _l, int _w, int _h) : l(_l), w(_w), h(_h) { + mat = cv::Mat_(l, w*h*N); + } + + VideoVolume(int _l, int _w, int _h, double value) : l(_l), w(_w), h(_h) { + mat = cv::Mat_(l, w*h*N, static_cast(value)); + } + + VideoVolume(cv::Mat other_volume, int _w, int _h) : w(_w), h(_h), l(other_volume.rows) { + if (other_volume.channels() * other_volume.cols * other_volume.rows != l*w*h*N) { + SIBR_ERR << l << " " << w << " " << h << " " << N << " : " << + other_volume.channels() << " " << other_volume.rows << " " << other_volume.cols << std::endl; + } + mat = other_volume; + } + + VideoVolume(const VideoVolume & other) : l(other.l) , w(other.w), h(other.h) { + mat = other.mat; + } + + template + void setupFrom(const VideoVolume & other) { + *this = VideoVolume(other.l, other.w, other.h); + } + + VideoVolume clone() const { + return VideoVolume(mat.clone(), w, h); + } + + template + VideoVolume convertTo() const { + VideoVolume out(l, w, h); + for (int f = 0; f < l; ++f) { + cvConvertMatTo(frame(f)).copyTo(out.frame(f)); + } + return out; + } + + void toggle(double d = 255) { + mat = d - mat; + } + + void shift(double d) { + mat += d; + } + void scale(double d) { + mat *= d; + } + template + void add(const VideoVolume & other) { + cv::add(mat, other.mat, mat, cv::noArray(), cv_type); + } + + template + void substract(const VideoVolume & other) { + cv::subtract(mat, other.mat, mat, cv::noArray(), cv_type); + } + + template + void multiply(const VideoVolume & other) { + for (int t = 0; t < l; ++t) { + cv::multiply(cvConvertMatTo(frame(t)), cvConvertMatTo(other.frame(t)), frame(t)); + } + } + + VideoVolume concat(const VideoVolume & other) const { + VideoVolume out(l + other.l, w, h); + mat.copyTo(out.mat.rowRange(0, l)); + other.mat.copyTo(out.mat.rowRange(l, l + other.l)); + return out; + } + + VideoVolume concatH(const VideoVolume & other) const { + VideoVolume out(l, w + other.w, h); +#pragma omp parallel for + for (int t = 0; t < l; ++t) { + cv::hconcat(std::vector>{frame(t), other.frame(t)}, out.frame(t)); + } + return out; + } + + VideoVolume applyMaskBinary(const Volume1u & mask) { + VideoVolume out = VideoVolume(l, w, h, 0); + for (int t = 0; t < l; ++t) { + frame(t).copyTo(out.frame(t), mask.frame(t)); + } + return out; + } + + VideoVolume swapRBchannels() const { + static_assert(N >= 3, "need 3 channels"); + VideoVolume out = VideoVolume(l, w, h, 0); + +#pragma omp parallel for + for (int t = 0; t < l; ++t) { + cv::cvtColor(frame(t), out.frame(t), cv::COLOR_BGR2RGB); + } + return out; + } + + template + VideoVolume applyMask(const VideoVolume & mask) { + VideoVolume out = VideoVolume(l, w, h); + for (int t = 0; t < l; ++t) { + cv::multiply(cvConvertMatTo(frame(t)), cvConvertMatTo(mask.frame(t)), out.frame(t), 1 / 255.0); + } + return out; + } + + template + void applyMaskInPlace(const VideoVolume & mask) { + for (int t = 0; t < l; ++t) { + cv::multiply(cvConvertMatTo(frame(t)), cvConvertMatTo(mask.frame(t)), frame(t), 1 / 255.0); + } + } + + VideoVolume cutFrames(int numBefore, int numAfter) { + int diff = l - (numBefore + numAfter); + assert(diff >= 0); + + VideoVolume out(diff, w, h); + mat(cv::Rect(0, numBefore, w*h*N, diff)).copyTo(out.mat); + return out; + } + + VideoVolume colorMapped(int colormap, double scaling = 1.0) { + + int custom_colormap_size; + /* + //twilight + static const float r[] = { 0.88575015840754434f, 0.88378520195539056f, 0.88172231059285788f, 0.8795410528270573f, 0.87724880858965482f, 0.87485347508575972f, 0.87233134085124076f, 0.86970474853509816f, 0.86696015505333579f, 0.86408985081463996f, 0.86110245436899846f, 0.85798259245670372f, 0.85472593189256985f, 0.85133714570857189f, 0.84780710702577922f, 0.8441261828674842f, 0.84030420805957784f, 0.83634031809191178f, 0.83222705712934408f, 0.82796894316013536f, 0.82357429680252847f, 0.81904654677937527f, 0.81438982121143089f, 0.8095999819094809f, 0.80469164429814577f, 0.79967075421267997f, 0.79454305089231114f, 0.78931445564608915f, 0.78399101042764918f, 0.77857892008227592f, 0.77308416590170936f, 0.76751108504417864f, 0.76186907937980286f, 0.75616443584381976f, 0.75040346765406696f, 0.74459247771890169f, 0.73873771700494939f, 0.73284543645523459f, 0.72692177512829703f, 0.72097280665536778f, 0.71500403076252128f, 0.70902078134539304f, 0.7030297722540817f, 0.6970365443886174f, 0.69104641009309098f, 0.68506446154395928f, 0.67909554499882152f, 0.67314422559426212f, 0.66721479803752815f, 0.6613112930078745f, 0.65543692326454717f, 0.64959573004253479f, 0.6437910831099849f, 0.63802586828545982f, 0.6323027138710603f, 0.62662402022604591f, 0.62099193064817548f, 0.61540846411770478f, 0.60987543176093062f, 0.60439434200274855f, 0.5989665814482068f, 0.59359335696837223f, 0.58827579780555495f, 0.58301487036932409f, 0.5778116438998202f, 0.5726668948158774f, 0.56758117853861967f, 0.56255515357219343f, 0.55758940419605174f, 0.55268450589347129f, 0.54784098153018634f, 0.54305932424018233f, 0.53834015575176275f, 0.53368389147728401f, 0.529090861832473f, 0.52456151470593582f, 0.52009627392235558f, 0.5156955988596057f, 0.51135992541601927f, 0.50708969576451657f, 0.5028853540415561f, 0.49874733661356069f, 0.4946761847863938f, 0.49067224938561221f, 0.4867359599430568f, 0.4828677867260272f, 0.47906816236197386f, 0.47533752394906287f, 0.47167629518877091f, 0.46808490970531597f, 0.46456376716303932f, 0.46111326647023881f, 0.45773377230160567f, 0.45442563977552913f, 0.45118918687617743f, 0.44802470933589172f, 0.44493246854215379f, 0.44191271766696399f, 0.43896563958048396f, 0.43609138958356369f, 0.43329008867358393f, 0.43056179073057571f, 0.42790652284925834f, 0.42532423665011354f, 0.42281485675772662f, 0.42037822361396326f, 0.41801414079233629f, 0.4157223260454232f, 0.41350245743314729f, 0.41135414697304568f, 0.4092768899914751f, 0.40727018694219069f, 0.40533343789303178f, 0.40346600333905397f, 0.40166714010896104f, 0.39993606933454834f, 0.3982719152586337f, 0.39667374905665609f, 0.39514058808207631f, 0.39367135736822567f, 0.39226494876209317f, 0.39092017571994903f, 0.38963580160340855f, 0.38841053300842432f, 0.38724301459330251f, 0.38613184178892102f, 0.38507556793651387f, 0.38407269378943537f, 0.38312168084402748f, 0.38222094988570376f, 0.38136887930454161f, 0.38056380696565623f, 0.37980403744848751f, 0.37908789283110761f, 0.378413635091359f, 0.37777949753513729f, 0.37718371844251231f, 0.37662448930806297f, 0.37610001286385814f, 0.37560846919442398f, 0.37514802505380473f, 0.37471686019302231f, 0.37431313199312338f, 0.37393499330475782f, 0.3735806215098284f, 0.37324816143326384f, 0.37293578646665032f, 0.37264166757849604f, 0.37236397858465387f, 0.37210089702443822f, 0.3718506155898596f, 0.37161133234400479f, 0.37138124223736607f, 0.37115856636209105f, 0.37094151551337329f, 0.37072833279422668f, 0.37051738634484427f, 0.37030682071842685f, 0.37009487130772695f, 0.36987980329025361f, 0.36965987626565955f, 0.36943334591276228f, 0.36919847837592484f, 0.36895355306596778f, 0.36869682231895268f, 0.36842655638020444f, 0.36814101479899719f, 0.36783843696531082f, 0.36751707094367697f, 0.36717513650699446f, 0.36681085540107988f, 0.36642243251550632f, 0.36600853966739794f, 0.36556698373538982f, 0.36509579845886808f, 0.36459308890125008f, 0.36405693022088509f, 0.36348537610385145f, 0.36287643560041027f, 0.36222809558295926f, 0.36153829010998356f, 0.36080493826624654f, 0.36002681809096376f, 0.35920088560930186f, 0.35832489966617809f, 0.35739663292915563f, 0.35641381143126327f, 0.35537415306906722f, 0.35427534960663759f, 0.35311574421123737f, 0.35189248608873791f, 0.35060304441931012f, 0.34924513554955644f, 0.34781653238777782f, 0.34631507175793091f, 0.34473901574536375f, 0.34308600291572294f, 0.34135411074506483f, 0.33954168752669694f, 0.33764732090671112f, 0.33566978565015315f, 0.33360804901486002f, 0.33146154891145124f, 0.32923005203231409f, 0.3269137124539796f, 0.32451307931207785f, 0.32202882276069322f, 0.31946262395497965f, 0.31681648089023501f, 0.31409278414755532f, 0.31129434479712365f, 0.30842444457210105f, 0.30548675819945936f, 0.30248536364574252f, 0.29942483960214772f, 0.29631000388905288f, 0.29314593096985248f, 0.28993792445176608f, 0.28669151388283165f, 0.28341239797185225f, 0.28010638576975472f, 0.27677939615815589f, 0.27343739342450812f, 0.27008637749114051f, 0.26673233211995284f, 0.26338121807151404f, 0.26003895187439957f, 0.25671191651083902f, 0.25340685873736807f, 0.25012845306199383f, 0.24688226237958999f, 0.24367372557466271f, 0.24050813332295939f, 0.23739062429054825f, 0.23433055727563878f, 0.23132955273021344f, 0.2283917709422868f, 0.22552164337737857f, 0.22272706739121817f, 0.22001251100779617f, 0.21737845072382705f, 0.21482843531473683f, 0.21237411048541005f, 0.21001214221188125f, 0.2077442377448806f, 0.20558051999470117f, 0.20352007949514977f, 0.20156133764129841f, 0.19971571438603364f, 0.19794834061899208f, 0.1960826032659409f, 0.19410351363791453f, 0.19199449184606268f, 0.18975853639094634f, 0.18739228342697645f, 0.18488035509396164f, 0.18774482037046955f, 0.19049578401722037f, 0.1931548636579131f, 0.19571853588267552f, 0.19819343656336558f, 0.20058760685133747f, 0.20290365333558247f, 0.20531725273301316f, 0.20785704662965598f, 0.21052882914958676f, 0.2133313859647627f, 0.21625279838647882f, 0.21930503925136402f, 0.22247308588973624f, 0.2257539681670791f, 0.22915620278592841f, 0.23266299920501882f, 0.23627495835774248f, 0.23999586188690308f, 0.24381149720247919f, 0.24772092990501099f, 0.25172899728289466f, 0.25582135547481771f, 0.25999463887892144f, 0.26425512207060942f, 0.26859095948172862f, 0.27299701518897301f, 0.27747150809142801f, 0.28201746297366942f, 0.28662309235899847f, 0.29128515387578635f, 0.2960004726065818f, 0.30077276812918691f, 0.30559226007249934f, 0.31045520848595526f, 0.31535870009205808f, 0.32029986557994061f, 0.32527888860401261f, 0.33029174471181438f, 0.33533353224455448f, 0.34040164359597463f, 0.34549355713871799f, 0.35060678246032478f, 0.35573889947341125f, 0.36088752387578377f, 0.36605031412464006f, 0.37122508431309342f, 0.3764103053221462f, 0.38160247377467543f, 0.38679939079544168f, 0.39199887556812907f, 0.39719876876325577f, 0.40239692379737496f, 0.40759120392688708f, 0.41277985630360303f, 0.41796105205173684f, 0.42313214269556043f, 0.42829101315789753f, 0.4334355841041439f, 0.43856378187931538f, 0.44367358645071275f, 0.44876299173174822f, 0.45383005086999889f, 0.45887288947308297f, 0.46389102840284874f, 0.46888111384598413f, 0.473841437035254f, 0.47877034239726296f, 0.48366628618847957f, 0.48852847371852987f, 0.49335504375145617f, 0.49814435462074153f, 0.50289524974970612f, 0.50760681181053691f, 0.51227835105321762f, 0.51690848800544464f, 0.52149652863229956f, 0.52604189625477482f, 0.53054420489856446f, 0.5350027976174474f, 0.53941736649199057f, 0.54378771313608565f, 0.54811370033467621f, 0.55239521572711914f, 0.55663229034969341f, 0.56082499039117173f, 0.56497343529017696f, 0.56907784784011428f, 0.57313845754107873f, 0.57715550812992045f, 0.58112932761586555f, 0.58506024396466882f, 0.58894861935544707f, 0.59279480536520257f, 0.59659918109122367f, 0.60036213010411577f, 0.60408401696732739f, 0.60776523994818654f, 0.6114062072731884f, 0.61500723236391375f, 0.61856865258877192f, 0.62209079821082613f, 0.62557416500434959f, 0.62901892016985872f, 0.63242534854210275f, 0.6357937104834237f, 0.6391243387840212f, 0.642417577481186f, 0.64567349382645434f, 0.64889230169458245f, 0.65207417290277303f, 0.65521932609327127f, 0.6583280801134499f, 0.66140037532601781f, 0.66443632469878844f, 0.66743603766369131f, 0.67039959547676198f, 0.67332725564817331f, 0.67621897924409746f, 0.67907474028157344f, 0.68189457150944521f, 0.68467850942494535f, 0.68742656435169625f, 0.6901389321505248f, 0.69281544846764931f, 0.69545608346891119f, 0.6980608153581771f, 0.70062962477242097f, 0.70316249458814151f, 0.70565951122610093f, 0.70812059568420482f, 0.7105456546582587f, 0.71293466839773467f, 0.71528760614847287f, 0.71760444908133847f, 0.71988521490549851f, 0.7221299918421461f, 0.72433865647781592f, 0.72651122900227549f, 0.72864773856716547f, 0.73074820754845171f, 0.73281270506268747f, 0.73484133598564938f, 0.73683422173585866f, 0.73879140024599266f, 0.74071301619506091f, 0.7425992159973317f, 0.74445018676570673f, 0.74626615789163442f, 0.74804739275559562f, 0.74979420547170472f, 0.75150685045891663f, 0.75318566369046569f, 0.75483105066959544f, 0.75644341577140706f, 0.75802325538455839f, 0.75957111105340058f, 0.7610876378057071f, 0.76257333554052609f, 0.76402885609288662f, 0.76545492593330511f, 0.76685228950643891f, 0.76822176599735303f, 0.7695642334401418f, 0.77088091962302474f, 0.77217257229605551f, 0.77344021829889886f, 0.77468494746063199f, 0.77590790730685699f, 0.7771103295521099f, 0.77829345807633121f, 0.77945862731506643f, 0.78060774749483774f, 0.78174180478981836f, 0.78286225264440912f, 0.78397060836414478f, 0.78506845019606841f, 0.78615737132332963f, 0.78723904108188347f, 0.78831514045623963f, 0.78938737766251943f, 0.79045776847727878f, 0.79152832843475607f, 0.79260034304237448f, 0.79367559698664958f, 0.79475585972654039f, 0.79584292379583765f, 0.79693854719951607f, 0.79804447815136637f, 0.7991624518501963f, 0.80029415389753977f, 0.80144124292560048f, 0.80260531146112946f, 0.80378792531077625f, 0.80499054790810298f, 0.80621460526927058f, 0.8074614045096935f, 0.80873219170089694f, 0.81002809466520687f, 0.81135014011763329f, 0.81269922039881493f, 0.81407611046993344f, 0.81548146627279483f, 0.81691575775055891f, 0.81837931164498223f, 0.81987230650455289f, 0.8213947205565636f, 0.82294635110428427f, 0.8245268129450285f, 0.82613549710580259f, 0.8277716072353446f, 0.82943407816481474f, 0.83112163529096306f, 0.83283277185777982f, 0.8345656905566583f, 0.83631898844737929f, 0.83809123476131964f, 0.83987839884120874f, 0.84167750766845151f, 0.84348529222933699f, 0.84529810731955113f, 0.84711195507965098f, 0.84892245563117641f, 0.85072697023178789f, 0.85251907207708444f, 0.85429219611470464f, 0.85604022314725403f, 0.85775662943504905f, 0.8594346370300241f, 0.86107117027565516f, 0.86265601051127572f, 0.86418343723941027f, 0.86564934325605325f, 0.86705314907048503f, 0.86839954695818633f, 0.86969131502613806f, 0.87093846717297507f, 0.87215331978454325f, 0.87335171360916275f, 0.87453793320260187f, 0.87571458709961403f, 0.87687848451614692f, 0.87802298436649007f, 0.87913244240792765f, 0.88019293315695812f, 0.88119169871341951f, 0.88211542489401606f, 0.88295168595448525f, 0.88369127145898041f, 0.88432713054113543f, 0.88485138159908572f, 0.88525897972630474f, 0.88554714811952384f, 0.88571155122845646f }; + static const float g[] = { 0.85000924943067835f, 0.85072940540310626f, 0.85127594077653468f, 0.85165675407495722f, 0.85187028338870274f, 0.85191526123023187f, 0.85180165478080894f, 0.85152403004797894f, 0.8510896085314068f, 0.85050391167507788f, 0.84976754857001258f, 0.84888934810281835f, 0.84787488124672816f, 0.84672735796116472f, 0.8454546229209523f, 0.84406482711037389f, 0.8425605950855084f, 0.84094796518951942f, 0.83923490627754482f, 0.83742600751395202f, 0.83552487764795436f, 0.8335364929949034f, 0.83146558694197847f, 0.82931896673505456f, 0.82709838780560663f, 0.82480781812080928f, 0.82245116226304615f, 0.82003213188702007f, 0.81755426400533426f, 0.81502089378742548f, 0.81243524735466011f, 0.8098007598713145f, 0.80711949387647486f, 0.80439408733477935f, 0.80162699008965321f, 0.79882047719583249f, 0.79597665735031009f, 0.79309746468844067f, 0.7901846863592763f, 0.78723995923452639f, 0.78426487091581187f, 0.78126088716070907f, 0.77822904973358131f, 0.77517050008066057f, 0.77208629460678091f, 0.7689774029354699f, 0.76584472131395898f, 0.76268908733890484f, 0.7595112803730375f, 0.75631202708719025f, 0.75309208756768431f, 0.74985201221941766f, 0.7465923800833657f, 0.74331376714033193f, 0.74001672160131404f, 0.73670175403699445f, 0.73336934798923203f, 0.73001995232739691f, 0.72665398759758293f, 0.7232718614323369f, 0.71987394892246725f, 0.7164606049658685f, 0.71303214646458135f, 0.70958887676997473f, 0.70613106157153982f, 0.7026589535425779f, 0.69917279302646274f, 0.69567278381629649f, 0.69215911458254054f, 0.68863194515166382f, 0.68509142218509878f, 0.68153767253065878f, 0.67797081129095405f, 0.67439093705212727f, 0.67079812302806219f, 0.66719242996142225f, 0.66357391434030388f, 0.65994260812897998f, 0.65629853981831865f, 0.65264172403146448f, 0.64897216734095264f, 0.6452898684900934f, 0.64159484119504429f, 0.63788704858847078f, 0.63416646251100506f, 0.6304330455306234f, 0.62668676251860134f, 0.62292757283835809f, 0.61915543242884641f, 0.61537028695790286f, 0.61157208822864151f, 0.607760777169989f, 0.60393630046586455f, 0.60009859503858665f, 0.59624762051353541f, 0.59238331452146575f, 0.5885055998308617f, 0.58461441100175571f, 0.58070969241098491f, 0.57679137998186081f, 0.57285941625606673f, 0.56891374572457176f, 0.5649543060909209f, 0.56098104959950301f, 0.55699392126996583f, 0.55299287158108168f, 0.54897785421888889f, 0.54494882715350401f, 0.54090574771098476f, 0.53684857765005933f, 0.53277730177130322f, 0.52869188011057411f, 0.52459228174983119f, 0.52047847653840029f, 0.51635044969688759f, 0.51220818143218516f, 0.50805166539276136f, 0.50388089053847973f, 0.49969585326377758f, 0.49549655777451179f, 0.49128300332899261f, 0.48705520251223039f, 0.48281316715123496f, 0.47855691131792805f, 0.47428645933635388f, 0.4700018340988123f, 0.46570306719930193f, 0.46139018782416635f, 0.45706323581407199f, 0.45272225034283325f, 0.44836727669277859f, 0.44399837208633719f, 0.43961558821222629f, 0.43521897612544935f, 0.43080859411413064f, 0.4263845142616835f, 0.42194680223454828f, 0.41749553747893614f, 0.41303079952477062f, 0.40855267638072096f, 0.4040612609993941f, 0.3995566498711684f, 0.39503894828283309f, 0.39050827529375831f, 0.38596474386057539f, 0.38140848555753937f, 0.37683963835219841f, 0.37225835004836849f, 0.36766477862108266f, 0.36305909736982378f, 0.35844148285875221f, 0.3538121372967869f, 0.34917126878479027f, 0.34451911410230168f, 0.33985591488818123f, 0.33518193808489577f, 0.33049741244307851f, 0.32580269697872455f, 0.3210981375964933f, 0.31638410101153364f, 0.31166098762951971f, 0.30692923551862339f, 0.30218932176507068f, 0.29744175492366276f, 0.29268709856150099f, 0.28792596437778462f, 0.28315901221182987f, 0.27838697181297761f, 0.27361063317090978f, 0.26883085667326956f, 0.26404857724525643f, 0.25926481158628106f, 0.25448043878086224f, 0.24969683475296395f, 0.24491536803550484f, 0.24013747024823828f, 0.23536470386204195f, 0.23059876218396419f, 0.22584149293287031f, 0.22109488427338303f, 0.21636111429594002f, 0.21164251793458128f, 0.20694122817889948f, 0.20226037920758122f, 0.197602942459778f, 0.19297208197842461f, 0.18837119869242164f, 0.18380392577704466f, 0.17927413271618647f, 0.17478570377561287f, 0.17034320478524959f, 0.16595129984720861f, 0.16161477763045118f, 0.15733863511152979f, 0.15312802296627787f, 0.14898820589826409f, 0.14492465359918028f, 0.1409427920655632f, 0.13704801896718169f, 0.13324562282438077f, 0.12954074251271822f, 0.12593818301005921f, 0.12244245263391232f, 0.11905764321981127f, 0.1157873496841953f, 0.11263459791730848f, 0.10960114111258401f, 0.10668879882392659f, 0.10389861387653518f, 0.10123077676403242f, 0.098684771934052201f, 0.096259385340577736f, 0.093952764840823738f, 0.091761187397303601f, 0.089682253716750038f, 0.087713250960463951f, 0.085850656889620708f, 0.08409078829085731f, 0.082429873848480689f, 0.080864153365499375f, 0.079389994802261526f, 0.078003941033788216f, 0.076702800237496066f, 0.075483675584275545f, 0.074344018028546205f, 0.073281657939897077f, 0.072294781043362205f, 0.071380106242082242f, 0.070533582926851829f, 0.069758206429106989f, 0.069053639449204451f, 0.068419855150922693f, 0.067857103814855602f, 0.067365888050555517f, 0.066935599661639394f, 0.066576186939090592f, 0.06628997924139618f, 0.066078173119395595f, 0.065933790675651943f, 0.065857918918907604f, 0.065859661233562045f, 0.065940385613778491f, 0.066085024661758446f, 0.066308573918947178f, 0.06661453200418091f, 0.066990462397868739f, 0.067444179612424215f, 0.067983271026200248f, 0.068592710553704722f, 0.069314066071660657f, 0.070321227242423623f, 0.071608304856891569f, 0.073182830649273306f, 0.075019861862143766f, 0.077102096899588329f, 0.079425730279723883f, 0.077251588468039312f, 0.075311278416787641f, 0.073606819040117955f, 0.072157781039602742f, 0.070974625252738788f, 0.070064576149984209f, 0.069435248580458964f, 0.068919592266397572f, 0.068484398797025281f, 0.06812195249816172f, 0.067830148426026665f, 0.067616330270516389f, 0.067465786362940039f, 0.067388214053092838f, 0.067382132300147474f, 0.067434730871152565f, 0.067557104388479783f, 0.06774359820987802f, 0.067985029964779953f, 0.068289851529011875f, 0.068653337909486523f, 0.069064630826035506f, 0.06953231029187984f, 0.070053855603861875f, 0.070616595622995437f, 0.071226716277922458f, 0.071883555446163511f, 0.072582969899254779f, 0.073315693214040967f, 0.074088460826808866f, 0.074899049847466703f, 0.075745336000958424f, 0.076617824336164764f, 0.077521963107537312f, 0.078456871676182177f, 0.079420997315243186f, 0.080412994737554838f, 0.081428390076546092f, 0.08246763389003825f, 0.083532434119003962f, 0.084622236191702671f, 0.085736654965126335f, 0.08687555176033529f, 0.088038974350243354f, 0.089227194362745205f, 0.090440685427697898f, 0.091679997480262732f, 0.092945198093777909f, 0.094238731263712183f, 0.09556181960083443f, 0.09691583650296684f, 0.098302320968278623f, 0.099722930314950553f, 0.10117945586419633f, 0.1026734006932461f, 0.10420644885760968f, 0.10578120994917611f, 0.1073997763055258f, 0.1090642347484701f, 0.11077667828375456f, 0.11253912421257944f, 0.11435355574622549f, 0.11622183788331528f, 0.11814571137706886f, 0.12012561256850712f, 0.12216445576414045f, 0.12426354237989065f, 0.12642401401409453f, 0.12864679022013889f, 0.13093210934893723f, 0.13328091630401023f, 0.13569380302451714f, 0.13817086581280427f, 0.14071192654913128f, 0.14331656120063752f, 0.14598463068714407f, 0.14871544765633712f, 0.15150818660835483f, 0.15436183633886777f, 0.15727540775107324f, 0.16024769309971934f, 0.16327738551419116f, 0.1663630904279047f, 0.16950338809328983f, 0.17269677158182117f, 0.17594170887918095f, 0.17923664950367169f, 0.18258004462335425f, 0.18597036007065024f, 0.18940601489760422f, 0.19288548904692518f, 0.19640737049066315f, 0.19997020971775276f, 0.20357251410079796f, 0.207212956082026f, 0.21089030138947745f, 0.21460331490206347f, 0.21835070166659282f, 0.22213124697023234f, 0.22594402043981826f, 0.22978799249179921f, 0.2336621873300741f, 0.23756535071152696f, 0.24149689191922535f, 0.24545598775548677f, 0.24944185818822678f, 0.25345365461983138f, 0.257490519876798f, 0.26155203161615281f, 0.26563755336209077f, 0.26974650525236699f, 0.27387826652410152f, 0.27803210957665631f, 0.28220778870555907f, 0.28640483614256179f, 0.29062280081258873f, 0.29486126309253047f, 0.29911962764489264f, 0.30339762792450425f, 0.30769497879760166f, 0.31201133280550686f, 0.31634634821222207f, 0.32069970535138104f, 0.32507091815606004f, 0.32945984647042675f, 0.33386622163232865f, 0.33828976326048621f, 0.34273019305341756f, 0.34718723719597999f, 0.35166052978120937f, 0.35614985523380299f, 0.36065500290840113f, 0.36517570519856757f, 0.36971170225223449f, 0.37426272710686193f, 0.37882848839337313f, 0.38340864508963057f, 0.38800301593162145f, 0.3926113126792577f, 0.39723324476747235f, 0.401868526884681f, 0.4065168468778026f, 0.41117787004519513f, 0.41585125850290111f, 0.42053672992315327f, 0.4252339389526239f, 0.42994254036133867f, 0.43466217184617112f, 0.43939245044973502f, 0.44413297780351974f, 0.44888333481548809f, 0.45364314496866825f, 0.45841199172949604f, 0.46318942799460555f, 0.46797501437948458f, 0.4727682731566229f, 0.47756871222057079f, 0.48237579130289127f, 0.48718906673415824f, 0.49200802533379656f, 0.49683212909727231f, 0.5016608471009063f, 0.50649362371287909f, 0.5113298901696085f, 0.51616892643469103f, 0.5210102658711383f, 0.52585332093451564f, 0.53069749384776732f, 0.53554217882461186f, 0.54038674910561235f, 0.54523059488426595f, 0.55007308413977274f, 0.55491335744890613f, 0.55975098052594863f, 0.56458533111166875f, 0.56941578326710418f, 0.5742417003617839f, 0.5790624629815756f, 0.58387743744557208f, 0.58868600173562435f, 0.5934875421745599f, 0.59828134277062461f, 0.60306670593147205f, 0.60784322087037024f, 0.61261029334072192f, 0.61736734400220705f, 0.62211378808451145f, 0.62684905679296699f, 0.63157258225089552f, 0.63628379372029187f, 0.64098213306749863f, 0.64566703459218766f, 0.65033793748103852f, 0.65499426549472628f, 0.65963545027564163f, 0.66426089585282289f, 0.6688700095398864f, 0.67346216702194517f, 0.67803672673971815f, 0.68259301546243389f, 0.68713033714618876f, 0.69164794791482131f, 0.69614505508308089f, 0.70062083014783982f, 0.70507438189635097f, 0.70950474978787481f, 0.7139109141951604f, 0.71829177331290062f, 0.72264614312088882f, 0.72697275518238258f, 0.73127023324078089f, 0.7355371221572935f, 0.73977184647638616f, 0.74397271817459876f, 0.7481379479992134f, 0.75226548952875261f, 0.75635314860808633f, 0.76039907199779677f, 0.76440101200982946f, 0.76835660399870176f, 0.77226338601044719f, 0.77611880236047159f, 0.77992021407650147f, 0.78366457342383888f, 0.78734936133548439f, 0.79097196777091994f, 0.79452963601550608f, 0.79801963142713928f, 0.8014392309950078f, 0.80478517909812231f, 0.80805523804261525f, 0.81124644224653542f, 0.81435544067514909f, 0.81737804041911244f, 0.82030875512181523f, 0.82314158859569164f, 0.82586857889438514f, 0.82848052823709672f, 0.83096715251272624f, 0.83331972948645461f, 0.8355302318472394f, 0.83759238071186537f, 0.83950165618540074f, 0.84125554884475906f, 0.84285224824778615f, 0.84429066717717349f, 0.84557007254559347f, 0.84668970275699273f, 0.84764891761519268f, 0.84844741572055415f, 0.84908426422893801f, 0.84955892810989209f, 0.84987174283631584f, 0.85002186115856315f }; + static const float b[] = { 0.8879736506427196f, 0.88723222096949894f, 0.88638056925514819f, 0.8854143767924102f, 0.88434120381311432f, 0.88316926967613829f, 0.88189704355001619f, 0.88053883390003362f, 0.87909766977173343f, 0.87757925784892632f, 0.87599242923439569f, 0.87434038553446281f, 0.8726282980930582f, 0.87086081657350445f, 0.86904036783694438f, 0.86716973322690072f, 0.865250882410458f, 0.86328528001070159f, 0.86127563500427884f, 0.85922399451306786f, 0.85713191328514948f, 0.85500206287010105f, 0.85283759062147024f, 0.85064441601050367f, 0.84842449296974021f, 0.84618210029578533f, 0.84392184786827984f, 0.8416486380471222f, 0.83936747464036732f, 0.8370834463093898f, 0.83480172950579679f, 0.83252816638059668f, 0.830266486168872f, 0.82802138994719998f, 0.82579737851082424f, 0.82359867586156521f, 0.82142922780433014f, 0.81929263384230377f, 0.81719217466726379f, 0.81513073920879264f, 0.81311116559949914f, 0.81113591855117928f, 0.80920618848056969f, 0.80732335380063447f, 0.80548841690679074f, 0.80370206267176914f, 0.8019646617300199f, 0.80027628545809526f, 0.79863674654537764f, 0.7970456043491897f, 0.79550271129031047f, 0.79400674021499107f, 0.79255653201306053f, 0.79115100459573173f, 0.78978892762640429f, 0.78846901316334561f, 0.78718994624696581f, 0.78595022706750484f, 0.78474835732694714f, 0.78358295593535587f, 0.78245259899346642f, 0.78135588237640097f, 0.78029141405636515f, 0.77925781820476592f, 0.77825345121025524f, 0.77727702680911992f, 0.77632748534275298f, 0.77540359142309845f, 0.7745041337932782f, 0.7736279426902245f, 0.77277386473440868f, 0.77194079697835083f, 0.77112734439057717f, 0.7703325054879735f, 0.76955552292313134f, 0.76879541714230948f, 0.76805119403344102f, 0.76732191489596169f, 0.76660663780645333f, 0.76590445660835849f, 0.76521446718174913f, 0.76453578734180083f, 0.76386719002130909f, 0.76320812763163837f, 0.76255780085924041f, 0.76191537149895305f, 0.76128000375662419f, 0.76065085571817748f, 0.76002709227883047f, 0.75940789891092741f, 0.75879242623025811f, 0.75817986436807139f, 0.75756936901859162f, 0.75696013660606487f, 0.75635120643246645f, 0.75574176474107924f, 0.7551311041857901f, 0.75451838884410671f, 0.75390276208285945f, 0.7532834105961016f, 0.75265946532566674f, 0.75203008099312696f, 0.75139443521914839f, 0.75075164989005116f, 0.75010086988227642f, 0.7494412559451894f, 0.74877193167001121f, 0.74809204459000522f, 0.74740073297543086f, 0.74669712855065784f, 0.74598030635707824f, 0.74524942637581271f, 0.74450365836708132f, 0.74374215223567086f, 0.7429640345324835f, 0.74216844571317986f, 0.74135450918099721f, 0.74052138580516735f, 0.73966820211715711f, 0.738794102296364f, 0.73789824784475078f, 0.73697977133881254f, 0.73603782546932739f, 0.73507157641157261f, 0.73408016787854391f, 0.7330627749243106f, 0.73201854033690505f, 0.73094665432902683f, 0.72984626791353258f, 0.72871656144003782f, 0.72755671317141346f, 0.72636587045135315f, 0.72514323778761092f, 0.72388798691323131f, 0.72259931993061044f, 0.72127639993530235f, 0.71991841524475775f, 0.71852454736176108f, 0.71709396919920232f, 0.71562585091587549f, 0.7141193695725726f, 0.71257368516500463f, 0.71098796522377461f, 0.70936134293478448f, 0.70769297607310577f, 0.70598200974806036f, 0.70422755780589941f, 0.7024287314570723f, 0.70058463496520773f, 0.69869434615073722f, 0.69675695810256544f, 0.69477149919380887f, 0.69273703471928827f, 0.69065253586464992f, 0.68851703379505125f, 0.68632948169606767f, 0.68408888788857214f, 0.68179411684486679f, 0.67944405399056851f, 0.67703755438090574f, 0.67457344743419545f, 0.67205052849120617f, 0.66946754331614522f, 0.66682322089824264f, 0.66411625298236909f, 0.66134526910944602f, 0.65850888806972308f, 0.65560566838453704f, 0.65263411711618635f, 0.64959272297892245f, 0.64647991652908243f, 0.64329409140765537f, 0.64003361803368586f, 0.63669675187488584f, 0.63328173520055586f, 0.62978680155026101f, 0.62621013451953023f, 0.62254988622392882f, 0.61880417410823019f, 0.61497112346096128f, 0.61104880679640927f, 0.60703532172064711f, 0.60292845431916875f, 0.5987265295935138f, 0.59442768517501066f, 0.59003011251063131f, 0.5855320765920552f, 0.58093191431832802f, 0.57622809660668717f, 0.57141871523555288f, 0.56650284911216653f, 0.56147964703993225f, 0.55634837474163779f, 0.55110853452703257f, 0.5457599924248665f, 0.54030245920406539f, 0.53473704282067103f, 0.52906500940336754f, 0.52328797535085236f, 0.51740807573979475f, 0.51142807215168951f, 0.50535164796654897f, 0.49918274588431072f, 0.49292595612342666f, 0.48658646495697461f, 0.48017007211645196f, 0.47368494725726878f, 0.46713728801395243f, 0.46053414662739794f, 0.45388335612058467f, 0.44719313715161618f, 0.44047194882050544f, 0.43372849999361113f, 0.42697404043749887f, 0.42021619665853854f, 0.41346259134143476f, 0.40672178082365834f, 0.40000214725256295f, 0.39331182532243375f, 0.38665868550105914f, 0.38005028528138707f, 0.37349382846504675f, 0.36699616136347685f, 0.36056376228111864f, 0.35420276066240958f, 0.34791888996380105f, 0.3417175669546984f, 0.33560648984600089f, 0.3295945757321303f, 0.32368100685760637f, 0.31786993834254956f, 0.31216524050888372f, 0.30657054493678321f, 0.30108922184065873f, 0.29574009929867601f, 0.29051361067988485f, 0.28541074411068496f, 0.28043398847505197f, 0.27559714652053702f, 0.27090279994325861f, 0.26634209349669508f, 0.26191675992376573f, 0.25765165093569542f, 0.2535289048041211f, 0.24954644291943817f, 0.24572497420147632f, 0.24205576625191821f, 0.23852974228695395f, 0.23517094067076993f, 0.23194647381302336f, 0.22874673279569585f, 0.22558727307410353f, 0.22243385243433622f, 0.2193005075652994f, 0.21618875376309582f, 0.21307651648984993f, 0.21387448578597812f, 0.2146562337112265f, 0.21542362939081539f, 0.21617499187076789f, 0.21690975060032436f, 0.21762721310371608f, 0.21833167885096033f, 0.21911516689288835f, 0.22000133917653536f, 0.22098759107715404f, 0.22207043213024291f, 0.22324568672294431f, 0.22451023616807558f, 0.22585960379408354f, 0.22728984778098055f, 0.22879681433956656f, 0.23037617493752832f, 0.23202360805926608f, 0.23373434258507808f, 0.23550427698321885f, 0.2373288009471749f, 0.23920260612763083f, 0.24112190491594204f, 0.24308218808684579f, 0.24507758869355967f, 0.24710443563450618f, 0.24915847093232929f, 0.25123493995942769f, 0.25332800295084507f, 0.25543478673717029f, 0.25755101595750435f, 0.25967245030364566f, 0.26179294097819672f, 0.26391006692119662f, 0.2660200572779356f, 0.26811904076941961f, 0.27020322893039511f, 0.27226772884656186f, 0.27430929404579435f, 0.27632534356790039f, 0.27831254595259397f, 0.28026769921081435f, 0.28218770540182386f, 0.2840695897279818f, 0.28591050458531014f, 0.2877077458811747f, 0.28945865397633169f, 0.29116024157313919f, 0.29281107506269488f, 0.29440901248173756f, 0.29595212005509081f, 0.29743856476285779f, 0.29886674369733968f, 0.30023519507728602f, 0.30154226437468967f, 0.30278652039631843f, 0.3039675809469457f, 0.30508479060294547f, 0.30613767928289148f, 0.30712600062348083f, 0.30804973095465449f, 0.30890905921943196f, 0.30970441249844921f, 0.31043636979038808f, 0.31110343446582983f, 0.31170911458932665f, 0.31225470169927194f, 0.31274172735821959f, 0.31317188565991266f, 0.31354553695453014f, 0.31386561956734976f, 0.314135190862664f, 0.31435662153833671f, 0.31453200120082569f, 0.3146630922831542f, 0.31475407592280041f, 0.31480767954534428f, 0.31482653406646727f, 0.31481299789187128f, 0.31477085207396532f, 0.31470295028655965f, 0.31461204226295625f, 0.31450102990914708f, 0.31437291554615371f, 0.31423043195101424f, 0.31407639883970623f, 0.3139136046337036f, 0.31374440956796529f, 0.31357126868520002f, 0.31339704333572083f, 0.31322399394183942f, 0.31305401163732732f, 0.31288922211590126f, 0.31273234839304942f, 0.31258523031121233f, 0.31244934410414688f, 0.31232652641170694f, 0.31221903291870201f, 0.31212881396435238f, 0.31205680685765741f, 0.31200463838728931f, 0.31197383273627388f, 0.31196698314912269f, 0.31198447195645718f, 0.31202765974624452f, 0.31209793953300591f, 0.31219689612063978f, 0.31232631707560987f, 0.31248673753935263f, 0.31267941819570189f, 0.31290560605819168f, 0.3131666792687211f, 0.3134643447952643f, 0.31379912926498488f, 0.31417223403606975f, 0.31458483752056837f, 0.31503813956872212f, 0.31553372323982209f, 0.3160724937230589f, 0.31665545668946665f, 0.31728380489244951f, 0.31795870784057567f, 0.31868137622277692f, 0.31945332332898302f, 0.3202754315314667f, 0.32114884306985791f, 0.32207478855218091f, 0.32305449047765694f, 0.32408913679491225f, 0.32518014084085567f, 0.32632861885644465f, 0.32753574162788762f, 0.3288027427038317f, 0.3301308728723546f, 0.33152138620958932f, 0.33297555200245399f, 0.33449469983585844f, 0.33607995965691828f, 0.3377325942005665f, 0.33945384341064017f, 0.3412449533046818f, 0.34310715173410822f, 0.34504169470809071f, 0.34704978520758401f, 0.34913260148542435f, 0.35129130890802607f, 0.35352709245374592f, 0.35584108091122535f, 0.35823439142300639f, 0.36070813602540136f, 0.36326337558360278f, 0.36590112443835765f, 0.36862236642234769f, 0.3714280448394211f, 0.37431909037543515f, 0.37729635531096678f, 0.380360657784311f, 0.38351275723852291f, 0.38675335037837993f, 0.39008308392311997f, 0.39350254000115381f, 0.39701221751773474f, 0.40061257089416885f, 0.40430398069682483f, 0.40808667584648967f, 0.41196089987122869f, 0.41592679539764366f, 0.41998440356963762f, 0.42413367909988375f, 0.42837450371258479f, 0.432706647838971f, 0.43712979856444761f, 0.44164332426364639f, 0.44624687186865436f, 0.45093985823706345f, 0.45572154742892063f, 0.46059116206904965f, 0.46554778281918402f, 0.47059039582133383f, 0.47571791879076081f, 0.48092913815357724f, 0.48622257801969754f, 0.49159667021646397f, 0.49705020621532009f, 0.50258161291269432f, 0.50818921213102985f, 0.51387124091909786f, 0.5196258425240281f, 0.52545108144834785f, 0.53134495942561433f, 0.53730535185141037f, 0.5433300863249918f, 0.54941691584603647f, 0.55556350867083815f, 0.56176745110546977f, 0.56802629178649788f, 0.57433746373459582f, 0.58069834805576737f, 0.58710626908082753f, 0.59355848909050757f, 0.60005214820435104f, 0.6065843782630862f, 0.61315221209322646f, 0.61975260637257923f, 0.62638245478933297f, 0.63303857040067113f, 0.63971766697672761f, 0.6464164243818421f, 0.65313137915422603f, 0.65985900156216504f, 0.66659570204682972f, 0.67333772009301907f, 0.68008125203631464f, 0.68682235874648545f, 0.69355697649863846f, 0.70027999028864962f, 0.70698561390212977f, 0.71367147811129228f, 0.72033299387284622f, 0.72696536998972039f, 0.73356368240541492f, 0.74012275762807056f, 0.74663719293664366f, 0.7530974636118285f, 0.7594994148789691f, 0.76583801477914104f, 0.77210610037674143f, 0.77829571667247499f, 0.78439788751383921f, 0.79039529663736285f, 0.796282666437655f, 0.80204612696863953f, 0.80766972324164554f, 0.81313419626911398f, 0.81841638963128993f, 0.82350476683173168f, 0.82838497261149613f, 0.8330486712880828f, 0.83748851001197089f, 0.84171925358069011f, 0.84575537519027078f, 0.84961373549150254f, 0.85330645352458923f, 0.85685572291039636f, 0.86027399927156634f, 0.86356595168669881f, 0.86673765046233331f, 0.86979617048190971f, 0.87274147101441557f, 0.87556785228242973f, 0.87828235285372469f, 0.88088414794024839f, 0.88336206121170946f, 0.88572538990087124f }; + custom_colormap_size = 510; + */ + + //inferno + static const float r[] = { 0.001462f, 0.002267f, 0.003299f, 0.004547f, 0.006006f, 0.007676f, 0.009561f, 0.011663f, 0.013995f, 0.016561f, 0.019373f, 0.022447f, 0.025793f, 0.029432f, 0.033385f, 0.037668f, 0.042253f, 0.046915f, 0.051644f, 0.056449f, 0.061340f, 0.066331f, 0.071429f, 0.076637f, 0.081962f, 0.087411f, 0.092990f, 0.098702f, 0.104551f, 0.110536f, 0.116656f, 0.122908f, 0.129285f, 0.135778f, 0.142378f, 0.149073f, 0.155850f, 0.162689f, 0.169575f, 0.176493f, 0.183429f, 0.190367f, 0.197297f, 0.204209f, 0.211095f, 0.217949f, 0.224763f, 0.231538f, 0.238273f, 0.244967f, 0.251620f, 0.258234f, 0.264810f, 0.271347f, 0.277850f, 0.284321f, 0.290763f, 0.297178f, 0.303568f, 0.309935f, 0.316282f, 0.322610f, 0.328921f, 0.335217f, 0.341500f, 0.347771f, 0.354032f, 0.360284f, 0.366529f, 0.372768f, 0.379001f, 0.385228f, 0.391453f, 0.397674f, 0.403894f, 0.410113f, 0.416331f, 0.422549f, 0.428768f, 0.434987f, 0.441207f, 0.447428f, 0.453651f, 0.459875f, 0.466100f, 0.472328f, 0.478558f, 0.484789f, 0.491022f, 0.497257f, 0.503493f, 0.509730f, 0.515967f, 0.522206f, 0.528444f, 0.534683f, 0.540920f, 0.547157f, 0.553392f, 0.559624f, 0.565854f, 0.572081f, 0.578304f, 0.584521f, 0.590734f, 0.596940f, 0.603139f, 0.609330f, 0.615513f, 0.621685f, 0.627847f, 0.633998f, 0.640135f, 0.646260f, 0.652369f, 0.658463f, 0.664540f, 0.670599f, 0.676638f, 0.682656f, 0.688653f, 0.694627f, 0.700576f, 0.706500f, 0.712396f, 0.718264f, 0.724103f, 0.729909f, 0.735683f, 0.741423f, 0.747127f, 0.752794f, 0.758422f, 0.764010f, 0.769556f, 0.775059f, 0.780517f, 0.785929f, 0.791293f, 0.796607f, 0.801871f, 0.807082f, 0.812239f, 0.817341f, 0.822386f, 0.827372f, 0.832299f, 0.837165f, 0.841969f, 0.846709f, 0.851384f, 0.855992f, 0.860533f, 0.865006f, 0.869409f, 0.873741f, 0.878001f, 0.882188f, 0.886302f, 0.890341f, 0.894305f, 0.898192f, 0.902003f, 0.905735f, 0.909390f, 0.912966f, 0.916462f, 0.919879f, 0.923215f, 0.926470f, 0.929644f, 0.932737f, 0.935747f, 0.938675f, 0.941521f, 0.944285f, 0.946965f, 0.949562f, 0.952075f, 0.954506f, 0.956852f, 0.959114f, 0.961293f, 0.963387f, 0.965397f, 0.967322f, 0.969163f, 0.970919f, 0.972590f, 0.974176f, 0.975677f, 0.977092f, 0.978422f, 0.979666f, 0.980824f, 0.981895f, 0.982881f, 0.983779f, 0.984591f, 0.985315f, 0.985952f, 0.986502f, 0.986964f, 0.987337f, 0.987622f, 0.987819f, 0.987926f, 0.987945f, 0.987874f, 0.987714f, 0.987464f, 0.987124f, 0.986694f, 0.986175f, 0.985566f, 0.984865f, 0.984075f, 0.983196f, 0.982228f, 0.981173f, 0.980032f, 0.978806f, 0.977497f, 0.976108f, 0.974638f, 0.973088f, 0.971468f, 0.969783f, 0.968041f, 0.966243f, 0.964394f, 0.962517f, 0.960626f, 0.958720f, 0.956834f, 0.954997f, 0.953215f, 0.951546f, 0.950018f, 0.948683f, 0.947594f, 0.946809f, 0.946392f, 0.946403f, 0.946903f, 0.947937f, 0.949545f, 0.951740f, 0.954529f, 0.957896f, 0.961812f, 0.966249f, 0.971162f, 0.976511f, 0.982257f, 0.988362f }; + static const float g[] = { 0.000466f, 0.001270f, 0.002249f, 0.003392f, 0.004692f, 0.006136f, 0.007713f, 0.009417f, 0.011225f, 0.013136f, 0.015133f, 0.017199f, 0.019331f, 0.021503f, 0.023702f, 0.025921f, 0.028139f, 0.030324f, 0.032474f, 0.034569f, 0.036590f, 0.038504f, 0.040294f, 0.041905f, 0.043328f, 0.044556f, 0.045583f, 0.046402f, 0.047008f, 0.047399f, 0.047574f, 0.047536f, 0.047293f, 0.046856f, 0.046242f, 0.045468f, 0.044559f, 0.043554f, 0.042489f, 0.041402f, 0.040329f, 0.039309f, 0.038400f, 0.037632f, 0.037030f, 0.036615f, 0.036405f, 0.036405f, 0.036621f, 0.037055f, 0.037705f, 0.038571f, 0.039647f, 0.040922f, 0.042353f, 0.043933f, 0.045644f, 0.047470f, 0.049396f, 0.051407f, 0.053490f, 0.055634f, 0.057827f, 0.060060f, 0.062325f, 0.064616f, 0.066925f, 0.069247f, 0.071579f, 0.073915f, 0.076253f, 0.078591f, 0.080927f, 0.083257f, 0.085580f, 0.087896f, 0.090203f, 0.092501f, 0.094790f, 0.097069f, 0.099338f, 0.101597f, 0.103848f, 0.106089f, 0.108322f, 0.110547f, 0.112764f, 0.114974f, 0.117179f, 0.119379f, 0.121575f, 0.123769f, 0.125960f, 0.128150f, 0.130341f, 0.132534f, 0.134729f, 0.136929f, 0.139134f, 0.141346f, 0.143567f, 0.145797f, 0.148039f, 0.150294f, 0.152563f, 0.154848f, 0.157151f, 0.159474f, 0.161817f, 0.164184f, 0.166575f, 0.168992f, 0.171438f, 0.173914f, 0.176421f, 0.178962f, 0.181539f, 0.184153f, 0.186807f, 0.189501f, 0.192239f, 0.195021f, 0.197851f, 0.200728f, 0.203656f, 0.206636f, 0.209670f, 0.212759f, 0.215906f, 0.219112f, 0.222378f, 0.225706f, 0.229097f, 0.232554f, 0.236077f, 0.239667f, 0.243327f, 0.247056f, 0.250856f, 0.254728f, 0.258674f, 0.262692f, 0.266786f, 0.270954f, 0.275197f, 0.279517f, 0.283913f, 0.288385f, 0.292933f, 0.297559f, 0.302260f, 0.307038f, 0.311892f, 0.316822f, 0.321827f, 0.326906f, 0.332060f, 0.337287f, 0.342586f, 0.347957f, 0.353399f, 0.358911f, 0.364492f, 0.370140f, 0.375856f, 0.381636f, 0.387481f, 0.393389f, 0.399359f, 0.405389f, 0.411479f, 0.417627f, 0.423831f, 0.430091f, 0.436405f, 0.442772f, 0.449191f, 0.455660f, 0.462178f, 0.468744f, 0.475356f, 0.482014f, 0.488716f, 0.495462f, 0.502249f, 0.509078f, 0.515946f, 0.522853f, 0.529798f, 0.536780f, 0.543798f, 0.550850f, 0.557937f, 0.565057f, 0.572209f, 0.579392f, 0.586606f, 0.593849f, 0.601122f, 0.608422f, 0.615750f, 0.623105f, 0.630485f, 0.637890f, 0.645320f, 0.652773f, 0.660250f, 0.667748f, 0.675267f, 0.682807f, 0.690366f, 0.697944f, 0.705540f, 0.713153f, 0.720782f, 0.728427f, 0.736087f, 0.743758f, 0.751442f, 0.759135f, 0.766837f, 0.774545f, 0.782258f, 0.789974f, 0.797692f, 0.805409f, 0.813122f, 0.820825f, 0.828515f, 0.836191f, 0.843848f, 0.851476f, 0.859069f, 0.866624f, 0.874129f, 0.881569f, 0.888942f, 0.896226f, 0.903409f, 0.910473f, 0.917399f, 0.924168f, 0.930761f, 0.937159f, 0.943348f, 0.949318f, 0.955063f, 0.960587f, 0.965896f, 0.971003f, 0.975924f, 0.980678f, 0.985282f, 0.989753f, 0.994109f, 0.998364f }; + static const float b[] = { 0.013866f, 0.018570f, 0.024239f, 0.030909f, 0.038558f, 0.046836f, 0.055143f, 0.063460f, 0.071862f, 0.080282f, 0.088767f, 0.097327f, 0.105930f, 0.114621f, 0.123397f, 0.132232f, 0.141141f, 0.150164f, 0.159254f, 0.168414f, 0.177642f, 0.186962f, 0.196354f, 0.205799f, 0.215289f, 0.224813f, 0.234358f, 0.243904f, 0.253430f, 0.262912f, 0.272321f, 0.281624f, 0.290788f, 0.299776f, 0.308553f, 0.317085f, 0.325338f, 0.333277f, 0.340874f, 0.348111f, 0.354971f, 0.361447f, 0.367535f, 0.373238f, 0.378563f, 0.383522f, 0.388129f, 0.392400f, 0.396353f, 0.400007f, 0.403378f, 0.406485f, 0.409345f, 0.411976f, 0.414392f, 0.416608f, 0.418637f, 0.420491f, 0.422182f, 0.423721f, 0.425116f, 0.426377f, 0.427511f, 0.428524f, 0.429425f, 0.430217f, 0.430906f, 0.431497f, 0.431994f, 0.432400f, 0.432719f, 0.432955f, 0.433109f, 0.433183f, 0.433179f, 0.433098f, 0.432943f, 0.432714f, 0.432412f, 0.432039f, 0.431594f, 0.431080f, 0.430498f, 0.429846f, 0.429125f, 0.428334f, 0.427475f, 0.426548f, 0.425552f, 0.424488f, 0.423356f, 0.422156f, 0.420887f, 0.419549f, 0.418142f, 0.416667f, 0.415123f, 0.413511f, 0.411829f, 0.410078f, 0.408258f, 0.406369f, 0.404411f, 0.402385f, 0.400290f, 0.398125f, 0.395891f, 0.393589f, 0.391219f, 0.388781f, 0.386276f, 0.383704f, 0.381065f, 0.378359f, 0.375586f, 0.372748f, 0.369846f, 0.366879f, 0.363849f, 0.360757f, 0.357603f, 0.354388f, 0.351113f, 0.347777f, 0.344383f, 0.340931f, 0.337424f, 0.333861f, 0.330245f, 0.326576f, 0.322856f, 0.319085f, 0.315266f, 0.311399f, 0.307485f, 0.303526f, 0.299523f, 0.295477f, 0.291390f, 0.287264f, 0.283099f, 0.278898f, 0.274661f, 0.270390f, 0.266085f, 0.261750f, 0.257383f, 0.252988f, 0.248564f, 0.244113f, 0.239636f, 0.235133f, 0.230606f, 0.226055f, 0.221482f, 0.216886f, 0.212268f, 0.207628f, 0.202968f, 0.198286f, 0.193584f, 0.188860f, 0.184116f, 0.179350f, 0.174563f, 0.169755f, 0.164924f, 0.160070f, 0.155193f, 0.150292f, 0.145367f, 0.140417f, 0.135440f, 0.130438f, 0.125409f, 0.120354f, 0.115272f, 0.110164f, 0.105031f, 0.099874f, 0.094695f, 0.089499f, 0.084289f, 0.079073f, 0.073859f, 0.068659f, 0.063488f, 0.058367f, 0.053324f, 0.048392f, 0.043618f, 0.039050f, 0.034931f, 0.031409f, 0.028508f, 0.026250f, 0.024661f, 0.023770f, 0.023606f, 0.024202f, 0.025592f, 0.027814f, 0.030908f, 0.034916f, 0.039886f, 0.045581f, 0.051750f, 0.058329f, 0.065257f, 0.072489f, 0.079990f, 0.087731f, 0.095694f, 0.103863f, 0.112229f, 0.120785f, 0.129527f, 0.138453f, 0.147565f, 0.156863f, 0.166353f, 0.176037f, 0.185923f, 0.196018f, 0.206332f, 0.216877f, 0.227658f, 0.238686f, 0.249972f, 0.261534f, 0.273391f, 0.285546f, 0.298010f, 0.310820f, 0.323974f, 0.337475f, 0.351369f, 0.365627f, 0.380271f, 0.395289f, 0.410665f, 0.426373f, 0.442367f, 0.458592f, 0.474970f, 0.491426f, 0.507860f, 0.524203f, 0.540361f, 0.556275f, 0.571925f, 0.587206f, 0.602154f, 0.616760f, 0.631017f, 0.644924f }; + custom_colormap_size = 256; + + static cv::Mat custom_colormap; + static bool first = true; + + if (first) { + cv::Mat red(custom_colormap_size, 1, CV_32FC1, (void*)r), + green(custom_colormap_size, 1, CV_32FC1, (void*)g), + blue(custom_colormap_size, 1, CV_32FC1, (void*)b); + + cv::merge(std::vector{red, green, blue}, custom_colormap); + cv::resize(custom_colormap, custom_colormap, cv::Size(1, 256)); + custom_colormap.convertTo(custom_colormap, CV_8UC3, 255.0); + + first = false; + } + + VideoVolume out(l, w, h); + for (int f = 0; f < l; ++f) { + cv::Mat ff = 4.0*(frame(f) - 128) + 128; + //cv::applyColorMap(cvConvertMatTo(ff, scaling), out.frame(f), custom_colormap); + cvConvertMatTo(ff, scaling).copyTo(out.frame(f)); + } + return out; + } + + void temporalBlur(float scaling = 1.0f) { + const cv::Mat1f kernel = (scaling / 16.0f)*(cv::Mat1f(5, 1) << 1, 4, 6, 4, 1); + cv::filter2D(mat, mat, -1, kernel, cv::Point(-1, -1), 0.0, cv::BORDER_DEFAULT); + } + + void temporalBlurBoundaryConditions(float scaling, double left, double right) { + const cv::Mat1f kernel = (scaling / 16.0f)*(cv::Mat1f(5, 1) << 1, 4, 6, 4, 1); + + VideoVolume tmp(l, w, h); + for (int i = 0; i < h; ++i) { + for (int j = 0; j < w; ++j) { + for (int c = 0; c < N; ++c) { + for (int t = 0; t < l; ++t) { + double res = 0; + for (int dt = -2; dt <= 2; ++dt) { + int u = t + dt; + double w = kernel(2 + dt), val; + if (u < 0) { + val = left; + } else if (u >= l) { + val = right; + } else { + val = valueAt(u, i, j, c); + } + res += w * val; + } + tmp.valueAt(t, i, j, c) = cv::saturate_cast(res) ; + } + } + } + } + std::swap(mat, tmp.mat); + } + + void extendedTemporalBlur() { + //const cv::Mat kernel = (1 / 5.0f)*(cv::Mat_(5, 1) << 1, 1, 1, 1, 1); + //cv::filter2D(mat, mat, -1, kernel, cv::Point(-1, -1), cv::BORDER_REPLICATE); + cv::boxFilter(mat, mat, -1, cv::Size(1, 25), cv::Point(-1, -1), true, cv::BORDER_REPLICATE); + } + + VideoVolume pyrDownSpacial() const { + VideoVolume out(l, (w + 1) / 2, (h + 1) / 2); + for (int f = 0; f < l; ++f) { + cv::pyrDown(frame(f), out.frame(f)); + } + return out; + } + + VideoVolume pyrDownTemporalModif() { + temporalBlur(); + VideoVolume out((l + 1) / 2, w, h); + for (int f = 0; f < out.l; ++f) { + frame(2 * f).copyTo(out.frame(f)); + } + return out; + } + + VideoVolume pyrDownTemporal() const { + VideoVolume tmp(mat.clone(), w, h); + return tmp.pyrDownTemporalModif(); + } + + VideoVolume pyrDownTemporalBox() const { + VideoVolume tmp(l, w, h); + const cv::Mat kernel = (1.0 / 16.0f)*(cv::Mat_(5, 1) << 1, 4, 6, 4, 1); + cv::filter2D(mat, tmp.mat, -1, kernel, cv::Point(-1, -1), 0.0, cv::BORDER_REPLICATE); + //cv::boxFilter(mat, tmp.mat, -1, cv::Size(1, 5), { -1,-1 }, true, cv::BORDER_REPLICATE); + VideoVolume out((l + 1) / 2, w, h); + cv::resize(tmp.mat, out.mat, out.mat.size(), 0, 0, cv::INTER_LINEAR); + return out; + } + + VideoVolume extendedDownScaleTemporal() const { + VideoVolume tmp(mat.clone(), w, h); + tmp.extendedTemporalBlur(); + VideoVolume out((l + 1) / 2, w, h); + for (int f = 0; f < out.l; ++f) { + tmp.frame(2 * f).copyTo(out.frame(f)); + } + return out; + } + + VideoVolume pyrDown() const { + return pyrDownSpacial().pyrDownTemporalModif(); + } + + VideoVolume pyrUpSpacial(int _w, int _h) const { + VideoVolume out(l, _w, _h); + for (int f = 0; f < l; ++f) { + cv::pyrUp(frame(f), out.frame(f), cv::Size(_w, _h)); + } + return out; + } + + VideoVolume pyrUpTemporal(int _l) const { + VideoVolume out(_l, w, h, 0); + //for (int f = 0; f < l; ++f) { + // frame(f).copyTo(out.frame(2 * f)); + //} + //out.temporalBlur(2.0f); + cv::resize(mat, out.mat, out.mat.size(), 0, 0, cv::INTER_LINEAR); + out.temporalBlur(1.0f); + + return out; + } + VideoVolume pyrUpTemporalBoundaryConditions(int _l, double left, double right) const { + VideoVolume out(_l, w, h, 0); + cv::resize(mat, out.mat, out.mat.size(), 0, 0, cv::INTER_LINEAR); + out.temporalBlurBoundaryConditions(1.0f, left, right); + + return out; + } + + VideoVolume pyrDownBoundaryConditions(double left, double right) const { + VideoVolume tmp = clone(); + tmp.temporalBlurBoundaryConditions(1.0f, left, right); + VideoVolume out((l + 1) / 2, w, h); + cv::resize(tmp.mat, out.mat, out.mat.size(), 0, 0, cv::INTER_LINEAR); + return out; + } + + VideoVolume pyrUp(int _l, int _w, int _h) const { + return pyrUpTemporal(_l).pyrUpSpacial(_w, _h); + } + + void play(int delay = 30, const sibr::Vector2i & res = { -1,-1 }, double scale = 1.0) const { + bool playing = true; + int t = 0; + + const std::string win_name = "playing"; + auto disp_frame = [&] { + if ((res.array() >= 0).all()) { + cv::Mat m; + cv::resize(cvConvertMatTo(frame(t), scale), m, cv::Size(res[0],res[1]), 0,0, cv::INTER_NEAREST); + cv::imshow(win_name, m); + } else { + cv::imshow(win_name, cvConvertMatTo(frame(t), scale)); + } + }; + + auto true_cb = [&](int new_t) { + t = new_t; + disp_frame(); + }; + auto cb_wrapper = [](int new_t, void * arg) { (*static_cast(arg))(new_t); }; + + while (playing) { + disp_frame(); + cv::createTrackbar("timestamp", win_name, &t, l - 1, cb_wrapper, &true_cb); + playing = (cv::waitKey(delay) != 27); + t = (t + 1) % l; + } + + cv::destroyWindow(win_name); + } + + void playStd(double scale = 1.0) const { + play(30, { 800,600 }, scale); + } + + void saveToVideoFile(const std::string & filepath, double framerate = 30.0) const { + Path file = filepath; + makeDirectory(file.parent_path().string()); + + sibr::FFVideoEncoder output(filepath, framerate, { w,h }); + for (int f = 0; f < l; ++f) { + output << sibr::cvConvertMatTo(frame(f)); + } + output.close(); + } + + cv::Mat_ frame(int t) { + return mat.row(t).reshape(N, h); + } + const cv::Mat_ frame(int t) const { + return mat.row(t).reshape(N, h); + } + + cv::Mat_ time_sequence(int i, int j, int c = 0) const { + return mat.col(N*(w*i + j) + c); + } + cv::Mat_ time_sequence_pixels(int i, int j) const { + return mat.colRange(N*(w*i + j), N*(w*i + j + 1)).reshape(N, 0); + } + + VideoVolume time_sequence_volume(int i, int j) const { + return VideoVolume(time_sequence_pixels(i,j).clone(), 1, 1); + } + + cv::Mat video_line(int i) const { + return mat.colRange(N*w*i, N*w*(i + 1)); + } + + VideoVolume subVolumeRef(int t_start, int t_end) { + return VideoVolume(mat.rowRange(t_start, t_end), w, h); + } + + VideoVolume subVolume(int t_start, int t_end) const { + return VideoVolume(mat.rowRange(t_start, t_end).clone(), w, h); + } + + VideoVolume subVolumeSpatial(int x, int y, int w, int h) const { + VideoVolume out(l, w, h); + cv::Rect rec(x, y, w, h); +#pragma omp parallel for + for (int t = 0; t < l; ++t) { + frame(t)(rec).copyTo(out.frame(t)); + } + return out; + } + + VideoVolume subVolume_i(int i_start, int i_end) const { + return VideoVolume(mat.colRange(N*w*i_start, N*w*i_end), w, i_end - i_start); + } + + VideoVolume subVolume_i_copy(int i_start, int i_end) const { + return VideoVolume(mat.colRange(N*w*i_start, N*w*i_end).clone(), w, i_end - i_start); + } + + VideoVolume duplicateTime(int num) const { + VideoVolume out(l*num, w, h); + for (int i = 0; i < num; ++i) { + mat.copyTo(out.mat.rowRange(l*i, l*(i + 1))); + } + return out; + } + + cv::Mat_ spatialSlice(int i_start, int j_start, int i_end, int j_end) { + Vector2i start = { i_start, j_start }, end = { i_end, j_end }; + Vector2i diff = end - start; + int num = diff.cwiseAbs().maxCoeff(); + + cv::Mat_ out(l, num + 1); + for (int s = 0; s <= num; ++s) { + Vector2i p = (start.cast() + (s / (float)num)*diff.cast()).cast(); + + time_sequence_pixels(p[0], p[1]).copyTo(out.col(s)); + //for (int c = 0; c < N; ++c) { + // out.col(c + i * N) = time_sequence(p[0], p[1], c); + //} + } + return out; + } + + cv::Mat_ median_frame() const { + cv::Mat_ out_median(h, w); + +#pragma omp parallel for + for (int i = 0; i < h; ++i) { + for (int j = 0; j < w; ++j) { + for (int c = 0; c < N; ++c) { + std::vector vals_vec; + time_sequence(i, j, c).copyTo(vals_vec); + std::nth_element(vals_vec.begin(), vals_vec.begin() + vals_vec.size() / 2, vals_vec.end()); + CV_Assign::assignValue(c, vals_vec[vals_vec.size() / 2], out_median(i, j)); + } + } + } + return out_median; + } + + T & valueAt(int t, int i, int j, int c = 0) { + return mat(t, N*(w*i + j) + c); + } + const T & valueAt(int t, int i, int j, int c = 0) const { + return mat(t, N*(w*i + j) + c); + } + + CVpixel & pixelAt(int t, int i, int j) { + return frame(t)(i, j); + } + const CVpixel & pixelAt(int t, int i, int j) const { + return frame(t)(i, j); + } + + bool isValid() const { + return !mat.empty(); + } + + void cout() const { + std::cout << l << " x " << w << " x " << h << std::endl; + } + + VideoVolume spatialRescale(float f) const { + Vector2i size = (f * Vector2f(w, h) + Vector2f(0.5f, 0.5f)).cast(); + + VideoVolume out(l, size[0], size[1]); + for (int f = 0; f < l; ++f) { + cv::resize(frame(f), out.frame(f), cv::Size(size[0], size[1]), 0, 0, cv::INTER_LINEAR); + } + return out; + } + + + }; + + SIBR_VIDEO_EXPORT Volume3u loadVideoVolume(const std::string & filepath); + SIBR_VIDEO_EXPORT Volume3u loadVideoVolume(sibr::Video & vid); + + template + VideoVolume concatVolumesChannels(const sibr::VideoVolume & A, const sibr::VideoVolume & B) { + VideoVolume out(A.l, A.w, A.h); + +#pragma omp parallel for + for (int t = 0; t < A.l; ++t) { + std::vector A_cs, B_cs; + cv::split(A.frame(t), A_cs); + cv::split(B.frame(t), B_cs); + A_cs.insert(A_cs.end(), B_cs.begin(), B_cs.end()); + cv::merge(A_cs, out.frame(t)); + } + return out; + } + + SIBR_VIDEO_EXPORT uint optimal_num_levels(uint length); + + template + std::vector> extendedBlurPyramid(const sibr::VideoVolume & vid, uint num_levels = 0) { + if (num_levels == 0) { + num_levels = optimal_num_levels(vid.l); + } + + std::vector> out(1, vid); + for (uint i = 1; i < num_levels; ++i) { + out.push_back(out.back().extendedDownScaleTemporal()); + } + return out; + } + + template + std::vector> gaussianPyramid(const sibr::VideoVolume & vid, uint num_levels = 0) { + if (num_levels == 0) { + num_levels = optimal_num_levels(vid.l); + } + + std::vector> out(1, vid); + for (uint i = 1; i < num_levels; ++i) { + out.push_back(out.back().pyrDown()); + } + return out; + } + + template + std::vector> gaussianPyramidTemporal (const sibr::VideoVolume & vid, uint num_levels = 0) { + if (num_levels == 0) { + num_levels = optimal_num_levels(vid.l); + } + + std::vector> out(1, vid); + for (uint i = 1; i < num_levels; ++i) { + out.push_back(out.back().pyrDownTemporal()); + } + return out; + } + + template + std::vector> gaussianPyramidTemporalBox(const sibr::VideoVolume & vid, uint num_levels = 0) { + if (num_levels == 0) { + num_levels = optimal_num_levels(vid.l); + } + + std::vector> out(1, vid); + for (uint i = 1; i < num_levels; ++i) { + out.push_back(out.back().pyrDownTemporalBox()); + } + return out; + } + + SIBR_VIDEO_EXPORT std::vector laplacianPyramid(const sibr::Volume3u & vid, uint num_levels = 0); + //SIBR_VIDEO_EXPORT std::vector laplacianPyramidTemporal(const sibr::Volume3u & vid, uint num_levels = 0); + SIBR_VIDEO_EXPORT std::vector laplacianPyramidTemporalDouble(const sibr::Volume3u & vid, uint num_levels = 0); + + + template< typename U, typename T = U> + std::vector> laplacianPyramidTemporal(const VideoVolume& vid, uint num_levels = 0) + { + if (num_levels == 0) { + num_levels = optimal_num_levels(vid.l); + } + + std::vector> out; + + sibr::Volume3f current_v = vid.template convertTo(), down, up; + for (int i = 0; i < (int)num_levels - 1; ++i) { + //std::cout << i << " " << current_v.l << std::endl; + down = current_v.pyrDownTemporal(); + up = down.pyrUpTemporal(current_v.l); + //current_v.play(30, { 1200,800 }); + //up.play(30, { 1200,800 }); + current_v.substract(up); + current_v.shift(128); + out.push_back(current_v.convertTo()); + std::swap(current_v, down); + } + out.push_back(current_v.convertTo()); + return out; + } + + SIBR_VIDEO_EXPORT sibr::Volume3u collapseLaplacianPyramid(const std::vector & pyr, double shift = 0); + + template + sibr::VideoVolume collapseLaplacianPyramidTemporal(const std::vector>& pyr, double shift, + bool debug = false) + { + sibr::Volume3f v = (VideoVolume) pyr.back().convertTo(); + for (int i = (int)pyr.size() - 2; i >= 0; --i) { + if (debug) { + v.play(); + } + v = v.pyrUpTemporal(pyr[i].l); + if (debug) { + v.play(); + } + v.add(pyr[i]); + if (shift != 0) { + v.shift(shift); + if (debug) { + v.play(); + } + } + } + return v.convertTo(); + } + + //SIBR_VIDEO_EXPORT sibr::Volume3u collapseLaplacianPyramidTemporal(const std::vector & pyr, double shift = 0); + + //SIBR_VIDEO_EXPORT sibr::Volume3u laplacianBlendingTemporal(const sibr::Volume3u & vA, const sibr::Volume3u & vB, std::vector & pyrM); + SIBR_VIDEO_EXPORT sibr::Volume3u laplacianBlending(const sibr::Volume3u & vA, const sibr::Volume3u & vB, std::vector & pyrM); + + template + sibr::VideoVolume laplacianBlendingTemporal( + const sibr::VideoVolume & vA, + const sibr::VideoVolume & vB, + std::vector> & pyrM) + { + uint num_levels = (uint)pyrM.size(); + + auto pyrA = laplacianPyramidTemporal(vA, num_levels); + + for (const auto & l : pyrA) { + //l.play(); + } + + auto pyrB = laplacianPyramidTemporal(vB, num_levels); + + //auto pyrM = gaussianPyramidTemporal(vM); + + for (int i = (int)pyrA.size() - 1; i >= 0; --i) { + //pyrA[i].playStd(); + //pyrM[i].playStd(); + pyrA[i].applyMaskInPlace(pyrM[i]); + //pyrA[i].playStd(); + pyrM[i].toggle(); + //pyrM[i].playStd(); + //pyrB[i].playStd(); + pyrB[i].applyMaskInPlace(pyrM[i]); + //pyrB[i].playStd(); + pyrA[i].add(pyrB[i]); + //pyrA[i].playStd(); + } + + return collapseLaplacianPyramidTemporal(pyrA, -128); + } + + template::CVpixel> + cv::Mat_ totalVariation(const VideoVolume & v) { + cv::Mat_ total_vars(v.h, v.w); + +#pragma omp parallel for + for (int i = 0; i < v.h; ++i) { + for (int j = 0; j < v.w; ++j) { + for (int c = 0; c < N; ++c) { + double total_var = 0; + auto seq = v.time_sequence(i, j, c).clone(); + for (int t = 0; t < v.l - 1; ++t) { + total_var += std::abs((double)seq(t) - (double)seq(t + 1)); + } + CV_Assign::assignValue(c, (float)total_var, total_vars(i, j)); + } + } + } + + return total_vars; + } + + struct SIBR_VIDEO_EXPORT PyramidLayer { + PyramidLayer() {} + PyramidLayer(int _w, int _h, int _l, int cv_type = CV_32FC1) : l(_l), w(_w), h(_h) { + volume = cv::Mat(l, 3 * w*h, cv_type); + } + PyramidLayer(const cv::Mat & _volume, int _w, int _h) : w(_w), h(_h), l(_volume.rows) { + _volume.convertTo(volume, CV_32FC1); + } + + PyramidLayer operator+(const PyramidLayer & other); + PyramidLayer operator-(const PyramidLayer & other); + + PyramidLayer clone() const { + PyramidLayer out = *this; + volume.copyTo(out.volume); + return out; + } + + cv::Mat getRGB(int frame, bool centered = false); + + void saveToVideoFile(const std::string & filename, double framerate); + + void copySizeFrom(const PyramidLayer & other) { + h = other.h; + w = other.w; + l = other.l; + } + + void cout() const { + std::cout << l << " " << w << " " << h << std::endl; + } + + void show(int s = 50) const; + static void show(PyramidLayer A, PyramidLayer B, int s = 50); + static void show(PyramidLayer A, PyramidLayer B, PyramidLayer C, int s = 50); + static void show(PyramidLayer A, PyramidLayer B, PyramidLayer C, PyramidLayer D, int s = 50, bool centered = false); + static void showDiff(PyramidLayer A, PyramidLayer B, int s = 50); + + cv::Mat volume; + int w, h, l; + }; + + + struct SIBR_VIDEO_EXPORT PyramidParameters { + PyramidParameters(int nlevels = 5, int temporal = 3, int spatial = 2, bool spatial_ds = true) : + num_levels(nlevels), temporal_radius(temporal), spatial_radius(spatial), splacialDS(spatial_ds) {} + int num_levels; + int temporal_radius; + int spatial_radius; + bool splacialDS = true; + }; + + SIBR_VIDEO_EXPORT PyramidLayer blur(const PyramidLayer & layer, const PyramidParameters & params ); + SIBR_VIDEO_EXPORT PyramidLayer temporalBlur(const PyramidLayer & volume, const PyramidParameters & params, float scaling = 1); + SIBR_VIDEO_EXPORT void temporalBlurInPlace(PyramidLayer & volume, const PyramidParameters & params, float scaling = 1); + + SIBR_VIDEO_EXPORT PyramidLayer decimate(const PyramidLayer & layer, const PyramidParameters & params); + SIBR_VIDEO_EXPORT PyramidLayer upscale(const PyramidLayer & layerUp, const PyramidLayer & layerDown, const PyramidParameters & params); + SIBR_VIDEO_EXPORT PyramidLayer downscale(const PyramidLayer & layer, const PyramidParameters & params); + + SIBR_VIDEO_EXPORT cv::Mat slice(const PyramidLayer & layer, int i, int j, bool vertical = true, bool center = false); + + + class SIBR_VIDEO_EXPORT VideoGaussianPyramid { + public: + PyramidParameters params; + std::vector layers; + + }; + + class SIBR_VIDEO_EXPORT VideoLaplacianPyramid { + public: + + public: + VideoLaplacianPyramid() {} + + public: + + PyramidParameters params; + + PyramidLayer collapse() const; + + std::vector layers; + + }; + + + SIBR_VIDEO_EXPORT VideoGaussianPyramid buildVideoGaussianPyramid(sibr::Video & vid, int nLevels, const PyramidParameters & params = {}, bool show = false); + SIBR_VIDEO_EXPORT VideoGaussianPyramid buildVideoGaussianPyramid(const cv::Mat & volume, int w, int h, int nLevels, const PyramidParameters & params = {}, bool show = false); + + SIBR_VIDEO_EXPORT VideoLaplacianPyramid buildVideoLaplacianPyramid(PyramidLayer vid, int nLevels, const PyramidParameters & params = {}, bool show = false); + SIBR_VIDEO_EXPORT VideoLaplacianPyramid buildVideoLaplacianPyramid(sibr::Video & vid, int nLevels, const PyramidParameters & params = {}, bool show = false); + + SIBR_VIDEO_EXPORT VideoLaplacianPyramid buildVideoLaplacianPyramidFullyReduced(PyramidLayer vid, int nLevels, const PyramidParameters & params = {}, bool show = false); + SIBR_VIDEO_EXPORT void convertReducedVideoPyramidTo128(VideoLaplacianPyramid & vid); + + SIBR_VIDEO_EXPORT PyramidLayer videoLaplacianBlending(sibr::Video & vidA, sibr::Video & vidB, PyramidLayer mask_volume ); + SIBR_VIDEO_EXPORT PyramidLayer videoLaplacianBlending(PyramidLayer vidA, PyramidLayer vidB, PyramidLayer mask_volume, PyramidParameters params = {}, bool show = false); + + struct SIBR_VIDEO_EXPORT ContribData { + PyramidLayer contrib, mask, partA, partB; + }; + + struct SIBR_VIDEO_EXPORT FullContribData { + ContribData scaled; + ContribData notScaled; + PyramidLayer result, inputA, inputB; + }; + + SIBR_VIDEO_EXPORT std::vector videoLaplacianBlendingContrib(PyramidLayer vidA, PyramidLayer vidB, PyramidLayer mask_volume, PyramidParameters params = {}); + + SIBR_VIDEO_EXPORT void videoLaplacianBlendingDebug(PyramidLayer vidA, PyramidLayer vidB, PyramidLayer mask_volume, PyramidParameters params = {}); + + template + class Histogram { + using Value = Vector; + using Indice = Vector; + using Range = Vector; + + public: + Histogram(const Value & _min, const Value & _max, uint _numBins = 100) + : min(_min.template cast()), max(_max.template cast()), numBins(_numBins) { + Range diff = max - min; + scaling = numBins * diff.cwiseInverse(); + bin_range = diff / numBins; + } + + Indice whatBin(const Value & value) { + Indice bin; + for (int c = 0; c < N; ++c) { + bin[c] = sibr::clamp((int)(scaling[c]*(value[c] - min[c])), 0, (int)numBins - 1); + } + return bin; + } + + void addValue(const Value & value) { + ++bins[whatBin(value)]; + } + void addValues(const std::vector & values) { + for (const Value & v : values) { + addValue(v); + } + } + + Indice getModeIndice() const { + Indice mode; + uint mode_size = 0; + for (const auto & key_val : bins) { + if (key_val.second > mode_size) { + mode_size = key_val.second; + mode = key_val.first; + } + } + return mode; + } + + Value getBinMiddle(const Indice & bin) const { + Value out; + for (int c = 0; c < 3; ++c) { + out[c] = static_cast(min[c] + bin_range[c] * (bin[c] + 0.5)); + } + return out; + } + + protected: + std::map bins; + Range max, min, scaling, bin_range; + uint numBins = 50; + }; + + template + class Histogram { + SIBR_CLASS_PTR(Histogram); + + public: + Histogram(double _min, double _max, int _numBins = 100) : min(_min), max(_max), numBins(_numBins), bins(_numBins, 0) { + scaling = numBins / (max - min); + bin_range = (max - min) / numBins; + } + + bool whatBin(T value, uint & bin) { + int t = (int)(scaling * (value - min)); + if (t >= 0 && t <= ((int)numBins - 1)) { + bin = t; + return true; + } + return false; + } + + void addValue(T value) { + uint bin; + if (whatBin(value, bin)) { + ++bins[bin]; + } + } + + void addValues(const std::vector & values) { + for (const T & v : values) { + addValue(v); + } + } + + uint getModeIndice() const { + uint mode, mode_size = 0; + for (const auto & [key, val] : bins) { + if (val > mode_size) { + mode_size = val; + mode = key; + } + } + return mode; + } + + T getBinMiddle(uint bin) const { + return static_cast(min + bin_range * (bin + 0.5)); + } + + std::vector normalized_values() const { + float sum = 0; + for (uint b = 0; b < numBins; ++b) { + sum += bins[b]; + } + std::vector out(numBins); + for (uint b = 0; b < numBins; ++b) { + out[b] = bins[b]/sum; + } + return out; + } + + protected: + std::vector bins; + double max, min, scaling, bin_range; + uint numBins = 50; + }; + + using Histo1f = Histogram; + using ColorHistogram = Histogram; + + struct TimeHistogram { + + TimeHistogram(double _min, double _max, int _numBins) : numBins(_numBins), max(_max), min(_min) { + assert(numBins > 0 && max > min); + scaling = numBins / (max - min); + bin_range = (max - min) / numBins; + } + + void addValues(const std::vector & values) { + for (const sibr::Vector3ub & value : values) { + addValue(value); + } + } + + sibr::Vector3ub getBinMiddle(const sibr::Vector3ub & bin) const { + sibr::Vector3ub out; + for (int c = 0; c < 3; ++c) { + out[c] = sibr::clamp((int)(min + bin_range * (bin[c] + 0.5)), 0, 255); + } + return out; + } + + sibr::Vector3ub getHMode() const { + sibr::Vector3ub mode; + int mode_size = 0; + for (const auto & key_val : bins) { + if (key_val.second > mode_size) { + mode_size = key_val.second; + mode = key_val.first; + } + } + return mode; + } + + void addValue(const sibr::Vector3ub & value) { + ++bins[whatBin(value)]; + } + + sibr::Vector3ub whatBin(const sibr::Vector3ub & value) { + sibr::Vector3ub bin; + for (int c = 0; c < 3; ++c) { + bin[c] = sibr::clamp((int)(scaling*(value[c] - min)), 0, numBins - 1); + } + return bin; + } + + void computeSortedBins() { + std::vector> all_bins; + int num_elts = 0; + for (const auto & bin : bins) { + num_elts += bin.second; + all_bins.push_back({ bin.second,bin.first }); + } + std::sort(all_bins.begin(), all_bins.end()); + float cdf = 0; + for (int i = (int)all_bins.size() - 1; i >= 0; --i) { + float f = all_bins[i].first /(float)num_elts; + //std::cout << "(" << all_bins[i].first << ", " << (int)all_bins[i].second[0] << "),"; + + sorted_bins[all_bins[i].second] = cdf; + cdf = std::min(cdf + f, 1.0f); + } + //std::cout << std::endl; + } + std::map bins; + std::map sorted_bins; + double max, min, scaling, bin_range; + int numBins = 50; + }; + + class SIBR_VIDEO_EXPORT VideoUtils { + + public: + static void simpleFlowViz(cv::VideoCapture & cap, float ratio); + static void simpleFlowSave(cv::VideoCapture & cap, float ratio, std::function naming_f); + + template + static void loopAndDisplay(cv::VideoCapture & cap, float ratio, FunType f, const OtherArgsTypes &... args); + + static void deepFlowViz(cv::VideoCapture & cap, float ratio); + + static cv::Mat getGrey(const cv::Mat & mat); + + static cv::Mat getFlowViz(const cv::Mat & flow); + + static cv::Mat cropFromSize(const cv::Mat & mat, const sibr::Vector2i & size); + + static void getMeanVariance(cv::VideoCapture & cap, cv::Mat & outMean, cv::Mat & outVariance, const sibr::Vector2i & finalSize); + static void getMeanVariance2(cv::VideoCapture & cap, cv::Mat & outMean, cv::Mat & outVariance, const sibr::Vector2i & finalSize, float starting_point_s = 0); + + static cv::Mat getMedian(sibr::Video & vid, float time_skiped_begin = 0, float time_skiped_end = 0); + static cv::Mat3b getMedian(const std::string & path, float time_percentage_crop = 0); + + static cv::Mat getBackgroundImage(sibr::Video & vid, int numBins = 50, float time_skip_begin = 0, float time_skip_end = 0); + static cv::Mat getBackgroundImage(const cv::Mat volume, int w, int h, int numBins = 50); + static void getBackGroundVideo(sibr::Video & vid, PyramidLayer & out_mask, PyramidLayer & out_video, cv::Mat & mask, + const sibr::ImageRGB & mean = {}, int threshold = 75, int numBins = 50, float time_skip_begin = 0, float time_skip_end = 0); + + static sibr::Volume1u getBackgroundVolume(const sibr::Volume3u & volume, int threshold = 75, int numBins = 150); + static sibr::Volume1f getBackgroundVolumeF(const sibr::Volume3u & volume, int numBins = 150); + + static void computeSaveSimpleFlow(sibr::Video & vid, bool viz = false); + + static cv::Mat getTemporalSpatialRatio(sibr::Video & vid, PyramidLayer & out_ratio, const sibr::ImageRGB & spatial_ratio, + int numBins = 50, float time_skip_begin = 0, float time_skip_end = 0); + + static cv::Mat getLaplacian(cv::Mat mat, int size = 3, bool smooth = false, bool absolute = false); + + static cv::Mat getCanny(cv::Mat mat); + + + static void computeSaveVideoMaskF(Video & vid, int threshold, bool viz = false); + static void computeSaveVideoMaskBlur(Video & vid, int time_window); + + static int rotationAngleFromMetadata(const std::string & videoPath); + + static void ECCtransform(cv::Mat matA, cv::Mat matB, cv::Mat & correctedB, cv::Mat & diff, int cvMotion); + + static void smallAlignmentVideo(sibr::Video & vid, const std::string & outputVidPath, bool viz = false); + static void smallAlignmentVideo2(sibr::Video & vid, const std::string & outputVidPath, bool viz = false); + + static int codec_ffdshow; + static int codec_OpenH264; + static int codec_OpenH264_fallback; + + protected: + static cv::Mat applyFlow(const cv::Mat & prev, const cv::Mat & flow); + + static void simpleFlow(cv::VideoCapture & cap, float ratio, + std::function f, + std::function end_function = []() {} + ); + + static void deepFlow(cv::VideoCapture & cap, float ratio, + std::function f, + std::function end_function = []() {} + ); + }; + + template + void VideoUtils::loopAndDisplay(cv::VideoCapture & cap, float ratio, FunType f, const OtherArgsTypes &... args) + { + cv::Mat next; + static_assert(std::is_same_v, "FunType must return cv::Mat"); + + cap.set(cv::VideoCaptureProperties::CAP_PROP_POS_FRAMES, 0); + + while (true) { + cap >> next; + if (next.empty()) { + break; + } + auto size = cv::Size((int)(ratio*next.size().width), (int)(ratio*next.size().height)); + cv::resize(next, next, size); + cv::imshow("imshow", f(next, args...)); + if (cv::waitKey(10) == 27) { + break; + } + } + cv::destroyAllWindows(); + } + + /** }@ */ + +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/video/sibr_video.dox b/submodules/gaussian-splatting/SIBR_viewers/src/core/video/sibr_video.dox new file mode 100644 index 0000000000000000000000000000000000000000..7d9b24fa639115c14df5be431a39bdd3a4db18b5 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/video/sibr_video.dox @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +/*! + \defgroup sibr_video sibr_video + + \brief Video loading, processing and display. + +*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/CMakeLists.txt b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..05f77da3d3dfa63ee3c2c3c6d66c4f7a3351c1b4 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/CMakeLists.txt @@ -0,0 +1,58 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +project(sibr_view) + +file(GLOB SOURCES "*.cpp" "*.h" "*.hpp") +source_group("Source Files" FILES ${SOURCES}) + +file(GLOB SHADERS "shaders/*.frag" "shaders/*.vert" "shaders/*.geom" "shaders/*.fp" "shaders/*.vp" "shaders/*.gp") +source_group("Source Files\\shaders" FILES ${SHADERS}) + +file(GLOB INTERFACE_SOURCES "interface/*.cpp" "interface/*.h" ) +source_group("Source Files\\interface" FILES ${INTERFACE_SOURCES}) + +file(GLOB SOURCES + "*.cpp" "*.h" "*.hpp" + "shaders/*.frag" "shaders/*.vert" "shaders/*.geom" "shaders/*.fp" "shaders/*.vp" "shaders/*.gp" + "interface/*.cpp" "interface/*.h" + ) + +## Specify target rules +add_library(${PROJECT_NAME} SHARED ${SOURCES}) + +include_directories( + ${Boost_INCLUDE_DIRS} + ${imgui_INCLUDE_DIRS} +) +target_link_libraries(${PROJECT_NAME} + ${Boost_LIBRARIES} + ${OpenCV_LIBRARIES} + OpenMP::OpenMP_CXX + imgui + sibr_graphics + sibr_assets + sibr_raycaster + sibr_scene + sibr_video +) + +add_definitions( -DSIBR_VIEW_EXPORTS -DBOOST_ALL_DYN_LINK ) + +set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER ${SIBR_FOLDER}) + +## High level macro to install in an homogen way all our ibr targets +include(install_runtime) +ibr_install_target(${PROJECT_NAME} + INSTALL_PDB ## mean install also MSVC IDE *.pdb file (DEST according to target type) + SHADERS "${SHADERS}" + RSC_FOLDER "core" + #COMPONENT ${PROJECT_NAME}_install ## will create custom target to install only this project +) diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/Config.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/Config.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e132a8127cb5e1605d33c29b4398068da80c0485 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/Config.hpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include "core/graphics/Config.hpp" + + +//// Export Macro (used for creating DLLs) //// +# ifdef SIBR_OS_WINDOWS +# ifdef SIBR_STATIC_VIEW_DEFINE +# define SIBR_VIEW_EXPORT +# define SIBR_NO_VIEW_EXPORT +# else +# ifndef SIBR_VIEW_EXPORT +# ifdef SIBR_VIEW_EXPORTS + /* We are building this library */ +# define SIBR_VIEW_EXPORT __declspec(dllexport) +# else + /* We are using this library */ +# define SIBR_VIEW_EXPORT __declspec(dllimport) +# endif +# endif +# ifndef SIBR_NO_EXPORT +# define SIBR_NO_EXPORT +# endif +# endif +# else +# define SIBR_VIEW_EXPORT +# endif + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/DatasetView.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/DatasetView.cpp new file mode 100644 index 0000000000000000000000000000000000000000..43328ffdde250a05c62d52f42e0e882b9af1264d --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/DatasetView.cpp @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "DatasetView.hpp" + +namespace sibr { + + DatasetView::DatasetView(const BasicIBRScene & scene, const Vector2u & defaultRenderingRes, const Vector2i & defaultViewRes) + : MultiViewBase(defaultViewRes) + { + const auto & input_cams = scene.cameras()->inputCameras(); + const auto & input_images = scene.images()->inputImages(); + + if (input_images.size() != input_cams.size()) { + SIBR_ERR << "cams not matching input images"; + + } + const std::string mmm_str = "mesh"; + MultiMeshManager::Ptr mmm(new MultiMeshManager(mmm_str)); + mmm->addMesh("proxy", scene.proxies()->proxyPtr()); + mmm->getCameraHandler().fromCamera(*input_cams[0]); + for (int i = 0; i < (int)input_cams.size(); ++i) { + cams.push_back(*input_cams[i]); + } + + const std::string grid_str = "grid"; + ImagesGrid::Ptr grid(new ImagesGrid()); + grid->addImageLayer("input images", input_images); + + addSubView(meshSubViewStr, mmm, defaultRenderingRes); + addSubView(gridSubViewStr, grid, defaultRenderingRes); + } + + void DatasetView::onGui(Window & win) + { + } + + void DatasetView::onUpdate(Input & input) + { + MultiViewBase::onUpdate(input); + + + Input meshInput = Input::subInput(input, getMeshView().viewport); + if (meshInput.key().isActivated(Key::LeftControl) && meshInput.mouseButton().isActivated(Mouse::Right)) { + RaycastingCamera cam = RaycastingCamera(getMMM()->getCameraHandler().getCamera()); + Ray ray = cam.getRay(meshInput.mousePosition().cast()); + auto hit = proxyData().raycaster->intersect(ray); + + if (hit.hitSomething()) { + currentRepro.point3D = ray.at(hit.dist()); + currentRepro.active = true; + currentRepro.repros.clear(); + repro(currentRepro); + getGrid()->addPixelsToHighlight("zinputRepro", { }, { 1,0,0 }, 0.25f); + } + } + + Input gridInput = Input::subInput(input, getGridView().viewport); + if (gridInput.key().isActivated(Key::LeftControl) && gridInput.mouseButton().isActivated(Mouse::Right)) { + const auto & pix = getGrid()->getCurrentPixel(); + if (pix) { + Ray ray = cams[pix.im].getRay(pix.pos.cast()); + auto hit = proxyData().raycaster->intersect(ray); + if (hit.hitSomething()) { + currentRepro.point3D = ray.at(hit.dist()); + currentRepro.active = true; + currentRepro.repros.clear(); + repro(currentRepro); + getGrid()->addPixelsToHighlight("zinputRepro", { pix }, { 1,0,0 }, 0.25f); + } + } + } + + + } + + void DatasetView::onRender(Window & win) + { + if (currentRepro) { + displayRepro(currentRepro); + } + + MultiViewBase::onRender(win); + } + + void DatasetView::repro(ReprojectionData & data) + { + const Vector3f & pt = data.point3D; + for (int im = 0; im<(int)cams.size(); ++im) { + const auto & cam = cams[im]; + if (!cam.frustumTest(pt)) { + continue; + } + Vector3f pt2d = cam.projectImgSpaceInvertY(pt); + + if (data.occlusionTest) { + float dist = (cam.position() - pt).norm(); + Ray ray = Ray(pt, (cam.position() - pt).normalized()); + auto hit = proxyData().raycaster->intersect(ray, 0.01f); + if (hit.hitSomething() && std::abs(hit.dist() - dist) / dist > 0.01f) { + continue; + } + } + + data.repros.push_back(MVpixel(im, pt2d.xy().cast())); + } + } + + void DatasetView::displayRepro(const ReprojectionData & data) + { + getMMM()->addPoints("repro 3D point", { data.point3D }); + + Mesh::Ptr reproLines(new Mesh()); + std::vector pixs; + std::vector repro_imgs; + for (const auto & rep : data.repros) { + const auto & cam = cams[rep.im]; + Mesh reproLine; + reproLine.vertices({ cam.position(), data.point3D }); + reproLine.triangles({ 0,0,1 }); + reproLines->merge(reproLine); + repro_imgs.push_back(rep.im); + } + + getMMM()->addMeshAsLines("repro ines", reproLines).setColor({ 1,0,1 }); + getGrid()->addPixelsToHighlight("repros", data.repros, { 0,0,1 }, 0.25f); + //getGrid()->addImagesToHighlight("reproImgs", repro_imgs, { 0,1,0 }, 0.1f); + } + + MultiViewBase::BasicSubView & DatasetView::getMeshView() + { + return _subViews[meshSubViewStr]; + } + + MultiViewBase::BasicSubView & DatasetView::getGridView() + { + return _subViews[gridSubViewStr]; + } + + MultiMeshManager::Ptr DatasetView::getMMM() + { + return std::static_pointer_cast(getMeshView().view); + } + + ImagesGrid::Ptr sibr::DatasetView::getGrid() + { + return std::static_pointer_cast(getGridView().view); + } + + MeshData & DatasetView::proxyData() + { + return getMMM()->getMeshData("proxy"); + } + +} + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/DatasetView.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/DatasetView.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0767e2645ef47dd4d5162baa35af36c934ffb319 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/DatasetView.hpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include "MultiViewManager.hpp" +#include "SceneDebugView.hpp" +#include "ImagesGrid.hpp" +#include "core/scene/BasicIBRScene.hpp" + +namespace sibr { + + /** Visualize and explore a MVS dataset. + Allow reprojections between one of the input images, scene geometry and other images. + \ingroup sibr_view + */ + class SIBR_VIEW_EXPORT DatasetView + : public MultiViewBase + { + SIBR_CLASS_PTR(DatasetView); + + public: + + /** Constructor. + * \param scene the IBR scene + * \param defaultRenderingRes the mesh view rendering resolution + * \param defaultViewRes the window/view resolution + */ + DatasetView(const BasicIBRScene & scene, const Vector2u & defaultRenderingRes = { 0,0 }, const Vector2i & defaultViewRes = { 800, 600 }); + + /** Reprojection mode. */ + enum ReprojectionMode { NONE, IMAGE_TO_IMAGE, MESH_TO_IMAGE }; + + /** Update the GUI. */ + virtual void onGui(Window& win) override; + + /** Update state based on user input. + *\param input the view input + */ + virtual void onUpdate(Input& input) override; + + /** Perform rendering. + *\param win the destination window + **/ + virtual void onRender(Window& win) override; + + protected: + + /** Contain data related to the reprojection of a point in input images. */ + struct ReprojectionData { + + /** \return true if point is active */ + operator bool() const { return active; } + + std::vector repros; ///< Store reprojected pixel positions. + MVpixel image_input; ///< Initial selected position. + + Vector3f point3D; ///< World space point. + bool occlusionTest = true; ///< Should occlusion test be applied. + bool active = false; ///< Is the point active. + }; + + /** populate reprojection information. + \param data the info to populate + */ + void repro(ReprojectionData & data); + + /** Visualize the reprojection information. + \param data the reprojection to display + */ + void displayRepro(const ReprojectionData & data); + + /** \return the mesh subview. */ + BasicSubView & getMeshView(); + + /** \return the images subview. */ + BasicSubView & getGridView(); + + /** \return the mesh display manager. */ + MultiMeshManager::Ptr getMMM(); + + /** \return the image grid manager. */ + ImagesGrid::Ptr getGrid(); + + /** \return the mesh display data. */ + MeshData & proxyData(); + + std::vector cams; ///< Input cameras. + ReprojectionData currentRepro; ///< Current selected reprojection. + ReprojectionMode reproMode = MESH_TO_IMAGE; ///< Current reprojection mode. + + const std::string meshSubViewStr = "dataset view - mesh"; + const std::string gridSubViewStr = "grid"; + + + }; +} \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/FPSCamera.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/FPSCamera.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e417527eff69366a9efef8ee80152ff6133a5a89 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/FPSCamera.cpp @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "FPSCamera.hpp" +#include +#include "core/graphics/Input.hpp" +#include "core/graphics/Viewport.hpp" +#include "core/graphics/Window.hpp" +#include "core/view/UIShortcuts.hpp" +#include "core/graphics/GUI.hpp" + + +# define IBRVIEW_CAMSPEED 1.f + +namespace sibr { + + FPSCamera::FPSCamera(void) : _hasBeenInitialized(false) + { + UIShortcuts::global().add("[FPS camera] j", "rotate camera -Y (look left)"); + UIShortcuts::global().add("[FPS camera] l", "rotate camera +Y (look right)"); + UIShortcuts::global().add("[FPS camera] i", "rotate camera +X (look up)"); + UIShortcuts::global().add("[FPS camera] k", "rotate camera -X (look down)"); + UIShortcuts::global().add("[FPS camera] u", "rotate camera +Z "); + UIShortcuts::global().add("[FPS camera] o", "rotate camera -Z "); + UIShortcuts::global().add("[FPS camera] w", "move camera -Z (move forward)"); + UIShortcuts::global().add("[FPS camera] s", "move camera +Z (move backward)"); + UIShortcuts::global().add("[FPS camera] a", "move camera -X (strafe left)"); + UIShortcuts::global().add("[FPS camera] d", "move camera +X (strafe right)"); + UIShortcuts::global().add("[FPS camera] q", "move camera -Y (move down)"); + UIShortcuts::global().add("[FPS camera] e", "move camera +Y (move up)"); + /* + _speedFpsCam = 1.0f; + _speedRotFpsCam = 1.0f; + _useAcceleration = true; */ + _speedFpsCam = 0.3f; + _speedRotFpsCam = 1.0f; + _useAcceleration = false; + } + + void FPSCamera::fromCamera( const sibr::InputCamera & cam) + { + _currentCamera = cam; + _hasBeenInitialized = true; + } + + void FPSCamera::update(const sibr::Input & input, float deltaTime) { + + if (!_hasBeenInitialized) { return; } + // Read input and update camera. + moveUsingWASD(input, deltaTime); + moveUsingMousePan(input, deltaTime); + } + + void FPSCamera::snap(const std::vector & cams){ + sibr::Vector3f sumDir(0.f, 0.f, 0.f); + sibr::Vector3f sumUp(0.f, 0.f, 0.f); + for (const auto& cam: cams) + { + float dist = 1.0f/std::max(1e-6f,distance(_currentCamera.position(), cam->position())); + sumDir += dist * cam->dir(); + sumUp += dist * cam->up(); + } + Matrix4f m = lookAt(Vector3f(0, 0, 0), sumDir, sumUp); + _currentCamera.rotation(quatFromMatrix(m)); + } + + void FPSCamera::update(const sibr::Input & input, const float deltaTime, const Viewport & viewport) + { + update(input, deltaTime); + } + + const sibr::InputCamera & FPSCamera::getCamera( void ) const + { + if( !_hasBeenInitialized ){ + SIBR_ERR << " FPS Camera : camera not initialized before use" << std::endl + << "\t you should use either fromMesh(), fromCamera() or load() " << std::endl; + } + return _currentCamera; + } + + void FPSCamera::setSpeed(const float speed, const float angular) { + _speedFpsCam = speed; + if(angular != 0.0f) { + _speedRotFpsCam = angular; + } + } + + void FPSCamera::setGoalAltitude(const float& goalAltitude) { + _goalAltitude = goalAltitude; + } + + void FPSCamera::onGUI(const std::string& suffix) { + if(ImGui::Begin(suffix.c_str())) { + ImGui::PushScaledItemWidth(130); + ImGui::Checkbox("Acceleration", &_useAcceleration); + ImGui::SameLine(); + if(!_useAcceleration) { + ImGui::InputFloat("Speed", &_speedFpsCam, 0.1f, 0.5f); + ImGui::SameLine(); + } + ImGui::InputFloat("Rot. speed", &_speedRotFpsCam, 0.1f, 0.5f); + ImGui::PopItemWidth(); + } + ImGui::End(); + } + + + void FPSCamera::moveUsingWASD(const sibr::Input& input, float deltaTime) + { + + + if (input.key().isActivated(sibr::Key::LeftControl)) { return; } + + float camSpeed = 2.f * deltaTime * IBRVIEW_CAMSPEED; + if (_currentCamera.ortho()) { + camSpeed *= 5.0f; + } + float camRotSpeed = 30.f * deltaTime * IBRVIEW_CAMSPEED; + //float camSpeed = 0.1f; + //float camRotSpeed = 1.f; + + sibr::Vector3f move(0, 0, 0); + + move.x() -= input.key().isActivated(sibr::Key::A) ? camSpeed : 0.f; + move.x() += input.key().isActivated(sibr::Key::D) ? camSpeed : 0.f; + move.z() -= input.key().isActivated(sibr::Key::W) ? camSpeed : 0.f; + move.z() += input.key().isActivated(sibr::Key::S) ? camSpeed : 0.f; + move.y() -= input.key().isActivated(sibr::Key::Q) ? camSpeed : 0.f; + move.y() += input.key().isActivated(sibr::Key::E) ? camSpeed : 0.f; + + // If the acceleration effect is enabled, we alter the speed along a move. + if(_useAcceleration) { + if (move.isNull() == true) { + _speedFpsCam = 1.f; + } else { + _speedFpsCam *= 1.02f; + } + } + + + sibr::Vector3f pivot(0, 0, 0); + + camRotSpeed *= _speedRotFpsCam; + pivot[1] += input.key().isActivated(sibr::Key::J) ? camRotSpeed : 0.f; + pivot[1] -= input.key().isActivated(sibr::Key::L) ? camRotSpeed : 0.f; + pivot[0] -= input.key().isActivated(sibr::Key::K) ? camRotSpeed : 0.f; + pivot[0] += input.key().isActivated(sibr::Key::I) ? camRotSpeed : 0.f; + pivot[2] -= input.key().isActivated(sibr::Key::O) ? camRotSpeed : 0.f; + pivot[2] += input.key().isActivated(sibr::Key::U) ? camRotSpeed : 0.f; + + if (_currentCamera.ortho()) { + if (input.key().isActivated(sibr::Key::Z)) { + _currentCamera.orthoRight(_currentCamera.orthoRight()/1.1f); + _currentCamera.orthoTop(_currentCamera.orthoTop()/1.1f); + _speedRotFpsCam /= 1.1f; + } + else if (input.key().isActivated(sibr::Key::X)) { + _currentCamera.orthoRight(_currentCamera.orthoRight()*1.1f); + _currentCamera.orthoTop(_currentCamera.orthoTop()*1.1f); + _speedRotFpsCam *= 1.1f; + } + } + + // Try to keep the same altitude as cameras around. + if (_goalAltitude != -1) { + sibr::Vector3f worldUp(0., 0., 1.); + const sibr::Vector3f custom_forward = _currentCamera.right().cross(worldUp); + const sibr::Vector3f translation_right = (_speedFpsCam * move.x()) * _currentCamera.right(); + + sibr::Vector3f translation = _speedFpsCam * (move.z() * custom_forward) + translation_right; + //const float altitudeDiff = _goalAltitude - _currentCamera.position().z(); + translation[2] = _goalAltitude - _currentCamera.position().z(); + + _currentCamera.translate(translation); + } + else { + _currentCamera.translate(move * _speedFpsCam, _currentCamera.transform()); + } + + _currentCamera.rotate(pivot, _currentCamera.transform()); + } + + void FPSCamera::moveUsingMousePan( const sibr::Input& input, float deltaTime ) + { + + float speed = 0.05f*deltaTime; + sibr::Vector3f move( + input.mouseButton().isActivated(sibr::Mouse::Left)? input.mouseDeltaPosition().x()*speed : 0.f, + input.mouseButton().isActivated(sibr::Mouse::Right)? input.mouseDeltaPosition().y()*speed : 0.f, + input.mouseButton().isActivated(sibr::Mouse::Middle)? input.mouseDeltaPosition().y()*speed : 0.f + ); + _currentCamera.translate(move, _currentCamera.transform()); + + } +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/FPSCamera.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/FPSCamera.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8f4d57deccc64ef9bad9ce8b9194d5e1ad47dbfc --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/FPSCamera.hpp @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include +#include + +#include "Config.hpp" +#include "core/graphics/Shader.hpp" +#include "core/assets/InputCamera.hpp" +#include "ICameraHandler.hpp" + + +namespace sibr { + + class Viewport; + class Mesh; + class Input; + + /** Interactive camera that can be moved using WASD keys. + * \ingroup sibr_view + */ + class SIBR_VIEW_EXPORT FPSCamera : public ICameraHandler + { + + public: + + /** + Default constructor. + */ + FPSCamera( void ); + + /** + Setup the FPS camera so that it has the same pose as the argument camera. + \param cam the reference camera + */ + void fromCamera(const sibr::InputCamera & cam); + + /** + Update the FPS camera based on the user input (keyboard). + \param input the user input + \param deltaTime time elapsed since last update + */ + void update( const sibr::Input & input, float deltaTime); + + /** Move to a camera position/orientation that is a distance-wieghted combination of the given cameras. + \param cams the cameras list. + */ + void snap(const std::vector & cams); + + // ICameraHandler interface + + /** Update the FPS camera based on the user input. + \param input the user input + \param deltaTime time elapsed since last update + \param viewport the view viewport + */ + virtual void update(const sibr::Input & input, const float deltaTime, const Viewport & viewport) override; + + /** \return the current camera */ + virtual const sibr::InputCamera & getCamera( void ) const override; + + /** Set the camera speed. + \param speed translation speed + \param angular rotation speed + */ + void setSpeed(const float speed, const float angular = 0.0); + + /** Dispaly GUI. + \param suffix Panel title suffix + */ + virtual void onGUI(const std::string& suffix) override; + + void setGoalAltitude(const float& goalAltitude); + + private: + + float _speedFpsCam, _speedRotFpsCam; ///< Camera speeds. + bool _hasBeenInitialized; ///< Has the camera been initialized. + sibr::InputCamera _currentCamera; ///< Current camera. + bool _useAcceleration; ///< Should the camera accelerate the longer keys are pressed. + float _goalAltitude; + + /** Update camera pose based on keys. + \param input user input + \param deltaTime elapsed time + */ + void moveUsingWASD( const sibr::Input& input, float deltaTime); + + /** Update camera pose based on mouse. + \param input user input + \param deltaTime elapsed time + */ + void moveUsingMousePan( const sibr::Input& input, float deltaTime); + + }; + +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/FPSCounter.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/FPSCounter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4476f00535aa73b81840cec216a85bb68fbcaf5e --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/FPSCounter.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include +#include + +#include "core/view/FPSCounter.hpp" +#include "core/assets/Resources.hpp" + +#include +#include "core/graphics/GUI.hpp" +#include "imgui/imgui_internal.h" + +#define SIBR_FPS_SMOOTHING 60 + + +namespace sibr +{ + + int FPSCounter::_count = 0; + + FPSCounter::FPSCounter(const bool overlayed){ + _frameTimes = std::vector(SIBR_FPS_SMOOTHING, 0.0f); + _frameIndex = 0; + _frameTimeSum = 0.0f; + _lastFrameTime = std::chrono::high_resolution_clock::now(); + _position = sibr::Vector2f(-1, -1); + if (overlayed) { + _flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings; + } else { + _flags = 0; + } + _hidden = false; + _name = "Metrics##" + std::to_string(_count); + ++_count; + } + + void FPSCounter::init(const sibr::Vector2f & position){ + _position = position; + } + + void FPSCounter::render(){ + + if (_hidden) { + return; + } + + if (_position.x() != -1) { + ImGui::SetNextWindowPos(ImVec2(_position.x(), _position.y())); + ImGui::SetNextWindowSize(ImVec2(0, ImGui::GetTitleBarHeight()), ImGuiCond_FirstUseEver); + } + + ImGui::SetNextWindowBgAlpha(0.5f); + if (ImGui::Begin(_name.c_str(), nullptr, _flags)) + { + ImGui::SetWindowFontScale(1.8); + const float frameTime = _frameTimeSum / float(SIBR_FPS_SMOOTHING); + ImGui::Text("%.2f (%.2f ms)", 1.0f/ frameTime, frameTime*1000.0f); + ImGui::SetWindowFontScale(1); + } + + ImGui::End(); + } + + void FPSCounter::update(float deltaTime){ + _frameTimeSum -= _frameTimes[_frameIndex]; + _frameTimeSum += deltaTime; + _frameTimes[_frameIndex] = deltaTime; + _frameIndex = (_frameIndex + 1) % SIBR_FPS_SMOOTHING; + } + + void FPSCounter::update(bool doRender) { + auto now = std::chrono::high_resolution_clock::now(); + float deltaTime = std::chrono::duration(now - _lastFrameTime).count(); + update(deltaTime); + if (doRender) { + render(); + } + _lastFrameTime = now; + + } + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/FPSCounter.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/FPSCounter.hpp new file mode 100644 index 0000000000000000000000000000000000000000..691970b0feb7b81f1ba889069fb5fee75929e604 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/FPSCounter.hpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include +# include "core/view/Config.hpp" +# include + +# include + +namespace sibr +{ + + /** Provde a small GUI panel to display the current framerate, smoothed over multiple frames. + * \ingroup sibr_view + */ + class SIBR_VIEW_EXPORT FPSCounter + { + public: + typedef std::chrono::time_point time_point; ///< Time type. + + /** Constructor. + \param overlayed if true, the GUI panel is always displayed on top of all others. + */ + FPSCounter(const bool overlayed = true); + + /** Setup at a given screen location. + \param position the position on screen (in pixels). + */ + void init(const sibr::Vector2f & position); + + /** generate the ImGui panel. */ + void render(); + + /** Update state using external timing. + \param deltaTime time elapsed since last udpate. + */ + void update(float deltaTime); + + /** Update state using internal timer. + \param doRender should the ImGui panel be genrated immediatly + */ + void update(bool doRender = true); + + /** Toggle the panel visibility. */ + void toggleVisibility() { + _hidden = !_hidden; + } + + /** \return true if the panel visible. */ + bool active() const { + return !_hidden; + } + + private: + time_point _lastFrameTime; ///< Last frame duration. + sibr::Vector2f _position; ///< on screen position. + std::vector _frameTimes; ///< Last N frame times. + size_t _frameIndex; ///< Current position in the time list. + float _frameTimeSum; ///< Current running sum. + int _flags; ///< Imgui display flags. + bool _hidden; ///< Visibility status. + std::string _name; ///< Panel name. + static int _count; ///< Internal counter to avoid collision when multiple framerate panels are displayed. + }; + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/IBRBasicUtils.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/IBRBasicUtils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c3451fb0c3f69d165e5ac84ad4763cb7fa4b0ff8 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/IBRBasicUtils.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "IBRBasicUtils.hpp" + +namespace sibr { + std::vector IBRBasicUtils::selectCameras(const std::vector& cams, const Camera & eye, uint count) + { + // Select one method + return selectCamerasAngleWeight(cams, eye, count); + //return selectCamerasSimpleDist(cams, eye, count); + } + + std::vector IBRBasicUtils::selectCamerasSimpleDist(const std::vector& cams, const sibr::Camera & eye, uint count, const bool& distOnly) + { + std::vector warped_img_id; + std::multimap dist; // distance wise closest input cameras + + for (uint i = 0; i < cams.size(); ++i) + { + if (cams.at(i)->isActive()) + { + float d = sibr::distance(cams[i]->position(), eye.position()); + float a = sibr::dot(cams[i]->dir(), eye.dir()); + if (distOnly) { + dist.insert(std::make_pair(d, i)); + } + else if (a > 0.707) { // cameras with 45 degrees + dist.insert(std::make_pair(d, i)); // sort distances in increasing order + } + } + } + + std::multimap::const_iterator d_it(dist.begin()); + for (uint i = 0; d_it != dist.end() && i < count; ++d_it, ++i) + warped_img_id.push_back(d_it->second); + + SIBR_ASSERT(warped_img_id.size() <= count); + + return warped_img_id; + } + + std::vector IBRBasicUtils::selectCamerasAngleWeight(const std::vector& cams, const sibr::Camera & eye, uint count) + { + const Vector3f& position = eye.position(); + const Quaternionf& rotation = eye.rotation(); + float angleWeight = 0.3f; + + float maxdist = 0.f; + std::vector sqrDists(cams.size(), 0.f); + + for (uint i = 0; i < cams.size(); ++i) + { + if (cams.at(i)->isActive()) + { + float sqrDist = (cams[i]->position() - position).squaredNorm(); + sqrDists[i] = sqrDist; + maxdist = std::max(sqrDist, maxdist); + } + } + + std::multimap factors; + for (uint i = 0; i < cams.size(); ++i) + { + if (cams.at(i)->isActive()) + { + float a = sibr::dot(cams[i]->dir(), eye.dir()); + if (a > 0.707) // cameras with 45 degrees + { + const float midAngle = 4.71239f; // = 270 degree + float sqrDist = sqrDists[i]; + float currNormalDist = inverseLerp(0.f, maxdist, sqrDist); + float currNormalAngle = inverseLerp(0.f, midAngle, angleRadian(rotation, cams[i]->rotation())); + float factor = currNormalDist*(1.f - angleWeight) + currNormalAngle*angleWeight; + + factors.insert(std::make_pair(factor, i)); // sort distances in increasing order + } + } + } + + std::vector warped_img_id; + std::multimap::const_iterator d_it(factors.begin()); + for (uint i = 0; d_it != factors.end() && i < count; ++d_it, ++i) + warped_img_id.push_back(d_it->second); + + SIBR_ASSERT(warped_img_id.size() <= count); + + return warped_img_id; + } +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/IBRBasicUtils.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/IBRBasicUtils.hpp new file mode 100644 index 0000000000000000000000000000000000000000..68aee8d867a76125dd453292f2485c04fb5dfa84 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/IBRBasicUtils.hpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include "core/view/Config.hpp" +#include "core/graphics/Utils.hpp" +#include "core/graphics/Camera.hpp" +#include "core/graphics/Image.hpp" +#include "core/assets/InputCamera.hpp" +#include + +namespace sibr{ + + /** Provide basic IBR utilities. + \ingroup sibr_view + */ + class SIBR_VIEW_EXPORT IBRBasicUtils + { + + public: + + /** Select cameras for a given viewpoint. + \param cams cameras to select from + \param eye novel viewpoint + \param count number of cameras to select + \return a list of selected camera indices. + \warning The number of cameras selected might be lower than count + \sa selectCamerasAngleWeight + */ + static std::vector selectCameras(const std::vector& cams, const sibr::Camera& eye, uint count); + + /** Select cameras based on distance to a given viewpoint. Cameras with an orientation that is more than 45οΏ½ off compared to the reference are ignored. + \param cams cameras to select from + \param eye novel viewpoint + \param count number of cameras to select + \return a list of selected camera indices. + \warning The number of cameras selected might be lower than count + */ + static std::vector selectCamerasSimpleDist(const std::vector& cams, const sibr::Camera& eye, uint count, const bool& distOnly = false); + + + /** Select cameras based on distance and orientation to a given viewpoint. Cameras with an orientation that is more than 45οΏ½ off compared to the reference are ignored. + \param cams cameras to select from + \param eye novel viewpoint + \param count number of cameras to select + \return a list of selected camera indices. + \warning The number of cameras selected might be lower than count + */ + static std::vector selectCamerasAngleWeight(const std::vector& cams, const sibr::Camera& eye, uint count); + + }; + +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/ICameraHandler.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/ICameraHandler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ece39727abf1d380a1c5753d21fa0db95232027a --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/ICameraHandler.cpp @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "ICameraHandler.hpp" \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/ICameraHandler.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/ICameraHandler.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1b86e7c238a2da77999a03ff554c21f927ae68c7 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/ICameraHandler.hpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include +#include + +#include "Config.hpp" + +#include "core/assets/InputCamera.hpp" +#include "core/graphics/Viewport.hpp" + +namespace sibr { + class Input; + + /** + * Represent an interaction mode (FPS, trackball,...) for a camera controlled by the user, or a combination of multiple modes. + \ingroup sibr_view + */ + class SIBR_VIEW_EXPORT ICameraHandler + { + public: + SIBR_CLASS_PTR(ICameraHandler) + + public: + + /** Update the camera handler state. + \param input user input + \param deltaTime time elapsed since last udpate + \param viewport view viewport + */ + virtual void update(const sibr::Input & input, const float deltaTime, const Viewport & viewport) = 0; + + /** \return the current camera. */ + virtual const InputCamera & getCamera(void) const = 0; + + // We allow for default empty implementations of render and onGUI. + + /** Render on top of the associated view(s). + \param viewport the rendering region + */ + virtual void onRender(const sibr::Viewport & viewport){}; + + /** Display GUI options and infos + \param windowName extra name to avoid collsiion between the windows of different handlers. + */ + virtual void onGUI(const std::string & windowName) {}; + + }; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/ImageView.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/ImageView.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8d92340e8c43ddfc39914f70e088c80efaa5c4cc --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/ImageView.cpp @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#include "ImageView.hpp" + +#include + +namespace sibr { + + ImageView::ImageView(bool interactiveMode) + { + _display.init("Display", sibr::loadFile( + sibr::getShadersDirectory("core") + "/image_viewer.vert"), + sibr::loadFile(sibr::getShadersDirectory("core") + "/image_viewer.frag")); + + _minVal.init(_display, "minVal"); + _maxVal.init(_display, "maxVal"); + _channels.init(_display, "channels"); + _size.init(_display, "size"); + _pos.init(_display, "pos"); + _scale.init(_display, "scale"); + _correctRatio.init(_display, "correctRatio"); + + _minVal = { 0.0f, 0.0f, 0.0f, 0.0f }; + _maxVal = {1.0f, 1.0f, 1.0f, 1.0f}; + _showChannels[0] = _showChannels[1] = _showChannels[2] = _showChannels[3] = true; + _bgColor = {0.25f, 0.25f, 0.25f}; + _pos = {0.0f, 0.0f}; + _scale = 1.0f; + // When in "fixed" mode, don't respect the aspect ratio, to make sure that the full image is visible to the viewer. + _correctRatio = interactiveMode; + _showGUI = interactiveMode; + _allowInteraction = interactiveMode; + } + + void ImageView::onUpdate(Input& input, const Viewport & vp) { + if(!_allowInteraction) { + return; + } + _scale = std::max(_scale - float(input.mouseScroll()) * 0.05f, 0.001f); + if(input.mouseButton().isActivated(Mouse::Left)) { + sibr::Vector2f delta = input.mouseDeltaPosition().cast().cwiseQuotient(vp.finalSize()); + delta[1] *= -1.0f; + _pos = _pos.get() + delta; + } + } + + void ImageView::onGUI() { + + if(!_showGUI) { + return; + } + const std::string guiName = name() + " options"; + if(ImGui::Begin(guiName.c_str())) { + + ImGui::Text("Size: %dx%d. Scale: %.2f%%", int(_size.get()[0]), int(_size.get()[1]), 100.0f * _scale); + + if (ImGui::Button("Reset view")) { + _pos = sibr::Vector2f(0.0f, 0.0f); + _scale = 1.0f; + } + ImGui::SameLine(); + ImGui::Checkbox("Correct aspect ratio", &_correctRatio.get()); + + ImGui::Separator(); + + ImGui::Text("Channels"); ImGui::SameLine(); + ImGui::Checkbox("R", &_showChannels[0]); ImGui::SameLine(); + ImGui::Checkbox("G", &_showChannels[1]); ImGui::SameLine(); + ImGui::Checkbox("B", &_showChannels[2]); ImGui::SameLine(); + ImGui::Checkbox("A", &_showChannels[3]); + + ImGui::ColorEdit3("Background", &_bgColor[0]); + + ImGui::Separator(); + + const float dragSpeed = 0.05f; + bool editBounds = false; + + if(_lockChannels) { + // Only display one value and ensure synchronisation between the RGB components. + editBounds = ImGui::DragFloat("Min.", &_minVal.get()[0], dragSpeed) || editBounds; + editBounds = ImGui::DragFloat("Max.", &_maxVal.get()[0], dragSpeed) || editBounds; + } else { + editBounds = ImGui::DragFloat4("Min.", &_minVal.get()[0], dragSpeed) || editBounds; + editBounds = ImGui::DragFloat4("Max.", &_maxVal.get()[0], dragSpeed) || editBounds; + } + // Ensure internal state consistency. + if(editBounds && _lockChannels) { + _minVal.get()[3] = _minVal.get()[2] = _minVal.get()[1] = _minVal.get()[0]; + _maxVal.get()[3] = _maxVal.get()[2] = _maxVal.get()[1] = _maxVal.get()[0]; + } + // Ensure ordering. + if(editBounds) { + const sibr::Vector4f temp = _minVal; + _minVal = temp.cwiseMin(_maxVal.get()); + _maxVal = temp.cwiseMax(_maxVal.get()); + } + + ImGui::Checkbox("Lock values", &_lockChannels); + ImGui::SameLine(); + if (ImGui::Button("Reset values")) { + _minVal = sibr::Vector4f(0.0f, 0.0f, 0.0f, 0.0f); + _maxVal = sibr::Vector4f(1.0f, 1.0f, 1.0f, 1.0f); + } + } + ImGui::End(); + } + + void ImageView::setRenderTarget(const IRenderTarget& rt, uint handle) { + _tex = nullptr; + _texHandle = rt.handle(handle); + _size.get()[0] = float(rt.w()); _size.get()[1] = float(rt.h()); + } + + void ImageView::setTexture(const ITexture2D& tex) + { + _tex = nullptr; + _texHandle = tex.handle(); + _size.get()[0] = float(tex.w()); _size.get()[1] = float(tex.h()); + } + + + void ImageView::onRender(const Viewport & vpRender){ + + vpRender.bind(); + vpRender.clear(_bgColor); + if (_texHandle == 0) { + return; + } + + // Update channels flags. + _channels.get()[0] = float(_showChannels[0]); + _channels.get()[1] = float(_showChannels[1]); + _channels.get()[2] = float(_showChannels[2]); + _channels.get()[3] = float(_showChannels[3]); + + _display.begin(); + + if(_showChannels[3]) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendEquation(GL_FUNC_ADD); + } + + _maxVal.send(); + _minVal.send(); + _channels.send(); + _scale.send(); + _pos.send(); + _size.send(); + _correctRatio.send(); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, _texHandle); + RenderUtility::renderScreenQuad(); + + glDisable(GL_BLEND); + _display.end(); + + CHECK_GL_ERROR; + } + +} \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/ImageView.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/ImageView.hpp new file mode 100644 index 0000000000000000000000000000000000000000..711169e86a25d7f605dcaf8543ec86d91eaeb6f6 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/ImageView.hpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include +# include +# include +# include +# include + +namespace sibr { + + /** Basic view to display an image and inspect it. + *Two modes are supported: + * * interactive, where the user can pan/zoom, rescale the values, display some channels, via the mouse and GUI. + * * fixed, where the image is displayed as is, without any modification possible. + */ + class SIBR_VIEW_EXPORT ImageView : public sibr::ViewBase + { + SIBR_CLASS_PTR(ImageView); + public: + + /** Constructor. + * \param interactiveMode should the GUI panel be displayed and the user be able to pan/zoom into the image + */ + ImageView(bool interactiveMode = true); + + /** Render the image in the currently bound rendertarget. + *\param vpRender the region to render into + */ + void onRender(const Viewport & vpRender) override; + + /** Update user interactions. + *\param input the user input for the view + *\param vp the view viewport + */ + void onUpdate(Input& input, const Viewport & vp) override; + + /*** Render GUI panels. */ + void onGUI() override; + + /** Set an attachment of a rendertarget as the texture to display. + *\param rt the rendertarget to display + *\param handle the index of the attachment to display + *\warning Will only be valid until the RT is deleted. + */ + void setRenderTarget(const IRenderTarget & rt, uint handle = 0); + + /** Set the texture to display. + *\param tex the texture to display + *\warning Will only be valid until the texture is deleted. + */ + void setTexture(const ITexture2D& tex); + + /** Set an image as the texture to display. An internal copy of the image will be sent to the GPU. + *\param img the image + */ + template + void setImage(const Image & img) { + // Create texture on the fly. + std::shared_ptr> tex(new Texture2D(img)); + _tex = tex; + _texHandle = _tex->handle(); + _size.get()[0] = float(_tex->w()); + _size.get()[1] = float(_tex->h()); + } + + /** Set if the GUI panel should be displayed or not. + *\param opt display option + **/ + void showGUI(bool opt) { + _showGUI = opt; + } + + /** Set if the user should be able to pan/zoom the image + *\param opt interaction option + **/ + void allowInteraction(bool opt) { + _allowInteraction = opt; + } + + protected: + + ITexture2D::Ptr _tex; ///< Internal texture for the image input case. + GLuint _texHandle = 0; ///< Texture to display. + + GLShader _display; ///< Shader. + + GLuniform _minVal; ///< Normalization minimum. + GLuniform _maxVal; ///< Normalization maximum. + bool _lockChannels = true; ///< Use the same normalization values for all channels. + + std::array _showChannels; ///< Display which channels. + GLuniform _channels; ///< Display which channels (shader). + + GLuniform _pos; ///< Center position. + GLuniform _size; ///< Image size. + GLuniform _scale; ///< Image scale. + GLuniform _correctRatio; ///< Use proper aspect ratio to display. + + sibr::Vector3f _bgColor; ///< Background color. + bool _showGUI = true; ///< Show the GUI be displayed or not. + bool _allowInteraction = true; ///< Should the user be able to pan/zoom into the image. + }; + +} \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/ImagesGrid.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/ImagesGrid.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e02700a02ae354605850f57d74fb5b4c4bce059f --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/ImagesGrid.cpp @@ -0,0 +1,638 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "ImagesGrid.hpp" + +#include + +#define GUI_TEXT(txt) { std::stringstream sss; sss << txt << std::endl; ImGui::Text(sss.str().c_str()); } + +namespace sibr +{ + void ImagesGrid::onUpdate(Input & input, const Viewport & vp) + { + const Vector2f size = vp.finalSize(); + + if (current_level_tex) { + imSizePixels = { current_level_tex->w(), current_level_tex->h() }; + imSizePixels = imSizePixels.cwiseQuotient(pow(2.0, current_lod)*Vector2f(1, 1)).unaryExpr([](float f) { return std::floor(f); }); + + num_imgs = (int)current_layer->imgs_texture_array->depth(); + } + + currentActivePix = pixFromScreenPos(input.mousePosition(), size); + _vp = vp; + + setupGrid(vp); + + updateZoomBox(input, vp); + updateZoomScroll(input); + updateDrag(input, size); + + if (currentActivePix && input.key().isActivated(Key::LeftControl) && input.mouseButton().isReleased(Mouse::Code::Left) ) { + if (selectionMode == IMAGE_SELECTION) { + current_layer->image_selection.switchSelection(currentActivePix.im); + } + if (selectionMode == PIXEL_SELECTION && !current_layer->flip_texture) { + current_layer->pixel_selection.switchSelection(currentActivePix); + } + } + + std::vector all_ims; + std::iota(all_ims.begin(), all_ims.end(), 0); + addImagesToHighlight("imBorders", all_ims, { 0,0,0 }); + + if (currentActivePix) { + addPixelsToHighlight("activePix", { currentActivePix }, { 0, 1, 0 }, 0.25f); + } + + const auto & imgs_list = current_layer->image_selection.get(); + if (!imgs_list.empty()) { + std::vector selected_ims(std::begin(imgs_list), std::end(imgs_list)); + addImagesToHighlight("imSelection", selected_ims, { 0,1,0 }, 0.1f); + } + + + } + + void ImagesGrid::onRender(const Viewport & viewport) + { + viewport.bind(); + + viewport.clear(Vector3f(0.7f, 0.7f, 0.7f)); + + if (!current_level_tex) { + return; + } + + draw_utils.image_grid(num_imgs, current_level_tex->handle(), grid_adjusted, viewRectangle.tl(), viewRectangle.br(), current_lod, current_layer->flip_texture); + + for (const auto & ims_highlight : images_to_highlight) { + const auto & imgs = ims_highlight.second; + for (int im : imgs.data) { + highlightImage(im, viewport, imgs.color, imgs.alpha); + } + } + + for (const auto & pixels_highlight : pixels_to_highlight) { + const auto & pix_data = pixels_highlight.second; + for (const auto pix : pix_data.data) { + highlightPixel(pix, viewport, pix_data.color); + } + } + + displayZoom(viewport, draw_utils); + } + + void ImagesGrid::onRender(IRenderTarget & dst) + { + dst.bind(); + + Viewport vp(0.0f, 0.0f, (float)dst.w(), (float)dst.h()); + onRender(vp); + + dst.unbind(); + } + + void ImagesGrid::onGUI() + { + if (ImGui::Begin("grid_gui")) { + + + optionsGUI(); + + listImagesLayerGUI(); + + if (currentActivePix) { + GUI_TEXT("current pix : " << currentActivePix.im << ", " << currentActivePix.pos.transpose()); + + Vector4f value = current_layer->imgs_texture_array->readBackPixel(currentActivePix.im, currentActivePix.pos[0], currentActivePix.pos[1], current_lod); + if (integer_pixel_values) { + Vector4i value_i = (255 * value).cast(); + GUI_TEXT(" \t value : " << value_i.transpose()); + } else { + GUI_TEXT(" \t value : " << value.transpose()); + } + + + } + + std::stringstream s; + s << "active images : "; + for (int im : current_layer->image_selection.get()) { + s << im << ", "; + } + ImGui::Text(s.str().c_str()); + + } + ImGui::End(); + } + + void ImagesGrid::addImagesToHighlight(const std::string & name, const std::vector& imgs, const Vector3f & col, float alpha_fill) + { + images_to_highlight[name] = { imgs, col, alpha_fill }; + } + + void ImagesGrid::addPixelsToHighlight(const std::string & name, const std::vector& pixs, const Vector3f & col, float alpha_fill) + { + pixels_to_highlight[name] = { pixs, col, alpha_fill }; + } + + const MVpixel & ImagesGrid::getCurrentPixel() + { + return currentActivePix; + } + + void ImagesGrid::listImagesLayerGUI() + { + + if (ImGui::CollapsingHeader("images_layers")) { + + // 0 name | 1 infos | 2 options + ImGui::Columns(3, "images_layers_list"); + + ImGui::Separator(); + + ImGui::Text("layer"); + ImGui::NextColumn(); + + ImGui::Text("num x w x h"); + ImGui::NextColumn(); + + ImGui::Text("options"); + ImGui::NextColumn(); + + ImGui::Separator(); + + for (auto imgs_it = images_layers.begin(); imgs_it != images_layers.end(); ++imgs_it) { + if (ImGui::Selectable(imgs_it->name.c_str(), current_layer == imgs_it)) { + current_layer = imgs_it; + current_level_tex = current_layer->imgs_texture_array; + } + + ImGui::NextColumn(); + + auto & tex_arr = imgs_it->imgs_texture_array; + GUI_TEXT(tex_arr->depth() << " x " << tex_arr->w() << " x " << tex_arr->h()); + ImGui::NextColumn(); + + ImGui::Checkbox(("flip##" + imgs_it->name).c_str(), &imgs_it->flip_texture); + + ImGui::NextColumn(); + + ImGui::Separator(); + } + + ImGui::Columns(1); + + } + } + + void ImagesGrid::optionsGUI() + { + if (ImGui::CollapsingHeader("grid_options")) { + + + if (ImGui::SliderInt("num per row", &num_per_row, 1, num_imgs)) { + viewRectangle.center = { 0.5f, 0.5f }; + viewRectangle.diagonal = { 0.5f, 0.5f }; + } + if (ImGui::SliderInt("pyramid level", ¤t_lod, 0, 10)) { + currentActivePix.isDefined = false; + } + + static const std::vector selection_mode_str = { "no selection", "image" ,"pixel" }; + for (int i = 0; i < (int)selection_mode_str.size(); ++i) { + if (i != 0) { + ImGui::SameLine(); + } + if (ImGui::RadioButton(selection_mode_str[i], selectionMode == (SelectionMode)i)) { + selectionMode = (SelectionMode)i; + } + } + + ImGui::Checkbox("integer pixel values", &integer_pixel_values); + } + } + + bool ImagesGrid::name_collision(const std::string & name) const + { + for (const auto & layer : images_layers) { + if (layer.name == name) { + return true; + } + } + return false; + } + + void ImagesGrid::setupFirstLayer() + { + if (images_layers.size() == 1) { + current_layer = images_layers.begin(); + current_level_tex = current_layer->imgs_texture_array; + } + } + + DrawUtilities::DrawUtilities() + { + initBaseShader(); + initGridShader(); + } + + void DrawUtilities::baseRendering(const Mesh & mesh, Mesh::RenderMode mode, const Vector3f & color, + const Vector2f & translation, const Vector2f & scaling, float alpha, const Viewport & vp) + { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendEquation(GL_FUNC_ADD); + + vp.bind(); + baseShader.begin(); + + scalingGL.set(scaling); + translationGL.set(translation); + colorGL.set(color); + alphaGL.set(alpha); + + mesh.render(false, false, mode); + + baseShader.end(); + + glDisable(GL_BLEND); + } + + void DrawUtilities::rectangle(const Vector3f & color, const Vector2f & tl, const Vector2f & br, bool fill, float alpha, const Viewport & vp) + { + auto rectangleMesh = std::make_shared(); + + rectangleMesh->vertices({ + { tl.x(), tl.y() , 0 }, + { tl.x(), br.y() , 0 }, + { br.x(), br.y() , 0 }, + { br.x(), tl.y() , 0 } + }); + + if (fill) { + rectangleMesh->triangles({ + { 0,1,2 }, + { 0,2,3 } + }); + + baseRendering(*rectangleMesh, Mesh::FillRenderMode, color, { 0,0 }, { 1,1 }, alpha, vp); + } + + rectangleMesh->triangles({ + { 0,0,1 },{ 1,1,2 },{ 2,2,3 },{ 3,3,0 } + }); + + baseRendering(*rectangleMesh, Mesh::LineRenderMode, color, { 0,0 }, { 1,1 }, 1.0f, vp); + } + + void DrawUtilities::rectanglePixels(const Vector3f & color, const Vector2f & center, const Vector2f & diagonalPixs, bool fill, float alpha, const Viewport & vp) + { + Vector2f diagUV = diagonalPixs.cwiseQuotient(vp.finalSize()); + Vector2f tl = center - diagUV; + Vector2f br = center + diagUV; + rectangle(color, tl, br, fill, alpha, vp); + } + + void DrawUtilities::circle(const Vector3f & color, const Vector2f & center, float radius, bool fill, float alpha, const Vector2f & scaling, int precision) + { + + static Mesh::Vertices vertices; + static Mesh::Triangles circleTriangles, circleFillTriangles; + + int n = precision; + if (circleFillTriangles.size() != n) { + n = precision; + circleTriangles.resize(n); + circleFillTriangles.resize(n); + for (int i = 0; i < n; ++i) { + int next = (i + 1) % n; + circleTriangles[i] = Vector3u(i, i, next); + circleFillTriangles[i] = Vector3u(i, next, n); + } + + vertices.resize(n + 1); + } + + double base_angle = 2.0*M_PI / (double)n; + float rho = 0.5f*radius*(float)(1.0 + cos(0.5*base_angle)); + + for (int i = 0; i < n; ++i) { + double angle = i * base_angle; + vertices[i] = Vector3f((float)cos(angle), (float)sin(angle), (float)0.0); + } + vertices[n] = Vector3f(0, 0, 0); + + auto circleMesh = std::make_shared(); + auto circleFilledMesh = std::make_shared(); + circleMesh->vertices(vertices); + circleFilledMesh->vertices(vertices); + circleMesh->triangles(circleTriangles); + circleFilledMesh->triangles(circleFillTriangles); + + if (fill) { + baseRendering(*circleFilledMesh, Mesh::FillRenderMode, color, { 0,0 }, { radius, radius }, alpha, {}); + } + baseRendering(*circleMesh, Mesh::LineRenderMode, color, { 0,0 }, { radius, radius }, 1.0f, {}); + } + + void DrawUtilities::circlePixels(const Vector3f & color, const Vector2f & center, float radius, bool fill, float alpha, const Vector2f & winSize, int precision) + { + Vector2f centerUV = center.cwiseQuotient(winSize); + Vector2f scaling = radius * Vector2f(1, 1).cwiseQuotient(winSize); + + circle(color, centerUV, 1.0f, fill, alpha, scaling, precision); + } + + void DrawUtilities::linePixels(const Vector3f & color, const Vector2f & ptA, const Vector2f & ptB, const Vector2f & winSize) + { + Vector2f uvA = ptA.cwiseQuotient(winSize); + Vector2f uvB = ptB.cwiseQuotient(winSize); + + Mesh line; + line.vertices({ + { uvA.x(), uvA.y(), 0.0f }, + { uvB.x(), uvB.y(), 0.0f } + }); + line.triangles({ + Vector3u(0,0,1) + }); + + baseRendering(line, Mesh::LineRenderMode, color, { 0,0 }, { 1.0, 1.0 }, 1.0f, {}); + + } + + void DrawUtilities::image_grid(int num_imgs, uint texture, const Vector2f & grid, const Vector2f & tl, const Vector2f & br, int lod, bool flip_texture) + { + gridShader.begin(); + + numImgsGL.set(num_imgs); + gridGL.set(grid); + lodGL.set((float)lod); + + gridTopLeftGL.set(tl); + gridBottomRightGL.set(br); + + flip_textureGL.set(flip_texture); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D_ARRAY, texture); + RenderUtility::renderScreenQuad(); + + gridShader.end(); + } + + void DrawUtilities::initBaseShader() + { + const std::string translationScalingVertexShader = + "#version 420 \n" + "layout(location = 0) in vec3 in_vertex; \n" + "uniform vec2 translation; \n" + "uniform vec2 scaling; \n" + "void main(void) { \n" + " gl_Position = vec4(scaling*in_vertex.xy+translation,0.0, 1.0); \n" + "} \n"; + + const std::string colorAlphaFragmentShader = + "#version 420 \n" + "uniform vec3 color; \n" + "uniform float alpha; \n" + "out vec4 out_color; \n" + "void main(void) { \n" + " out_color = vec4(color,alpha); \n" + "} \n"; + + baseShader.init("InterfaceUtilitiesBaseShader", translationScalingVertexShader, colorAlphaFragmentShader); + colorGL.init(baseShader, "color"); + alphaGL.init(baseShader, "alpha"); + scalingGL.init(baseShader, "scaling"); + translationGL.init(baseShader, "translation"); + } + + void DrawUtilities::initGridShader() + { + const std::string gridVertexShader = + "#version 420 \n" + "layout(location = 0) in vec3 in_vertex; \n" + "out vec2 uv_coord; \n" + "uniform vec2 zoomTL; \n" + "uniform vec2 zoomBR; \n" + "void main(void) { \n" + " uv_coord = 0.5*in_vertex.xy + vec2(0.5); \n" + " uv_coord.y = 1.0 - uv_coord.y; \n" + " uv_coord = zoomTL + (zoomBR-zoomTL)*uv_coord; \n" + " gl_Position = vec4(in_vertex.xy,0.0, 1.0); \n" + "} \n"; + + + + + const std::string gridFragmentShader = + "#version 420 \n" + "layout(binding = 0) uniform sampler2DArray texArray; \n" + "uniform int numImgs; \n" + "uniform vec2 grid; \n" + "uniform float lod; \n" + "uniform bool flip_texture; \n" + "in vec2 uv_coord; \n" + "out vec4 out_color; \n" + "void main(void) { \n" + " vec2 uvs = uv_coord; \n" + " uvs = grid*uvs; \n" + " if( uvs.x < 0 || uvs.y < 0 ) { discard; } \n" + " vec2 fracs = fract(uvs); \n" + " vec2 mods = uvs - fracs; \n" + " int n = int(mods.x + grid.x*mods.y); \n" + " if ( n< 0 || n > numImgs || mods.x >= grid.x || mods.y >= (float(numImgs)/grid.x) ) { discard; } else { \n" + " out_color = textureLod(texArray,vec3(fracs.x, flip_texture ? 1.0 -fracs.y : fracs.y,n), lod); } \n" + " //out_color = vec4(n/64.0,0.0,0.0,1.0); } \n" + " //out_color = vec4(uv_coord.x,uv_coord.y,0.0,1.0); } \n" + "} \n"; + + + gridShader.init("InterfaceUtilitiesMultiViewShader", gridVertexShader, gridFragmentShader); + gridTopLeftGL.init(gridShader, "zoomTL"); + gridBottomRightGL.init(gridShader, "zoomBR"); + numImgsGL.init(gridShader, "numImgs"); + gridGL.init(gridShader, "grid"); + lodGL.init(gridShader, "lod"); + flip_textureGL.init(gridShader, "flip_texture"); + } + + MVpixel GridMapping::pixFromScreenPos(const Vector2i & pos, const Vector2f & size) + { + Vector2f uvScreen = (pos.cast() + 0.5*Vector2f(1, 1)).cwiseQuotient(size); + + Vector2f posF = viewRectangle.tl() + 2.0*viewRectangle.diagonal.cwiseProduct(uvScreen); + posF = posF.cwiseProduct(grid_adjusted); + + //std::cout << posF.transpose() << " " << numImgs << std::endl; + + if (posF.x() < 0 || posF.y() < 0 || posF.x() >= grid_adjusted.x() /* || posF.y() >= grid.y() */) { + return MVpixel(); + } + + int x = (int)std::floor(posF.x()); + int y = (int)std::floor(posF.y()); + + int n = x + num_per_row * y; + if (n >= num_imgs) { + return MVpixel(); + } + + Vector2f frac = posF - Vector2f(x, y); + int j = (int)std::floor(frac.x()*imSizePixels.x()); + int i = (int)std::floor(frac.y()*imSizePixels.y()); + return MVpixel(n, Vector2i(j, i)); + } + + Vector2f GridMapping::uvFromMVpixel(const MVpixel & pix, bool use_center) + { + Vector2f pos = ((pix.pos.cast() + (use_center ? 0.5 : 0)*Vector2f(1, 1)).cwiseQuotient(imSizePixels) + + Vector2f(pix.im % num_per_row, pix.im / num_per_row)).cwiseQuotient(grid_adjusted); + pos = (pos - viewRectangle.tl()).cwiseQuotient(viewRectangle.diagonal) - Vector2f(1, 1); + pos.y() = -pos.y(); + return pos; + } + + void GridMapping::updateZoomBox(const Input & input, const sibr::Viewport & vp) + { + Vector2f size = vp.finalSize(); + + if (input.key().isPressed(Key::Q)) { + viewRectangle.center = Vector2f(0.5, 0.5); + viewRectangle.diagonal = Vector2f(0.5, 0.5); + } + + if (input.mouseButton().isPressed(Mouse::Code::Right) && !input.key().isActivated(Key::LeftControl) && !zoomSelection) { + zoomSelection.isActive = true; + zoomSelection.first = input.mousePosition(); + } + + if (zoomSelection) { + zoomSelection.second = input.mousePosition(); + + Viewport aligned_vp = Viewport(0, 0, vp.finalWidth(), vp.finalHeight()); + + Vector2f currentTL = (zoomSelection.first.cwiseMin(zoomSelection.second)).cast(); + Vector2f currentBR = (zoomSelection.first.cwiseMax(zoomSelection.second)).cast(); + + const auto clamp = [](Vector2f & v, float w, float h) { v = v.cwiseMax(Vector2f(1, 1)).cwiseMin(Vector2f(w - 2, h - 2)); }; + clamp(currentTL, vp.finalRight(), vp.finalBottom()); + clamp(currentBR, vp.finalRight(), vp.finalBottom()); + + if (input.mouseButton().isReleased(Mouse::Code::Right)) { + zoomSelection.isActive = false; + if (((currentBR - currentTL).array() > Vector2f(5, 5).array()).all()) { + Vector2f tlPix = viewRectangle.tl().cwiseProduct(size) + (viewRectangle.br() - viewRectangle.tl()).cwiseProduct(currentTL); + Vector2f brPix = viewRectangle.tl().cwiseProduct(size) + (viewRectangle.br() - viewRectangle.tl()).cwiseProduct(currentBR); + + Vector2f center = 0.5f*(brPix + tlPix); + Vector2f diag = 0.5f*(brPix - tlPix); + + float new_ratio = diag.x() / diag.y(); + float target_ratio = size.x() / size.y(); + if (new_ratio > target_ratio) { + diag.y() = diag.x() / target_ratio; + } else { + diag.x() = diag.y() * target_ratio; + } + + viewRectangle.center = center.cwiseQuotient(size); + viewRectangle.diagonal = diag.cwiseQuotient(size); + } + + } else if (!input.mouseButton().isActivated(Mouse::Code::Right) && input.isInsideViewport(aligned_vp)) { + zoomSelection.isActive = false; + } + } + + } + + void GridMapping::updateZoomScroll(const Input & input) + { + double scroll = input.mouseScroll(); + if (scroll) { + float ratio = (scroll > 0 ? 0.75f : 1.33f); + if (input.key().isActivated(Key::LeftControl)) { + ratio *= ratio; + } + viewRectangle.diagonal *= ratio; + } + } + + void GridMapping::updateCenter(const Input & input, const Vector2f & size) + { + } + + void GridMapping::updateDrag(const Input & input, const Vector2f & size) + { + if (input.mouseButton().isPressed(Mouse::Left)) { + drag.isActive = true; + drag.position = input.mousePosition(); + drag.center = viewRectangle.center.cast(); + } else if (drag.isActive && input.mouseButton().isReleased(Mouse::Left)) { + drag.isActive = false; + } + if (drag.isActive && input.mouseButton().isActivated(Mouse::Left)) { + Vector2f translation = 2.0*(input.mousePosition() - drag.position).cast().cwiseQuotient(size).cwiseProduct(viewRectangle.diagonal); + viewRectangle.center = drag.center - translation; + } + } + + void GridMapping::displayZoom(const Viewport & viewport, DrawUtilities & utils) + { + if (zoomSelection) { + Vector2f tl = 2.0*zoomSelection.first.cast().cwiseQuotient(_vp.finalSize()) - Vector2f(1, 1); + Vector2f br = 2.0*zoomSelection.second.cast().cwiseQuotient(_vp.finalSize()) - Vector2f(1, 1); + tl.y() = -tl.y(); + br.y() = -br.y(); + utils.rectangle(Vector3f(1, 0, 0), tl, br, false, 0.15f, viewport); + } + } + + void GridMapping::highlightPixel(const MVpixel & pix, const Viewport & viewport, const Vector3f & color, const Vector2f & pixScreenSize) + { + Vector2f pixTl = uvFromMVpixel(pix); + Vector2f pixBR = uvFromMVpixel(MVpixel(pix.im, pix.pos + Vector2i(1, 1))); + + viewport.bind(); + + if ((pixBR - pixTl).cwiseProduct(viewport.finalSize()).norm() < pixScreenSize.diagonal().norm()) { + //if pixel size in screen space is too tiny + draw_utils.rectanglePixels(color, 0.5*(pixTl + pixBR), pixScreenSize, true, 0.15f, viewport); + } else { + //otherwise highlight pixel intirely + draw_utils.rectangle(color, pixTl, pixBR, true, 0.15f, viewport); + } + } + + void GridMapping::highlightImage(int im, const sibr::Viewport & viewport, const sibr::Vector3f & color, float alpha) + { + Vector2f imTl = uvFromMVpixel(MVpixel(im, { 0, 0 })); + Vector2f imBR = uvFromMVpixel(MVpixel(im, imSizePixels.cast())); + + draw_utils.rectangle(color, imTl, imBR, alpha != 0 , alpha, viewport); + } + + void GridMapping::setupGrid(const Viewport & vp) + { + float ratio_img = imSizePixels.x() / imSizePixels.y(); + float ratio_vp = vp.finalWidth() / vp.finalHeight(); + grid_adjusted = num_per_row * Vector2f(1, ratio_img / ratio_vp); + } + +} + +#undef GUI_TEXT \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/ImagesGrid.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/ImagesGrid.hpp new file mode 100644 index 0000000000000000000000000000000000000000..32fbf33d6534887aadbd4a8b01de1b9e880bfbe4 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/ImagesGrid.hpp @@ -0,0 +1,282 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once +# include "Config.hpp" +#include +# include +#include +#include +#include + +namespace sibr +{ + + class SIBR_VIEW_EXPORT DrawUtilities + { + public: + + DrawUtilities(); + + GLShader baseShader; + + GLuniform colorGL; + GLuniform alphaGL; + GLuniform scalingGL; + GLuniform translationGL; + + GLShader gridShader; + + + GLuniform gridGL; + GLuniform gridTopLeftGL; + GLuniform gridBottomRightGL; + GLuniform lodGL; + GLuniform numImgsGL; + GLuniform flip_textureGL; + + void baseRendering(const Mesh & mesh, Mesh::RenderMode mode, const Vector3f & color, const Vector2f & translation, const Vector2f & scaling, float alpha, const Viewport & vp); + + void rectangle(const Vector3f & color, const Vector2f & tl, const Vector2f & br, bool fill, float alpha, const Viewport & vp ); + void rectanglePixels(const Vector3f & color, const Vector2f & center, const Vector2f & diagonalPixs, bool fill, float alpha, const Viewport & vp); + void circle(const Vector3f & color, const Vector2f & center, float radius, bool fill, float alpha, const Vector2f & scaling = Vector3f(1, 1), int precision = 50); + void circlePixels(const Vector3f & color, const Vector2f & center, float radius, bool fill, float alpha, const Vector2f & winSize, int precision = 50); + void linePixels(const Vector3f & color, const Vector2f & ptA, const Vector2f & ptB, const Vector2f & winSize); + + void image_grid(int num_imgs, uint texture, const Vector2f & grid, const Vector2f & tl, const Vector2f & br, int lod, bool flip_texture); + + private: + + void initBaseShader(); + void initGridShader(); + + }; + + struct QuadData + { + Vector2f center = { 0.5, 0.5 }; + Vector2f diagonal = { 0.5, 0.5 }; + + Vector2f br() const { return center + diagonal; } + Vector2f tl() const { return center - diagonal; } + }; + + struct QuadSelectionData + { + operator bool() const { return isActive; } + Vector2i first; + Vector2i second; + bool isActive = false; + }; + + struct DragClickData + { + Vector2f center; + Vector2i position; + bool isActive = false; + }; + + struct MVpixel { + MVpixel() : isDefined(false) {} + MVpixel(int i, const Vector2i & px) : im(i), pos(px), isDefined(true) {} + + operator bool() const { return isDefined; } + bool operator ==(const MVpixel & other) const { return im == other.im && pos == other.pos; } + + Vector2i pos; + int im; + bool isDefined = false; + }; + + + class SIBR_VIEW_EXPORT GridMapping { + + protected: + MVpixel pixFromScreenPos(const Vector2i & pos, const Vector2f & size); + + //uvs in opengl [1,-1] + Vector2f uvFromMVpixel(const MVpixel & pix, bool use_center = false); + + void updateZoomBox(const Input & input, const sibr::Viewport & vp); + void updateZoomScroll(const Input & input); + void updateCenter(const Input & input, const Vector2f & size); + void updateDrag(const Input & input, const Vector2f & size); + + void displayZoom(const sibr::Viewport & viewport, DrawUtilities & utils); + + void highlightPixel(const MVpixel & pix, const sibr::Viewport & viewport, const sibr::Vector3f & color = { 0, 1, 0 }, const sibr::Vector2f & minPixSize = { 10.0f, 10.0f }); + void highlightImage(int im, const sibr::Viewport & viewport, const sibr::Vector3f & color = { 0, 1, 0 }, float alpha = 0); + void setupGrid(const Viewport & vp); + + DrawUtilities draw_utils; + Viewport _vp; + QuadData viewRectangle; + QuadSelectionData zoomSelection; + DragClickData drag; + + int num_per_row = 4; + Vector2f grid_adjusted; + + Vector2f imSizePixels; + int num_imgs; + }; + + + + template + class ObjectSelection { + public: + void switchSelection(const T & t) { + for (auto it = _selected.begin(); it != _selected.end(); ++it) { + if (*it == t) { + _selected.erase(it); + return; + } + } + _selected.push_back(t); + } + + const std::list get() const { + return _selected; + } + + protected: + std::list _selected; + }; + + struct ImageGridLayer { + ITexture2DArray::Ptr imgs_texture_array; + + ObjectSelection pixel_selection; + ObjectSelection image_selection; + + std::string name; + bool flip_texture = false; + }; + + template + struct HighlightData { + std::vector data; + Vector3f color; + float alpha = 0; + }; + + + class SIBR_VIEW_EXPORT ImagesGrid : public ViewBase, GridMapping + { + SIBR_CLASS_PTR(ImagesGrid); + + public: + + enum SelectionMode { NO_SELECTION, IMAGE_SELECTION, PIXEL_SELECTION }; + + //ViewBase interface + virtual void onUpdate(Input& input, const Viewport & vp) override; + virtual void onRender(const Viewport & viewport) override; + virtual void onRender(IRenderTarget & dst); + virtual void onGUI() override; + + void addImagesToHighlight(const std::string & name, const std::vector & imgs, const Vector3f & col, float alpha_fill = 0); + void addPixelsToHighlight(const std::string & name, const std::vector & pixs, const Vector3f & col, float alpha_fill = 0); + + + const MVpixel & getCurrentPixel(); + + protected: + + void listImagesLayerGUI(); + void optionsGUI(); + + bool name_collision(const std::string & name) const; + void setupFirstLayer(); + + std::list images_layers; + std::list::iterator current_layer; + ITexture2DArray::Ptr current_level_tex; + int current_lod = 0; + bool integer_pixel_values = true; + + std::map< std::string, HighlightData > pixels_to_highlight; + std::map > images_to_highlight; + + MVpixel currentActivePix; + SelectionMode selectionMode = IMAGE_SELECTION; + + public: + template + void addImageLayer( + const std::string & layer_name, + const std::vector > & images, + uint flags = 0 + ) { + std::vector images_cv(images.size()); + for (size_t im = 0; im < images.size(); ++im) { + images_cv[im] = images[im].toOpenCVBGR(); + } + addImageLayer(layer_name, images_cv, flags); + } + + template + void addImageLayer( + const std::string & layer_name, + const std::vector> & images, + uint flags = 0 + ) { + std::vector images_cv(images.size()); + for (size_t im = 0; im < images.size(); ++im) { + images_cv[im] = images[im]->toOpenCVBGR(); + } + addImageLayer(layer_name, images_cv, flags); + } + + template + void addImageLayer( + const std::string & layer_name, + const std::shared_ptr> & images + ) { + if (name_collision(layer_name)) { + return; + } + + ImageGridLayer layer; + layer.name = layer_name; + layer.imgs_texture_array = { std::static_pointer_cast(images) }; + + images_layers.push_back(layer); + + setupFirstLayer(); + } + + template + void addImageLayer( + const std::string & layer_name, + const std::vector & images, + uint flags = 0 + ) { + + if (!images.size()) { + return; + } + + if (name_collision(layer_name)) { + return; + } + + ImageGridLayer layer; + layer.name = layer_name; + layer.imgs_texture_array = std::make_shared>(images, flags | SIBR_GPU_AUTOGEN_MIPMAP); + images_layers.push_back(layer); + + setupFirstLayer(); + } + }; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/InteractiveCameraHandler.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/InteractiveCameraHandler.cpp new file mode 100755 index 0000000000000000000000000000000000000000..88145b07abac072b93a08fb6a1191555c0009823 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/InteractiveCameraHandler.cpp @@ -0,0 +1,762 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "InteractiveCameraHandler.hpp" +#include "core/graphics/Input.hpp" +#include "core/graphics/Viewport.hpp" +#include "core/graphics/Window.hpp" +#include "core/raycaster/Raycaster.hpp" +#include "core/view/UIShortcuts.hpp" +#include "core/graphics/GUI.hpp" + +# define IBRVIEW_SMOOTHCAM_POWER 0.1f +# define IBRVIEW_USESMOOTHCAM true +# define SIBR_INTERPOLATE_FRAMES 30 + + +namespace sibr { + + InteractiveCameraHandler::InteractiveCameraHandler(const bool supportRecording) : _trackball(true) { + _currentMode = FPS; + _shouldSmooth = IBRVIEW_USESMOOTHCAM; + _startCam = 0; + _interpFactor = 0; + _shouldSnap = false; + _supportRecording = supportRecording; + _radius = 100.0f; + _currentCamId = 0; + _saveFrame = false; + _saveFrameVideo = false; + _viewport = Viewport(0, 0, 0, 0); + _triggerCameraUpdate = false; + _isSetup = false; + + sibr::UIShortcuts::global().add("[Camera] b", "orbit mode"); + sibr::UIShortcuts::global().add("[Camera] y", "trackball mode"); + sibr::UIShortcuts::global().add("[Camera] v", "interpolation mode"); + sibr::UIShortcuts::global().add("[Camera] maj+y", "show/hide trackball"); + if (_supportRecording) { + sibr::UIShortcuts::global().add("c", "playback camera path"); + sibr::UIShortcuts::global().add("ctrl+c", "save camera path (enter filename in the prompt)"); + sibr::UIShortcuts::global().add("shift+c", "load camera path (enter filename in the prompt)"); + sibr::UIShortcuts::global().add("alt+c", "start recording camera path"); + } + + + } + + // save default camera for a scene + void InteractiveCameraHandler::saveDefaultCamera(const std::string& datasetPath) + { + std::string selectedFile = datasetPath; + + selectedFile.append("/default_camera.bin"); + _currentCamera.saveToBinary(selectedFile); + SIBR_LOG << "Saved camera (" << selectedFile << ")." << std::endl; + } + + void InteractiveCameraHandler::loadDefaultCamera(const sibr::InputCamera& cam, const std::string& datasetPath) + { + sibr::InputCamera savedCam; + std::ifstream camFile(datasetPath + "/default_camera.bin"); + fromCamera(cam, false); + if (camFile.good()) { + savedCam.loadFromBinary(datasetPath + "/default_camera.bin"); + SIBR_LOG << "Loaded " << datasetPath << "/default_camera.bin" << std::endl; + fromCamera(savedCam, false); + } + } + + void InteractiveCameraHandler::setup(const std::vector& cams, const sibr::Vector2u & resolution, const sibr::Viewport & viewport, const std::shared_ptr raycaster) + { + setup(cams, viewport, raycaster); + + } + + void InteractiveCameraHandler::setup(const sibr::InputCamera & cam, const sibr::Viewport & viewport, const std::shared_ptr raycaster) { + _raycaster = raycaster; + _viewport = viewport; + fromCamera(cam, false); + } + + void InteractiveCameraHandler::setup(const Eigen::AlignedBox & areaOfInterest, const sibr::Viewport & viewport, const std::shared_ptr raycaster) + { + _raycaster = raycaster; + _viewport = viewport; + _radius = areaOfInterest.diagonal().norm(); + // Use the trackball to compute an initial camera. + _trackball.fromBoundingBox(areaOfInterest, viewport); + fromCamera(_trackball.getCamera(), false); + } + + void InteractiveCameraHandler::setup(const std::vector& cams, const sibr::Viewport & viewport, const std::shared_ptr raycaster, const sibr::Vector2f & clippingPlanes) { + + // setup interpolation path if not set + if (_interpPath.empty()) { + setupInterpolationPath(cams); + } + // Update the near and far planes. + + sibr::Vector3f center(0, 0, 0); + for (const auto& cam : cams) { + center += cam->transform().position(); + } + center /= cams.size(); + + float avgDist = 0; + for (const auto& cam : cams) { + avgDist += (cam->transform().position() - center).norm(); + } + avgDist /= cams.size(); + _radius = avgDist; + + sibr::InputCamera idealCam = *cams[0]; + if(clippingPlanes[0] < 0.0f || clippingPlanes[1] < 0.0f) { + float zFar = -1.0f, zNear = -1.0f; + for (const auto & cam : cams) { + zFar = (zFar<0 || cam->zfar() > zFar ? cam->zfar() : zFar); + zNear = (zNear < 0 || cam->znear() < zNear ? cam->znear() : zNear); + } + idealCam.zfar(zFar*1.1f); + idealCam.znear(zNear*0.9f); + } else { + idealCam.znear(clippingPlanes[0]); + idealCam.zfar(clippingPlanes[1]); + } + + SIBR_LOG << "Interactive camera using (" << idealCam.znear() << "," << idealCam.zfar() << ") near/far planes." << std::endl; + + setup(idealCam, viewport, raycaster); + } + + void InteractiveCameraHandler::setup(const std::shared_ptr mesh, const sibr::Viewport & viewport) { + _raycaster = std::make_shared(); + _raycaster->addMesh(*mesh); + _viewport = viewport; + _trackball.fromBoundingBox(mesh->getBoundingBox(), viewport); + _radius = mesh->getBoundingBox().diagonal().norm(); + fromCamera(_trackball.getCamera(), false); + } + + void InteractiveCameraHandler::fromCamera(const sibr::InputCamera & cam, bool interpolate, bool updateResolution) { + _isSetup = true; + + sibr::InputCamera idealCam(cam); + if (updateResolution) { + // Viewport might have not been set, in this case defer the full camera update + // until after the viewport has been updated, ie in onUpdate(). + if (_viewport.isEmpty()) { + _triggerCameraUpdate = true; + } + else { + const float w = _viewport.finalWidth(); + const float h = _viewport.finalHeight(); + idealCam.size(uint(w), uint(h)); + idealCam.aspect(w / h); + } + } + + _orbit.fromCamera(idealCam, _raycaster); + _fpsCamera.fromCamera(idealCam); + + + if (_raycaster != nullptr) { + sibr::RayHit hit = _raycaster->intersect(sibr::Ray(idealCam.position(), idealCam.dir())); + // If hit at the proxy surface, save the distance between the camera and the mesh, to use as a trackball radius. + if (hit.hitSomething()) { + _radius = hit.dist(); + } + } + _trackball.fromCamera(idealCam, _viewport, _radius); + + _currentCamera = idealCam; + _cameraFovDeg = _currentCamera.fovy() * 180.0f / float(M_PI); + + if (!interpolate) { + _previousCamera = _currentCamera; + } + + _clippingPlanes[0] = _currentCamera.znear(); + _clippingPlanes[1] = _currentCamera.zfar(); + } + + void InteractiveCameraHandler::fromTransform(const Transform3f & transform, bool interpolate, bool updateResolution) + { + InputCamera camCopy = getCamera(); + camCopy.transform(transform); + fromCamera(camCopy, interpolate, updateResolution); + } + + void InteractiveCameraHandler::setClippingPlanes(float znear, float zfar) { + if (znear > 0.0f) { + _clippingPlanes[0] = znear; + } + if (zfar > 0.0f) { + _clippingPlanes[1] = zfar; + } + _currentCamera.znear(_clippingPlanes[0]); + _currentCamera.zfar(_clippingPlanes[1]); + fromCamera(_currentCamera); + } + + void InteractiveCameraHandler::switchMode(const InteractionMode mode) { + if (_currentMode == mode) { + return; + } + _currentMode = mode; + + // Synchronize internal cameras. + fromCamera(_currentCamera, _shouldSmooth); + + _interpFactor = 0; + + std::cout << "Switched to "; + switch (_currentMode) { + case ORBIT: + std::cout << "orbit"; + break; + case INTERPOLATION: + std::cout << "interpolation"; + break; + case TRACKBALL: + std::cout << "trackball"; + break; + case NONE: + std::cout << "none"; + break; + case FPS: + default: + std::cout << "fps&pan"; + break; + } + std::cout << " mode." << std::endl; + + } + + int InteractiveCameraHandler::findNearestCamera(const std::vector& inputCameras, const bool& useRotation) const + { + if (inputCameras.size() == 0) + return -1; + + int selectedCam = 0; + int numCams = inputCameras.size(); + + std::vector sortByDistance = sibr::IBRBasicUtils::selectCamerasSimpleDist(inputCameras, _currentCamera, numCams); + std::vector sortByAngle = sibr::IBRBasicUtils::selectCamerasAngleWeight(inputCameras, _currentCamera, numCams); + + std::map weights; + for (uint cam_id = 0; cam_id < sortByDistance.size(); cam_id++) { + weights[sortByDistance[cam_id]] = cam_id; + } + + if (useRotation) { + std::vector sortByAngle = sibr::IBRBasicUtils::selectCamerasAngleWeight(inputCameras, _currentCamera, numCams); + for (uint cam_id = 0; cam_id < sortByAngle.size(); cam_id++) { + weights[sortByAngle[cam_id]] += cam_id; + } + } + + std::multimap combinedWeight; + + for (auto const& weight : weights) { + combinedWeight.insert(std::make_pair(weight.second, weight.first)); + } + + selectedCam = combinedWeight.begin()->second; + + return selectedCam; + } + + void InteractiveCameraHandler::setupInterpolationPath(const std::vector & cameras) { + _interpPath.resize(cameras.size()); + + bool defaultPath = false; + for (int i = 0; i < cameras.size(); i++) { + if (cameras[i]->isActive()) { + if (cameras[i]->id() < cameras.size()) { + _interpPath[cameras[i]->id()] = cameras[i]; + } + else { + std::cout << "Cameras ID inconsistent. Setting default interpolation path." << std::endl; + defaultPath = true; + break; + } + } + } + + if (defaultPath) { + _interpPath.clear(); + for (int i = 0; i < cameras.size(); i++) { + if (cameras[i]->isActive()) { + _interpPath.push_back(cameras[i]); + } + } + std::sort(_interpPath.begin(), _interpPath.end(), [](const InputCamera::Ptr & a, const InputCamera::Ptr & b) { + return a->id() < b->id(); + }); + } + } + + void InteractiveCameraHandler::interpolate() { + if (_interpPath.empty()) { + return; + } + + // If we reach the last frame of the interpolation b/w two cameras, skip to next camera. + if (_interpFactor == SIBR_INTERPOLATE_FRAMES - 1) + { + _interpFactor = 0; + _startCam++; + } + + // If we reach the last camera, restart the interpolation. + if (_startCam >= _interpPath.size() - 1) { + _interpFactor = 0; + _startCam = 0; + } + + float k = std::min(std::max(((_interpFactor) / (float)SIBR_INTERPOLATE_FRAMES), 1e-6f), 1.0f - 1e-6f); + + sibr::InputCamera & camStart = *_interpPath[_startCam]; + sibr::InputCamera & camNext = *_interpPath[_startCam + 1]; + const sibr::Camera cam = sibr::Camera::interpolate(camStart, camNext, k); + _currentCamera = sibr::InputCamera(cam, camStart.w(), camStart.h()); + _currentCamera.aspect(_viewport.finalWidth() / _viewport.finalHeight()); + + + _interpFactor = _interpFactor + 1; + } + + void InteractiveCameraHandler::snapToCamera(const int i) { + if (!_interpPath.empty()) { + unsigned int nearestCam = (i == -1 ? findNearestCamera(_interpPath) : i); + nearestCam = sibr::clamp(nearestCam, (unsigned int)(0), (unsigned int)(_interpPath.size() - 1)); + fromCamera(*_interpPath[nearestCam], true, false); + } + } + + float InteractiveCameraHandler::getInterpolatedHeight(const std::vector& inputCameras) + { + const uint numCams = inputCameras.size(); + std::vector sortByDistance = sibr::IBRBasicUtils::selectCamerasSimpleDist(inputCameras, _currentCamera, numCams, true); + Vector3f pos0 = 0.5f * (_interpPath[sortByDistance[0]]->position() + _interpPath[sortByDistance[1]]->position()); + Vector3f pos1 = 0.5f * (_interpPath[sortByDistance[2]]->position() + _interpPath[sortByDistance[3]]->position()); + + const float dist = (pos1 - pos0).norm(); + const float currentDist = (_currentCamera.position() - pos0).norm(); + const float dist0 = (_currentCamera.position() - pos0).norm(); + const float dist1 = (_currentCamera.position() - pos1).norm(); + const float t = dist1 / (dist0 + dist1); + + const float height = t * pos0.z() + (1 - t) * pos1.z(); // (cam1->position().z() - cam0->position().z()); + return height; + } + + void InteractiveCameraHandler::setFPSCameraSpeed(const float speed) { + _fpsCamera.setSpeed(speed); + } + + void InteractiveCameraHandler::update(const sibr::Input & input, float deltaTime, const sibr::Viewport & viewport) { + if (!viewport.isEmpty()) { + _viewport = viewport; + } + if (_triggerCameraUpdate && !_viewport.isEmpty()) { + fromCamera(_currentCamera, false, true); + _triggerCameraUpdate = false; + } + if (input.key().isReleased(Key::N)) { + _keyCameras.emplace_back(new InputCamera(getCamera())); + } + + if (input.key().isReleased(sibr::Key::B)) { + switchMode(_currentMode == ORBIT ? FPS : ORBIT); + } + else if (input.key().isReleased(sibr::Key::V)) { + switchMode(_currentMode == INTERPOLATION ? FPS : INTERPOLATION); + } + else if (input.key().isActivated(sibr::Key::LeftShift) && input.key().isReleased(sibr::Key::Y)) { + if (_currentMode == TRACKBALL) { + _trackball.drawThis = !_trackball.drawThis; + SIBR_LOG << "[Trackball] Display visual guides: " << (_trackball.drawThis ? "on" : "off") << "." << std::endl; + } + } + // only free key + else if (input.key().isReleased(sibr::Key::M)) { + _cameraRecorder.saveImage("", _currentCamera, _currentCamera.w(), _currentCamera.h()); + } + else if (input.key().isReleased(sibr::Key::Y)) { + switchMode(_currentMode == TRACKBALL ? FPS : TRACKBALL); + } + else if (input.key().isReleased(sibr::Key::Space)) { + switchSnapping(); + } + else if (input.key().isReleased(sibr::Key::P)) { + snapToCamera(-1); + + } + else if (_supportRecording) { + if (input.key().isActivated(Key::LeftShift) && (input.key().isActivated(Key::LeftAlt) || input.key().isActivated(Key::LeftControl)) && input.key().isReleased(Key::C)) + { + + _saveFrame = !_saveFrame; + if (_saveFrame) { + std::string pathOutView; + for (uint i = 0; i < 10; ++i) std::cout << std::endl; + std::cout << "Enter path to output the frames:" << std::endl; + safeGetline(std::cin, pathOutView); + + if (!pathOutView.empty()) { + _cameraRecorder.saving(pathOutView + "/"); + } + else { + _cameraRecorder.stopSaving(); + _saveFrame = false; + } + } + else { + _cameraRecorder.stopSaving(); + } + } + else if (input.key().isActivated(Key::LeftShift) && input.key().isReleased(Key::C)) + { + std::string filename; + + int w, h; + for (uint i = 0; i < 10; ++i) std::cout << std::endl; + std::cout << "Enter a filename for loading a camera path:" << std::endl; + safeGetline(std::cin, filename); + std::cout << "Enter width for camera" << std::endl; + std::cin >> w; + std::cout << "Enter height for camera" << std::endl; + std::cin >> h; + std::cin.get(); + + _cameraRecorder.reset(); + if (boost::filesystem::extension(filename) == ".out") + _cameraRecorder.loadBundle(filename, w, h); + else + _cameraRecorder.load(filename); + _cameraRecorder.playback(); + } + else if (input.key().isActivated(Key::LeftControl) && input.key().isReleased(Key::C)) + { + std::string filename; + for (uint i = 0; i < 10; ++i) std::cout << std::endl; + std::cout << "Enter a filename for saving a camera path:" << std::endl; + safeGetline(std::cin, filename); + _cameraRecorder.save(filename); + _cameraRecorder.saveAsBundle(filename + ".out", _currentCamera.h()); + _cameraRecorder.saveAsLookAt(filename + ".lookat"); + if (_fribrExport) { + const int height = int(std::floor(1920.0f / _currentCamera.aspect())); + _cameraRecorder.saveAsFRIBRBundle(filename + "_fribr/", 1920, height); + } + _cameraRecorder.stop(); + } + else if (input.key().isActivated(Key::LeftAlt) && input.key().isReleased(Key::C)) + { + _cameraRecorder.reset(); + _cameraRecorder.record(); + } + else if (input.key().isActivated(Key::RightAlt) && input.key().isReleased(Key::C)) { + std::string filename; + for (uint i = 0; i < 10; ++i) std::cout << std::endl; + std::cout << "Enter a filename for saving a camera path:" << std::endl; + safeGetline(std::cin, filename); + _cameraRecorder.playback(); + _cameraRecorder.saveAsBundle(filename + ".out", _currentCamera.h()); + _cameraRecorder.saveAsLookAt(filename + ".lookat"); + if (_fribrExport) { + const int height = int(std::floor(1920.0f / _currentCamera.aspect())); + _cameraRecorder.saveAsFRIBRBundle(filename + "_fribr/", 1920, height); + } + } + else if (input.key().isReleased(Key::C)) { + _cameraRecorder.playback(); + } + } + + // If the camera recorder is currently playing, don't update the various camera modes. + if (!_cameraRecorder.isPlaying()) { + + switch (_currentMode) { + case ORBIT: + _orbit.update(input, _raycaster); + _currentCamera = _orbit.getCamera(); + break; + case INTERPOLATION: + interpolate(); + break; + case TRACKBALL: + _trackball.update(input, _viewport, _raycaster); + _currentCamera = _trackball.getCamera(); + break; + case NONE: + //do nothing + break; + case FPS: + default: + + if (_altitudeInterp) { + + _fpsCamera.setGoalAltitude(getInterpolatedHeight(_interpPath)); + } + else { + _fpsCamera.setGoalAltitude(-1.f); + } + + _fpsCamera.update(input, deltaTime); + if (_shouldSnap) { + _fpsCamera.snap(_interpPath); + } + _currentCamera = _fpsCamera.getCamera(); + break; + } + + if (_shouldSmooth && _currentMode != INTERPOLATION) { + const sibr::Camera newcam = sibr::Camera::interpolate(_previousCamera, _currentCamera, IBRVIEW_SMOOTHCAM_POWER); + _currentCamera = sibr::InputCamera(newcam, _currentCamera.w(), _currentCamera.h()); + } + + } + + // Note this call has three modes: record (only read the arg camera) | playback (overwrite the arg camera) | do nothing (do nothing) + _cameraRecorder.use(_currentCamera); + + _previousCamera = _currentCamera; + _clippingPlanes[0] = _currentCamera.znear(); + _clippingPlanes[1] = _currentCamera.zfar(); + } + + const sibr::InputCamera& InteractiveCameraHandler::getCamera(void) const { + return _currentCamera; + } + + void InteractiveCameraHandler::onRender(const sibr::Viewport& viewport) { + if (_currentMode == TRACKBALL) { + _trackball.onRender(viewport); + } + } + + void InteractiveCameraHandler::onGUI(const std::string& suffix) { + + const std::string fullName = (suffix); + + + // Saving camera. + if (ImGui::Begin(fullName.c_str())) { + + ImGui::PushScaledItemWidth(130); + ImGui::Combo("Mode", (int*)&_currentMode, "FPS\0Orbit\0Interp.\0Trackball\0None\0\0"); + switchMode(_currentMode); + ImGui::SameLine(); + if (ImGui::Button("Load camera")) { + std::string selectedFile; + if (sibr::showFilePicker(selectedFile, Default)) { + if (!selectedFile.empty()) { + sibr::InputCamera savedCam; + savedCam.loadFromBinary(selectedFile); + SIBR_LOG << "Loaded saved camera (" << selectedFile << ")." << std::endl; + fromCamera(savedCam, false); + } + } + } + + ImGui::SameLine(); + if (ImGui::Button("Save camera (bin)")) { + std::string selectedFile; + if (sibr::showFilePicker(selectedFile, Save)) { + if (!selectedFile.empty()) { + if (selectedFile[selectedFile.size() - 1] == '/' || selectedFile[selectedFile.size() - 1] == '\\') { + selectedFile.append("default_camera.bin"); + } + _currentCamera.saveToBinary(selectedFile); + SIBR_LOG << "Saved camera (" << selectedFile << ")." << std::endl; + } + } + } + + + ImGui::Separator(); + if (ImGui::Button("Snap to closest")) { + _currentCamId = findNearestCamera(_interpPath); + snapToCamera(_currentCamId); + } + + ImGui::SameLine(); + ImGui::Checkbox("Altitude interp", &_altitudeInterp); + + ImGui::SameLine(); + if (ImGui::InputInt("Snap to", &_currentCamId, 1, 10)) { + _currentCamId = sibr::clamp(_currentCamId, 0, int(_interpPath.size()) - 1); + snapToCamera(_currentCamId); + } + + if (_currentMode == TRACKBALL) { + ImGui::SameLine(); + ImGui::Checkbox("Show trackball", &_trackball.drawThis); + } + + if (ImGui::InputFloat("Fov Y", &_cameraFovDeg, 1.0f, 5.0f)) { + _cameraFovDeg = sibr::clamp(_cameraFovDeg, 1.0f, 180.0f); + _currentCamera.fovy(_cameraFovDeg * float(M_PI) / 180.0f); + // Synchronize internal cameras. + fromCamera(_currentCamera, _shouldSmooth); + } + ImGui::SameLine(); + if (ImGui::InputFloat("Near", &_clippingPlanes[0], 1.0f, 10.0f)) { + _currentCamera.znear(_clippingPlanes[0]); + fromCamera(_currentCamera); + } + ImGui::SameLine(); + if (ImGui::InputFloat("Far", &_clippingPlanes[1], 1.0f, 10.0f)) { + _currentCamera.zfar(_clippingPlanes[1]); + fromCamera(_currentCamera); + } + + ImGui::Separator(); + ImGui::PopItemWidth(); + + // Record camera keypoints. + ImGui::Text("Key cameras: %d", _keyCameras.size()); + ImGui::SameLine(); + if (ImGui::Button("Add key")) { + _keyCameras.emplace_back(new InputCamera(getCamera())); + } + ImGui::SameLine(); + + if (!_keyCameras.empty()) { + if (ImGui::Button("Remove key")) { + _keyCameras.pop_back(); + } + ImGui::SameLine(); + } + + if (ImGui::Button("Save key cameras...")) { + std::string outpath; + if (sibr::showFilePicker(outpath, Save, "", "lookat") && !outpath.empty()) { + InputCamera::saveAsLookat(_keyCameras, outpath); + } + } + ImGui::Separator(); + } + ImGui::End(); + + // Recording handling. + if (_supportRecording) { + std::string selectedFile; + + if (ImGui::Begin(fullName.c_str())) { + ImGui::PushScaledItemWidth(130); + + if (ImGui::Button("Play")) { + _cameraRecorder.playback(); + } + ImGui::SameLine(); + if (ImGui::Button("Play (No Interp)")) { + _cameraRecorder.playback(); + _cameraRecorder.playNoInterpolation(true); + } + ImGui::SameLine(); + if (ImGui::Button("Record")) { + _cameraRecorder.reset(); + _cameraRecorder.record(); + } + ImGui::SameLine(); + if (ImGui::Button("Stop")) { + _cameraRecorder.stop(); + } + ImGui::SameLine(); + if(ImGui::InputFloat("Speed##CamRecorder", &_cameraRecorder.speed(), 0.1f)) { + _cameraRecorder.speed() = sibr::clamp(_cameraRecorder.speed(), 0.0f, 1.0f); + } + + if (ImGui::Button("Load path")) { + if (sibr::showFilePicker(selectedFile, Default)) { + if (!selectedFile.empty()) { + SIBR_LOG << "Loading" << std::endl; + _cameraRecorder.reset(); + if (boost::filesystem::extension(selectedFile) == ".out") + _cameraRecorder.loadBundle(selectedFile, _currentCamera.w(), _currentCamera.h()); + else if (boost::filesystem::extension(selectedFile) == ".lookat") + _cameraRecorder.loadLookat(selectedFile, _currentCamera.w(), _currentCamera.h()); + else if (boost::filesystem::extension(selectedFile) == ".txt") + _cameraRecorder.loadColmap(selectedFile, _currentCamera.w(), _currentCamera.h()); + else + _cameraRecorder.load(selectedFile); +// dont play back until explicitly requested +// _cameraRecorder.playback(); + } + + } + } + + ImGui::SameLine(); + if (ImGui::Button("Save path")) { + _cameraRecorder.stop(); + if (sibr::showFilePicker(selectedFile, Save)) { + if (!selectedFile.empty()) { + SIBR_LOG << "Saving" << std::endl; + _cameraRecorder.save(selectedFile + ".path"); + _cameraRecorder.saveAsBundle(selectedFile + ".out", _currentCamera.h()); + _cameraRecorder.saveAsColmap(selectedFile, _currentCamera.h(), _currentCamera.w()); + _cameraRecorder.saveAsLookAt(selectedFile + ".lookat"); + if (_fribrExport) { + const int height = int(std::floor(1920.0f / _currentCamera.aspect())); + _cameraRecorder.saveAsFRIBRBundle(selectedFile + "_fribr/", 1920, height); + } + } + } + } + + //ImGui::SameLine(); + ImGui::Checkbox("Save video (from playing)", (&_saveFrame)); + if (_saveFrame) { + _cameraRecorder.savingVideo(_saveFrame); + } + + ImGui::SameLine(); + const bool saveFrameOld = _saveFrameVideo; + ImGui::Checkbox("Save frames (from playing)", (&_saveFrameVideo)); + if (_saveFrameVideo && !saveFrameOld) { + if (sibr::showFilePicker(selectedFile, Directory)) { + if (!selectedFile.empty()) { + _cameraRecorder.saving(selectedFile + "/"); + _cameraRecorder.savingVideo(_saveFrameVideo); + } + else { + _cameraRecorder.stopSaving(); + _saveFrameVideo = false; + _cameraRecorder.savingVideo(_saveFrameVideo); + } + } + } + else if (!_saveFrameVideo && saveFrameOld) { + _cameraRecorder.stopSaving(); + _cameraRecorder.savingVideo(_saveFrameVideo); + } + + //ImGui::SameLine(); + //ImGui::Checkbox("Fribr export", &_fribrExport); + ImGui::Separator(); + ImGui::PopItemWidth(); + } + ImGui::End(); + } + // add the FPS camera controls in the same ImGui window. + _fpsCamera.onGUI(suffix); + + + } + +} + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/InteractiveCameraHandler.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/InteractiveCameraHandler.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9a7d3c22c00f06c57a4134e3d82522c9752b2fc9 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/InteractiveCameraHandler.hpp @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include +#include + +#include "Config.hpp" +#include "core/graphics/Shader.hpp" +#include "core/assets/InputCamera.hpp" + +#include "core/view/IBRBasicUtils.hpp" +#include "core/view/FPSCamera.hpp" +#include "core/view/Orbit.hpp" +#include "core/view/TrackBall.h" +#include "core/assets/CameraRecorder.hpp" +#include "core/graphics/Viewport.hpp" +#include "core/graphics/Mesh.hpp" +#include "ICameraHandler.hpp" + +namespace sibr { + class Mesh; + class Input; + class Raycaster; + + /** + The InteractiveCameraHandler gathers various types of camera interactions and + allows the user to switch between them, keeping them in sync. + It can also perform camera interpolation along a path. + \ingroup sibr_view + */ + class SIBR_VIEW_EXPORT InteractiveCameraHandler : public ICameraHandler + { + + public: + + SIBR_CLASS_PTR(InteractiveCameraHandler); + + /** Current handler interaction mode. */ + enum InteractionMode { + FPS = 0, ORBIT = 1, INTERPOLATION = 2, TRACKBALL = 3, NONE=4 + }; + + /** Constructor. + *\param supportRecording can this handler record camera paths. + *\todo Do we really need this option? + */ + InteractiveCameraHandler(const bool supportRecording = true); + + /** \deprecated Resolution is deprecated and will be removed in the near future. + * See setup(const std::vector&, const sibr::Viewport&, std::shared_ptr,...) instead. */ + void setup(const std::vector & cams, const sibr::Vector2u & resolution, const sibr::Viewport & viewport, const std::shared_ptr raycaster); + + /** Setup an interactive camera handler from an existing camera. + The interactive camera will be initialized at the position of the argument camera. + \param cam initialization camera + \param viewport the window viewport + \param raycaster raycaster containing the mesh displayed (used for the trackball centering), can be nullptr + */ + void setup(const sibr::InputCamera & cam, const sibr::Viewport & viewport, const std::shared_ptr raycaster); + + /** Setup an interactive camera handler from an area of interest. + The interactive camera will be initialized so that the area is completely visible. + \param areaOfInterest the region of space to show + \param viewport the window viewport + \param raycaster raycaster containing the mesh displayed (used for the trackball centering), can be nullptr + */ + void setup(const Eigen::AlignedBox& areaOfInterest, const sibr::Viewport & viewport, const std::shared_ptr raycaster); + + /** Setup an interactive camera handler from a series of existing cameras and mesh. + The interactive camera will be initialized at the position of the first camera from the list. + \param cams a list of cameras (used for interpolation path) + \param viewport the window viewport + \param raycaster raycaster containing the mesh displayed (used for the trackball centering), can be nullptr + \param clippingPlanes optional clipping planes to enforce + */ + void setup(const std::vector& cams, const sibr::Viewport& viewport, std::shared_ptr raycaster, const sibr::Vector2f & clippingPlanes = {-1.0f,-1.0f}); + + /** Setup an interactive camera handler from a mesh. + The interactive camera will be initialized so that the mesh is completely visible. + \param mesh the mesh to display + \param viewport the window viewport + \note a raycaster will be set up internally + */ + void setup(std::shared_ptr mesh, const sibr::Viewport& viewport); + + /** Setup a camera path for the interpolation mode. + * \param cameras to interpolate along + */ + void setupInterpolationPath(const std::vector & cameras); + + /** Move the interactive camera to a new position and change its internal parameters. + \param cam the cameras the parameters and pose should be copied from + \param interpolate smooth interpolation between the current pose and the new one + \param updateResolution should the resolution of the camera be updated or not. Can be disabled if the new cam has a size incompatible with the current viewport. + */ + void fromCamera(const sibr::InputCamera & cam, bool interpolate = true, bool updateResolution = true); + + /** Move the interactive camera to a new position. + \param transform the transform the orientation and pose should be copied from + \param interpolate smooth interpolation between the current pose and the new one + \param updateResolution should the resolution of the camera be updated or not. Can be disabled if the new cam has a size incompatible with the current viewport. + */ + void fromTransform(const Transform3f & transform, bool interpolate = true, bool updateResolution = true); + + /** Set the clipping planes. + *\param znear near plane + *\param zfar far plane + */ + void setClippingPlanes(float znear, float zfar); + + /** Find the camera in a list closest to the current interactive camera position + \param inputCameras the list to search in + \return the index of the closest camera in the list, or -1 + \note This function ignores cameras that are not 'active' in the list. + */ + int findNearestCamera(const std::vector& inputCameras, const bool& useRotation = true) const; + + /** Toggle camera motion smoothing. */ + void switchSmoothing() { _shouldSmooth = !_shouldSmooth; SIBR_LOG << "Smoothing " << (_shouldSmooth ? "enabled" : "disabled") << std::endl; } + + /** Toggle automatic snapping when getting close to a camera from the interpolation path. */ + void switchSnapping() { _shouldSnap = !_shouldSnap; SIBR_LOG << "Snapping " << (_shouldSnap ? "enabled" : "disabled") << std::endl; } + + /** Switch the interaction mode (trackball, fps,...). + \param mode the new mode + */ + void switchMode(const InteractionMode mode); + + /** Save the current camera as a binary file to a standard location. + * \param datasetPath destination directory + * \note "default_camera.bin" will be appended to the path. + */ + void saveDefaultCamera(const std::string& datasetPath); + + /** Load a camera parameters from a binary file at a standard location. + *\param cam the camera to use if loading fails + * \param datasetPath source directory + * \note "default_camera.bin" will be appended to the path. + */ + void loadDefaultCamera(const sibr::InputCamera& cam, const std::string& datasetPath); + + /** \return the current interaction mode. */ + InteractionMode getMode() const { return _currentMode; } + + /** Set the speed of the FPS camera. + \param speed the new speed + */ + void setFPSCameraSpeed(const float speed); + + /// ICameraHandler interface. + /** Update function, call at every tick. + \param input the input object for the current view. + \param deltaTime time elapsed since last frame + \param viewport optional window viewport (can be used by the trackball for instance) + */ + virtual void update(const sibr::Input & input, float deltaTime, const sibr::Viewport & viewport = Viewport(0.0f, 0.0f, 0.0f, 0.0f)) override; + + /** \return the current camera. */ + virtual const sibr::InputCamera & getCamera(void) const override; + + /** Render additional information on screen (trackball gizmo). + \param viewport the window viewport + */ + virtual void onRender(const sibr::Viewport & viewport) override; + + /** Show the GUI. + \param suffix additional GUI name suffix to avoid collisions when having multiple handlers. + */ + virtual void onGUI(const std::string & suffix) override; + + /** \return the camera recorder */ + sibr::CameraRecorder & getCameraRecorder() { return _cameraRecorder; }; + + /** \return the camera trackball */ + sibr::TrackBall & getTrackball() { return _trackball; } + + /** Snap the interactive camera to one of the interpolation path cameras. + \param id the index of the camera to snap to. if -1, the closest camera. + */ + void snapToCamera(int id = -1); + + /** \return the handler raycaster. + \warning Can be nullptr + */ + std::shared_ptr & getRaycaster() { return _raycaster; } + + /** \return true if the handler has been entirely setup */ + bool isSetup() const { return _isSetup; } + + /** \return the handler viewport */ + const sibr::Viewport & getViewport() const { return _viewport; } + + /** \return radius used for trackball*/ + float & getRadius() { return _radius; } + + float getInterpolatedHeight(const std::vector& inputCameras); + + private: + + int _currentCamId; ///< Current snapped camera ID. + + bool _shouldSmooth; ///< Motion smoothing. + bool _shouldSnap; ///< Currently snapping. + bool _altitudeInterp = false; ///< Interpolate altitude on the cameras height or not. + + float _bottom_vp = 1.f; + + sibr::FPSCamera _fpsCamera; ///< FPS handler. + sibr::Orbit _orbit; ///< Orbit handler. + sibr::TrackBall _trackball; ///< Trackball handler. + + InteractionMode _currentMode; ///< Current handler mode. + + float _radius; ///< Trackball radius property (for GUI). + + std::shared_ptr _raycaster; ///< Raycaster (for trackball). + sibr::Viewport _viewport; ///< Current viewport. + + sibr::InputCamera _previousCamera; ///< Previous camera (for interpolation). + sibr::InputCamera _currentCamera; ///< Current camera. + + /// Parameters for path interpolation. + uint _startCam; ///< Start camera index in the list. + uint _interpFactor; ///< Current interpolation factor between cam _startCam and _startCam+1. + std::vector _interpPath; ///< Cameras along the path. + + sibr::CameraRecorder _cameraRecorder; ///< Camera recorder. + bool _supportRecording; ///< Does the camera support recording (uneeded). + std::vector _keyCameras; ///< Key cameras saved punctually. \note This could be merged with the camera recorder. + + sibr::Vector2f _clippingPlanes; ///< Clipping planes parameter (for GUI). + bool _saveFrame; ///< Should the frame be saved as an image. + bool _saveFrameVideo; ///< Should the frame be saved as part of a video. + bool _triggerCameraUpdate; ///< Should the camera be updated (delayed if info is missing). + bool _isSetup; ///< Is the handler setup. + float _cameraFovDeg = 0.0f; ///< Camera field of view in degrees (for GUI). + bool _fribrExport = false; ///< Switch to FRIBR compatible export mode for paths. + + /** Interpolate along the path. */ + void interpolate(); + + }; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/MultiMeshManager.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/MultiMeshManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fc5dd3192639b76abff44c3ffead578b3d8031d5 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/MultiMeshManager.cpp @@ -0,0 +1,758 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "MultiMeshManager.hpp" + +#include + +namespace sibr { + + MeshData MeshData::dummy = MeshData("dummy", Mesh::Ptr(), DUMMY, Mesh::FillRenderMode); + + MeshData::MeshData(const std::string & _name, Mesh::Ptr mesh_ptr, MeshType mType, Mesh::RenderMode render_mode) : + meshPtr(mesh_ptr), renderMode(render_mode), name(_name), meshType(mType) + { + if (mType == POINTS) { + renderMode = Mesh::PointRenderMode; + } + if (mType == LINES && renderMode == Mesh::FillRenderMode) { + renderMode = Mesh::LineRenderMode; + } + if (renderMode != Mesh::FillRenderMode) { + backFaceCulling = false; + } + } + + MeshData MeshData::getNormalsMeshData() const + { + MeshData data(name + "_normals", meshPtr, normalMode == PER_TRIANGLE ? TRIANGLES : POINTS); + data.setColor(normalsColor).setDepthTest(depthTest); + data.normalsLength = (normalsInverted ? -normalsLength : normalsLength); + return data; + } + + MeshData::operator bool() const + { + return meshType != DUMMY; + } + + void MeshData::renderGeometry() const + { + CHECK_GL_ERROR; + if (!meshPtr) { + return; + } + if (renderMode == Mesh::PointRenderMode) { + meshPtr->render_points(depthTest); + } else { + meshPtr->render(depthTest, backFaceCulling, renderMode, frontFaceCulling, invertDepthTest); + } + CHECK_GL_ERROR; + } + + void MeshData::onGUI(const std::string & name) + { + // rendering mode + static const std::string renderModeStrs[3] = { "Points", "Lines", "Fill" }; + + if (ImGui::BeginCombo(("##render_mode_" + name).c_str(), renderModeStrs[(int)renderMode].data())) { + for (int t = (int)meshType; t >= 0; --t) { + if (ImGui::Selectable(renderModeStrs[t].data(), t == (int)renderMode)) { + renderMode = (Mesh::RenderMode)t; + } + } + ImGui::EndCombo(); + } + ImGui::NextColumn(); + + //alpha + ImGui::SliderFloat(("##alpha_" + name).c_str(), &alpha, 0, 1); + ImGui::NextColumn(); + + //user color + static const std::string colorModeStrs[2] = { "User-defined", "Vertex" }; + if (ImGui::BeginCombo(("##color_mode_" + name).c_str(), colorModeStrs[(int)colorMode].data())) { + if (meshPtr && meshPtr->hasColors()) { + if (ImGui::Selectable(colorModeStrs[VERTEX].data(), colorMode == VERTEX)) { + colorMode = VERTEX; + } + } + if (ImGui::Selectable(colorModeStrs[USER_DEFINED].data(), colorMode == USER_DEFINED)) { + colorMode = USER_DEFINED; + } + ImGui::EndCombo(); + } + if (colorMode == USER_DEFINED) { + ImGui::SameLine(); + ImGui::ColorEdit3(("##color_picker_" + name).c_str(), &userColor[0], ImGuiColorEditFlags_NoInputs); + } + ImGui::NextColumn(); + + //rendering options + if (ImGui::ArrowButton(("##OptionsArrow" + name).c_str(), ImGuiDir_Down)) { + ImGui::OpenPopup(("##Options_popup_" + name).c_str()); + } + if (ImGui::BeginPopup(("##Options_popup_" + name).c_str())) { + ImGui::Checkbox(("Depth Test##" + name).c_str(), &depthTest); + if (meshType == TRIANGLES) { + ImGui::Checkbox(("Cull faces##" + name).c_str(), &backFaceCulling); + ImGui::Checkbox(("Swap back/front##" + name).c_str(), &frontFaceCulling); + } + if (renderMode == Mesh::PointRenderMode) { + ImGui::PushItemWidth(75); + ImGui::SliderInt(("PointSize##" + name).c_str(), &radius, 1, 50); + ImGui::PopItemWidth(); + } + if (meshType == TRIANGLES) { + ImGui::Separator(); + ImGui::Checkbox(("ShowNormals##" + name).c_str(), &showNormals); + if (showNormals) { + static const std::string normalModeStrs[2] = { "Per-triangle", "Per-vertex"}; + if (ImGui::BeginCombo(("##normal_mode_" + name).c_str(), normalModeStrs[(int)normalMode].data())) { + if (ImGui::Selectable(normalModeStrs[PER_TRIANGLE].data(), normalMode == PER_TRIANGLE)) { + normalMode = PER_TRIANGLE; + } + if (meshPtr && meshPtr->hasNormals()) { + if (ImGui::Selectable(normalModeStrs[PER_VERTEX].data(), normalMode == PER_VERTEX)) { + normalMode = PER_VERTEX; + } + } + ImGui::EndCombo(); + } + ImGui::Checkbox(("NormalInverted##" + name).c_str(), &normalsInverted); + ImGui::PushItemWidth(90); + ImGui::SliderFloat(("NormalSize##" + name).c_str(), &normalsLength, 0.001f, 10.0f, "%.3f", 3.0f); + ImGui::PopItemWidth(); + ImGui::ColorEdit3(("NormalsColor##color_picker_" + name).c_str(), &normalsColor[0], ImGuiColorEditFlags_NoInputs); + } + if (!meshPtr->hasNormals()) { + if (ImGui::Button(("Compute Normals##" + name).c_str()) ){ + meshPtr->generateNormals(); + } + } else { + ImGui::Checkbox(("Phong shading##" + name).c_str(), &phongShading); + } + ImGui::Separator(); + } + ImGui::EndPopup(); + } + ImGui::NextColumn(); + } + + std::string MeshData::getInfos() const + { + if (!meshPtr) { + return "no mesh"; + } + + std::stringstream s; + s << meshPtr->vertices().size() << " vertices \n" << + meshPtr->triangles().size() << " triangles \n" << + "hasNormals() : " << meshPtr->hasNormals() << "\n" << + "hasColors() : " << meshPtr->hasColors() << "\n" << + "hasTexCoords() : " << meshPtr->hasTexCoords() << "\n" + ; + + return s.str(); + } + + MeshData & MeshData::setColor(const Vector3f & col) + { + userColor = col; + return *this; + } + + MeshData & MeshData::setBackFace(bool backface) + { + backFaceCulling = backface; + return *this; + } + + MeshData & MeshData::setDepthTest(bool depth_test) + { + depthTest = depth_test; + return *this; + } + + MeshData & MeshData::setColorRandom() + { + static const auto baseHash = [](uint p) { + p = 1103515245U * ((p >> 1U) ^ (p)); + uint h32 = 1103515245U * ((p) ^ (p >> 3U)); + return h32 ^ (h32 >> 16); + }; + + static const uint mask = 0x7fffffffU; + + static int seed_x = 0; + + ++seed_x; + + uint n = baseHash(uint(seed_x)); + Vector3u tmp = Vector3u(n, n * 16807U, n * 48271U); + for (int c = 0; c < 3; ++c) { + userColor[c] = (tmp[c] & mask) / float(0x7fffffff); + } + + return *this; + } + + MeshData & MeshData::setRadiusPoint(int rad) + { + radius = rad; + return *this; + } + + MeshData& MeshData::setScale(float s) + { + // TODO: insΓ©rer une instruction return ici + scale = s; + return *this; + } + + MeshData& MeshData::setTransformation(sibr::Matrix4f& tr) + { + // TODO: insΓ©rer une instruction return ici + transformation = tr; + return *this; + } + + MeshData & MeshData::setAlpha(float _alpha) { + alpha = _alpha; + return *this; + } + + MeshData & MeshData::setColorMode(ColorMode mode) + { + colorMode = mode; + return *this; + } + + void ShaderAlphaMVP::initShader(const std::string & name, const std::string & vert, const std::string & frag, const std::string & geom) + { + shader.init(name, vert, frag, geom); + mvp.init(shader, "mvp"); + alpha.init(shader, "alpha"); + } + + void ShaderAlphaMVP::setUniforms(const Camera & eye, const MeshData & data) + { + mvp.set(eye.viewproj()*data.transformation); + alpha.set(data.alpha); + } + + void ShaderAlphaMVP::render(const Camera & eye, const MeshData & data) + { + shader.begin(); + + setUniforms(eye, data); + + data.renderGeometry(); + + shader.end(); + } + + void ColorMeshShader::initShader(const std::string & name, const std::string & vert, const std::string & frag, const std::string & geom) + { + ShaderAlphaMVP::initShader(name, vert, frag, geom); + user_color.init(shader, "user_color"); + } + + void ColorMeshShader::setUniforms(const Camera & eye, const MeshData & data) + { + ShaderAlphaMVP::setUniforms(eye, data); + user_color.set(data.userColor); + } + + void PointShader::initShader(const std::string & name, const std::string & vert, const std::string & frag, const std::string & geom) + { + ColorMeshShader::initShader(name, vert, frag, geom); + radius.init(shader, "radius"); + } + + void PointShader::setUniforms(const Camera & eye, const MeshData & data) + { + ColorMeshShader::setUniforms(eye, data); + radius.set(data.radius); + } + + void PointShader::render(const Camera & eye, const MeshData & data) + { + glEnable(GL_PROGRAM_POINT_SIZE); + ColorMeshShader::render(eye, data); + glDisable(GL_PROGRAM_POINT_SIZE); + } + + void NormalRenderingShader::initShader(const std::string & name, const std::string & vert, const std::string & frag, const std::string & geom) + { + ColorMeshShader::initShader(name, vert, frag, geom); + normals_size.init(shader, "normals_size"); + } + + void NormalRenderingShader::setUniforms(const Camera & eye, const MeshData & data) + { + ColorMeshShader::setUniforms(eye, data); + normals_size.set(data.normalsLength); + } + + void MeshShadingShader::initShader(const std::string & name, const std::string & vert, const std::string & frag, const std::string & geom) + { + ColorMeshShader::initShader(name, vert, frag, geom); + light_position.init(shader, "light_position"); + phong_shading.init(shader, "phong_shading"); + use_mesh_color.init(shader, "use_mesh_color"); + } + + void MeshShadingShader::setUniforms(const Camera & eye, const MeshData & data) + { + ColorMeshShader::setUniforms(eye, data); + light_position.set(eye.position()); + phong_shading.set(data.phongShading); + use_mesh_color.set(data.colorMode == MeshData::ColorMode::VERTEX); + } + + MultiMeshManager::MultiMeshManager(const std::string & _name) : name(_name) + { + initShaders(); + + auto cube = Mesh::getTestCube(); + TrackBall tb; + tb.fromMesh(*cube, Viewport(0,0,1600,1200)); + camera_handler.fromCamera(tb.getCamera()); + + camera_handler.switchMode(InteractiveCameraHandler::InteractionMode::TRACKBALL); + } + + void MultiMeshManager::onUpdate(Input & input, const Viewport & vp) + { + if (!camera_handler.isSetup() && list_meshes.size() > 0) { + for (const auto & mesh_data : list_meshes) { + if (mesh_data.raycaster && mesh_data.meshPtr) { + auto bbox = mesh_data.meshPtr->getBoundingBox(); + if (bbox.volume() > 0) { + camera_handler.getRaycaster() = mesh_data.raycaster; + TrackBall tb; + tb.fromBoundingBox(bbox, vp); + camera_handler.fromCamera(tb.getCamera()); + break; + } + } + } + } + + if (camera_handler.isSetup() && !camera_handler.getRaycaster()) { + for (const auto & mesh : list_meshes) { + if (mesh.raycaster) { + camera_handler.getRaycaster() = mesh.raycaster; + break; + } + } + } + + if (selected_mesh_it_is_valid) { + const auto & mesh = *selected_mesh_it; + if( mesh.raycaster) { + camera_handler.getRaycaster() = mesh.raycaster; + } + } + + camera_handler.update(input, 1 / 60.0f, vp); + } + + void MultiMeshManager::onRender(const Viewport & viewport) + { + glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, -1, "Multimesh manager"); + + viewport.clear(backgroundColor); + viewport.bind(); + renderMeshes(); + camera_handler.onRender(viewport); + + glPopDebugGroup(); + } + + void MultiMeshManager::onRender(IRenderTarget & dst) + { + dst.bind(); + + const Viewport vp(0.0f, 0.0f, (float)dst.w(), (float)dst.h()); + onRender(vp); + + dst.unbind(); + } + + void MultiMeshManager::onGUI() + { + if (ImGui::Begin(name.c_str())) { + ImGui::Separator(); + + list_mesh_onGUI(); + + } + ImGui::End(); + } + + void MultiMeshManager::removeMesh(const std::string & name) + { + for (auto it = list_meshes.begin(); it != list_meshes.end(); ++it) { + if (it->name == name) { + list_meshes.erase(it); + return; + } + } + } + + void MultiMeshManager::setIntialView(const std::string& dataset_path) + { + const std::string topViewPath = dataset_path + "/cameras/topview.txt"; + std::ifstream topViewFile(topViewPath); + if (topViewFile.good()) + { + SIBR_LOG << "Loaded saved topview (" << topViewPath << ")." << std::endl; + // Intialize a temp camera (used to load the saved top view pose) with + // the current top view camera to get the resolution/fov right. + InputCamera cam(camera_handler.getCamera()); + cam.readFromFile(topViewFile); + // Apply it to the top view FPS camera. + //camera_handler.fromCamera(cam, false); + camera_handler.fromTransform(cam.transform(), false, true); + } + } + + void MultiMeshManager::initShaders() + { + const std::string folder = sibr::getShadersDirectory("core") + "/"; + + colored_mesh_shader.initShader("colored_mesh_shader", + loadFile(folder + "alpha_colored_mesh.vert"), + loadFile(folder + "alpha_colored_mesh.frag") + ); + points_shader.initShader("points_shader", + loadFile(folder + "alpha_points.vert"), + loadFile(folder + "alpha_points.frag") + ); + per_vertex_normals_shader.initShader("per_vertex_normal_shader", + loadFile(folder + "alpha_colored_per_vertex_normals.vert"), + loadFile(folder + "alpha_colored_mesh.frag"), + loadFile(folder + "alpha_colored_per_vertex_normals.geom") + ); + per_triangle_normals_shader.initShader("per_triangle_normal_shader", + loadFile(folder + "alpha_colored_per_triangle_normals.vert"), + loadFile(folder + "alpha_colored_mesh.frag"), + loadFile(folder + "alpha_colored_per_triangle_normals.geom") + ); + } + + void MultiMeshManager::renderMeshes() + { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendEquation(GL_FUNC_ADD); + + for (const auto & mesh_data : list_meshes) { + if (!mesh_data.active) { + continue; + } + + if (mesh_data.renderMode == Mesh::PointRenderMode) { + points_shader.render(camera_handler.getCamera(), mesh_data); + } else { + colored_mesh_shader.render(camera_handler.getCamera(), mesh_data); + } + + if (mesh_data.showNormals) { + if (mesh_data.normalMode == MeshData::PER_VERTEX ) { + per_vertex_normals_shader.render(camera_handler.getCamera(), mesh_data.getNormalsMeshData()); + } else { + per_triangle_normals_shader.render(camera_handler.getCamera(), mesh_data.getNormalsMeshData()); + } + + } + } + + glDisable(GL_BLEND); + } + + void MultiMeshManager::list_mesh_onGUI() + { + Iterator swap_it_src, swap_it_dst; + bool do_swap = false; + static int num_swap = 1; + + if (ImGui::CollapsingHeader(("Meshes list##" + name).c_str(), ImGuiTreeNodeFlags_DefaultOpen)) { + + static char loaded_mesh_str[128] = ""; + static std::string loaded_mesh_path; + static int loaded_mesh_counter = 0; + + if(ImGui::Button("load Mesh##MeshesList") && showFilePicker(loaded_mesh_path, FilePickerMode::Default, "", "obj,ply")) { + Mesh::Ptr mesh = std::make_shared(); + + if (mesh->load(loaded_mesh_path)) { + Path mesh_path = loaded_mesh_path; + std::string mesh_name = loaded_mesh_str; + mesh_name = (mesh_name == "") ? mesh_path.stem().string() : loaded_mesh_str; + + for (const auto & mesh_it : list_meshes) { + if (mesh_name == mesh_it.name) { + mesh_name += std::to_string(loaded_mesh_counter); + break; + } + } + + addMesh(mesh_name, mesh); + ++loaded_mesh_counter; + } + } + + ImGui::SameLine(); + ImGui::InputText("mesh name##MeshesList", loaded_mesh_str, IM_ARRAYSIZE(loaded_mesh_str)); + + // 0 name | 1 snapto delete | 2 active | 3 rendering mode | 4 alpha | 5 color | 6 Options + ImGui::Columns(7, "mesh options"); + + //ImGui::SetColumnWidth(4, 50); + + ImGui::Separator(); + if (ImGui::Button("Mesh##MeshesList")) { + list_meshes.reverse(); + } + ImGui::NextColumn(); + + ImGui::NextColumn(); + + if (ImGui::Button("Active##MeshesList")) { + for (auto & mesh : list_meshes) { + mesh.active = !mesh.active; + } + } + ImGui::SameLine(); + if (ImGui::Button("All##MeshesList")) { + for (auto & mesh : list_meshes) { + mesh.active = true; + } + } + ImGui::NextColumn(); + + ImGui::Text("Mode"); + ImGui::NextColumn(); + + static bool full_alpha = false; + if (ImGui::Button("Alpha##MeshesList")) { + for (auto & mesh : list_meshes) { + if (mesh.active) { + mesh.alpha = full_alpha ? 1.0f : 0.0f; + } + } + full_alpha = !full_alpha; + } + ImGui::NextColumn(); + + ImGui::Text("Color"); + ImGui::SameLine(); + ImGui::ColorEdit3(("Background##" + name).c_str(), &backgroundColor[0], ImGuiColorEditFlags_NoInputs); + ImGui::NextColumn(); + + ImGui::Text("Options"); + ImGui::NextColumn(); + + ImGui::Separator(); + + selected_mesh_it_is_valid = false; + for (auto mesh_it = list_meshes.begin(); mesh_it != list_meshes.end(); ++mesh_it) { + auto & mesh = *mesh_it; + if (ImGui::Selectable(mesh.name.c_str(), (selected_mesh_it_is_valid && mesh_it == selected_mesh_it))) { + selected_mesh_it = mesh_it; + selected_mesh_it_is_valid = true; + } + if (ImGui::IsItemActive()) { + float threshold = ImGui::GetItemRectSize().y + 5.0f; + ImVec2 value_raw = ImGui::GetMouseDragDelta(0, 0.0f); + + if (value_raw.y > threshold * num_swap) { + swap_it_dst = swap_it_src = mesh_it; + ++swap_it_dst; + if (swap_it_dst != list_meshes.end()) { + do_swap = true; + } + } else if (value_raw.y < -threshold * num_swap) { + swap_it_dst = swap_it_src = mesh_it; + --swap_it_dst; + if (swap_it_src != list_meshes.begin()) { + do_swap = true; + } + } + } + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::Text(mesh.getInfos().c_str()); + ImGui::EndTooltip(); + } + ImGui::NextColumn(); + + if (ImGui::Button(("SnapTo##" + mesh_it->name).c_str()) && mesh_it->meshPtr) { + auto box = mesh_it->meshPtr->getBoundingBox(); + if ((box.diagonal().array() > 1e-6f ).all()) { + InputCamera cam = camera_handler.getCamera(); + cam.setLookAt(box.center() + 2.0f*box.diagonal(), box.center(), { 0,1,0 }); + camera_handler.fromCamera(cam); + } + } + ImGui::SameLine(); + if (ImGui::Button(("X##" + mesh_it->name).c_str())) { + removeMesh(mesh_it->name); + } + ImGui::NextColumn(); + + ImGui::Checkbox(("##active_" + mesh.name).c_str(), &mesh.active); + ImGui::SameLine(); + if (ImGui::Button(("OnlyMe##" + mesh.name).c_str())) { + for (auto other_it = list_meshes.begin(); other_it != list_meshes.end(); ++other_it) { + other_it->active = (other_it == mesh_it); + } + } + + + ImGui::NextColumn(); + + mesh.onGUI(mesh.name); + ImGui::Separator(); + } + + ImGui::Columns(1); + } + if (do_swap) { + std::swap(*swap_it_src, *swap_it_dst); + ++num_swap; + } + if (ImGui::IsMouseReleased(0)) { + num_swap = 1; + } + } + + MeshData & MultiMeshManager::addMesh(const std::string & name, Mesh::Ptr mesh, bool use_raycaster) + { + if (!mesh) { + SIBR_WRG << "no mesh ptr in " << name; + return MeshData::dummy; + } + + return addMesh(name, mesh, 0, use_raycaster); + } + + MeshData & MultiMeshManager::addMesh(const std::string & name, Mesh::Ptr mesh, Raycaster::Ptr raycaster, bool create_raycaster) + { + if (!mesh) { + SIBR_WRG << "no mesh ptr in " << name; + return MeshData::dummy; + } + + MeshData data(name, mesh, MeshData::TRIANGLES, Mesh::FillRenderMode); + data.colorMode = mesh->hasColors() ? MeshData::ColorMode::VERTEX : MeshData::ColorMode::USER_DEFINED; + data.normalMode = (mesh->hasNormals() ? MeshData::PER_VERTEX : MeshData::PER_TRIANGLE); + data.phongShading = mesh->hasNormals(); + data.raycaster = raycaster; + + return addMeshData(data, create_raycaster).setColorRandom(); + } + + MeshData & MultiMeshManager::addMeshAsLines(const std::string & name, Mesh::Ptr mesh) + { + if (!mesh) { + SIBR_WRG << "no mesh ptr in " << name; + return MeshData::dummy; + } + + MeshData data(name, mesh, MeshData::LINES, Mesh::LineRenderMode); + return addMeshData(data).setColorRandom().setDepthTest(false); + } + + MeshData & MultiMeshManager::addLines(const std::string & name, const std::vector& endPoints, const Vector3f & color) + { + Mesh::Triangles tris(endPoints.size() / 2); + for (uint t = 0; t < tris.size(); ++t) { + tris[t] = Vector3u(2 * t, 2 * t, 2 * t + 1); + } + + Mesh::Ptr mesh = std::make_shared(); + mesh->vertices(endPoints); + mesh->triangles(tris); + + MeshData data(name, mesh, MeshData::LINES, Mesh::LineRenderMode); + data.userColor = color; + data.depthTest = false; + + return addMeshData(data).setColorMode(MeshData::USER_DEFINED); + } + + MeshData & MultiMeshManager::addPoints(const std::string & name, const std::vector& points, const Vector3f & color) + { + Mesh::Vertices vertices(points); + + Mesh::Ptr mesh = std::make_shared(); + mesh->vertices(vertices); + + MeshData data(name, mesh, MeshData::POINTS, Mesh::PointRenderMode); + data.userColor = color; + data.depthTest = false; + + return addMeshData(data).setColorMode(MeshData::USER_DEFINED); + } + + MeshData & MultiMeshManager::getMeshData(const std::string & name) + { + for (auto & m : list_meshes) { + if (m.name == name ) { + return m; + } + } + return MeshData::dummy; + } + + MeshData & MultiMeshManager::addMeshData(MeshData & data, bool create_raycaster) + { + bool collision = false; + Iterator collision_it; + for (collision_it = list_meshes.begin(); collision_it != list_meshes.end(); ++collision_it) { + if (collision_it->name == data.name) { + collision = true; + break; + } + } + + if (collision) { + collision_it->meshPtr = data.meshPtr; + return MeshData::dummy; + } else { + Raycaster::Ptr raycaster; + if (create_raycaster) { + raycaster = std::make_shared(); + raycaster->init(); + raycaster->addMesh(*data.meshPtr); + } + data.raycaster = raycaster; + + list_meshes.push_back(data); + + + auto box = data.meshPtr->getBoundingBox(); + if (!box.isEmpty()) { + InputCamera cam = camera_handler.getCamera(); + cam.zfar(std::max(cam.zfar(), 5.0f*box.diagonal().norm())); + camera_handler.fromCamera(cam); + } + + return list_meshes.back(); + } + } + +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/MultiMeshManager.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/MultiMeshManager.hpp new file mode 100644 index 0000000000000000000000000000000000000000..353e863884b33979d23b0d78fa003cc30c9ea03b --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/MultiMeshManager.hpp @@ -0,0 +1,439 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include +#include +#include +#include +#include + +#include + +namespace sibr { + + class MultiMeshManager; + class MeshData; + + // Hierarchy of shader wrappers, so there is no duplication for uniforms, init(), set() and render(). + + /** Shader wrapper for sending mesh display options to the GPU (while avoiding duplicated uniforms) . + * Contains an MVP matrix and an opacity value. + \ingroup sibr_view + */ + class SIBR_VIEW_EXPORT ShaderAlphaMVP { + SIBR_CLASS_PTR(ShaderAlphaMVP); + public: + /** Initialize the shader. + *\param name the shader name + *\param vert the vertex shader content + *\param frag the fragment shader ocntent + *\param geom the geometry shader content + */ + virtual void initShader(const std::string & name, const std::string & vert, const std::string & frag, const std::string & geom = ""); + + /* Set uniforms based on the camera position and mesh options. + * \param eye the current viewpoint + * \param data the mesh display options + */ + virtual void setUniforms(const Camera & eye, const MeshData & data); + + /** Render using the passed information. + * \param eye the current viewpoint + * \param data the mesh display options + */ + virtual void render(const Camera & eye, const MeshData & data); + + protected: + GLShader shader; ///< Base shader object. + GLuniform mvp; ///< MVP matrix. + GLuniform alpha = 1.0; ///< Opacity. + }; + + /** Shader wrapper for sending mesh display options to the GPU (while avoiding duplicated uniforms) . + * Adds a user-defined color. \sa ShaderAlphaMVP + \ingroup sibr_view + */ + class SIBR_VIEW_EXPORT ColorMeshShader : public ShaderAlphaMVP { + public: + /** Initialize the shader. + *\param name the shader name + *\param vert the vertex shader content + *\param frag the fragment shader ocntent + *\param geom the geometry shader content + */ + virtual void initShader(const std::string & name, const std::string & vert, const std::string & frag, const std::string & geom = ""); + + /* Set uniforms based on the camera position and mesh options. + * \param eye the current viewpoint + * \param data the mesh display options + */ + virtual void setUniforms(const Camera & eye, const MeshData & data); + + protected: + GLuniform user_color; ///< user-defined constant color. + }; + + /** Shader wrapper for sending mesh display options to the GPU (while avoiding duplicated uniforms) . + * Adds a point size. \sa ShaderAlphaMVP + \ingroup sibr_view + */ + class SIBR_VIEW_EXPORT PointShader : public ColorMeshShader { + public: + /** Initialize the shader. + *\param name the shader name + *\param vert the vertex shader content + *\param frag the fragment shader ocntent + *\param geom the geometry shader content + */ + void initShader(const std::string & name, const std::string & vert, const std::string & frag, const std::string & geom = "") override; + + /* Set uniforms based on the camera position and mesh options. + * \param eye the current viewpoint + * \param data the mesh display options + */ + virtual void setUniforms(const Camera & eye, const MeshData & data) override; + + /** Render using the passed information. + * \param eye the current viewpoint + * \param data the mesh display options + */ + virtual void render(const Camera & eye, const MeshData & data) override; + + protected: + GLuniform radius; ///< Point screenspace radius. + }; + + /** Shader wrapper for sending mesh display options to the GPU (while avoiding duplicated uniforms) . + * Adds shading parameters. \sa ShaderAlphaMVP + \ingroup sibr_view + */ + class SIBR_VIEW_EXPORT MeshShadingShader : public ColorMeshShader { + public: + /** Initialize the shader. + *\param name the shader name + *\param vert the vertex shader content + *\param frag the fragment shader ocntent + *\param geom the geometry shader content + */ + void initShader(const std::string & name, const std::string & vert, const std::string & frag, const std::string & geom = "") override; + + /* Set uniforms based on the camera position and mesh options. + * \param eye the current viewpoint + * \param data the mesh display options + */ + virtual void setUniforms(const Camera & eye, const MeshData & data) override; + + protected: + GLuniform light_position; ///< Light position for shading. + GLuniform phong_shading, use_mesh_color; ///< Should the mesh be shaded, which color should be used. + }; + + /** Shader wrapper for sending mesh display options to the GPU (while avoiding duplicated uniforms) . + * Adds line length option. \sa ShaderAlphaMVP + \ingroup sibr_view + */ + class SIBR_VIEW_EXPORT NormalRenderingShader : public ColorMeshShader { + public: + /** Initialize the shader. + *\param name the shader name + *\param vert the vertex shader content + *\param frag the fragment shader ocntent + *\param geom the geometry shader content + */ + void initShader(const std::string & name, const std::string & vert, const std::string & frag, const std::string & geom = "") override; + + /* Set uniforms based on the camera position and mesh options. + * \param eye the current viewpoint + * \param data the mesh display options + */ + virtual void setUniforms(const Camera & eye, const MeshData & data) override; + + protected: + GLuniform normals_size; ///< Normal line length. + }; + + + /** Helper class containing all information relative to how to render a mesh for debugging purpose in a MultiMeshManager. + * You can chain setters to modify multiple properties sequentially (chaining). + \sa MultiMeshManager + \ingroup sibr_view + */ + class SIBR_VIEW_EXPORT MeshData { + SIBR_CLASS_PTR(MeshData); + + public: + friend class MultiMeshManager; + + /** Color mode: constant defined by the user, or per-vertex attribute. */ + enum ColorMode : int { USER_DEFINED, VERTEX }; + /** Type of mesh: points, lines or faces. Dummy is for unitialized objects. */ + enum MeshType : int { POINTS = 0, LINES = 1, TRIANGLES = 2, DUMMY }; + /** When displaying normals, use the per-face or per-vertices normals */ + enum NormalMode { PER_TRIANGLE, PER_VERTEX }; + + /** COnstructor. + *\param _name the object name + *\param mesh_ptr the geoemtry to display + *\param mesh_type the type of mesh + *\param render_mode for triangle meshes, should they be displayed filled, as wireframes, or point clouds (\sa Mesh). + */ + MeshData(const std::string & _name = "", Mesh::Ptr mesh_ptr = {}, MeshType mesh_type = TRIANGLES, Mesh::RenderMode render_mode = Mesh::FillRenderMode); + + /** Render the geometry. */ + void renderGeometry() const; + + /** Display the GUI list item associated to this object. + *\param name additional display name + */ + void onGUI(const std::string & name); + + /** \return if the object is valid. */ + operator bool() const; + + /** \return a string describing the geometry. */ + std::string getInfos() const; + + /** Set the color. + *\param col the color to use + *\return the options object, for chaining. + *\note To see the color, you might also have to specify the color mode if your mesh has vertex colors. + */ + MeshData & setColor(const Vector3f & col); + + /** Set the backface culling. + *\param bf should culling be performed + *\return the options object, for chaining. + */ + MeshData & setBackFace(bool bf); + + /** Set the depth test. + *\param dt should depth testing be enabled + *\return the options object, for chaining. + */ + MeshData & setDepthTest(bool dt); + + /** Set a random constant color. + *\return the options object, for chaining. + */ + MeshData & setColorRandom(); + + /** Set the size of points for point-based display. + *\param rad the point radius in screenspace + *\return the options object, for chaining. + */ + MeshData & setRadiusPoint(int rad); + + /** Set the size of points for point-based display. + *\param scale + *\return the options object, for chaining. + */ + MeshData& setScale(float s); + + /** Set Transformation matrix. + *\param model matrix + *\return the options object, for chaining. + */ + MeshData& setTransformation(sibr::Matrix4f& tr); + + /** Set the opacity. + *\param alpha the opacity value for the whole object + *\return the options object, for chaining. + */ + MeshData & setAlpha(float alpha); + + /** Set the color mode (either user-defined constant or vertex color). + *\param mode the color mode + *\return the options object, for chaining. + */ + MeshData & setColorMode(ColorMode mode); + + /** Get the display options of the additional normals geometry. + *\return the normals options. + */ + MeshData getNormalsMeshData() const; + + std::string name; ///< Mesh name. + + Mesh::Ptr meshPtr; ///< Geometry. + MeshType meshType; ///< Type of mesh. + Mesh::RenderMode renderMode; ///< Render mode for triangle meshes. + + Matrix4f transformation = Matrix4f::Identity(); ///< Additional model transformation. + + Raycaster::Ptr raycaster; ///< Associated raycaster (optional) + + bool depthTest = true; ///< Perform depth test. + bool backFaceCulling = true; ///< Perform culling. + bool frontFaceCulling = false; ///< Swap front and back faces for culling. + bool invertDepthTest = false; ///< Switch the depth test to "greater than". + bool active = true; ///< Should the object be displayed. + bool phongShading = false; ///< Apply Phong shading to the object. + + // Points + int radius = 5; ///< Point screenspace radius. + float scale = 1.0f; + + // Colors + ColorMode colorMode = USER_DEFINED; ///< Color mode. + Vector3f userColor = { 0.5,0.5,0.5 }; ///< Constant user-defined color. + float alpha = 1.0f; ///< Opacity. + + // Normals + Vector3f normalsColor = { 1,0,1 }; ///< Normal lines color. + float normalsLength = 1.0f; ///< Normal lines length. + NormalMode normalMode = PER_TRIANGLE; ///< Which normals should be displayed. + bool normalsInverted = false; ///< Flip the normal lines orientation. + bool showNormals = false; ///< Should the normals be displayed. + + protected: + + static MeshData dummy; ///< OPtions object used for non-existing objects. + }; + + + /** Provide a view to render and interact with several meshes, + * useful for debugging purposes for instance. + * The API supports chaining when setting mesh display options. You can for instance do: + * manager.addMesh("my mesh", mesh).setDepthtest(true).setAlpha(0.5f); + \ingroup sibr_view + */ + class SIBR_VIEW_EXPORT MultiMeshManager : public ViewBase { + SIBR_CLASS_PTR(MultiMeshManager); + + public: + + /** Constructor + \param _name Name used for GUI panels as a prefix to avoid collision. + \note Requires an OpenGL context setup + */ + MultiMeshManager(const std::string & _name = "MultiMeshManager"); + + /** Add a mesh to the visualization. + \param name name used for the object, if it already exist it will update the geometry and preserve display options + \param mesh the mesh + \param use_raycaster should a raycaster be setup, for trackball centering for instance + \return a reference to the object display options (for chained modifications). + */ + MeshData & addMesh(const std::string & name, Mesh::Ptr mesh, bool use_raycaster = true); + + /** Add a mesh to the visualization. + \param name name used for the object, if it already exist it will update the geometry and preserve display options + \param mesh the mesh + \param raycaster existing raycaster, for trackball centering for instance + \param create_raycaster should a raycaster be setup if the passed raycaster is null + \return a reference to the object display options (for chained modifications). + */ + MeshData & addMesh(const std::string & name, Mesh::Ptr mesh, Raycaster::Ptr raycaster, bool create_raycaster = false); + + /** Add lines to the visualization, using the mesh vertices as line endpoints. + \param name name used for the object, if it already exist it will update the geometry and preserve display options + \param mesh the mesh + \return a reference to the object display options (for chained modifications). + */ + MeshData & addMeshAsLines(const std::string & name, Mesh::Ptr mesh); + + /** Add lines to the visualization, defined by their endpoints. + \param name name used for the object, if it already exist it will update the geometry and preserve display options + \param endPoints the line endpoints + \param color the display color to use + \return a reference to the object display options (for chained modifications). + */ + MeshData & addLines(const std::string & name, const std::vector & endPoints, const Vector3f & color = { 0,1,0 }); + + /** Add points to the visualization. + \param name name used for the mesh, if it already exist it will update the geometry and preserve display options + \param points the points + \param color the display color to use + \return a reference to the display options (for chained modifications). + */ + MeshData & addPoints(const std::string & name, const std::vector & points, const Vector3f & color = { 1,0,0 }); + + /** Accessor to the options of a visualized object. + \param name the object name to look for + \return a reference to the object options if it exists, or to MeshData::dummy if no match was found. + */ + MeshData & getMeshData(const std::string & name); + + /** Remove a object from the viewer. + \param name the name of the object to remove + */ + void removeMesh(const std::string & name); + + void setIntialView(const std::string& dataset_path); + + // ViewBase interface + + /** Update state based on user input. + * \param input user input + * \param vp input viewport + * \note Used when the view is in a multi-view system. + */ + virtual void onUpdate(Input& input, const Viewport & vp) override; + + /** Render content in the currently bound RT, using a specific viewport. + * \param viewport destination viewport + * \note Used when the view is in a multi-view system. + */ + virtual void onRender(const Viewport & viewport) override; + + /** Render content in a RT, using the RT viewport. + * \param dst destination RT + */ + virtual void onRender(IRenderTarget & dst) ; + + /** Display GUI. */ + virtual void onGUI() override; + + /** \return the view camera handler */ + InteractiveCameraHandler & getCameraHandler() { return camera_handler; } + + /** \return the colored mesh shader */ + MeshShadingShader & getMeshShadingShader() { return colored_mesh_shader; } + + protected: + + /** Helper to add some geometry to the view. + \param data the object to add + \param update_raycaster should the associated raycaster be updated with the new geometry + \return the update object options + */ + MeshData & addMeshData(MeshData & data, bool update_raycaster = false); + + /** Create the shaders */ + void initShaders(); + + /** Render all the registered meshes. */ + void renderMeshes(); + + /** Generate the list of objects in the GUI panel of the view. */ + void list_mesh_onGUI(); + + using ListMesh = std::list; + using Iterator = ListMesh::iterator; + + std::string name; ///< View name. + ListMesh list_meshes; ///< Meshes to display. + Iterator selected_mesh_it; ///< Currently selected mesh. + bool selected_mesh_it_is_valid = false; ///< Is there a valid currently selected mesh. + + InteractiveCameraHandler camera_handler; ///< View camera handler. + + PointShader points_shader; ///< Shader for points. + MeshShadingShader colored_mesh_shader; ///< Shader for meshes. + NormalRenderingShader per_vertex_normals_shader, per_triangle_normals_shader; ///< Shaders for visualizing an object normals. + + Vector3f backgroundColor = { 0.7f, 0.7f, 0.7f }; ///< Background clear color. + }; + +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/MultiViewManager.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/MultiViewManager.cpp new file mode 100755 index 0000000000000000000000000000000000000000..dcf84e96b2c82cec849b8533bc14255a20b4edcc --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/MultiViewManager.cpp @@ -0,0 +1,654 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +# include "core/graphics/GUI.hpp" +# include "core/view/MultiViewManager.hpp" + +namespace sibr +{ + MultiViewBase::MultiViewBase(const Vector2i & defaultViewRes) + { + /// \todo TODO: support launch arg for stereo mode. + renderingMode(IRenderingMode::Ptr(new MonoRdrMode())); + + //Default view resolution. + setDefaultViewResolution(defaultViewRes); + + _timeLastFrame = std::chrono::steady_clock::now(); + _deltaTime = 0.0; + _exportPath = "./screenshots"; + } + + void MultiViewBase::onUpdate(Input& input) + { + if (input.key().isActivated(Key::LeftControl) && input.key().isPressed(Key::LeftAlt) && input.key().isPressed(Key::P)) { + _onPause = !_onPause; + } + if (_onPause) { + return; + } + + // Elapsed time since last rendering. + const auto timeNow = std::chrono::steady_clock::now(); + _deltaTime = (float)(std::chrono::duration_cast(timeNow - _timeLastFrame).count())/1000000.0f; + _timeLastFrame = timeNow; + + for (auto & subview : _subViews) { + if (subview.second.view->active()) { + auto subInput = !subview.second.view->isFocused() ? Input() : Input::subInput(input, subview.second.viewport, false); + + if (subview.second.handler) { + subview.second.handler->update(subInput, _deltaTime, subview.second.viewport); + } + + subview.second.updateFunc(subview.second.view, subInput, subview.second.viewport, _deltaTime); + + } + } + + for (auto & subview : _ibrSubViews) { + MultiViewBase::IBRSubView & fView = subview.second; + + if (fView.view->active()) { + auto subInput = !fView.view->isFocused() ? Input() : Input::subInput(input, fView.viewport, false); + + if (fView.handler) { + fView.handler->update(subInput, _deltaTime, fView.viewport); + } + + fView.cam = fView.updateFunc(fView.view, subInput, fView.viewport, _deltaTime); + + /// If we use the default update func and the integrated handler, + /// we have to use the handler's camera. + if (fView.defaultUpdateFunc && fView.handler) { + fView.cam = fView.handler->getCamera(); + } + + } + } + + for (auto & subMultiView : _subMultiViews) { + subMultiView.second->onUpdate(input); + } + } + + void MultiViewBase::onRender(Window& win) + { + // Render all views. + for (auto & subview : _ibrSubViews) { + if (subview.second.view->active()) { + + renderSubView(subview.second); + + if (_enableGUI && _showSubViewsGui) { + subview.second.view->onGUI(); + if (subview.second.handler) { + subview.second.handler->onGUI("Camera " + subview.first); + } + } + } + } + for (auto & subview : _subViews) { + if (subview.second.view->active()) { + + renderSubView(subview.second); + + if (_enableGUI && _showSubViewsGui) { + subview.second.view->onGUI(); + if (subview.second.handler) { + subview.second.handler->onGUI("Camera " + subview.first); + } + } + } + } + for (auto & subMultiView : _subMultiViews) { + subMultiView.second->onRender(win); + } + + + } + + void MultiViewBase::onGui(Window & win) + { + } + + void MultiViewBase::addSubView(const std::string & title, ViewBase::Ptr view, const Vector2u & res, const ImGuiWindowFlags flags) + { + const ViewUpdateFunc updateFunc = + [](ViewBase::Ptr& vi, Input& in, const Viewport& vp, const float dt) { + vi->onUpdate(in, vp); + }; + addSubView(title, view, updateFunc, res, flags); + } + + void MultiViewBase::addSubView(const std::string & title, ViewBase::Ptr view, const ViewUpdateFunc updateFunc, const Vector2u & res, const ImGuiWindowFlags flags) + { + float titleBarHeight = 0.0f; + if(_enableGUI) titleBarHeight = ImGui::GetTitleBarHeight(); + // We have to shift vertically to avoid an overlap with the menu bar. + const Viewport viewport(0.0f, titleBarHeight, + res.x() > 0 ? res.x() : (float)_defaultViewResolution.x(), + (res.y() > 0 ? res.y() : (float)_defaultViewResolution.y()) + titleBarHeight); + RenderTargetRGB::Ptr rtPtr(new RenderTargetRGB((uint)viewport.finalWidth(), (uint)viewport.finalHeight(), SIBR_CLAMP_UVS)); + _subViews[title] = {view, rtPtr, viewport, title, flags, updateFunc }; + + } + + void MultiViewBase::addIBRSubView(const std::string & title, ViewBase::Ptr view, const IBRViewUpdateFunc updateFunc, const Vector2u & res, const ImGuiWindowFlags flags, const bool defaultFuncUsed) + { + float titleBarHeight = 0.0f; + if(_enableGUI) titleBarHeight = ImGui::GetTitleBarHeight(); + // We have to shift vertically to avoid an overlap with the menu bar. + const Viewport viewport(0.0f, titleBarHeight, + res.x() > 0 ? res.x() : (float)_defaultViewResolution.x(), + (res.y() > 0 ? res.y() : (float)_defaultViewResolution.y()) + titleBarHeight); + RenderTargetRGB::Ptr rtPtr(new RenderTargetRGB((uint)viewport.finalWidth(), (uint)viewport.finalHeight(), SIBR_CLAMP_UVS)); + if (_ibrSubViews.count(title) > 0){ + const auto handler = _ibrSubViews[title].handler; + _ibrSubViews[title] = { view, rtPtr, viewport, title, flags, updateFunc, defaultFuncUsed }; + _ibrSubViews[title].handler = handler; + } + else { + _ibrSubViews[title] = { view, rtPtr, viewport, title, flags, updateFunc, defaultFuncUsed }; + } + _ibrSubViews[title].shouldUpdateLayout = true; + } + + void MultiViewBase::addIBRSubView(const std::string & title, ViewBase::Ptr view, const Vector2u & res, const ImGuiWindowFlags flags) + { + const auto updateFunc = [](ViewBase::Ptr& vi, Input& in, const Viewport& vp, const float dt) { + vi->onUpdate(in, vp); + return InputCamera(); + }; + addIBRSubView(title, view, updateFunc, res, flags, true); + } + + void MultiViewBase::addIBRSubView(const std::string & title, ViewBase::Ptr view, const IBRViewUpdateFunc updateFunc, const Vector2u & res, const ImGuiWindowFlags flags) + { + addIBRSubView(title, view, updateFunc, res, flags, false); + } + + void MultiViewBase::addSubMultiView(const std::string & title, MultiViewBase::Ptr multiview) + { + _subMultiViews[title] = multiview; + } + + ViewBase::Ptr & MultiViewBase::getIBRSubView(const std::string & title) + { + if (_subViews.count(title) > 0) { + return _subViews.at(title).view; + } + if (_ibrSubViews.count(title) > 0) { + return _ibrSubViews.at(title).view; + } + + SIBR_ERR << " No subview with name <" << title << "> found." << std::endl; + + return _subViews.begin()->second.view; + } + + Viewport & MultiViewBase::getIBRSubViewport(const std::string & title) + { + if (_subViews.count(title) > 0) { + return _subViews.at(title).viewport; + } + else if (_ibrSubViews.count(title) > 0) { + return _ibrSubViews.at(title).viewport; + } + + SIBR_ERR << " No subviewport with name <" << title << "> found." << std::endl; + + return _subViews.begin()->second.viewport; + } + + void MultiViewBase::renderSubView(SubView & subview) + { + + if (!_onPause) { + + const Viewport renderViewport(0.0, 0.0, (float)subview.rt->w(), (float)subview.rt->h()); + subview.render(_renderingMode, renderViewport); + + // Offline video dumping, continued. We ignore additional rendering as those often are GUI overlays. + if (subview.handler != NULL && (subview.handler->getCamera().needVideoSave() || subview.handler->getCamera().needSave())) { + + ImageRGB frame; + + subview.rt->readBack(frame); + + if (subview.handler->getCamera().needSave()) { + frame.save(subview.handler->getCamera().savePath()); + } + _videoFrames.push_back(frame.toOpenCVBGR()); + + } + + // Additional rendering. + subview.renderFunc(subview.view, renderViewport, std::static_pointer_cast(subview.rt)); + + // Render handler if needed. + if (subview.handler) { + subview.rt->bind(); + renderViewport.bind(); + subview.handler->onRender(renderViewport); + subview.rt->unbind(); + } + } + + if(_enableGUI) + { + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); + subview.view->setFocus(showImGuiWindow(subview.view->name(), *subview.rt, subview.flags, subview.viewport, false, subview.shouldUpdateLayout)); + ImGui::PopStyleVar(); + } + // If we have updated the layout, don't do it next frame. + subview.shouldUpdateLayout = false; + } + + ViewBase::Ptr MultiViewBase::removeSubView(const std::string & title) + { + ViewBase::Ptr viewPtr = nullptr; + if (_subViews.count(title) > 0) { + viewPtr = _subViews.at(title).view; + _subViews.erase(title); + } + else if (_ibrSubViews.count(title) > 0) { + viewPtr = _ibrSubViews.at(title).view; + _ibrSubViews.erase(title); + } + else { + SIBR_WRG << "No view named <" << title << "> found." << std::endl; + } + return viewPtr; + } + + void MultiViewBase::renderingMode(const IRenderingMode::Ptr& mode) + { + _renderingMode = std::move(mode); + } + + const Viewport MultiViewBase::getViewport(void) const + { + return Viewport(0.0f, 0.0f, (float)_defaultViewResolution.x(), (float)_defaultViewResolution.y()); + } + + void MultiViewBase::addCameraForView(const std::string & name, ICameraHandler::Ptr cameraHandler) + { + if (_subViews.count(name) > 0) { + _subViews.at(name).handler = cameraHandler; + } + else if (_ibrSubViews.count(name) > 0) { + _ibrSubViews.at(name).handler = cameraHandler; + + SubView & subview = _ibrSubViews.at(name); + } + else { + SIBR_WRG << "No view named <" << name << "> found." << std::endl; + } + + } + + void MultiViewBase::addAdditionalRenderingForView(const std::string & name, const AdditionalRenderFunc renderFunc) + { + if (_subViews.count(name) > 0) { + _subViews.at(name).renderFunc = renderFunc; + } + else if (_ibrSubViews.count(name) > 0) { + _ibrSubViews.at(name).renderFunc = renderFunc; + } + else { + SIBR_WRG << "No view named <" << name << "> found." << std::endl; + } + } + + int MultiViewBase::numSubViews() const + { + return static_cast(_subViews.size() + _ibrSubViews.size() + _subMultiViews.size()); + } + + void MultiViewBase::captureView(const std::string & subviewName, const std::string & path, const std::string & filename) + { + if (_subViews.count(subviewName)) { + captureView(_subViews[subviewName], path, filename); + } + else if (_ibrSubViews.count(subviewName)) { + captureView(_ibrSubViews[subviewName], path, filename); + } + else { + SIBR_WRG << "No View in the MultiViewManager with " << subviewName << " as a name!" << std::endl; + } + } + + void MultiViewBase::captureView(const SubView & view, const std::string& path, const std::string & filename) { + + const uint w = view.rt->w(); + const uint h = view.rt->h(); + + ImageRGB renderingImg(w, h); + + view.rt->readBack(renderingImg); + + std::string finalPath = path + (!path.empty() ? "/" : ""); + if (!filename.empty()) { + finalPath.append(filename); + } + else { + const std::string autoName = view.view->name() + "_" + sibr::timestamp(); + finalPath.append(autoName + ".png"); + } + + makeDirectory(path); + renderingImg.save(finalPath, true); + } + + void MultiViewBase::mosaicLayout(const Viewport & vp) + { + const int viewsCount = numSubViews(); + + // Do square decomposition for now. + // Find the next square. + const int sideCount = int(std::ceil(std::sqrt(viewsCount))); + int verticalShift = 0; + if(_enableGUI) verticalShift = ImGui::GetTitleBarHeight(); + + Viewport usedVP = Viewport(vp.finalLeft(), vp.finalTop() + verticalShift, vp.finalRight(), vp.finalBottom()); + Vector2f itemRatio = Vector2f(1, 1) / sideCount; + + int vid = 0; + for (auto & view : _ibrSubViews) { + // Compute position on grid. + const int col = vid % sideCount; + const int row = vid / sideCount; + view.second.viewport = Viewport(usedVP, col*itemRatio[0], row * itemRatio[1], (col + 1)*itemRatio[0], (row + 1)*itemRatio[1]); + view.second.shouldUpdateLayout = true; + ++vid; + } + for (auto & view : _subViews) { + // Compute position on grid. + const int col = vid % sideCount; + const int row = vid / sideCount; + view.second.viewport = Viewport(usedVP, col*itemRatio[0], row * itemRatio[1], (col + 1)*itemRatio[0], (row + 1)*itemRatio[1]); + view.second.shouldUpdateLayout = true; + ++vid; + } + for (auto & view : _subMultiViews) { + // Compute position on grid. + const int col = vid % sideCount; + const int row = vid / sideCount; + view.second->mosaicLayout(Viewport(usedVP, col*itemRatio[0], row * itemRatio[1], (col + 1)*itemRatio[0], (row + 1)*itemRatio[1])); + ++vid; + } + + } + + void MultiViewBase::toggleSubViewsGUI() + { + _showSubViewsGui = !_showSubViewsGui; + + for (auto & view : _subMultiViews) { + view.second->toggleSubViewsGUI(); + } + } + + void MultiViewBase::setExportPath(const std::string & path) { + _exportPath = path; + sibr::makeDirectory(path); + } + + MultiViewBase::SubView::SubView(ViewBase::Ptr view_, RenderTargetRGB::Ptr rt_, const sibr::Viewport viewport_, const std::string& name_, const ImGuiWindowFlags flags_) : + view(view_), rt(rt_), handler(), viewport(viewport_), flags(flags_), shouldUpdateLayout(false) { + renderFunc = [](ViewBase::Ptr&, const Viewport&, const IRenderTarget::Ptr&) {}; + view->setName(name_); + } + + MultiViewBase::BasicSubView::BasicSubView(ViewBase::Ptr view_, RenderTargetRGB::Ptr rt_, const sibr::Viewport viewport_, const std::string& name_, const ImGuiWindowFlags flags_, ViewUpdateFunc f_) : + SubView(view_, rt_, viewport_, name_, flags_), updateFunc(f_) { + } + + void MultiViewBase::BasicSubView::render(const IRenderingMode::Ptr& rm, const Viewport& renderViewport) const { + rt->bind(); + renderViewport.bind(); + renderViewport.clear(); + view->onRender(renderViewport); + rt->unbind(); + } + + MultiViewBase::IBRSubView::IBRSubView(ViewBase::Ptr view_, RenderTargetRGB::Ptr rt_, const sibr::Viewport viewport_, const std::string& name_, const ImGuiWindowFlags flags_, IBRViewUpdateFunc f_, const bool defaultUpdateFunc_) : + SubView(view_, rt_, viewport_, name_, flags_), updateFunc(f_), defaultUpdateFunc(defaultUpdateFunc_) { + cam = sibr::InputCamera(); + } + + void MultiViewBase::IBRSubView::render(const IRenderingMode::Ptr& rm, const Viewport& renderViewport) const { + if (rm) { + rm->render(*view, cam, renderViewport, rt.get()); + } + } + + MultiViewManager::MultiViewManager(Window& window, bool resize) + : _window(window), _fpsCounter(false) + { + _enableGUI = window.isGUIEnabled(); + + if (resize) { + window.size( + Window::desktopSize().x() - 200, + Window::desktopSize().y() - 200); + window.position(100, 100); + } + + /// \todo TODO: support launch arg for stereo mode. + renderingMode(IRenderingMode::Ptr(new MonoRdrMode())); + + //Default view resolution. + int w = int(window.size().x() * 0.5f); + int h = int(window.size().y() * 0.5f); + setDefaultViewResolution(Vector2i(w, h)); + + if(_enableGUI) ImGui::GetStyle().WindowBorderSize = 0.0; + } + + void MultiViewManager::onUpdate(Input & input) + { + MultiViewBase::onUpdate(input); + + if (input.key().isActivated(Key::LeftControl) && input.key().isActivated(Key::LeftAlt) && input.key().isReleased(Key::G)) { + toggleGUI(); + } + } + + void MultiViewManager::onRender(Window & win) + { + win.viewport().bind(); + glClearColor(37.f / 255.f, 37.f / 255.f, 38.f / 255.f, 1.f); + glClear(GL_COLOR_BUFFER_BIT); + glClearColor(1.f, 1.f, 1.f, 1.f); + + onGui(win); + + MultiViewBase::onRender(win); + + _fpsCounter.update(_enableGUI && _showGUI); + } + + void MultiViewManager::onGui(Window & win) + { + MultiViewBase::onGui(win); + + // Menu + if (_showGUI && ImGui::BeginMainMenuBar()) + { + if (ImGui::BeginMenu("Menu")) + { + ImGui::MenuItem("Pause", "", &_onPause); + if (ImGui::BeginMenu("Display")) { + const bool currentScreenState = win.isFullscreen(); + if (ImGui::MenuItem("Fullscreen", "", currentScreenState)) { + win.setFullscreen(!currentScreenState); + } + + const bool currentSyncState = win.isVsynced(); + if (ImGui::MenuItem("V-sync", "", currentSyncState)) { + win.setVsynced(!currentSyncState); + } + + const bool isHiDPI = ImGui::GetIO().FontGlobalScale > 1.0f; + if (ImGui::MenuItem("HiDPI", "", isHiDPI)) { + if (isHiDPI) { + ImGui::GetStyle().ScaleAllSizes(1.0f / win.scaling()); + ImGui::GetIO().FontGlobalScale = 1.0f; + } else { + ImGui::GetStyle().ScaleAllSizes(win.scaling()); + ImGui::GetIO().FontGlobalScale = win.scaling(); + } + } + + if (ImGui::MenuItem("Hide GUI (!)", "Ctrl+Alt+G")) { + toggleGUI(); + } + ImGui::EndMenu(); + } + + + if (ImGui::MenuItem("Mosaic layout")) { + mosaicLayout(win.viewport()); + } + + if (ImGui::MenuItem("Row layout")) { + Vector2f itemSize = win.size().cast(); + itemSize[0] = std::round(float(itemSize[0]) / float(_subViews.size() + _ibrSubViews.size())); + const float verticalShift = ImGui::GetTitleBarHeight(); + float vid = 0.0f; + for (auto & view : _ibrSubViews) { + // Compute position on grid. + view.second.viewport = Viewport(vid*itemSize[0], verticalShift, (vid + 1.0f)*itemSize[0] - 1.0f, verticalShift + itemSize[1] - 1.0f); + view.second.shouldUpdateLayout = true; + ++vid; + } + for (auto & view : _subViews) { + // Compute position on grid. + view.second.viewport = Viewport(vid*itemSize[0], verticalShift, (vid + 1.0f)*itemSize[0] - 1.0f, verticalShift + itemSize[1] - 1.0f); + view.second.shouldUpdateLayout = true; + ++vid; + } + } + + + if (ImGui::MenuItem("Quit", "Escape")) { win.close(); } + ImGui::EndMenu(); + } + + if (ImGui::BeginMenu("Views")) + { + for (auto & subview : _subViews) { + if (ImGui::MenuItem(subview.first.c_str(), "", subview.second.view->active())) { + subview.second.view->active(!subview.second.view->active()); + } + } + for (auto & subview : _ibrSubViews) { + if (ImGui::MenuItem(subview.first.c_str(), "", subview.second.view->active())) { + subview.second.view->active(!subview.second.view->active()); + } + } + if (ImGui::MenuItem("Metrics", "", _fpsCounter.active())) { + _fpsCounter.toggleVisibility(); + } + if (ImGui::BeginMenu("Front when focus")) + { + for (auto & subview : _subViews) { + const bool isLockedInBackground = subview.second.flags & ImGuiWindowFlags_NoBringToFrontOnFocus; + if (ImGui::MenuItem(subview.first.c_str(), "", !isLockedInBackground)) { + if(isLockedInBackground) { + subview.second.flags &= ~ImGuiWindowFlags_NoBringToFrontOnFocus; + } else { + subview.second.flags |= ImGuiWindowFlags_NoBringToFrontOnFocus; + } + } + } + for (auto & subview : _ibrSubViews) { + const bool isLockedInBackground = subview.second.flags & ImGuiWindowFlags_NoBringToFrontOnFocus; + if (ImGui::MenuItem(subview.first.c_str(), "", !isLockedInBackground)) { + if (isLockedInBackground) { + subview.second.flags &= ~ImGuiWindowFlags_NoBringToFrontOnFocus; + } else { + subview.second.flags |= ImGuiWindowFlags_NoBringToFrontOnFocus; + } + } + } + ImGui::EndMenu(); + } + if (ImGui::MenuItem("Reset Settings to Default", "")) { + _window.resetSettingsToDefault(); + } + ImGui::EndMenu(); + } + + if (ImGui::BeginMenu("Capture")) + { + + if (ImGui::MenuItem("Set export directory...")) { + std::string selectedDirectory; + if (showFilePicker(selectedDirectory, FilePickerMode::Directory)) { + if (!selectedDirectory.empty()) { + _exportPath = selectedDirectory; + } + } + } + + for (auto & subview : _subViews) { + if (ImGui::MenuItem(subview.first.c_str())) { + captureView(subview.second, _exportPath); + } + } + for (auto & subview : _ibrSubViews) { + if (ImGui::MenuItem(subview.first.c_str())) { + captureView(subview.second, _exportPath); + } + } + + if (ImGui::MenuItem("Export Video")) { + std::string saveFile; + if (showFilePicker(saveFile, FilePickerMode::Save)) { + const std::string outputVideo = saveFile + ".mp4"; + if(!_videoFrames.empty()) { + SIBR_LOG << "Exporting video to : " << outputVideo << " ..." << std::flush; + FFVideoEncoder vdoEncoder(outputVideo, 30, Vector2i(_videoFrames[0].cols, _videoFrames[0].rows)); + for (int i = 0; i < _videoFrames.size(); i++) { + vdoEncoder << _videoFrames[i]; + } + _videoFrames.clear(); + std::cout << " Done." << std::endl; + + } else { + SIBR_WRG << "No frames to export!! Check save frames in camera options for the view you want to render and play the path and re-export!" << std::endl; + } + } + } + + ImGui::EndMenu(); + } + + ImGui::EndMainMenuBar(); + } + } + + void MultiViewManager::toggleGUI() + { + _showGUI = !_showGUI; + if (!_showGUI) { + SIBR_LOG << "[MultiViewManager] GUI is now hidden, use Ctrl+Alt+G to toggle it back on." << std::endl; + } + toggleSubViewsGUI(); + } + + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/MultiViewManager.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/MultiViewManager.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e1a42c9fba3f120b4127dbdc1a2d90558b78894c --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/MultiViewManager.hpp @@ -0,0 +1,439 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include +# include + +# include "core/view/Config.hpp" +# include "core/graphics/Window.hpp" +# include "core/graphics/Texture.hpp" +# include "core/view/RenderingMode.hpp" +# include "core/view/FPSCamera.hpp" + +# include "core/assets/InputCamera.hpp" +# include "core/graphics/Input.hpp" +# include "core/graphics/Image.hpp" +# include "core/graphics/RenderUtility.hpp" +# include "core/assets/CameraRecorder.hpp" +# include "core/view/ViewBase.hpp" +# include "core/graphics/Shader.hpp" +# include "core/view/FPSCounter.hpp" +#include "core/video/FFmpegVideoEncoder.hpp" +#include "InteractiveCameraHandler.hpp" +#include +#include + + +namespace sibr +{ + + /** + * MultiViewBase is designed to provide + * more flexibility and with a multi-windows system in mind. + * Once a MultiViewBase is created, you can register standard and + * IBR subviews, providing additional functions for update and + * rendering if needed, along with support for ImGui interfaces. + * MultiViewBase will wrap those views and manage them on screen. + * To support legacy rendering modes and views, we introduce a + * distinction between standard subviews, that will be rendered through + * a call to onRender(Viewport&), and IBR subviews rendered through + * a onRenderIBR(rt, eye) call. This also means that after updating + * (via onUpdate) an IBR subview, you have to return the camera + * that will be used for the onRenderIBR call. + * Note: new IBR views don't have to implement this distinction. + * \ingroup sibr_view + */ + class SIBR_VIEW_EXPORT MultiViewBase + { + SIBR_CLASS_PTR(MultiViewBase); + + public: + + /// Update callback for a standard view. Passes the view pointer, the correct input state, and the correct viewport. + typedef std::function ViewUpdateFunc; + /// Update callback for an IBR view, see main description for the return value. + typedef std::function IBRViewUpdateFunc; + /// Additional render callback for a subview. + typedef std::function AdditionalRenderFunc; + + /* + * \brief Creates a MultiViewBase in a given OS window. + * \param defaultViewRes the default resolution for each subview + */ + MultiViewBase(const Vector2i & defaultViewRes = { 800, 600 }); + + /** + * \brief Update subviews and the MultiViewBase. + * \param input The input state to use. + */ + virtual void onUpdate(Input & input); + + /** + * \brief Render the content of the MultiViewBase + * \param win The OS window into which the rendering should be performed. + */ + virtual void onRender(Window& win); + + /** + * \brief Render additional gui + * \param win The OS window into which the rendering should be performed. + */ + virtual void onGui(Window& win); + + /** + * \brief Register a standard subview (for instance a SceneDebugView). It will be rendered via a call to onRender(Viewport) in an implicit rendertarget managed by the MultiViewBase. + * \param title the title of the view. + * \param view a pointer to the view. + * \param res a custom resolution used for the internal rendering and display. If null, the default value is used. + * \param flags ImGui_WindowFlags to pass to the internal window manager. + */ + void addSubView(const std::string& title, ViewBase::Ptr view, + const Vector2u & res = Vector2u(0,0), + const ImGuiWindowFlags flags = 0); + + /** + * \brief Register a standard subview (for instance a SceneDebugView). It will be rendered via a call to onRender(Viewport) in an implicit rendertarget managed by the MultiViewBase. + * \param title the title of the view. + * \param view a pointer to the view. + * \param updateFunc the function that will be called to update your view. + * It will pass you the view, the correct Input (mouse position + * from 0,0 in the top left corner, key presses and mouse clicks + * only if the cursor is over the view), and the Viewport in the + * OS window. + * \param res a custom resolution used for the internal rendering and display. If null, the default value is used. + * \param flags ImGui_WindowFlags to pass to the internal window manager. + */ + void addSubView(const std::string& title, ViewBase::Ptr view, + const ViewUpdateFunc updateFunc, + const Vector2u & res = Vector2u(0, 0), + const ImGuiWindowFlags flags = 0); + + /** + * \brief Register an IBR subview (for instance an ULRView). It will be rendered via a call to onRenderIBR(rt,cam,dst). + * \param title the title of the view. + * \param view a pointer to the view. + * \param res a custom resolution used for the internal rendering. If null, the default value is used. + * \param flags ImGui_WindowFlags to pass to the internal window manager. + */ + void addIBRSubView(const std::string& title, ViewBase::Ptr view, + const Vector2u & res = Vector2u(0, 0), + const ImGuiWindowFlags flags = 0); + + /** + * \brief Register an IBR subview (for instance an ULRView). It will be rendered via a call to onRenderIBR(rt,cam,dst). + * \param title the title of the view. + * \param view a pointer to the view. + * \param updateFunc the function that will be called to update your view. + * It will pass you the view, the correct Input (mouse position + * from 0,0 in the top left corner, key presses and mouse clicks + * only if the cursor is over the view), and the Viewport in the + * OS window. You should return the camera to use during rendering. + * \param res a custom resolution used for the internal rendering. If null, the default value is used. + * \param flags ImGui_WindowFlags to pass to the internal window manager. + */ + void addIBRSubView(const std::string& title, ViewBase::Ptr view, + const IBRViewUpdateFunc updateFunc, + const Vector2u & res = Vector2u(0, 0), + const ImGuiWindowFlags flags = 0); + + /** Add another multi-view system as a subsystem of this one. + * \param title a name for the multiview + * \param multiview the multiview system to add as a subview + */ + void addSubMultiView(const std::string & title, MultiViewBase::Ptr multiview); + + /** + * \param title + * \return Return viewbase associated with title, will EXIT_ERROR if no view found + * \note This covers both basic and IBR subviews. + * \todo Rename without the IBR prefix + */ + ViewBase::Ptr & getIBRSubView(const std::string& title); + + /** + * \param title + * \return the Viewport associated with title, will EXIT_ERROR if no viewport found + * \note This covers both basic and IBR subviews. + * \todo Rename without the IBR prefix + */ + Viewport & getIBRSubViewport(const std::string &title); + + /** + * \brief Unregister a subview. + * \param title the title of the view to remove. + * \return the view removed from the MultiViewManager. + */ + ViewBase::Ptr removeSubView(const std::string& title); + + /** + * \brief Change the rendering mode. + * \param mode The rendering mode to use. + */ + void renderingMode(const IRenderingMode::Ptr& mode); + + + /** + * \brief Define the default rendering and display size for new subviews. + * \param size the default size to use. + */ + void setDefaultViewResolution(const Vector2i& size); + + /** + * \brief Returns the default viewport used for subviews rendering. + * \return the current default subview viewport + */ + const Viewport getViewport(void) const; + + /** + * \brief Returns the last frame time. + * \return the last frame time. + */ + const float & deltaTime() const { return _deltaTime; } + + /** + * \brief Add a camera handler that will automatically be updated and used by the MultiViewManager for the given subview. + * \param name the name of the subview to which the camera should be associated. + * \param cameraHandler a pointer to the camera handler to register. + */ + void addCameraForView(const std::string & name, ICameraHandler::Ptr cameraHandler); + + /** + * \brief Register a function performing additional rendering for a given subview, + * called by the MultiViewManager after calling onRender() on the subview. + * \param name the name of the subview to which the function should be associated. + * \param renderFunc the function performing additional rendering.. + */ + void addAdditionalRenderingForView(const std::string & name, const AdditionalRenderFunc renderFunc); + + /** + * \brief Count NOT recursively the number of subviews. + */ + int numSubViews() const; + + /** Place all subviews on a regular grid in the given viewport. + * \param vp the region in which the views should be layed out. + */ + void mosaicLayout(const Viewport & vp); + + /** Toggle the display of sub-managers GUIs. */ + void toggleSubViewsGUI(); + + /** + * \brief Set the export path. + * \param path path to the directory to use. + */ + void setExportPath(const std::string & path); + /** + * \brief captures a View content into an image file. + * \param subviewName a string with the name of the subview. + * \param path the path to save the output. + * \param filename the name of the output file, needs to have an OpenCV compatible file type. + */ + void captureView(const std::string& subviewName, const std::string& path = "./screenshots", const std::string& filename = ""); + protected: + + /** Internal representation of a subview. + * Note: this representation should remain *internal* to the multi view system, avoid any abstraction leak. + */ + struct SubView { + ViewBase::Ptr view; ///< Pointer to the view. + RenderTargetRGB::Ptr rt; ///< Destination RT. + ICameraHandler::Ptr handler; ///< Potential camera handler. + AdditionalRenderFunc renderFunc; ///< Optional additonal rendering function. + sibr::Viewport viewport; ///< Viewport in the global window. + ImGuiWindowFlags flags = 0; ///< ImGui flags. + bool shouldUpdateLayout = false; ///< Should the layout be updated at the next frame. + + /// Default constructor. + SubView() = default; + + /// Destructor. + virtual ~SubView() = default; + + /** Constructor. + *\param view_ the view + *\param rt_ the destination RT + *\param viewport_ the viewport + *\param name_ the view name + *\param flags_ the ImGui flags + */ + SubView(ViewBase::Ptr view_, RenderTargetRGB::Ptr rt_, const sibr::Viewport viewport_, + const std::string & name_, const ImGuiWindowFlags flags_); + + /** Render the subview. + *\param rm the rendering mode to use + *\param renderViewport the viewport to use in the destination RT + */ + virtual void render(const IRenderingMode::Ptr & rm, const Viewport & renderViewport) const = 0; + }; + + /** Specialization of Subview for basic views. */ + struct BasicSubView final : SubView { + ViewUpdateFunc updateFunc; ///< The update function. + + /// Default constructor. + BasicSubView() : SubView() {}; + + /// Destructor. + virtual ~BasicSubView() = default; + + /** Constructor. + *\param view_ the view + *\param rt_ the destination RT + *\param viewport_ the viewport + *\param name_ the view name + *\param flags_ the ImGui flags + *\param f_ the update function + */ + BasicSubView(ViewBase::Ptr view_, RenderTargetRGB::Ptr rt_, const sibr::Viewport viewport_, + const std::string & name_, const ImGuiWindowFlags flags_, ViewUpdateFunc f_); + + /** Render the subview. + *\param rm the rendering mode to use (unused) + *\param renderViewport the viewport to use in the destination RT + */ + void render(const IRenderingMode::Ptr & rm, const Viewport & renderViewport) const override; + }; + + /** Specialization of Subview for views using a render mode (IBR views mainly). */ + struct IBRSubView final : SubView { + IBRViewUpdateFunc updateFunc; ///< The update function. + sibr::InputCamera cam; ///< The current camera. + bool defaultUpdateFunc = true; ///< Was the default update function used. + + /// Default constructor. + IBRSubView() : SubView() {}; + + /// Destructor. + virtual ~IBRSubView() = default; + + /** Constructor. + *\param view_ the view + *\param rt_ the destination RT + *\param viewport_ the viewport + *\param name_ the view name + *\param flags_ the ImGui flags + *\param f_ the update function + *\param defaultUpdateFunc_ was the default update function use (to avoid some collisions) + */ + IBRSubView(ViewBase::Ptr view_, RenderTargetRGB::Ptr rt_, const sibr::Viewport viewport_, + const std::string & name_, const ImGuiWindowFlags flags_, IBRViewUpdateFunc f_, const bool defaultUpdateFunc_); + + /** Render the subview. + *\param rm the rendering mode to use + *\param renderViewport the viewport to use in the destination RT + */ + void render(const IRenderingMode::Ptr & rm, const Viewport & renderViewport) const override; + }; + + protected: + + /** Helper to add an IBR subview. + * \param title the title of the view. + * \param view a pointer to the view. + * \param updateFunc the function that will be called to update your view. + * It will pass you the view, the correct Input (mouse position + * from 0,0 in the top left corner, key presses and mouse clicks + * only if the cursor is over the view), and the Viewport in the + * OS window. You should return the camera to use during rendering. + * \param res a custom resolution used for the internal rendering. If null, the default value is used. + * \param flags ImGui_WindowFlags to pass to the internal window manager. + * \param defaultFuncUsed a flag denoting if the default function had to be used + * */ + void addIBRSubView(const std::string & title, ViewBase::Ptr view, + const IBRViewUpdateFunc updateFunc, const Vector2u & res, + const ImGuiWindowFlags flags, const bool defaultFuncUsed); + + /** Perform rendering for a given subview. + *\param subview the subview to render + **/ + void renderSubView(SubView & subview); + + /** Capture a view as an image on disk. + *\param view the view to capture + *\param path the destination direcotry path + *\param filename an optional filename, a timestamp will be appended + *\note if the filename is empty, the name of the view is used, with a timestamp appended. + **/ + static void captureView(const SubView & view, const std::string & path = "./screenshots/", const std::string & filename = ""); + + IRenderingMode::Ptr _renderingMode = nullptr; ///< Rendering mode. + std::map _subViews; ///< Regular subviews. + std::map _ibrSubViews; ///< IBR subviews. + std::map > _subMultiViews; ///< Nested multi-views. + + Vector2i _defaultViewResolution; ///< Default view resolution. + + std::string _exportPath; ///< Capture output path. + std::vector _videoFrames; ///< Video frames. + + std::chrono::time_point _timeLastFrame; ///< Last frame time point. + float _deltaTime; ///< Elapsed time. + bool _showSubViewsGui = true; ///< Show the GUI of the subviews. + bool _onPause = false; ///< Paused interaction and update. + bool _enableGUI = true; ///< Should the GUI be enabled. + }; + + /** A multiview manager is a multi-view system that displays its subviews in an OS window. + use it as a based for applications with multiple subviews. + * \ingroup sibr_view + */ + class SIBR_VIEW_EXPORT MultiViewManager : public MultiViewBase + { + public: + /* + * \brief Creates a MultiViewManager in a given OS window. + * \param window The OS window to use. + * \param resize Should the window be resized by the manager to maximize usable space. + */ + MultiViewManager(Window& window, bool resize = true); + + /** + * \brief Update subviews and the MultiViewManager. + * \param input The Input state to use. + */ + void onUpdate(Input & input) override; + + /** + * \brief Render the content of the MultiViewManager and its interface + * \param win The OS window into which the rendering should be performed. + */ + void onRender(Window& win) override; + + /** + * \brief Render menus and additional gui + * \param win The OS window into which the rendering should be performed. + */ + void onGui(Window& win) override; + + private: + + /** Show/hide the GUI. */ + void toggleGUI(); + + Window& _window; ///< The OS window. + FPSCounter _fpsCounter; ///< A FPS counter. + bool _showGUI = true; ///< Should the GUI be displayed. + + }; + + ///// INLINE ///// + + inline void MultiViewBase::setDefaultViewResolution(const Vector2i& size) { + _defaultViewResolution = size; + } + + + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/Orbit.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/Orbit.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6800bd6d099eeb6bae596c4b5ddb709f7a6e79ac --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/Orbit.cpp @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "Orbit.hpp" +#include +#include "core/graphics/Input.hpp" +#include "core/graphics/Viewport.hpp" +#include "core/raycaster/CameraRaycaster.hpp" +#include "core/graphics/Window.hpp" +#include "core/graphics/Mesh.hpp" +#include "core/view/UIShortcuts.hpp" + +# define SIBR_ORBIT_INTERPOLATE_FRAMES 900 + +namespace sibr { + + Orbit::Orbit(void) : _hasBeenInitialized(false), _orbitPointClicked(false) { + UIShortcuts::global().add("[Orbit cam] alt+click", "Select new orbit center."); + UIShortcuts::global().add("[Orbit cam] 4", "move left"); + UIShortcuts::global().add("[Orbit cam] 6", "move right"); + UIShortcuts::global().add("[Orbit cam] 8", "move down"); + UIShortcuts::global().add("[Orbit cam] 2", "move up"); + UIShortcuts::global().add("[Orbit cam] 7", "rotate left "); + UIShortcuts::global().add("[Orbit cam] 9", "rotate right "); + UIShortcuts::global().add("[Orbit cam] 1", "get closer"); + UIShortcuts::global().add("[Orbit cam] 3", "get further"); + UIShortcuts::global().add("[Orbit cam] 5", "flip up vector (look upside down)"); + UIShortcuts::global().add("[Orbit cam] alt+1-9", "automatic move"); + UIShortcuts::global().add("[Orbit cam] 0", "stop automatic move, restore previous cam"); + UIShortcuts::global().add("[Orbit cam] .", "stop automatic move, keep current cam"); + } + + void Orbit::update(const sibr::Input & input, const std::shared_ptr raycaster) { + + if (!_hasBeenInitialized) { return; } + + if (raycaster != nullptr && input.mouseButton().isReleased(sibr::Mouse::Left) + && input.key().isActivated(sibr::Key::LeftAlt)) { + updateOrbitParameters(input, raycaster); + } + + const float sensibility = 64.0f; + + if (input.key().isActivated(sibr::Key::LeftAlt)) { + //orbit.factor = 0; + if (input.key().isReleased(sibr::Key::KPNum4) || + input.key().isReleased(sibr::Key::Num4) || + input.key().isReleased(sibr::Key::F) // for laptops + ) { + _orbit.status = OrbitParameters::FORWARD_X; + _orbit.direction = OrbitParameters::ACW; + } + else if (input.key().isReleased(sibr::Key::KPNum6) || + input.key().isReleased(sibr::Key::Num6)) { + _orbit.status = OrbitParameters::FORWARD_X; + _orbit.direction = OrbitParameters::CW; + } + else if (input.key().isReleased(sibr::Key::KPNum2) || + input.key().isReleased(sibr::Key::Num2)) { + _orbit.status = OrbitParameters::FORWARD_Y; + _orbit.direction = OrbitParameters::ACW; + } + else if (input.key().isReleased(sibr::Key::KPNum8) || + input.key().isReleased(sibr::Key::Num8)) { + _orbit.status = OrbitParameters::FORWARD_Y; + _orbit.direction = OrbitParameters::CW; + } + else if (input.key().isReleased(sibr::Key::KPNum7) || + input.key().isReleased(sibr::Key::Num7)) { + _orbit.status = OrbitParameters::FORWARD_Z; + _orbit.direction = OrbitParameters::ACW; + } + else if (input.key().isReleased(sibr::Key::KPNum9) || + input.key().isReleased(sibr::Key::Num9)) { + _orbit.status = OrbitParameters::FORWARD_Z; + _orbit.direction = OrbitParameters::CW; + } + } + else if ((input.key().isReleased(sibr::Key::KPNum0) || input.key().isReleased(sibr::Key::Num0)) + && _orbit.status != OrbitParameters::STATIC) { + _orbit.status = OrbitParameters::STATIC; + } + else if (input.key().isReleased(sibr::Key::KPDecimal) + && _orbit.status != OrbitParameters::STATIC) { + _orbit.keepCamera = true; + } + else if (input.key().isActivated(sibr::Key::KPNum4) || + input.key().isActivated(sibr::Key::Num4)) { + _orbit.theta = -(float)M_2_PI / sensibility; + } + else if (input.key().isActivated(sibr::Key::KPNum6) || + input.key().isActivated(sibr::Key::Num6)) { + _orbit.theta = (float)M_2_PI / sensibility; + } + else if (input.key().isActivated(sibr::Key::KPNum2) || + input.key().isActivated(sibr::Key::Num2)) { + _orbit.phi = -(float)M_2_PI / sensibility; + } + else if (input.key().isActivated(sibr::Key::KPNum8) || + input.key().isActivated(sibr::Key::Num8)) { + _orbit.phi = (float)M_2_PI / sensibility; + } + else if (input.key().isActivated(sibr::Key::KPNum7) || + input.key().isActivated(sibr::Key::Num7)) { + _orbit.roll = -(float)M_2_PI / sensibility; + } + else if (input.key().isActivated(sibr::Key::KPNum9) || + input.key().isActivated(sibr::Key::Num9)) { + _orbit.roll = (float)M_2_PI / sensibility; + } + else if (input.key().isActivated(sibr::Key::KPNum1) || + input.key().isActivated(sibr::Key::Num1)) { + _orbit.radius *= 0.98f; + } + else if (input.key().isActivated(sibr::Key::KPNum3) || + input.key().isActivated(sibr::Key::Num3)) { + _orbit.radius *= 1.02f; + } + else if (input.key().isReleased(sibr::Key::KPNum5) || + input.key().isReleased(sibr::Key::Num5)) { + if (_orbit.status == OrbitParameters::STATIC) { + _orbit.flip(); + std::cout << "\t orbit flip ! " << std::endl; + } + else { + if (_orbit.direction == OrbitParameters::CW) { + _orbit.direction = OrbitParameters::ACW; + std::cout << "\t orbit anti clockwise " << std::endl; + } + else { + _orbit.direction = OrbitParameters::CW; + std::cout << "\t orbit clockwise " << std::endl; + } + } + } + + interpolateOrbit(); + } + + void Orbit::interpolateOrbit() { + using namespace Eigen; + + float k = (_orbit.factor) / (float)(SIBR_ORBIT_INTERPOLATE_FRAMES); + bool keepCam = _orbit.keepCamera; + + float theta = (_orbit.status == OrbitParameters::FORWARD_X ? (float)(SIBR_2PI * k) : _orbit.theta); + float phi = (_orbit.status == OrbitParameters::FORWARD_Y ? (float)(SIBR_2PI * k) : _orbit.phi); + float roll = (_orbit.status == OrbitParameters::FORWARD_Z ? (float)(SIBR_2PI * k) : _orbit.roll); + + sibr::Vector3f dir = -(_orbit.zAxis); + sibr::Quaternionf qRoll(AngleAxisf(roll, _orbit.zAxis)); + sibr::Quaternionf qTheta(AngleAxisf(theta, _orbit.yAxis)); + sibr::Quaternionf qPhi(AngleAxisf(phi, _orbit.xAxis)); + + sibr::Vector3f center = _orbit.center; + sibr::Vector3f Eye = center + _orbit.radius*((qTheta*qPhi)*(dir)); + sibr::Vector3f up(qRoll*_orbit.yAxis); + + sibr::Camera n(_orbit.initialCamera); + n.setLookAt(Eye, center, up); + n.aspect(_orbit.initialCamera.aspect()); + + + if (_orbit.status == OrbitParameters::STATIC || keepCam) { + sibr::Quaternionf qTot = qTheta*qPhi*qRoll; + _orbit.xAxis = qTot*_orbit.xAxis; + _orbit.yAxis = qTot*_orbit.yAxis; + _orbit.zAxis = qTot*_orbit.zAxis; + + _orbit.theta = 0; + _orbit.phi = 0; + _orbit.roll = 0; + } + else { + _orbit.factor += _orbit.direction; + } + + if (keepCam) { + _orbit.status = OrbitParameters::STATIC; + _orbit.keepCamera = false; + } + + _currentCamera = sibr::InputCamera(n, _currentCamera.w(), _currentCamera.h()); + } + + void Orbit::updateOrbitParameters(const sibr::Input& input, std::shared_ptr raycaster) + { + + // Clicked pixel (might need to check against viewport ?) + const float px = (float)input.mousePosition().x(); + const float py = (float)input.mousePosition().y(); + + sibr::Vector3f dx; + sibr::Vector3f dy; + sibr::Vector3f upLeftOffset; + + sibr::CameraRaycaster::computePixelDerivatives(_currentCamera, dx, dy, upLeftOffset); + const sibr::Vector3f worldPos = px*dx + py*dy + upLeftOffset; + + // Cast a ray. + if (raycaster != nullptr) { + sibr::Vector3f dir = worldPos - _currentCamera.position(); + //sibr::Vector3f dir = sibr::CameraRaycaster::computeRayDir(_currentCamera, input.mousePosition().cast()).normalized(); + sibr::RayHit hit = raycaster->intersect(sibr::Ray(_currentCamera.position(), dir)); + + // If hit at the proxy surface, compute the corresponding worls position, save it. + if (hit.hitSomething()) { + _orbit.center = _currentCamera.position() + hit.dist()*dir.normalized(); + + // \todo TODO: SR reimplement the fitting of planes by either passing cameras all the way down, or something else. + //_orbit.planePointCams = computeFittingPlaneCameras(_orbit.center); + _orbit.yAxis = _currentCamera.up(); // _orbit.planePointCams.xyz(); + + //cheap trick to solve the ambiguity of the up direction + if (_orbit.yAxis.dot(_currentCamera.up()) < 0) { + _orbit.yAxis = -_orbit.yAxis; + } + + _orbit.zAxis = dir.normalized(); + _orbit.xAxis = _orbit.yAxis.cross(_orbit.zAxis); + _orbit.radius = (_orbit.initialCamera.position() - _orbit.center).norm(); + _orbit.initialCamera = _currentCamera; + + _orbitPointClicked = true; + } + + } + + } + + void Orbit::update(const sibr::Input & input, const float deltaTime, const Viewport & viewport) + { + update(input); + } + + const sibr::InputCamera & Orbit::getCamera( void ) const + { + if( !_hasBeenInitialized ){ + SIBR_ERR << " Orbit : camera not initialized before use" << std::endl + << "\t you should use either fromMesh(), fromCamera() or load() " << std::endl; + } + return _currentCamera; + + } + + void Orbit::fromCamera( const sibr::InputCamera & cam, const std::shared_ptr raycaster ) + { + _orbit.initialCamera = cam; + _currentCamera = cam; + _hasBeenInitialized = true; + + // If no point has already been selected by the user, we simply pick it automatically by intersecting cam dir and the mesh. + if (!_orbitPointClicked) { + // We need to transfer the camera parameters to the orbit. + updateOrbitParametersCentered(raycaster); + } + } + + void Orbit::updateOrbitParametersCentered(const std::shared_ptr raycaster) + { + if (raycaster != nullptr) { + sibr::RayHit hit = raycaster->intersect(sibr::Ray(_currentCamera.position(), _currentCamera.dir())); + // If hit at the proxy surface, compute the corresponding world position, save it. + if (hit.hitSomething()) { + sibr::Vector3f intersection(_currentCamera.position() + hit.dist()* _currentCamera.dir().normalized()); + _orbit.center = intersection; + _orbit.yAxis = _currentCamera.up(); + _orbit.zAxis = _currentCamera.dir(); + _orbit.xAxis = _currentCamera.right(); + _orbit.radius = (_currentCamera.position() - _orbit.center).norm(); + _orbit.initialCamera = _currentCamera; + //orbitPointClicked -->; don't set it, the center is picked automatically. + } + } + + } + + sibr::Vector4f Orbit::computeFittingPlaneCameras(sibr::Vector3f & clickedPoint, const std::vector & cams) + { + using namespace Eigen; + + std::vector positions(cams.size()); + + for (int i = 0; i<(int)cams.size(); ++i) { + positions.at(i) = cams.at(i)->position(); + } + positions.push_back(clickedPoint); + + std::vector colors(positions.size(), sibr::Vector3f(1, 0, 0)); + + MatrixXf data(3, positions.size()); + int posId = 0; + for (auto & pos : positions) { + data(0, posId) = pos.x(); + data(1, posId) = pos.y(); + data(2, posId) = pos.z(); + ++posId; + } + + sibr::Vector3f center = data.rowwise().mean(); + Eigen::MatrixXf dataCentered = data.colwise() - center; + + JacobiSVD svd(dataCentered, ComputeFullU | ComputeThinV); + + //the normal to the fitting plane is the eigenvector associated to the smallest eigenvalue (i.e. the direction in which the variance of all points is the smallest) + sibr::Vector3f normal = svd.matrixU().col(2); + normal.normalize(); + sibr::Vector3f n(normal); + + //the fitting plane contains the mean point + float d = -center.dot(normal); + + + std::cout << " \t plane ( clicked point + input cams ) : " << n.x() << "*x + " << n.y() << "*y + " << n.z() << "*z + " << d << std::endl; + + return sibr::Vector4f(n.x(), n.y(), n.z(), d); + } +} \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/Orbit.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/Orbit.hpp new file mode 100644 index 0000000000000000000000000000000000000000..edf34b1f015197354833969e11a851c84624a1b9 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/Orbit.hpp @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include +#include + +#include "Config.hpp" +#include "core/graphics/Shader.hpp" +#include "core/assets/InputCamera.hpp" +#include "ICameraHandler.hpp" + + +namespace sibr { + + class Viewport; + class Mesh; + class Input; + class Raycaster; + + /** + * Interactive camera that allow the user to roate around an object using the keypad. + * Commands: + + to enable/disable the orbit (note that using at least once ( atl + click ) to retrieve a 3D point on the proxy is mandatory before enabling the orbit) : + b + in static mode (default mode) : + 5 to flip the orbit (might be the first thing to do if all commands seem broken/reversed, it is needed because there is an ambiguity when using the normal of the plan containing the input cameras and the clicked point) + 4 or 6 to rotate towards current camera x-axis + 2 or 8 to rotate towards current camera y-axis + 7 or 9 to rotate towards current camera z-axis + 1 or 3 to zoom in or out + in dynamic mode ( rotates without interruption around an axis ) : + alt + ( 4 or 6 ) to rotate towards current camera x-axis + alt + ( 2 or 8 ) to rotate towards current camera y-axis + alt + ( 7 or 9 ) to rotate towards current camera z-axis + 5 to inverse the direction (same axis) + 0 to switch back to static mode with initial camera + . to switch back to static mode with current camera + * \ingroup sibr_view + */ + class SIBR_VIEW_EXPORT Orbit : public ICameraHandler + { + + public: + + /** + Create an orbit centered at (0,0,0) with basic initial parameters. + It is recommended to call fromCamera after that to setup the orbit with a valid set of parameters. + */ + Orbit( void ); + + /** + Setup the orbit so that its camera has the same pose as the argument camera. A raycaster is required to find the center of the orbit. + \param cam the reference camera + \param raycaster raycaster to use for centering intersection tests. + */ + void fromCamera(const sibr::InputCamera & cam, const std::shared_ptr raycaster); + + /** + Update the orbit camera based on the user input (keyboard). Can require a raycaster if the user is alt-clicking to select a new orbit center. + \param input user input + \param raycaster optional raycaster + */ + void update( const sibr::Input & input, const std::shared_ptr raycaster = std::shared_ptr()); + + /** Update the camera handler state. + \param input user input + \param deltaTime time elapsed since last udpate + \param viewport view viewport + */ + virtual void update(const sibr::Input & input, const float deltaTime, const Viewport & viewport) override; + + /** \return the current camera. */ + virtual const sibr::InputCamera & getCamera( void ) const override; + + private: + + /** Internal orbit parameters. */ + struct OrbitParameters + { + /** Motion direction: Clockwise, AntiClockWis e*/ + enum OrbitDirection { CW = 1, ACW = -1 }; + /** Orbit current motion status. */ + enum OrbitStatus { STATIC, FORWARD_X, FORWARD_Y, FORWARD_Z }; + + /** Default constructor. */ + OrbitParameters(void) : factor(0), status(STATIC), + center(sibr::Vector3f(0.0f, 0.0f, 0.0f)), radius(1.0f), theta(0), phi(0), roll(0), direction(CW), keepCamera(false) + {} + + /** Flip motion. */ + void flip(void) { + yAxis = -yAxis; + xAxis = yAxis.cross(zAxis); + } + + bool keepCamera; ///< ? + int factor; ///< Interpolation ID. + + OrbitStatus status; ///< Current status. + OrbitDirection direction; ///< Current motion direction. + + sibr::Vector3f center; ///< Orbit center. + sibr::Vector3f xAxis; ///< Orbit X axis. + sibr::Vector3f yAxis; ///< Orbit Y axis. + sibr::Vector3f zAxis; ///< Orbit Z axis. + + float radius; ///< Orbit radius. + float theta, phi, roll; ///< Orbit angles. + + sibr::Camera initialCamera; ///< Starting camera. + sibr::Vector4f planePointCams; ///< Fitted plane points. + + }; + + /** + * Compute new camera pose from current orbit parameters. + */ + void interpolateOrbit(); + + /** + * Updates the orbit's center and camera pose, by casting a ray from the clicked point (in Input) to the mesh. + * \param input user input + * \param raycaster scene raycaster + */ + void updateOrbitParameters(const sibr::Input& input, const std::shared_ptr raycaster); + + /** + * Updates the orbit's center and camera pose, by casting a ray from the center of the screen to the mesh. + * \param raycaster scene raycaster + */ + void updateOrbitParametersCentered(const std::shared_ptr raycaster); + + /** + * Compute the best fitting plane of the clicked points plus the input cams positions. + * \param clickedPoint point clicked by the user + * \param cams reference cameras + */ + static sibr::Vector4f computeFittingPlaneCameras(sibr::Vector3f& clickedPoint, const std::vector& cams); + + bool _hasBeenInitialized; ///< Has the orbit been initialized. + bool _orbitPointClicked; ///< Has the user clicked on a point in the scene. + sibr::InputCamera _currentCamera; ///< Current camera. + OrbitParameters _orbit; ///< Parameters. + + }; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/RenderingMode.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/RenderingMode.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5bb367a57cc5bec66beb28d54743bc52fb76f873 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/RenderingMode.cpp @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#include "core/graphics/RenderUtility.hpp" +#include "core/view/RenderingMode.hpp" +#include "core/assets/Resources.hpp" +#include "core/graphics/Image.hpp" + +namespace sibr +{ + MonoRdrMode::MonoRdrMode( void ) + { + _clear = true; + _quadShader.init("Texture", + sibr::loadFile(sibr::Resources::Instance()->getResourceFilePathName("texture.vp")), + sibr::loadFile(sibr::Resources::Instance()->getResourceFilePathName("texture.fp"))); + } + + void MonoRdrMode::render( ViewBase& view, const sibr::Camera& eye, const sibr::Viewport& viewport, IRenderTarget* optDest ) + { + /// TODO: clean everything. Resolution handling. + + //int w = (int)viewport.finalWidth(); + //int h = (int)viewport.finalHeight(); + + //if (!_destRT || _destRT->w() != w || _destRT->h() != h) + // _destRT.reset( new RenderTarget(w, h) ); + // + //view.onRenderIBR(*_destRT, eye); + //_destRT->unbind(); + + //_quadShader.begin(); + ////if(_ibr->isPortraitAcquisition() && !_ibr->args().fullscreen) + //// glViewport(0,0, _h, _w); + ////else + //// glViewport(0,0, _w * _ibr->args().rt_factor, (_ibr->args().fullscreen ? screenHeight : _h) * _ibr->args().rt_factor); + //viewport.use(); + ////glViewport(0,0, size().x(), size().y()); + + //glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, _destRT->texture()); + //RenderUtility::renderScreenQuad(false /*_ibr->isPortraitAcquisition()*/); + //_quadShader.end(); + + int w = (int)viewport.finalWidth(); + int h = (int)viewport.finalHeight(); + + if (!_destRT)// || _destRT->w() != w || _destRT->h() != h) + _destRT.reset( new RenderTarget(w, h, SIBR_GPU_LINEAR_SAMPLING) ); + glViewport(0, 0, w, h); + _destRT->bind(); + + if( _clear ) { + viewport.clear(); + // blend with previous + view.preRender(*_destRT); + } + else { + // can come from somewhere else + view.preRender(*_prevR); + } + + view.onRenderIBR(*_destRT, eye); + _destRT->unbind(); + + //show(*_destRT, "before"); + + //glEnable (GL_BLEND); + //glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glDisable (GL_BLEND); + glDisable(GL_DEPTH_TEST); + //glDepthMask(GL_FALSE); + + //glEnable (GL_BLEND); + //glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + _quadShader.begin(); + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, _destRT->texture()); + + if (optDest) // Optionally you can render to another RenderTarget + { + glViewport(0, 0, optDest->w(), optDest->h()); + optDest->bind(); + } + else + { + viewport.bind(); + } + + RenderUtility::renderScreenQuad(/*_ibr->isPortraitAcquisition()*/); + + if (optDest) // Optionally you can render to another RenderTarget + optDest->unbind(); + + _quadShader.end(); + +#if 0 +std::cerr <<"End of render pass 1" << std::endl; + show(*(_destRT)); +#endif + + } + + StereoAnaglyphRdrMode::StereoAnaglyphRdrMode( void ) + { + _clear = true; + _stereoShader.init("StereoAnaglyph", + sibr::loadFile(sibr::Resources::Instance()->getResourceFilePathName("anaglyph.vp")), + sibr::loadFile(sibr::Resources::Instance()->getResourceFilePathName("anaglyph.fp"))); + _leftRT.reset(), _rightRT.reset(); +/* default values good for Street-10 scene */ + + _focalDist = 100; + _eyeDist = (float)0.065; /* meters */ + } + + void StereoAnaglyphRdrMode::render( ViewBase& view, const sibr::Camera& eye, const sibr::Viewport& viewport, IRenderTarget* optDest) + { + int w = (int)viewport.finalWidth(); + int h = (int)viewport.finalHeight(); + + if (!_leftRT || _leftRT->w() != w || _leftRT->h() != h) + _leftRT.reset( new RenderTarget(w, h) ); + if (!_rightRT || _rightRT->w() != w || _rightRT->h() != h) + _rightRT.reset( new RenderTarget(w, h) ); + + InputCamera leye(eye, w, h); + InputCamera reye(eye, w, h); + leye.size(w, h); reye.size(w, h); + leye.position(eye.position()-_eyeDist*eye.right()); + + // setup left eye + leye.setStereoCam(true, _focalDist, _eyeDist); + _leftRT->bind(); + if( _clear ) { + viewport.clear(); + view.preRender(*_leftRT); + } + else { + // can come from somewhere else + view.preRender(*_prevL); + } + + view.onRenderIBR(*_leftRT, leye); + _leftRT->unbind(); + + // setup right eye + reye.position(eye.position()+_eyeDist*eye.right()); + reye.setStereoCam(false, _focalDist, _eyeDist); + + // render right eye + _rightRT->bind(); + if( _clear ) { + viewport.clear(); + view.preRender(*_rightRT); + } + else { + // can come from somewhere else + view.preRender(*_prevR); + } + view.onRenderIBR(*_rightRT, reye); + _rightRT->unbind(); + + glDisable (GL_BLEND); + glDisable(GL_DEPTH_TEST); + + _stereoShader.begin(); + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, _leftRT->texture()); + glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, _rightRT->texture()); + + if (optDest) // Optionally you can render to another RenderTarget + { + glViewport(0, 0, optDest->w(), optDest->h()); + optDest->bind(); + } + + RenderUtility::renderScreenQuad(); + + if (optDest) // Optionally you can render to another RenderTarget + optDest->unbind(); + + _stereoShader.end(); + + } + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/RenderingMode.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/RenderingMode.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6b592b0f2c1b19b82b50376260bbfd13207a8f39 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/RenderingMode.hpp @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include "core/graphics/Camera.hpp" +# include "core/graphics/Viewport.hpp" +# include "core/graphics/Texture.hpp" +# include "core/view/Config.hpp" +# include "core/view/ViewBase.hpp" +# include "core/graphics/Image.hpp" +# include "core/graphics/Shader.hpp" +# include "core/assets/InputCamera.hpp" + +namespace sibr +{ + /** + * Rendering mode manages the rendertarget and camera fed to an IBR view. Can be used to render a view using a stereoscopic mode (anaglyph or VR). + * \ingroup sibr_view + */ + class SIBR_VIEW_EXPORT IRenderingMode + { + SIBR_CLASS_PTR(IRenderingMode); + + public: + typedef RenderTargetRGB RenderTarget; + public: + /// Destructor. + virtual ~IRenderingMode( void ) { } + + /** Perform rendering of a view. + *\param view the view to render + *\param eye the current camera + *\param viewport the current viewport + *\param optDest an optional destination RT + */ + virtual void render( + ViewBase& view, const sibr::Camera& eye, const sibr::Viewport& viewport, + IRenderTarget* optDest = nullptr) = 0; + + /** Get the current rendered image as a CPU image + *\param current_img will contain the content of the RT */ + virtual void destRT2img( sibr::ImageRGB& current_img ) = 0; + + protected: + std::unique_ptr _prevL, _prevR; ///< prev RT to link renderers across different views in multipass + + public: + bool _clear; ///< Should the dst RT be cleared before rendering. + + /** Set common previous step RT. + *\param p the RT + */ + void setPrev(const std::unique_ptr& p) { std::cerr<<"ERROR " << std::endl; } + /** Set left and right previous step RTs. + *\param pl the left eye RT + *\param pr the right eye RT + */ + void setPrevLR(const std::unique_ptr& pl, const std::unique_ptr& pr) { std::cerr<<"ERROR " << std::endl;} + + /** \return the left eye (or common) RT. */ + virtual const std::unique_ptr& lRT() = 0; + /** \return the right eye (or common) RT. */ + virtual const std::unique_ptr& rRT() = 0; + + }; + + /** Default rendering mode: monoview, passthrough. + * \ingroup sibr_view + */ + class SIBR_VIEW_EXPORT MonoRdrMode : public IRenderingMode + { + public: + + /// Constructor. + MonoRdrMode( void ); + + /** Perform rendering of a view. + *\param view the view to render + *\param eye the current camera + *\param viewport the current viewport + *\param optDest an optional destination RT + */ + void render( ViewBase& view, const sibr::Camera& eye, const sibr::Viewport& viewport, IRenderTarget* optDest = nullptr); + + /** Get the current rendered image as a CPU image + *\param current_img will contain the content of the RT */ + void destRT2img( sibr::ImageRGB& current_img ) + { + _destRT->readBack(current_img); + return; + } + + /** \return the common RT. */ + virtual const std::unique_ptr& lRT() { return _destRT; } + /** \return the common RT. */ + virtual const std::unique_ptr& rRT() { return _destRT; } + + private: + sibr::GLShader _quadShader; ///< Passthrough shader. + std::unique_ptr _destRT; ///< Common destination RT. + }; + + /** + *Stereo rendering mode: two slightly shifted views are rendered and composited as anaglyphs. + * \ingroup sibr_view + */ + class SIBR_VIEW_EXPORT StereoAnaglyphRdrMode : public IRenderingMode + { + public: + + /// Constructor. + StereoAnaglyphRdrMode( void ); + + /** Perform rendering of a view. + *\param view the view to render + *\param eye the current camera + *\param viewport the current viewport + *\param optDest an optional destination RT + */ + void render( ViewBase& view, const sibr::Camera& eye, const sibr::Viewport& viewport, IRenderTarget* optDest = nullptr); + + /** Set the focal distance. + \param focal focal distance + */ + void setFocalDist(float focal) { _focalDist = focal; } + + /** Set the distance between the two eyes. + \param iod intra-ocular distance + */ + void setEyeDist(float iod) { _eyeDist = iod; } + + /** \return the focal distance */ + float focalDist() { return _focalDist; } + /** \return the intra-ocular distance */ + float eyeDist() { return _eyeDist; } + + /** Get the current rendered image as a CPU image (empty). + *\param current_img will contain the content of the RT */ + void destRT2img( sibr::ImageRGB& current_img ){}; + + /** \return the left eye RT. */ + virtual const std::unique_ptr& lRT() { return _leftRT; } + /** \return the right eye RT. */ + virtual const std::unique_ptr& rRT() { return _rightRT; } + + private: + sibr::GLShader _stereoShader; ///< Anaglyph shader. + RenderTarget::UPtr _leftRT, _rightRT; ///< Each eye RT. + float _focalDist, _eyeDist; ///< Focal and inter-eyes distances. + }; + + ///// DEFINITIONS ///// + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/SceneDebugView.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/SceneDebugView.cpp new file mode 100755 index 0000000000000000000000000000000000000000..97a1d196ac69ff659e9b5bc7af5071c1dfc86e8b --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/SceneDebugView.cpp @@ -0,0 +1,668 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +# include "core/view/SceneDebugView.hpp" +# include "core/graphics/RenderUtility.hpp" +# include "core/graphics/Input.hpp" +# include "core/graphics/GUI.hpp" +#include + +#include + +namespace sibr +{ + + Mesh::Ptr generateCamFrustum(const InputCamera & cam, float near, float far, bool useCam) + { + static const Mesh::Triangles tris = { + {0,0,1},{1,1,2},{2,2,3},{3,3,0}, + {4,4,5},{5,5,6},{6,6,7},{7,7,4}, + {0,0,4},{1,1,5},{2,2,6},{3,3,7}, + }; + + std::vector dirs; + if (!useCam) { + dirs.resize(4); + dirs[0] = Vector3f(-1, -0.8, -1); + dirs[1] = Vector3f(1, -0.8, -1); + dirs[2] = Vector3f(1, 0.8, -1); + dirs[3] = Vector3f(-1, 0.8, -1); + } else { + for (const auto& c : cam.getImageCorners()) + dirs.push_back(CameraRaycaster::computeRayDir(cam, c.cast() + 0.5f * Vector2f(1, 1))); + + } + + float znear = (near >= 0 ? near : cam.znear()); + float zfar = (far >= 0 ? far : cam.zfar()); + Mesh::Vertices vertices; + for (int k = 0; k < 2; k++) { + float dist = (k == 0 ? znear : zfar); + for (const auto & d : dirs) { + if (useCam) + vertices.push_back(cam.position() + dist * d); + else + vertices.push_back(dist * d); + } + } + + auto out = std::make_shared(); + out->vertices(vertices); + out->triangles(tris); + return out; + } + + Mesh::Ptr generateCamFrustumColored(const InputCamera & cam, const Vector3f & col, float znear, float zfar) + { + auto out = generateCamFrustum(cam, znear, zfar); + Mesh::Colors cols(out->vertices().size(), col); + out->colors(cols); + return out; + } + + Mesh::Ptr generateCamQuadWithUvs(const InputCamera & cam, float dist) + { + static const Mesh::Triangles quadTriangles = { + { 0,1,2 },{ 0,2,3 } + }; + static const Mesh::UVs quadUVs = { + { 0,1 } ,{ 1,1 } ,{ 1,0 } ,{ 0,0 } + }; + + std::vector dirs; + for (const auto & c : cam.getImageCorners()) { + dirs.push_back(CameraRaycaster::computeRayDir(cam, c.cast() + 0.5f*Vector2f(1, 1))); + } + std::vector vertices; + for (const auto & d : dirs) { + vertices.push_back(cam.position() + dist * d); + } + + auto out = std::make_shared(); + out->vertices(vertices); + out->triangles(quadTriangles); + out->texCoords(quadUVs); + return out; + } + + + LabelsManager::CameraInfos::CameraInfos(const InputCamera& cam, uint id, bool highlight) + : cam(cam), id(id), highlight(highlight) { + } + + void LabelsManager::setupLabelsManagerShader() + { + _labelShader.init("text-imgui", + loadFile(Resources::Instance()->getResourceFilePathName("text-imgui.vp")), + loadFile(Resources::Instance()->getResourceFilePathName("text-imgui.fp"))); + _labelShaderPosition.init(_labelShader, "position"); + _labelShaderScale.init(_labelShader, "scale"); + _labelShaderViewport.init(_labelShader, "viewport"); + } + + void LabelsManager::setupLabelsManagerMeshes(const std::vector & cams) + { + _labelMeshes.clear(); + for (const auto & cam : cams) { + unsigned int sepIndex = 0; + _labelMeshes[cam->id()] = {}; + _labelMeshes[cam->id()].mesh = generateMeshForText(std::to_string(cam->id()), sepIndex); + _labelMeshes[cam->id()].splitIndex = sepIndex; + } + } + + void LabelsManager::renderLabels(const Camera & eye, const Viewport & vp, const std::vector& cams_info) + { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + _labelShader.begin(); + // Bind the ImGui font texture. + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)(ImGui::GetFont()->ContainerAtlas->TexID)); + _labelShaderViewport.set(Vector2f(vp.finalWidth(), vp.finalHeight())); + + for (const auto & camInfos : cams_info) { + const auto & inputCam = camInfos.cam; + if (!inputCam.isActive()) { continue; } + const uint uid = camInfos.id; + if (_labelMeshes.count(uid) == 0) { + continue; + } + // Draw the label. + // TODO: we could try to use depth testing to have the labels overlap properly. + // As the label is put at the position of the camera, the label will intersect with the frustum mesh, causing artifacts. + // One way of solving this would be to just shift the label away a bit and enable depth testing (+ GL_LEQUAl for the text). + const Vector3f camProjPos = eye.project(inputCam.position()); + if (!eye.frustumTest(inputCam.position(), camProjPos.xy())) { + continue; + } + _labelShaderPosition.set(camProjPos); + const auto & label = _labelMeshes[uid]; + // Render the background label. + _labelShaderScale.set(0.8f*_labelScale); + label.mesh->renderSubMesh(0, label.splitIndex, false, false); + // Render the text label. + _labelShaderScale.set(1.0f*_labelScale); + label.mesh->renderSubMesh(label.splitIndex, int(label.mesh->triangles().size()) * 3, false, false); + + } + _labelShader.end(); + glDisable(GL_BLEND); + } + + void ImageCamViewer::initImageCamShaders() + { + const std::string vertex_str = loadFile(Resources::Instance()->getResourceFilePathName("uv_mesh.vert")); + + _shader2D.init("cameraImageShader", vertex_str, loadFile(Resources::Instance()->getResourceFilePathName("alpha_uv_tex.frag"))); + _mvp2D.init(_shader2D, "mvp"); + _alpha2D.init(_shader2D, "alpha"); + + _shaderArray.init("cameraImageShaderArray", vertex_str, loadFile(Resources::Instance()->getResourceFilePathName("alpha_uv_tex_array.frag"))); + _mvpArray.init(_shaderArray, "mvp"); + _alphaArray.init(_shaderArray, "alpha"); + _sliceArray.init(_shaderArray, "slice"); + } + + void ImageCamViewer::renderImage(const Camera & eye, const InputCamera & cam, + const std::vector & rts, int cam_id) + { + const auto quad = generateCamQuadWithUvs(cam, _pathScaling); + if (cam_id < rts.size() && rts[cam_id]) { + _shader2D.begin(); + _mvp2D.set(eye.viewproj()); + _alpha2D.set(_alphaImage); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, rts[cam_id]->handle()); + quad->render(true, false, Mesh::FillRenderMode, false, false); + _shader2D.end(); + } + } + + void ImageCamViewer::renderImage(const Camera & eye, const InputCamera & cam, uint tex2Darray_handle, int cam_id) + { + const auto quad = generateCamQuadWithUvs(cam, _pathScaling); + _shaderArray.begin(); + _mvpArray.set(eye.viewproj()); + _alphaArray.set(_alphaImage); + _sliceArray.set(cam_id); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D_ARRAY, tex2Darray_handle); + quad->render(true, false, Mesh::FillRenderMode, false, false); + _shaderArray.end(); + } + void ImageCamViewer::renderImage(const Camera& eye, const InputCamera& cam, const RenderTargetRGBA32F::Ptr& rt) + { + const auto quad = generateCamQuadWithUvs(cam, _pathScaling); + _shader2D.begin(); + _mvp2D.set(eye.viewproj()); + _alpha2D.set(_alphaImage); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, rt->handle()); + quad->render(true, false, Mesh::FillRenderMode, false, false); + _shader2D.end(); + } + + void ImageCamViewer::updateImgRt(const InputCamera& cam, const sibr::ImageRGBA& img) + { + uint w = cam.w(); + uint h = cam.h(); + + //Force using image aspect ratio + if (cam.w() >= cam.h()) h = cam.w(), w = cam.h(); + else w = cam.w(), h = cam.h(); + + GLShader textureShader; + textureShader.init("Texture", + loadFile(Resources::Instance()->getResourceFilePathName("texture.vp")), + loadFile(Resources::Instance()->getResourceFilePathName("texture.fp"))); + uint interpFlag = (SIBR_SCENE_LINEAR_SAMPLING & SIBR_SCENE_LINEAR_SAMPLING) ? SIBR_GPU_LINEAR_SAMPLING : 0; // LINEAR_SAMPLING Set to default + + std::cerr << "."; + ImageRGBA cloned_img = std::move(img.clone()); + cloned_img.flipH(); + + std::shared_ptr rawInputImage(new Texture2DRGBA(cloned_img, interpFlag)); + + glViewport(0, 0, w, h); + _imgRt.reset(new RenderTargetRGBA32F(w, h, interpFlag)); + _imgRt->clear(); + _imgRt->bind(); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, rawInputImage->handle()); + + //Render texture (mapped to screenquad geometry) in the framebuffer (renderTarget) + // so that it matches afterwards the same camera settings when applied as a texture + glDisable(GL_DEPTH_TEST); + textureShader.begin(); + RenderUtility::renderScreenQuad(); + textureShader.end(); + _imgRt->unbind(); + } + + SceneDebugView::SceneDebugView(const IIBRScene::Ptr & scene, + const InteractiveCameraHandler::Ptr & camHandler, const BasicDatasetArgs & myArgs, const std::string& imagesPath) + { + + initImageCamShaders(); + setupLabelsManagerShader(); + + _scene = scene; + _userCurrentCam = camHandler; + + if (!_scene->cameras()->inputCameras().empty()) { + camera_handler.fromTransform(_scene->cameras()->inputCameras()[0]->transform(), true, false); + camera_handler.setupInterpolationPath(_scene->cameras()->inputCameras()); + } + + _showImages = false; + if (directoryExists(imagesPath)) { + _images_path = imagesPath; + } + else { + _images_path = ""; + } + + const std::string camerasDir = myArgs.dataset_path.get() + "/cameras"; + if (directoryExists(camerasDir)) { + _topViewPath = camerasDir + "/topview.txt"; + if (!directoryExists(camerasDir)) { + makeDirectory(camerasDir); + } + } + else { + _topViewPath = parentDirectory(myArgs.dataset_path) + "/topview.txt"; + } + + setup(); + } + + SceneDebugView::SceneDebugView(const IIBRScene::Ptr & scene, const Viewport & viewport, + const InteractiveCameraHandler::Ptr & camHandler, const BasicDatasetArgs & myArgs) : SceneDebugView(scene, camHandler, myArgs) { + SIBR_WRG << "Deprecated SceneDebugView constructor, use the version without viewport passed as argument." << std::endl; + } + + void SceneDebugView::onUpdate(Input & input, const float deltaTime, const Viewport & viewport) + { + MultiMeshManager::onUpdate(input, viewport); + + //Camera stub size + if (input.key().isActivated(Key::LeftControl) && input.mouseScroll() != 0.0) { + _userCameraScaling = std::max(0.001f, _userCameraScaling + (float)input.mouseScroll() * 0.1f); + } + if (input.key().isActivated(Key::LeftControl) && input.key().isReleased(Key::P)) { + MeshData & guizmo = getMeshData("guizmo"); + guizmo.active = !guizmo.active; + } + + MeshData & proxy = getMeshData("proxy"); + if( proxy.meshPtr->triangles().size() == 0 ) + // SfM Points only + proxy.renderMode = Mesh::RenderMode::PointRenderMode; + + if (input.key().isActivated(Key::LeftControl) && input.key().isReleased(Key::Z)) { + //MeshData & proxy = getMeshData("proxy"); + if (proxy.renderMode == Mesh::RenderMode::FillRenderMode) { + proxy.renderMode = Mesh::RenderMode::LineRenderMode; + } else { + proxy.renderMode = Mesh::RenderMode::FillRenderMode; + } + } + + if (input.key().isReleased(Key::T)) { + save(); + } + + //user camera transform update + sibr::Transform3f scaled = _userCurrentCam->getCamera().transform(); + scaled.scale(_userCameraScaling); + sibr::Matrix4f scaledMatrix = scaled.matrix(); + getMeshData("scene cam").setTransformation(scaledMatrix); + + // update input camera (path) scales + if (_pathScaling != _lastPathScaling) { + removeMesh("used cams"); + _used_cams.reset(); + _used_cams = std::make_shared(); + for (const auto& camInfos : _cameras) { + if (!camInfos.cam.isActive()) { continue; } + (camInfos.highlight ? _used_cams : _non_used_cams)->merge(*generateCamFrustum(camInfos.cam, 0.0f, _pathScaling)); + } + _lastPathScaling = _pathScaling; + addMeshAsLines("used cams", _used_cams).setColor({ 0,1,0 }).setDepthTest(true); + + } + } + + void SceneDebugView::onUpdate(Input & input, const Viewport & viewport) + { + onUpdate(input, 1.0f / 60.0f, viewport); + } + + void SceneDebugView::onUpdate(Input & input) + { + // Update camera with a fixed timestep. + onUpdate(input, 1.0f / 60.0f); + } + + void SceneDebugView::onRender(Window & win) + { + // We need no information about the window, we render wherever we are. + onRender(win.viewport()); + } + + void SceneDebugView::onRender(const Viewport & viewport) + { + glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, -1, "Scene debug view"); + + viewport.clear(backgroundColor); + viewport.bind(); + + renderMeshes(); + + if (_displayImg) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + //renderFromTex(camera_handler.getCamera(), _cameras[_cameraIdInfoGUI].cam, _imgTex->handle()); + renderImage(camera_handler.getCamera(), _cameras[_cameraIdInfoGUI].cam, _imgRt); + glDisable(GL_BLEND); + } + + + if (_showLabels) { + renderLabels(camera_handler.getCamera(), viewport, _cameras); + } + + camera_handler.onRender(viewport); + glPopDebugGroup(); + } + + void SceneDebugView::onGUI() + { + if (ImGui::Begin("Top view settings")) { + gui_options(); + list_mesh_onGUI(); + gui_cameras(); + } + ImGui::End(); + + } + + void SceneDebugView::save() + { + + std::ofstream outfile(_topViewPath, std::ios::out | std::ios::trunc); + std::cerr << "Saving topview camera to " << _topViewPath << std::endl; + // save camera view proj matrix + camera_handler.getCamera().writeToFile(outfile); + } + + void SceneDebugView::setScene(const IIBRScene::Ptr & scene, bool preserveCamera) + { + _scene = scene; + const InputCamera cameraBack = camera_handler.getCamera(); + setup(); + camera_handler.setup(_scene->cameras()->inputCameras(), camera_handler.getViewport(), camera_handler.getRaycaster()); + camera_handler.setupInterpolationPath(_scene->cameras()->inputCameras()); + // Optionally restore the camera pose. + if (preserveCamera) { + camera_handler.fromCamera(cameraBack, false); + } + } + + void SceneDebugView::updateActiveCams(const std::vector& cams_id) + { + for (auto & cam : _cameras) { + cam.highlight = false; + } + for (const uint id : cams_id) { + if (id < _cameras.size()) { + _cameras[id].highlight = true; + } + } + } + + void SceneDebugView::gui_options() + { + + if (ImGui::CollapsingHeader("OptionsSceneDebugView##")) { + if (ImGui::Button("Save topview")) { + save(); + } + + ImGui::PushScaledItemWidth(120); + ImGui::InputFloat("Input cameras scale", &_pathScaling, 0.1f, 10.0f); + ImGui::InputFloat("User camera scale", &_userCameraScaling, 0.1f, 10.0f); + _pathScaling = std::max(0.001f, _pathScaling); + _userCameraScaling = std::max(0.001f, _userCameraScaling); + + ImGui::Checkbox("Draw labels ", &_showLabels); + if (_showLabels) { + ImGui::SameLine(); + ImGui::InputFloat("Label scale", &_labelScale, 0.2f, 10.0f); + } + + ImGui::Separator(); + ImGui::Checkbox("Draw Input Images ", &_showImages); + if (_showImages) { + ImGui::SameLine(); + ImGui::SliderFloat("Alpha", &_alphaImage, 0, 1.0); + } + + camera_handler.onGUI("Top view settings"); + ImGui::PopItemWidth(); + ImGui::Separator(); + } + } + + void SceneDebugView::gui_cameras() + { + if (ImGui::CollapsingHeader("Cameras##SceneDebugView")) { + + ImGui::SliderInt("Camera ID info", &_cameraIdInfoGUI, 0, static_cast(_cameras.size()) - 1); + + //Snap topView cam to closest input camera in mainView + if (ImGui::Button(std::string("Snap to closest").c_str())) { + _cameraIdInfoGUI = _userCurrentCam->findNearestCamera(_scene->cameras()->inputCameras()); + const auto& input_cam = _scene->cameras()->inputCameras()[0]; + + auto size = camera_handler.getViewport().finalSize(); + float ratio_dst = size[0] / size[1]; + float ratio_src = input_cam->w() / (float)input_cam->h(); + InputCamera cam = InputCamera(_cameras[_cameraIdInfoGUI].cam, (int)size[0], (int)size[1]); + + if (_displayImg) + _displayImg = false; + + if (ratio_src < ratio_dst) { + float fov_h = 2 * atan(tan(input_cam->fovy() / 2) * ratio_src / ratio_dst); + cam.fovy(fov_h); + } + else { + cam.fovy(input_cam->fovy()); + } + + //cam.znear(0.0001f); + camera_handler.fromCamera(cam, true, true); + } + + ImGui::Columns(4); // 0 name | snapto | active| size + + ImGui::Separator(); + ImGui::Text("Camera"); ImGui::NextColumn(); + ImGui::Text("SnapTo"); ImGui::NextColumn(); + ImGui::Text("alpha"); ImGui::NextColumn(); + + static std::vector cam_info_option_str = { "size", "focal", "fov_y","aspect" }; + if (ImGui::BeginCombo("Info", cam_info_option_str[_camInfoOption].c_str())) { + for (int i = 0; i < (int)cam_info_option_str.size(); ++i) { + if (ImGui::Selectable(cam_info_option_str[i].c_str(), _camInfoOption == i)) { + _camInfoOption = (CameraInfoDisplay)i; + } + } + ImGui::EndCombo(); + } + ImGui::NextColumn(); + ImGui::Separator(); + + //for (uint i = 0; i < _cameras.size(); ++i) + { + std::string name = "cam_" + intToString<4>(_cameraIdInfoGUI); + ImGui::Text(name.c_str()); + ImGui::NextColumn(); + + if (ImGui::Button(("SnapTo##" + name).c_str())) { + const auto & input_cam = _scene->cameras()->inputCameras()[0]; + + auto size = camera_handler.getViewport().finalSize(); + float ratio_dst = size[0] / size[1]; + float ratio_src = input_cam->w() / (float)input_cam->h(); + InputCamera cam = InputCamera(_cameras[_cameraIdInfoGUI].cam, (int)size[0], (int)size[1]); + + if (ratio_src < ratio_dst) { + float fov_h = 2 * atan(tan(input_cam->fovy() / 2) * ratio_src / ratio_dst); + cam.fovy(fov_h); + } else { + cam.fovy(input_cam->fovy()); + } + + if (_displayImg) + _displayImg = false; + + //cam.znear(0.0001f); + camera_handler.fromCamera(cam, true, true); + } + + if (_images_path != "") { + + ImGui::SameLine(); + if (ImGui::Button("DisplayImg##")) { + + if (_imgToFetch != _cameras[_cameraIdInfoGUI].cam.name()) { + _imgToFetch = _cameras[_cameraIdInfoGUI].cam.name(); + + std::string fullPath = _images_path + "/" + _imgToFetch; + sibr::ImageRGBA img; + + if (!fileExists(fullPath)) { + fullPath = fullPath.substr(0, fullPath.length() - 3) + "JPG"; + } + + if (img.load(fullPath)) { + updateImgRt(_cameras[_cameraIdInfoGUI].cam, img); + } + } + _displayImg = !_displayImg; + //(sibr::Image)img.load(fullPath); + } + + } + ImGui::NextColumn(); + + ImGui::SliderFloat("Alpha##", &_alphaImage, 0, 1.0); + ImGui::NextColumn(); + + const InputCamera & cam = _cameras[_cameraIdInfoGUI].cam; + std::stringstream tmp; + switch (_camInfoOption) + { + case SIZE: tmp << cam.w() << " x " << cam.h(); break; + case FOCAL: tmp << cam.focal(); break; + case FOV_Y: tmp << cam.fovy(); break; + case ASPECT: tmp << cam.aspect(); break; + default: break; + } + ImGui::Text(tmp.str().c_str()); + ImGui::NextColumn(); + ImGui::Columns(1); + } + + } + } + + void SceneDebugView::setup() + { + if (_scene) { + setupLabelsManagerMeshes(_scene->cameras()->inputCameras()); + setupMeshes(); + _user_cam = generateCamFrustum(_userCurrentCam->getCamera(), 0.0f, _userCameraScaling, false); + _cameras.clear(); + + int index = 0; + for (const auto& inputCam : _scene->cameras()->inputCameras()) { + const bool isUsed = _scene->cameras()->isCameraUsedForRendering(index); + _cameras.push_back(CameraInfos(*inputCam, inputCam->id(), isUsed)); + + if (inputCam->isActive()) + (isUsed ? _used_cams : _non_used_cams)->merge(*generateCamFrustum(*inputCam, 0.0f, _pathScaling)); + index++; + } + addMeshAsLines("scene cam", _user_cam).setColor({ 1,0,0 }).setDepthTest(true); + addMeshAsLines("used cams", _used_cams).setColor({ 0,1,0 }).setDepthTest(true); + addMeshAsLines("non used cams", _non_used_cams).setColor({ 0,0,1 }).setDepthTest(true); + } + + _snapToImage = 0; + _showLabels = false; + + // check if topview.txt exists + std::ifstream topViewFile(_topViewPath); + if (topViewFile.good()) + { + SIBR_LOG << "Loaded saved topview (" << _topViewPath << ")." << std::endl; + // Intialize a temp camera (used to load the saved top view pose) with + // the current top view camera to get the resolution/fov right. + InputCamera cam(camera_handler.getCamera()); + cam.readFromFile(topViewFile); + // Apply it to the top view FPS camera. + //camera_handler.fromCamera(cam, false); + camera_handler.fromTransform(cam.transform(), false, true); + } + + } + + void SceneDebugView::setupMeshes() + { + // no colors and no texture ? try to find capreal + bool success = false; + Mesh sdv_mesh; + Mesh::Ptr mp; + if (!_scene->proxies()->proxyPtr()->hasColors() && !_scene->proxies()->proxyPtr()->hasTexCoords()) { + std::string fn; + if (fileExists(fn = _scene->data()->basePathName() + "/capreal/mesh.ply")) { + if (sdv_mesh.load(fn, _scene->data()->basePathName())) + success = true; + } + // in sibr subdir + else if (fileExists(fn = _scene->data()->basePathName() + "/../capreal/mesh.ply")) { + if (sdv_mesh.load(fn, _scene->data()->basePathName())) + success = true; + } + if (success) { + Mesh::Ptr mp; + mp.reset(new Mesh); + mp->merge(sdv_mesh); + addMesh("proxy", mp); + } + else + addMesh("proxy", _scene->proxies()->proxyPtr()).setRadiusPoint(2).setDepthTest(false); + } + else + addMesh("proxy", _scene->proxies()->proxyPtr()).setRadiusPoint(2).setDepthTest(false); + + // Add a gizmo. + addMeshAsLines("guizmo", RenderUtility::createAxisGizmo()) + .setDepthTest(false).setColorMode(MeshData::ColorMode::VERTEX); + } + +} // namespace diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/SceneDebugView.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/SceneDebugView.hpp new file mode 100755 index 0000000000000000000000000000000000000000..c2b33054edfd21f27fcf6654b9fe63815fdb423d --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/SceneDebugView.hpp @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#pragma once + +# include "core/assets/InputCamera.hpp" +# include "core/assets/CameraRecorder.hpp" +# include "core/graphics/Texture.hpp" +# include "core/graphics/Camera.hpp" +# include "core/graphics/Window.hpp" +# include "core/graphics/Shader.hpp" +# include "core/graphics/Mesh.hpp" +# include "core/view/InteractiveCameraHandler.hpp" +# include "core/view/ViewBase.hpp" +# include "core/scene/BasicIBRScene.hpp" +# include "core/system/CommandLineArgs.hpp" + +#include + +namespace sibr +{ + + /** Generate an accurate camera frustum + \param cam camera to visualize as a stub + \param znear near value to use for the frustum (if < 0, cam.near() will be used) + \param zfar far value to use for the frustum (if < 0, cam.far() will be used) + \ingroup sibr_view + */ + Mesh::Ptr SIBR_VIEW_EXPORT generateCamFrustum(const InputCamera & cam, float znear = -1, float zfar = -1, bool useCam = true); + + /** Generate an accurate camera frustum with a custom color. + \param cam camera to visualize as a stub + \param col the mesh line color + \param znear near value to use for the frustum (if < 0, cam.near() will be used) + \param zfar far value to use for the frustum (if < 0, cam.far() will be used) + \ingroup sibr_view + */ + Mesh::Ptr SIBR_VIEW_EXPORT generateCamFrustumColored(const InputCamera & cam, const Vector3f & col, float znear = -1, float zfar = -1); + + /** Generate a quad representing a camera image plane. + *\param cam the camera + *\param dist the distance in world space from the camera position to the image plane + \ingroup sibr_view + **/ + Mesh::Ptr SIBR_VIEW_EXPORT generateCamQuadWithUvs(const InputCamera & cam, float dist); + + /** Helper used to display camera labels on screen. + * Internally use ImGui to generate labels data. + \ingroup sibr_view + * */ + struct SIBR_VIEW_EXPORT LabelsManager { + + protected: + + /** Displayed cameras info. */ + struct CameraInfos { + /** Constructor. + *\param cam the camera + *\param id the corresponding vector ID + *\param highlight should the camera be highlighted. + */ + CameraInfos(const InputCamera& cam, uint id, bool highlight); + + const InputCamera & cam; ///< Camera. + uint id = 0; ///< Array ID. + bool highlight = false; ///< Highlight status. + }; + + /** Initialize the shaders. */ + void setupLabelsManagerShader(); + + /** Generate labels data based on input camera informations. + *\param cams the cameras + */ + void setupLabelsManagerMeshes(const std::vector & cams); + + /** Render the camera labels. + *\param eye the current viewpoint + *\param vp the view viewport + *\param cams_info the current state of the cameras. + * \todo Get rid of the viewport if possible. + **/ + void renderLabels(const Camera & eye, const Viewport & vp, const std::vector & cams_info); + + + /** Label geometry info. The mesh is split in two parts, + * one containing the background label shape, + * and one containing the quads that support the text. */ + struct LabelMesh { + Mesh::Ptr mesh; ///< The generated mesh. + unsigned int splitIndex = 0; ///< The boundary between foreground and background mesh. + }; + + std::map _labelMeshes; ///< Generated geometry for each label. + GLShader _labelShader; ///< Shader. + GLuniform _labelShaderPosition; ///< Uniform for the label position. + GLuniform _labelShaderScale = 1.0f; ///< Uniform for the label scale (used twice per label, with different values derived from _labelScale). + GLuniform _labelShaderViewport; ///< The viewport of the view, for ratio adjustment. + float _labelScale = 1.0f; ///< The label scale ons creen. + + }; + + /** Helper used to render image planes in front of the camera, + * for both scenes storing 2D separate images or a texture array. + \ingroup sibr_view + */ + struct SIBR_VIEW_EXPORT ImageCamViewer { + + protected: + + /** Initialize the shaders. */ + void initImageCamShaders(); + + /** Render one specific input image on a camera image plane. + *\param eye the current viewpoint + *\param cam the camera to show the image plane of + *\param rts input 2D textures list + *\param cam_id the list index associated to the camera + */ + void renderImage(const Camera & eye, const InputCamera & cam, const std::vector & rts, int cam_id); + + /** Render one specific input image on a camera image plane. + *\param eye the current viewpoint + *\param cam the camera to show the image plane of + *\param tex2Darray_handle input images texture array + *\param cam_id the array slice associated to the camera + */ + void renderImage(const Camera & eye, const InputCamera & cam, uint tex2Darray_handle, int cam_id); + + void renderImage(const Camera& eye, const InputCamera& cam, const RenderTargetRGBA32F::Ptr& rt); + + void updateImgRt(const InputCamera& cam, const sibr::ImageRGBA& img); + + GLShader _shader2D; ///< Shader for the 2D separate case. + GLShader _shaderArray; ///< Shader for the texture array case. + GLuniform _mvp2D, _mvpArray; ///< MVP matrix. + GLuniform _alpha2D = 1.0f; ///< Opacity. + GLuniform _alphaArray = 1.0f; ///< Opacity. + GLuniform _sliceArray = 1; ///< Slice location (for the texture array case). + float _alphaImage = 0.5f; ///< Opacity shared value. + + RenderTargetRGBA32F::Ptr _imgRt; + float _userCameraScaling = 3.f; ///< User camera scaling. + float _pathScaling = 0.3f; ///< Input cameras scaling. + float _lastPathScaling = 0.2f; + std::string _imgToFetch = ""; + uint _imgTexHandle; + bool _displayImg = false; + sibr::Texture2D* _imgTex = nullptr; + }; + + /** Scene viewer for IBR scenes with a proxy, cameras and input images. + * It adds camera visualization options (labels, frusta, image planes) on top of the MeshManager. + \ingroup sibr_view + */ + class SIBR_VIEW_EXPORT SceneDebugView : public MultiMeshManager, public ImageCamViewer, public LabelsManager + { + SIBR_CLASS_PTR(SceneDebugView); + + public: + + /** Which camera info should be displayed in the GUI. */ + enum CameraInfoDisplay { SIZE, FOCAL, FOV_Y, ASPECT }; + + /** Constructor. + * \param scene the scene to display + * \param camHandler a camera handler to display as a "user camera" + * \param myArgs dataset arguments (needed to load/save the camera location) + */ + SceneDebugView(const IIBRScene::Ptr& scene, const InteractiveCameraHandler::Ptr & camHandler, const BasicDatasetArgs& myArgs, const std::string& imagesPath = ""); + + /** Constructor. + * \param scene the scene to display + * \param viewport the view viewport + * \param camHandler a camera handler to display as a "user camera" + * \param myArgs dataset arguments (needed to load/save the camera location) + * \warning Deprecated, use the version without the viewport. + */ + SceneDebugView(const IIBRScene::Ptr& scene, const Viewport& viewport, const InteractiveCameraHandler::Ptr& camHandler, const BasicDatasetArgs& myArgs); + + /** Update state based on user input. + * \param input user input + * \param deltaTime the time elapsed since last update + * \param viewport input viewport + * \note Used when the view is in a multi-view system. + */ + virtual void onUpdate(Input & input, const float deltaTime, const Viewport & viewport = Viewport(0.0f, 0.0f, 0.0f, 0.0f)); + + /** Update state based on user input. + * \param input user input + * \param viewport input viewport + * \note Used when the view is in a multi-view system. + */ + virtual void onUpdate(Input & input, const Viewport & viewport) override; + + /* Update state based on user input. + * \param input user input + */ + virtual void onUpdate(Input& input) override; + + /** Render content in a window. + *\param win destination window + */ + virtual void onRender(Window& win) override; + + /** Render content in the currently bound RT, using a specific viewport. + * \param viewport destination viewport + * \note Used when the view is in a multi-view system. + */ + virtual void onRender(const Viewport & viewport) override; + + using MultiMeshManager::onRender; + + /** Update and display GUI panels. */ + virtual void onGUI() override; + + /** Save the top view camera to scene/cameras/topview.txt. */ + void save(); + + /** \return the camera handler for the view. */ + const InteractiveCameraHandler & getCamera() const { return camera_handler; } + + /** \return the camera handler for the view. */ + InteractiveCameraHandler & getCamera() { return camera_handler; } + + /** Replace the scene. + *\param scene the new scene + *\param preserveCamera should the current camera position be preserved + **/ + void setScene(const IIBRScene::Ptr & scene, bool preserveCamera = false); + + /** Update the active status of all cameras + *\param cams_id the active camera IDs. + */ + void updateActiveCams(const std::vector & cams_id); + + protected: + + /** Generate the GUI for the display options. */ + void gui_options(); + + /** generate the GUI with the camera infos. */ + void gui_cameras(); + + /** Setup the view. */ + void setup(); + + /** Setup the geometry. */ + void setupMeshes(); + + InteractiveCameraHandler::Ptr _userCurrentCam; ///< The "main view" camera handler (will be displayed as an extra camera). + IIBRScene::Ptr _scene; ///< Current displayed scene. + std::vector _cameras; ///< Additional scene cameras info. + CameraInfoDisplay _camInfoOption = SIZE; ///< Camera info to display in the GUI. + std::string _topViewPath; ///< Path to the topview saved file. + int _snapToImage = 0; ///< ID of the camera to snap to. + int _cameraIdInfoGUI = 0; ///< ID of the camera to display info about. + bool _showImages = true; ///< Show the image planes. + bool _showLabels = false; ///< Show camera labels. + + std::string _images_path; + int _renderingCam; ///< ID of the camera used for rendering + Mesh::Ptr _used_cams = std::make_shared(); + Mesh::Ptr _non_used_cams = std::make_shared(); + Mesh::Ptr _user_cam = std::make_shared(); + }; + +} // namespace diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/Skybox.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/Skybox.cpp new file mode 100644 index 0000000000000000000000000000000000000000..578e871443c62062374d0a8d508bd6384efdbda4 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/Skybox.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +# include "core/assets/Resources.hpp" +# include "core/view/Skybox.hpp" + +namespace sibr +{ + bool Skybox::load(const std::string& skyFolder) + { + if (!sibr::directoryExists(skyFolder)) + return false; + + _shader.init("Skybox", + sibr::loadFile(sibr::Resources::Instance()->getResourceFilePathName("skybox.vp")), + sibr::loadFile(sibr::Resources::Instance()->getResourceFilePathName("skybox.fp"))); + _paramView.init(_shader, "in_View"); + _paramAspect.init(_shader, "in_Aspect"); + + std::array filenames = { + "right.jpg" , + "left.jpg" , + "top.jpg" , + "bottom.jpg" , + "forward.jpg" , + "back.jpg" + }; + + std::array images; + + for (uint i = 0; i < filenames.size(); ++i) + { + std::string file = (skyFolder + "/") + filenames[i]; + if (images[i].load(file) == false) + { + SIBR_ERR << "cannot open " << file << " (loading the skybox)" << std::endl; + } + } + _cubemap.reset(new TextureCubeMapRGB(images[0], images[1], images[2], images[3], images[4], images[5])); + + return true; + } + + + void Skybox::render(const Camera& eye, const sibr::Vector2u& imgSize) + { + if (_cubemap == nullptr) + return; + + + glDisable(GL_DEPTH_TEST); + + CHECK_GL_ERROR; + _shader.begin(); + CHECK_GL_ERROR; + _paramAspect.set(Vector2f(float(imgSize.x())/float(imgSize.y()), float(imgSize.y())/float(imgSize.x()))); + CHECK_GL_ERROR; + _paramView.set(Matrix4f(eye.view().inverse())); + CHECK_GL_ERROR; + // cube map texture should already be bound + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_CUBE_MAP, _cubemap->handle()); + CHECK_GL_ERROR; + + RenderUtility::useDefaultVAO(); + const unsigned char indices[] = { 0, 1, 2, 3 }; + glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, indices); + CHECK_GL_ERROR; + + _shader.end(); + } +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/Skybox.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/Skybox.hpp new file mode 100644 index 0000000000000000000000000000000000000000..df4e4747ca09f5839cd2f75f691689c939e40ec7 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/Skybox.hpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include "core/view/Config.hpp" +# include "core/graphics/Shader.hpp" +# include "core/graphics/Texture.hpp" +# include "core/graphics/Camera.hpp" + +namespace sibr +{ + /** A skybox object for rendering a cubemap texture. + * \ingroup sibr_view + */ + class SIBR_VIEW_EXPORT Skybox + { + SIBR_CLASS_PTR(Skybox); + + public: + + /** Load skybox faces from a directory. The files should be named: {right, left, top, bottom, forward, back}.jpg + \param skyFolder directory path + \return a success boolean + */ + bool load(const std::string& skyFolder); + + /** Render in the current RT. + \param eye current viewpoint + \param imgSize the destination RT size + */ + void render(const Camera& eye, const sibr::Vector2u& imgSize); + + private: + + GLShader _shader; ///< Skybox shader. + GLParameter _paramView; ///< VP parameter. + GLParameter _paramAspect; ///< Aspect ratio parameter. + + TextureCubeMapRGB::Ptr _cubemap = nullptr; ///< Cubemap texture. + + }; + + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/TrackBall.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/TrackBall.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3ef15a357f7ea37bc7cf6970b5138ad02131f838 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/TrackBall.cpp @@ -0,0 +1,642 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "TrackBall.h" +#include +#include "core/graphics/Input.hpp" +#include "core/graphics/Viewport.hpp" +#include "core/raycaster/CameraRaycaster.hpp" +#include "core/graphics/Window.hpp" +#include "core/graphics/Mesh.hpp" + +namespace sibr { + + float TrackBall::ratioTrackBall2D = 0.75f; + + TrackBall::TrackBall(bool _verbose) : hasBeenInitialized(false), shadersCompiled(false), state(TrackBallState::IDLE), verbose(_verbose), + fixedCamera(InputCamera()), tempCamera(InputCamera()) + { + drawThis = true; + } + + void TrackBall::update(const sibr::Input& input, const float deltaTime, const Viewport& viewport) { + update(input, viewport, std::shared_ptr()); + } + + const InputCamera & TrackBall::getCamera(void) const + { + if (!hasBeenInitialized) { + SIBR_ERR << " TrackBall : camera not initialized before use" << std::endl + << "\t you should use either fromMesh(), fromCamera() or load() " << std::endl; + } + if (state == TrackBallState::IDLE) { + return fixedCamera; + } + else { + return tempCamera; + } + } + + void TrackBall::onRender(const sibr::Viewport& viewport) { + if (!drawThis) { return; } + + if (!shadersCompiled) { + initTrackBallShader(); + } + + if (state == TrackBallState::IDLE) { return; } + + // Save current blending state and function. + GLboolean blendState; + glGetBooleanv(GL_BLEND, &blendState); + GLint blendSrc, blendDst; + glGetIntegerv(GL_BLEND_SRC_ALPHA, &blendSrc); + glGetIntegerv(GL_BLEND_DST_ALPHA, &blendDst); + + // Enable basic blending. + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + + // Render. + viewport.bind(); + trackBallShader.begin(); + ratioTrackBall2Dgpu.set(ratioTrackBall2D); + trackBallStateGPU.set((int)state); + quadMesh->render(false, false, Mesh::RenderMode::FillRenderMode); + trackBallShader.end(); + + // Restore blend state. + if (!blendState) { + glDisable(GL_BLEND); + } + glBlendFunc(blendSrc, blendDst); + } + + void TrackBall::saveVectorInFile(std::ofstream & s, const Vector3f & v) const { + s << v.x() << " " << v.y() << " " << v.z() << std::endl; + } + + void TrackBall::setCameraAttributes(const Viewport & viewport) + { + fixedCamera.size((int)viewport.finalWidth(), (int)viewport.finalHeight()); + fixedCamera.aspect(viewport.finalWidth() / viewport.finalHeight()); + } + + void TrackBall::updateTrackBallCameraSize(const Viewport & viewport) + { + sibr::Vector2i viewPortSize = viewport.finalSize().cast(); + fixedCamera.size(viewPortSize[0], viewPortSize[1]); + } + + bool TrackBall::load(std::string & filePath, const Viewport & viewport) + { + std::ifstream file(filePath.c_str()); + if (file.is_open()) { + float a, b, c, fov, zNear, zFar; + file >> a >> b >> c; + Vector3f tbCenter(a, b, c); + file >> a >> b >> c; + Vector3f eye(a, b, c); + file >> a >> b >> c; + Vector3f up(a, b, c); + file >> fov >> zNear >> zFar; + + tempCenter = fixedCenter = tbCenter; + + fixedCamera.setLookAt(eye, fixedCenter, up); + fixedCamera.fovy(fov); + fixedCamera.znear(zNear); + fixedCamera.zfar(zFar); + setCameraAttributes(viewport); + tempCamera = fixedCamera; + + hasBeenInitialized = true; + printMessage(" n trackBall loaded " + filePath); + return true; + } + else { + printMessage(" could not open trackBall" + filePath); + return false; + } + } + + void TrackBall::save(std::string & filePath) const + { + if (boost::filesystem::exists(filePath)) { + char c; + SIBR_LOG << " a track ball already exists, override ? y/n ... " << std::flush; + std::cin >> c; + if (c != 'y') { + std::cout << " not saved ! " << std::endl; + return; + } + } + std::ofstream file(filePath.c_str()); + if (file.is_open()) { + saveVectorInFile(file, fixedCenter); + saveVectorInFile(file, fixedCamera.position()); + saveVectorInFile(file, fixedCamera.up()); + file << fixedCamera.fovy() << " " << fixedCamera.znear() << " " << fixedCamera.zfar() << std::endl; + SIBR_LOG << " TrackBall saved at " << filePath << std::endl; + } + else { + SIBR_LOG << " Could not save trackBall" << std::endl; + } + } + + void TrackBall::fromCamera(const InputCamera & cam, const Viewport & viewport, const float & radius) + { + fixedCamera = cam; + + if (fixedCamera.zfar() == 0 || fixedCamera.znear() == 0) { + InputCamera defaultCam = InputCamera(); + fixedCamera.znear(defaultCam.znear()); + fixedCamera.zfar(defaultCam.zfar()); + } + + setCameraAttributes(viewport); + tempCamera = fixedCamera; + tempCenter = fixedCenter = cam.position() + cam.dir().normalized() * radius; + + hasBeenInitialized = true; + } + + bool TrackBall::fromMesh(const Mesh & mesh, const Viewport & viewport) + { + return fromBoundingBox(mesh.getBoundingBox(), viewport); + } + + bool TrackBall::fromBoundingBox(const Eigen::AlignedBox & box, const Viewport & viewport) + { + + if (box.isEmpty() || (box.diagonal().array() == 0.0f).any()) { + SIBR_LOG << " [WARNING] TrackBall::fromMesh : cannot create camera from flat mesh " << std::endl; + return false; + } + else { + tempCenter = fixedCenter = box.center(); + Vector3f eye = fixedCenter + box.diagonal(); + Vector3f up(0, 1, 0); + + fixedCamera.setLookAt(eye, fixedCenter, up); + + fixedCamera.zfar(2.0f*box.diagonal().norm()); + setCameraAttributes(viewport); + tempCamera = fixedCamera; + hasBeenInitialized = true; + printMessage(" TrackBall::fromMesh : camera created "); + return true; + } + } + + void TrackBall::update(const Input & input, const Viewport & viewport, std::shared_ptr raycaster) + { + if( !hasBeenInitialized || input.empty()) { return; } + + updateTrackBallCameraSize(viewport); + + updateTrackBallStatus(input, viewport); + + updateTrackBallCamera(input, viewport, raycaster); + + updateFromKeyboard(input); + } + + void TrackBall::updateAspectWithViewport(const Viewport & viewport) + { + fixedCamera.size(static_cast(viewport.finalWidth()), static_cast(viewport.finalHeight())); + fixedCamera.aspect(viewport.finalHeight() / viewport.finalWidth()); + } + + void TrackBall::updateTrackBallStatus(const Input & input, const Viewport & viewport) + { + currentPoint2D = input.mousePosition(); + + if (input.key().isActivatedOnly(Key::T) && input.key().isActivatedOnly(Key::V)) { + verbose = !verbose; + if (verbose) { + printMessage("trackBall is now verbose "); + } + else { + SIBR_LOG << " TrackBall not verbose anymore " << std::endl; + } + } + if (input.key().isActivated(Key::LeftControl)) { + state = TrackBallState::IDLE; + } + else if (input.mouseButton().isPressed(Mouse::Right)) { + lastPoint2D = currentPoint2D; + tempCamera = fixedCamera; + tempCenter = fixedCenter; + if (isInTrackBall2dRegion(lastPoint2D, viewport)) { + state = TrackBallState::TRANSLATION_PLANE; + } + else { + state = TrackBallState::TRANSLATION_Z; + } + } + else if (input.mouseButton().isPressed(Mouse::Left)) { + lastPoint2D = currentPoint2D; + tempCamera = fixedCamera; + if (isInTrackBall2dRegion(lastPoint2D, viewport)) { + state = TrackBallState::ROTATION_SPHERE; + } + else { + state = TrackBallState::ROTATION_ROLL; + } + } + else if (input.mouseButton().isReleased(Mouse::Right) || input.mouseButton().isReleased(Mouse::Left)) { + if (state != TrackBallState::IDLE) { + state = TrackBallState::IDLE; + fixedCamera = tempCamera; + fixedCenter = tempCenter; + + } + } + } + + void TrackBall::updateTrackBallCamera(const Input & input, const Viewport & viewport, std::shared_ptr raycaster) + { + if (state == TrackBallState::ROTATION_SPHERE) { + updateRotationSphere(input, viewport); + } + else if (state == TrackBallState::ROTATION_ROLL) { + updateRotationRoll(input, viewport); + } + else if (state == TrackBallState::TRANSLATION_PLANE) { + updateTranslationPlane(input, viewport, raycaster); + } + else if (state == TrackBallState::TRANSLATION_Z) { + updateTranslationZ(input, viewport); + } + else if (state == TrackBallState::IDLE) { + if (input.key().isActivated(Key::LeftControl)) { + updateBallCenter(input, raycaster); + } + else if (input.mouseScroll() != 0) { + updateZnearZFar(input); + updateRadius(input); + } + } + } + + void TrackBall::updateBallCenter(const Input & input, std::shared_ptr raycaster) + { + + if (raycaster.get() == nullptr || !input.mouseButton().isPressed(Mouse::Left)) { + return; + } + + sibr::Vector3f worldPos, dir; + if(fixedCamera.ortho()) + { + sibr::Vector2i clickPos = input.mousePosition(); + worldPos = fixedCamera.position() + + (2.0f*clickPos.x() / (float)fixedCamera.w() - 1.0f)*fixedCamera.orthoRight()*fixedCamera.right() + + (2.0f*((float)fixedCamera.h() - 1 - clickPos.y()) / (float)fixedCamera.h() - 1.0f)*fixedCamera.orthoTop()*fixedCamera.up(); + dir = fixedCamera.dir(); + + } + else { + dir = CameraRaycaster::computeRayDir(fixedCamera, input.mousePosition().cast()).normalized(); + worldPos = fixedCamera.position(); + } + RayHit hit = raycaster->intersect(Ray(worldPos, dir)); + + if (hit.hitSomething()) { + printMessage(" TrackBall::updateBallCenter : updating center from mesh "); + Vector3f intersection(worldPos + hit.dist()*dir.normalized()); + fixedCenter = tempCenter = intersection; + fixedCamera.setLookAt(worldPos, fixedCenter, fixedCamera.up()); + } + else { + printMessage(" TrackBall::updateBallCenter : could not intersect mesh "); + } + + } + + void TrackBall::updateRotationSphere(const Input & input, const Viewport & viewport) + { + if (!isInTrackBall2dRegion(input.mousePosition(), viewport) || input.mousePosition() == lastPoint2D) { return; } + Vector3f lastPointSphere(mapToSphere(lastPoint2D, viewport)); + Vector3f newPointSphere(mapToSphere(input.mousePosition(), viewport)); + Vector3f rotationAxisScreenSpace((lastPointSphere.cross(newPointSphere)).normalized()); + Vector4f axis; + axis << rotationAxisScreenSpace, 0.0f; + Vector3f rotationAxisWorldSpace((fixedCamera.view().inverse()* axis).xyz()); + + float angleCos = newPointSphere.dot(lastPointSphere); + if (std::abs(angleCos) < 1.0f) { + float rotationAngle = -2.0f * acos(angleCos); + Eigen::Quaternionf rot(Eigen::AngleAxisf(rotationAngle, rotationAxisWorldSpace)); + + float radius = (fixedCamera.position() - fixedCenter).norm(); + Vector3f oldEye = -fixedCamera.dir().normalized(); + Vector3f newEye = fixedCenter + radius * (rot*oldEye); + tempCamera.setLookAt(newEye, fixedCenter, fixedCamera.up()); + + } + } + + void TrackBall::updateRotationRoll(const Input & input, const Viewport & viewport) + { + if (isInTrackBall2dRegion(input.mousePosition(), viewport)) { return; } + + Vector2f viewportCenter(0.5f*(viewport.finalLeft() + viewport.finalRight()), 0.5f*(viewport.finalTop() + viewport.finalBottom())); + float clockwise = (areClockWise(viewportCenter, lastPoint2D.cast(), input.mousePosition().cast()) ? -1.0f : 1.0f); + float diagonal = std::sqrt((float)(viewport.finalWidth()*viewport.finalWidth() + viewport.finalHeight()*viewport.finalHeight())); + float rollAngle = clockwise * (float)M_PI * (float)(lastPoint2D - input.mousePosition()).norm() / diagonal; + + Eigen::Quaternionf rot(Eigen::AngleAxisf(rollAngle, -fixedCamera.dir().normalized())); + Vector3f newUp = rot * fixedCamera.up().normalized(); + + tempCamera.setLookAt(fixedCamera.position(), fixedCenter, newUp); + } + + void TrackBall::updateTranslationPlane(const Input & input, const Viewport & viewport, std::shared_ptr raycaster) + { + if (!isInTrackBall2dRegion(input.mousePosition(), viewport)) { return; } + + if (input.mouseButton().isPressed(Mouse::Right)) { + + sibr::Vector3f worldPos, dir; + if(fixedCamera.ortho()) + { + sibr::Vector2i clickPos = input.mousePosition(); + worldPos = fixedCamera.position() + + (2.0f*clickPos.x() / (float)fixedCamera.w() - 1.0f)*fixedCamera.orthoRight()*fixedCamera.right() + + (2.0f*((float)fixedCamera.h() - 1 - clickPos.y()) / (float)fixedCamera.h() - 1.0f)*fixedCamera.orthoTop()*fixedCamera.up(); + dir = fixedCamera.dir(); + + } + else { + dir = CameraRaycaster::computeRayDir(fixedCamera, input.mousePosition().cast()).normalized(); + worldPos = fixedCamera.position(); + } + + Vector3f pointOnPlane = fixedCenter; + if (raycaster.get() != nullptr) { + RayHit hit = raycaster->intersect(Ray(worldPos, dir)); + if (hit.hitSomething()) { + pointOnPlane = worldPos + hit.dist()*dir; + } + } + trackballPlane = Eigen::Hyperplane(fixedCamera.dir().normalized(), pointOnPlane); + } + + Vector3f clicked3DPosition(mapTo3Dplane(lastPoint2D)); + Vector3f current3DPosition(mapTo3Dplane(input.mousePosition())); + Vector3f shift3D = clicked3DPosition - current3DPosition; + + tempCenter = fixedCenter + shift3D / zoom; + tempCamera.setLookAt(fixedCamera.position() + shift3D, tempCenter, fixedCamera.up()); + } + + void TrackBall::updateTranslationZ(const Input & input, const Viewport & viewport) + { + if (isInTrackBall2dRegion(input.mousePosition(), viewport)) { return; } + Vector3f zAxis = -fixedCamera.dir().normalized(); + + Vector2i shift2D(input.mousePosition() - lastPoint2D); + Vector2f shift2Df(shift2D.cast().array() / Vector2f(viewport.finalWidth(), viewport.finalHeight()).array()); + + int whichDir = (std::abs(shift2D.x()) > std::abs(shift2D.y()) ? 0 : 1); + + float shift = 4.0f*(fixedCenter - fixedCamera.position()).norm()*(whichDir == 0 ? -1.0f : 1.0f)*shift2Df[whichDir]; + Vector3f shift3D = shift * zAxis; + tempCenter = fixedCenter + shift3D / zoom; + tempCamera.setLookAt(fixedCamera.position() + shift3D, tempCenter, fixedCamera.up()); + } + + void TrackBall::updateFromKeyboard(const Input & input) + { + float angle = 0.005f; + float angleChange = 0.0f; + enum Change { NONE, X, Y, Z }; + Change change = NONE; + + if (input.key().isActivated(sibr::Key::KPNum6)) { + angleChange = +angle; + change = Y; + } + if (input.key().isActivated(sibr::Key::KPNum4)) { + angleChange = -angle; + change = Y; + } + if (input.key().isActivated(sibr::Key::KPNum8)) { + angleChange = -angle; + change = X; + } + if (input.key().isActivated(sibr::Key::KPNum2)) { + angleChange = +angle; + change = X; + } + if (input.key().isActivated(sibr::Key::KPNum7)) { + angleChange = -angle; + change = Z; + } + if (input.key().isActivated(sibr::Key::KPNum9)) { + angleChange = +angle; + change = Z; + } + if (change != NONE) { + Vector3f zAxis = -fixedCamera.dir().normalized(); + Vector3f yAxis = fixedCamera.up().normalized(); + Vector3f xAxis = fixedCamera.right().normalized(); + + Vector3f rotAxis = (change == Z ? zAxis : change == Y ? yAxis : xAxis); + + Eigen::Quaternionf rot(Eigen::AngleAxisf(angleChange, rotAxis)); + sibr::Vector3f newEye = fixedCamera.position(); + sibr::Vector3f newUp = yAxis; + if (change == Z) { + newUp = rot * newUp; + } + else { + newEye = rot * (newEye - fixedCenter) + fixedCenter; + } + + fixedCamera.setLookAt(newEye, fixedCenter, newUp); + } + + } + + void TrackBall::updateRadius(const Input & input) + { + if(input.key().getNumActivated() != 0){ return; } + if (!fixedCamera.ortho()) { + float zoomIn = (input.mouseScroll() > 0 ? -1.0f : 1.0f); + float radius = (fixedCamera.position() - fixedCenter).norm(); + Vector3f oldEye = -fixedCamera.dir().normalized(); + radius = radius * pow(1.25f, zoomIn); + Vector3f newEye = fixedCenter + radius * oldEye; + fixedCamera.setLookAt(newEye, fixedCenter, fixedCamera.up()); + } + else + { + float zoomIn = (input.mouseScroll() > 0.0f ? -1.0f : 1.0f); + fixedCamera.orthoRight(fixedCamera.orthoRight() * pow(1.25f, zoomIn)); + fixedCamera.orthoTop(fixedCamera.orthoTop() * pow(1.25f, zoomIn)); + zoom /= pow(1.25f, zoomIn); + } + } + + void TrackBall::updateZnearZFar(const Input & input) + { + float direction = (input.mouseScroll() > 0 ? 1.0f : -1.0f); + + if (input.key().isActivatedOnly(Key::Z)) { + fixedCamera.zfar(fixedCamera.zfar()* pow(1.25f, direction)); + printMessage(" zFar : " + std::to_string(fixedCamera.zfar())); + } + else if (input.key().isActivatedOnly(sibr::Key::Z) && input.key().isActivatedOnly(Key::LeftShift)) { + fixedCamera.znear(fixedCamera.znear()* pow(1.25f, direction)); + printMessage(" zNear : " + std::to_string(fixedCamera.znear())); + } + tempCamera = fixedCamera; + } + + bool TrackBall::isInTrackBall2dRegion(const Vector2i & pos2D, const Viewport & viewport) const + { + float pos_x = (lastPoint2D.x()) / viewport.finalWidth(); + float pos_y = (lastPoint2D.y()) / viewport.finalHeight(); + float min_ratio = 0.5f * (1.0f - TrackBall::ratioTrackBall2D); + float max_ratio = 0.5f * (1.0f + TrackBall::ratioTrackBall2D); + return pos_x >= min_ratio && pos_x <= max_ratio && pos_y >= min_ratio && pos_y <= max_ratio; + } + + Vector3f TrackBall::mapToSphere(const Vector2i & pos2D, const Viewport & viewport) const + { + + int xMin = (int)0; + int xMax = (int)(viewport.finalRight() - viewport.finalLeft()); + int yMin = (int)0; + int yMax = (int)(viewport.finalBottom() - viewport.finalTop()); + + Vector2i clampPos = pos2D.cwiseMin(Vector2i(xMax, yMax)).cwiseMax(Vector2i(xMin, yMin)); + + double x = clampPos.x() / (double)viewport.finalWidth() - 0.5; + double y = 0.5 - clampPos.y() / (double)viewport.finalHeight(); + + double sinx = sin(M_PI * x * 0.5); + double siny = sin(M_PI * y * 0.5); + double sinx2siny2 = sinx * sinx + siny * siny; + + return Vector3d(sinx, siny, sinx2siny2 < 1.0 ? sqrt(1.0 - sinx2siny2) : 0.0).cast(); + } + + Vector3f TrackBall::mapTo3Dplane(const Vector2i & pos2D) const + { + sibr::Vector3f worldPos, dir; + if(fixedCamera.ortho()) + { + worldPos = fixedCamera.position() + + (2.0f*pos2D.x() / (float)fixedCamera.w() - 1.0f)*fixedCamera.orthoRight()*fixedCamera.right() + + (2.0f*((float)fixedCamera.h() - 1 - pos2D.y()) / (float)fixedCamera.h() - 1.0f)*fixedCamera.orthoTop()*fixedCamera.up(); + dir = fixedCamera.dir(); + + } + else { + dir = CameraRaycaster::computeRayDir(fixedCamera, pos2D.cast()).normalized(); + worldPos = fixedCamera.position(); + } + + Eigen::ParametrizedLine line(worldPos, dir); + return line.intersectionPoint(trackballPlane); + } + + bool TrackBall::areClockWise(const Vector2f & a, const Vector2f & b, const Vector2f & c) const + { + Vector2f u((b - a).normalized()); + Vector2f v((c - b).normalized()); + Vector2f uOrtho(u.y(), -u.x()); + return v.dot(uOrtho) >= 0; + } + + + void TrackBall::initTrackBallShader(void) + { + quadMesh = std::shared_ptr(new Mesh(true)); + + int corners[4][2] = { {-1,-1}, {-1,1}, {1,-1}, {1,1} }; + + std::vector vertexBuffer; + for (int i = 0; i < 4; i++) { + Vector3f corner((float)corners[i][0], (float)corners[i][1], 0.0f); + for (int c = 0; c < 3; c++) { + vertexBuffer.push_back(corner[c]); + } + } + + int indices[6] = { 0, 1, 3, 0, 2, 3 }; + std::vector indicesBuffer(&indices[0], &indices[0] + 6); + + quadMesh->vertices(vertexBuffer); + quadMesh->triangles(indicesBuffer); + + std::string trackBallVertexShader = + "#version 420 \n" + "layout(location = 0) in vec3 in_vertex; \n" + "out vec2 uv_coord; \n" + "void main(void) { \n" + " uv_coord = in_vertex.xy; \n" + " gl_Position = vec4(in_vertex.xy,0.0, 1.0); \n" + "} \n"; + + std::string trackBallFragmentShader = + "#version 420 \n" + "uniform float ratio; \n" + "uniform int mState; \n" + "in vec2 uv_coord; \n" + "out vec4 out_color; \n" + "void main(void) { \n" + " float minB = -ratio; \n" + " float maxB = +ratio; \n" + " float x = uv_coord.x; \n" + " float y = uv_coord.y; \n" + " bool fragOutside = ( xmaxB || ymaxB ); \n" + " if( mState == 1 ){ \n" //plane transl + " vec2 d = abs(uv_coord ) - vec2(ratio,ratio); \n" + " float v = min(max(d.x,d.y),0.0) + length(max(d,0.0)); \n" + " float a = 0.2 * exp( - 5000.0 *v*v ); \n" + " out_color = vec4(1.0,0.0,0.0,a); \n" + " } else if ( mState == 2 && fragOutside ){ \n" //zoom transl + " out_color = vec4(0.0,1.0,0.0,0.1); \n" + " } else if ( mState == 3 ){ \n" //sphere rot + " float d = x*x + y*y - ratio*ratio; \n" + " float a = 0.2 * exp( - 5000.0 *d*d ); \n" + " out_color = vec4(1.0,0.0,0.0,a); \n" + " } else if ( mState == 4 ){ \n" //roll rot + " float d = x*x + y*y - 0.5*(ratio+1.0)*ratio*ratio; \n" + " float a = 0.2 * exp( - 5000.0 *d*d ); \n" + " out_color = vec4(0.0,1.0,0.0,a); \n" + " } else { \n" + " out_color = vec4(0.0,0.0,0.0,0.0); \n" + " } \n" + "} \n"; + + trackBallShader.init("trackBallShader", trackBallVertexShader, trackBallFragmentShader); + + ratioTrackBall2Dgpu.init(trackBallShader, "ratio"); + trackBallStateGPU.init(trackBallShader, "mState"); + + shadersCompiled = true; + } + + void TrackBall::printMessage(const std::string & msg) const + { + if (verbose) { + std::cout << msg << std::endl; + } + } + +} \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/TrackBall.h b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/TrackBall.h new file mode 100644 index 0000000000000000000000000000000000000000..6d9e393cfbb061c67b3bf1513a95af3c9c3fa5ae --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/TrackBall.h @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include +#include + +#include "Config.hpp" +#include "core/graphics/Shader.hpp" +#include "core/assets/InputCamera.hpp" +#include "ICameraHandler.hpp" + +namespace sibr { + + class Viewport; + class Mesh; + class Input; + class Raycaster; + + + /** Provide a handler to interact using a trackball (based on mouse motions). + * \ingroup sibr_view + */ + class SIBR_VIEW_EXPORT TrackBall : public ICameraHandler + { + public: + /** Constructor + \param verbose log updates and infos. + */ + TrackBall( bool verbose = false ); + + /** Load a trackball settings from a file on disk. + \param filePath path to the file + \param viewport current viewport + \return a success boolean + \note The viewport is needed to fill-in missing info. + */ + bool load( std::string & filePath , const Viewport & viewport); + + /** Save trackball settings to a file on disk. + \param filePath file path + */ + void save( std::string & filePath ) const ; + + /** Update the trackball pose from a reference camera. + \param cam the reference camera + \param viewport the viewport to use + \param radius the default trackball radius to use + **/ + void fromCamera( const InputCamera & cam , const Viewport & viewport , const float & radius = 100.0f ); + + /** Setup the trackball so that a mesh if visible and centered. + \param mesh the mesh to show + \param viewport the view viewport + */ + bool fromMesh( const Mesh & mesh, const Viewport & viewport ); + + /** Setup the trackball so that a region of space if visible and centered. + \param box the region of space to cover + \param viewport the view viewport + */ + bool fromBoundingBox(const Eigen::AlignedBox& box, const Viewport & viewport); + + /** Update the trackball handler state. the raycaster is used when the user is clicking to center the trackball or panning. + \param input user input + \param viewport view viewport + \param raycaster an optional raycaster + */ + void update( const Input & input , const Viewport & viewport, std::shared_ptr raycaster = std::shared_ptr()); + + /** update the internal aspect ratio. + \param viewport the new viewport + */ + void updateAspectWithViewport(const Viewport & viewport); + + bool drawThis; ///< Should the trackball overlay be displayed. + + /** \return true if the trackball has been initialized */ + bool initialized() const { return hasBeenInitialized; } + + /// ICameraHandler interface + /** Update the camera handler state. + \param input user input + \param deltaTime time elapsed since last udpate + \param viewport view viewport + */ + virtual void update(const sibr::Input & input, const float deltaTime, const Viewport & viewport) override; + + /** \return the current camera. */ + virtual const InputCamera & getCamera(void) const override; + + /** Render on top of the associated view(s). + \param viewport the rendering region + */ + virtual void onRender(const sibr::Viewport & viewport) override; + + private: + + /** Trackball interaction status. */ + enum class TrackBallState { IDLE, TRANSLATION_PLANE, TRANSLATION_Z, ROTATION_SPHERE, ROTATION_ROLL }; + + /** Map a pixel to a point on the sphere. + \param pos2D pixel position + \param viewport view viewport + \return a 3D point on the sphere + */ + Vector3f mapToSphere( const Vector2i & pos2D, const Viewport & viewport ) const; + + + /** Map a pixel to a point on the plane. + \param pos2D pixel position + \return a 3D point on the plane + */ + Vector3f mapTo3Dplane( const Vector2i & pos2D ) const; + + /** update near and far planes. + \param input user input + */ + void updateZnearZFar( const Input & input ); + + /** update the trackball pivot center. + \param input user input + \param raycaster the scene raycaster + */ + void updateBallCenter( const Input & input, std::shared_ptr raycaster ); + + /** Update the trackball radius. + \param input user input + */ + void updateRadius( const Input & input ); + + /** Update the rotation parameters. + \param input user input + \param viewport view viewport + */ + void updateRotationSphere( const Input & input , const Viewport & viewport ); + + /** Update the rotation parameters. + \param input user input + \param viewport view viewport + */ + void updateRotationRoll( const Input & input , const Viewport & viewport ); + + /** Update the translation parameters. + \param input user input + \param viewport view viewport + \param raycaster optional scene raycaster + */ + void updateTranslationPlane( const Input & input , const Viewport & viewport, std::shared_ptr raycaster = std::shared_ptr() ); + + /** Update the translation parameters. + \param input user input + \param viewport view viewport + */ + void updateTranslationZ( const Input & input , const Viewport & viewport ); + + /** Update based on keys input + \param input user input + */ + void updateFromKeyboard(const Input & input); + + /** Check if a point is in the central trackball region. + \param pos2D position in the view + \param viewport view viewport + \return true if it falls inside + */ + bool isInTrackBall2dRegion( const Vector2i & pos2D, const Viewport & viewport ) const; + + /** + * Check if three points are in clockwise order. + * \param a first point + * \param b second point + * \param c third point + * \return true if their order is clockwise. + */ + bool areClockWise( const Vector2f & a, const Vector2f & b, const Vector2f & c ) const; + + /** Log a message. + \param msg essage string + */ + void printMessage( const std::string & msg ) const; + + /** Save vector to output stream. + \param s stream + \param v vector + */ + void saveVectorInFile( std::ofstream & s , const Vector3f & v ) const ; + + /** Setup trackball shader. */ + void initTrackBallShader( void ); + + /** Set camera attributes + \param viewport the viewport to use + */ + void setCameraAttributes( const Viewport & viewport ); + + /** Update camera size. + \param viewport the viewport to use + */ + void updateTrackBallCameraSize(const Viewport & viewport); + + /** Update trackball interaction status. + \param input user input + \param viewport the viewport to use + */ + void updateTrackBallStatus( const Input & input, const Viewport & viewport ); + + /** Main update function. + \param input user input + \param viewport the viewport to use + \param raycaster optional scene raycaster + */ + void updateTrackBallCamera( const Input & input, const Viewport & viewport , std::shared_ptr raycaster = std::shared_ptr() ); + + + InputCamera fixedCamera; ///< Reference camera. + InputCamera tempCamera; ///< Temp camera. + + Vector3f fixedCenter; ///< Current center. + Vector3f tempCenter; ///< Temp center. + + Vector2i lastPoint2D; ///< Last clicked 2D point. + Vector2i currentPoint2D; ///< Current clicked point. + + Eigen::Hyperplane trackballPlane; ///< Trackball translation plane. + + TrackBallState state; ///< Current status. + + bool hasBeenInitialized; ///< Initialized or not. + bool verbose; ///< verbose or not. + + float zoom=1.0f;//zoom factor used for ortho cams + //members used for interaction drawing + std::shared_ptr quadMesh; ///< Supporting mesh for the overlay. + GLShader trackBallShader; ///< Overlay shader. + GLParameter ratioTrackBall2Dgpu; ///< Aspect ratio. + GLParameter trackBallStateGPU; ///< Trackball state uniform. + bool shadersCompiled; ///< Are the sahders ready. + static float ratioTrackBall2D; ///< 2D ratio parameter. + + }; + +} \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/UIShortcuts.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/UIShortcuts.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b8e3d194eb25b56dc4bc31dd07d1f0520646ddf3 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/UIShortcuts.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include +#include +#include +#include +#include "core/view/UIShortcuts.hpp" + +namespace sibr +{ + /*static*/ UIShortcuts& UIShortcuts::global( void ) + { + static UIShortcuts instance; + return instance; + } + + void UIShortcuts::list( void ) + { + // Sort elements in alphabetical order. + std::vector> elems(_shortcuts.begin(), _shortcuts.end()); + std::sort(elems.begin(), elems.end(), [](std::pair a, std::pair b) { return b.first < a.first; }); + + std::ostringstream oss; + for (auto& pair: elems) + oss << " " << std::setw(24)<< std::left << pair.first << " : " << pair.second << std::endl; + SIBR_LOG << "List of Shortcuts:\n" << oss.str() << std::endl; + } + + void UIShortcuts::add( const std::string& shortcut, const char* desc ) + { + std::string lshortcut = shortcut; + std::transform(lshortcut.begin(), lshortcut.end(), lshortcut.begin(), ::tolower); + + if (_shortcuts.find(lshortcut) == _shortcuts.end()) + _shortcuts[lshortcut] = desc; + else + { + const char* current = _shortcuts[lshortcut]; + if (current != desc) + { + SIBR_ERR << "conflict with shortcuts.\n" + "Trying to register:\n" + "[" << shortcut << "] : " << desc + << "\nBut already exists as:\n" + "[" << shortcut << "] : " << current + << std::endl; + } + } + } + + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/UIShortcuts.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/UIShortcuts.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7956a4c5d3b16eef0e549efe5d5281dd33079714 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/UIShortcuts.hpp @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include +# include "core/view/Config.hpp" + +namespace sibr +{ + /** Register and display keyboard shortcuts. + * \todo The system should be more robust for collision detection. + * \ingroup sibr_view + */ + class SIBR_VIEW_EXPORT UIShortcuts + { + public: + + /** Singleton. */ + static UIShortcuts& global( void ); + + /** Print all registered shortcuts. */ + void list( void ); + + /** Register a shortcut. + *\param shortcut the shortcut keys + *\param desc the description + */ + void add( const std::string& shortcut, const char* desc ); + + + private: + std::unordered_map _shortcuts; ///< List of shortcuts. + + }; + + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/ViewBase.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/ViewBase.cpp new file mode 100644 index 0000000000000000000000000000000000000000..057cda36f64913f3adae60d1ddbfa85ba13f7c7a --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/ViewBase.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +# include "core/view/ViewBase.hpp" + +namespace sibr +{ + ViewBase::ViewBase(const unsigned int w, const unsigned int h) + { + _resolution = Vector2i(w, h); + _whichRT = 6; // poisson filling + } + + void ViewBase::onUpdate(Input& input, const Viewport & vp) { + onUpdate(input); + } + + void ViewBase::setResolution(const Vector2i& size) + { + _resolution = size; + } + + const Vector2i& ViewBase::getResolution( void ) const + { + return _resolution; + } + + void ViewBase::setFocus(bool focus) + { + _focus = focus; + } + + bool ViewBase::isFocused(void) const + { + return _focus; + } + + void ViewBase::setName(const std::string& name) { + _name = name; + } + + const std::string & ViewBase::name() const { + return _name; + } + + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/ViewBase.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/ViewBase.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4d1991516742860b9bd523062dfba6e1993032ac --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/ViewBase.hpp @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include + +# include "core/graphics/Texture.hpp" +# include "core/graphics/Camera.hpp" +# include "core/view/Config.hpp" +//# include "core/view/IBRScene.hpp" +#include "core/graphics/Input.hpp" +#include "core/graphics/Window.hpp" + +namespace sibr +{ + + /** Basic view representation. All views should inherit from it. + * Can be added as a subview in a multi-window system. + * \sa MultiViewBase + * \ingroup sibr_view + */ + class SIBR_VIEW_EXPORT ViewBase + { + public: + + typedef std::shared_ptr Ptr; + + /** Constructor. + *\param w view width + *\param h view height + */ + ViewBase( const unsigned int w=720, const unsigned int h=480); + + /** Destructor. */ + virtual ~ViewBase() = default; + + /* Update state based on user input. + * \param input user input + */ + virtual void onUpdate(Input& input) { } + + /** Render content in a window. + *\param win destination window + */ + virtual void onRender( Window& win) { } + + /** Render content in a given rendertarget. + *\param dst destination RT + *\param eye current viewpoint + *\sa IRenderingMode + */ + virtual void onRenderIBR(IRenderTarget& dst, const Camera& eye) {}; + + /** Display GUI. */ + virtual void onGUI() { } + + /** Render content in the currently bound RT, using a specific viewport. + * \param vpRender destination viewport + * \note Used when the view is in a multi-view system. + */ + virtual void onRender(const Viewport & vpRender) { } + + /** Update state based on user input. + * \param input user input + * \param vp input viewport + * \note Used when the view is in a multi-view system. + */ + virtual void onUpdate(Input& input, const Viewport & vp); + + /** Legacy: Used to mix with previous pass. + * \param prev the previous step RT + */ + virtual void preRender(RenderTargetRGB& prev) {} ; + + /** Legacy: Set the internal RT to use. + *\param i RT index */ + virtual void whichRT(uint i) { _whichRT=i; } + /** Legacy: \return the current selected RT ID. */ + virtual uint whichRT(void) { return _whichRT; } + + /** Set the view resolution. + \param size the new resolution, in pixels. + */ + void setResolution(const Vector2i& size); + /**\return the current resolution. */ + const Vector2i& getResolution( void ) const; + + /** Toggle view status. + \param act if true, the view is active. + */ + void active(bool act) { _active = act; } + /** \return true if the view is currently active. */ + bool active() { return _active; } + + /** Toggle view focus (ie the user is interacting with it). + \param focus if true, the view is currently focused + */ + void setFocus(bool focus); + /** \return true if the view is currently focused (ie the user is interacting with it). */ + bool isFocused(void) const; + + + /** Define the name of the view (used for disambiguation of GUI, etc.). + * \param name the new name + */ + void setName(const std::string & name); + + /** \return the name of the view. */ + const std::string & name() const; + + protected: + uint _whichRT; ///< Selected RT id. + std::vector _masks; ///< Rendering masks that can beused by some views/renderers. + + bool _active = true; ///< Is the view active. + Vector2i _resolution; ///< View resolution. + bool _focus = false; ///< Is the view focused. + std::string _name = ""; ///< View name. + + }; + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/interface/Interface.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/interface/Interface.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3da9e634bd5b69457d08ae27a105b6644481fb22 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/interface/Interface.cpp @@ -0,0 +1,643 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "Interface.h" + +#include "MeshViewer.h" +#include + +#include + +namespace sibr { + + MultiViewInterface::MultiViewInterface() + { + numImgs = 0; + currentLayer = 0; + currentScale = 0; + grid = sibr::Vector2i(4, 4); + hightligthChanged = false; + reproMeshMode = sibr::Mesh::FillRenderMode; + reproMeshBackFace = true; + + imagesViewBase = std::make_shared(this, MultiViewInterfaceView::ViewType::IMAGES); + meshViewBase = std::make_shared(this, MultiViewInterfaceView::ViewType::MESH); + } + + void MultiViewInterface::displayLoop(sibr::Window & window, std::function f) + { + + if (layersData.size() == 0) { + SIBR_ERR << " cant display interface without image layer added" << std::endl; + } + + utils.initAllShaders(); + + glClearColor(0.8f, 0.8f, 0.8f, 1.0f); + + window.size(window.size().x(), (int)std::ceil(window.size().x() / scalesData[0].imRatio)); + + std::cout << " window size : " << window.size().transpose() << std::endl; + + imagesView.viewport = sibr::Viewport(&window.viewport(),0,0,1,1); + imagesView.isActive = true; + + if (cpuMesh.get()) { + meshViewer.setMainMesh(*cpuMesh, sibr::Mesh::FillRenderMode, false, true); + } else { + std::cout << " no mesh " << std::endl; + } + + winSize = window.size().cast(); + + while (window.isOpened()) { + + //std::cout << "." << std::flush; + + window.makeContextCurrent(); + sibr::Input::poll(); + + winSize = window.size().cast(); + imagesInput = sibr::Input::subInput(sibr::Input::global(), imagesView.viewport); + meshInput = sibr::Input::subInput(sibr::Input::global(), meshView.viewport); + + if (sibr::Input::global().key().isPressed(sibr::Key::Escape)) { + break; + } + + update(window, sibr::Input::global()); + + onGui(); + + render(); + + f(this); + + window.swapBuffer(); + + } + } + + void MultiViewInterface::addCameras(const std::vector& input_cams) + { + cams = input_cams; + } + + void MultiViewInterface::addMesh(const sibr::Mesh::Ptr &mesh) + { + cpuMesh = mesh; + cpuMesh->generateNormals(); + } + + void MultiViewInterface::addMesh(const sibr::Mesh & mesh) + { + cpuMesh = std::make_shared(); + cpuMesh->vertices(mesh.vertices()); + cpuMesh->triangles(mesh.triangles()); + cpuMesh->generateNormals(); + } + + void MultiViewInterface::update(sibr::Window & window, const sibr::Input & input) + { + updateImageView(imagesView.viewport, imagesInput); + updateMeshView(meshInput, window); + } + + void MultiViewInterface::updateImageView(const sibr::Viewport & viewport, const sibr::Input & input) + { + sibr::Vector2f winSize = viewport.finalSize(); + currentActivePos = pixFromScreenPos(input.mousePosition(), winSize); + imagesViewBase->currentActivePos = currentActivePos; + + imgPixelScreenSize = screenPosPixelsFloat({ 0,{ 1,1 } }, winSize) - screenPosPixelsFloat({ 0,{ 0,0 } }, winSize); + + updateCurrentLayer(input); + + if (input.key().isActivated(sibr::Key::LeftShift)) { + return; + } + + updateZoomBox(input, winSize); + //updateCenter(imagesInput, imagesViewSize); + updateZoomScroll(input); + updateDrag(input, winSize); + } + + void MultiViewInterface::render() + { + renderImageView(imagesView.viewport); + + + ////if (hightligthChanged) { + //renderHighlightPixels(); + ////} + //displayHighlightedPixels(sibr::Vector3f(0, 1, 0), 0.15); + + displayMesh(meshView.viewport); + + //if (sibr::Input::global().key().isActivated(sibr::Key::C)) { + // int r = 50; + // utils.rectanglePixels(sibr::Vector3f(1, 0, 1), sibr::Input::global().mousePosition().cast(), sibr::Vector2f(r, r), true, 0.15f, imagesViewSize); + // utils.circlePixels(sibr::Vector3f(0, 1, 1), sibr::Input::global().mousePosition().cast(), r, true, 0.15f, imagesViewSize); + // + //} + + } + + void MultiViewInterface::renderImageView(const sibr::Viewport & viewport) + { + sibr::Vector2f imagesViewSize = viewport.finalSize(); + displayImages(viewport); + + displayZoom(viewport); + + if (currentActivePos.isDefined) { + highlightPixel(currentActivePos, viewport); + } + + } + + sibr::ViewBase::Ptr MultiViewInterface::getViewBase(MultiViewInterfaceView::ViewType type) + { + if (type == MultiViewInterfaceView::ViewType::IMAGES) { + return sibr::ViewBase::Ptr(imagesViewBase.get()); + } else { + return sibr::ViewBase::Ptr(meshViewBase.get()); + } + + } + + void MultiViewInterface::onGui() + { + ImGui::Separator(); + if (imagesLayers.size() != 1) { + ImGui::SliderInt("Laplacian scale", ¤tScale, 0, (int)imagesLayers.size() - 1); + ImGui::Separator(); + } + const size_t nLayers = layersData.size(); + if (nLayers > 1) { + ImGui::Text("Image Layers : "); + ImGui::Separator(); + + for (size_t n = 0; n < nLayers; ++n) { + if (ImGui::Selectable(layersData[n].name.c_str(), currentLayer == n)) { + currentLayer = (int)n; + } + } + ImGui::Separator(); + } + if (currentScale == 0 && currentActivePos.isDefined) { + std::stringstream ss; + ss << "Image : " << currentActivePos.im << ", pixel : " << currentActivePos.pos << std::endl; + ImGui::Text(ss.str().c_str()); + if (currentActivePos.isDefined) { + //std::cout << imagesPtr[currentLayer][currentActivePos.im] << std::endl; + //std::cout << imagesPtr[currentLayer][currentActivePos.im]->size() << std::endl; +/* if (imagesPtr[currentLayer][currentActivePos.im]) { + ImGui::Text(imagesPtr[currentLayer][currentActivePos.im]->pixelStr(currentActivePos.pos).c_str()); + } */ + } + ImGui::Separator(); + } + + } + + //MultiViewInterface::~MultiViewInterface() + //{ + // CHECK_GL_ERROR; + + // CHECK_GL_ERROR; + //} + + PixPos MultiViewInterface::pixFromScreenPos(const sibr::Vector2i & posScreen, const sibr::Vector2f & winSize) + { + UV01 uvScreen = UV10::from((posScreen.cast()+0.5f*sibr::Vector2f(1,1)).cwiseQuotient(winSize)); + + //std::cout << uvScreen.transpose() << std::endl; + + sibr::Vector2f posF = viewRectangle.tl() + (viewRectangle.br() - viewRectangle.tl()).cwiseProduct(uvScreen); + posF.y() = 1.0f - posF.y(); + + posF = posF.cwiseProduct(grid.cast()); + + //std::cout << posF.transpose() << " " << numImgs << std::endl; + + if (posF.x() < 0 || posF.y() < 0 || posF.x() >= grid.x() /* || posF.y() >= grid.y() */ ) { + return PixPos(); + } + + int x = (int)std::floor(posF.x()); + int y = (int)std::floor(posF.y()); + sibr::Vector2f frac = posF - sibr::Vector2f(x, y); + + int n = x + grid.x() * y; + int j = (int)std::floor(frac.x()*scalesData[currentScale].imSize.x()); + int i = (int)std::floor(frac.y()*scalesData[currentScale].imSize.y()); + + if (n >= numImgs) { + return PixPos(); + } + + return PixPos(n, sibr::Vector2i(j, i)); + } + + UV01 MultiViewInterface::screenPos(const PixPos & pix) + { + sibr::Vector2f pos = (pix.pos.cast().cwiseQuotient(scalesData[currentScale].imSize) + + sibr::Vector2f(pix.im % grid.x(), pix.im / grid.x())).cwiseQuotient(grid.cast()); + pos.y() = 1.0f - pos.y(); + return UV01::from((pos - viewRectangle.tl()).cwiseQuotient(viewRectangle.br() - viewRectangle.tl())); + } + + UV01 MultiViewInterface::screenPosPixelCenter(const PixPos & pix) + { + sibr::Vector2f pos = ((pix.pos.cast()+sibr::Vector2f(0.5,0.5)).cwiseQuotient(scalesData[currentScale].imSize) + + sibr::Vector2f(pix.im % grid.x(), pix.im / grid.x())).cwiseQuotient(grid.cast()); + pos.y() = 1.0f - pos.y(); + return UV01::from((pos - viewRectangle.tl()).cwiseQuotient(viewRectangle.br() - viewRectangle.tl())); + } + + sibr::Vector2i MultiViewInterface::screenPosPixels(const PixPos & pix, const sibr::Vector2f & winSize) + { + return (screenPos(pix).cwiseProduct(winSize)).cast(); + } + + sibr::Vector2f MultiViewInterface::screenPosPixelsFloat(const PixPos & pix, const sibr::Vector2f & winSize) + { + return screenPosPixelCenter(pix).cwiseProduct(winSize); + } + + //void MultiViewInterface::setupFromImSizeAndNumIm(LayerData & layerData, const sibr::Vector2i & imSize) + //{ + // imRatio = imSize[0] / (float)imSize[1]; + // imSizeF = imSize.cast(); + // numImgs = numIms; + //} + + void MultiViewInterface::addHighlightPixel(const PixPos & pix, const sibr::Vector2f & winSize) + { + highlightedPixels.push_back(pix); + //hightligthChanged = true; + } + + void MultiViewInterface::renderHighlightPixels() + { + int pixsSize = (int)highlightedPixels.size(); + + if (pixsSize == 0) { + return; + } + + if (!highlightedPixelsMesh.get()) { + highlightedPixelsMesh = std::make_shared(); + } + + sibr::Mesh::Vertices vs(4 * pixsSize); + sibr::Mesh::Triangles ts(2 * pixsSize); + + unsigned pixId = 0; + for (const auto & pix : highlightedPixels) { + UV11 tl = screenPos(pix); + PixPos otherCorner(pix.im, pix.pos + sibr::Vector2i(1, 1)); + UV11 br = screenPos(otherCorner); + + vs[4 * pixId + 0] = { tl.x(), tl.y() , 0 }; + vs[4 * pixId + 1] = { tl.x(), br.y() , 0 }; + vs[4 * pixId + 2] = { br.x(), br.y() , 0 }; + vs[4 * pixId + 3] = { br.x(), tl.y() , 0 }; + + ts[2 * pixId + 0] = { 4 * pixId + 0,4 * pixId + 1,4 * pixId + 2 }; + ts[2 * pixId + 1] = { 4 * pixId + 0,4 * pixId + 2,4 * pixId + 3 }; + + ++pixId; + } + + + + highlightedPixelsMesh->vertices(vs); + highlightedPixelsMesh->triangles(ts); + + //hightligthChanged = false; + } + + void MultiViewInterface::highlightPixel(const PixPos & pix, const sibr::Viewport & viewport, const sibr::Vector3f & color, const sibr::Vector2f & pixScreenSize) + { + UV01 pixTl = screenPos(pix); + PixPos otherCorner(pix.im, pix.pos + sibr::Vector2i(1, 1)); + UV01 pixBR = screenPos(otherCorner); + + viewport.bind(); + + if ((pixBR-pixTl).cwiseProduct(viewport.finalSize()).cwiseAbs().minCoeff() < 2.0f) { + //if pixel size in screen space is tinier than 2 screen pix + utils.rectanglePixels(color, 0.5f*(pixTl+pixBR).cwiseProduct(viewport.finalSize()), pixScreenSize, true, 0.15f, viewport.finalSize()); + } else { + //otherwise hightligh pixel intirely + utils.rectangle(color, pixTl, pixBR, true, 0.15f); + } + + } + + void MultiViewInterface::displayImages(const sibr::Viewport & viewport) + { + + //const sibr::Vector2f & winSize; + //std::cout << imagesView.viewport.left() << " " << imagesView.viewport.right() << " " << imagesView.viewport.top() << " " << imagesView.viewport.bottom() << std::endl; + viewport.bind(); + + viewport.clear(sibr::Vector3f(0.7f, 0.7f, 0.7f)); + //glClear(GL_COLOR_BUFFER_BIT); + + utils.multiViewShader.begin(); + + utils.numImgsGL.set((int)imagesLayers[currentScale][currentLayer]->depth() - 1); + sibr::Vector2f gridF = grid.cast(); + utils.gridGL.set(gridF); + + utils.multiViewTopLeftGL.set(viewRectangle.tl()); + utils.multiViewBottomRightGL.set(viewRectangle.br()); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D_ARRAY, imagesLayers[currentScale][currentLayer]->handle()); + sibr::RenderUtility::renderScreenQuad(); + + utils.multiViewShader.end(); + + for (int i = 0; i <(int)imagesLayers[currentScale][currentLayer]->depth(); ++i) { + UV01 imTl = screenPos(PixPos(i, sibr::Vector2i(0, 0))); + UV01 imBR = screenPos(PixPos(i, scalesData[currentScale].imSize.cast())); + utils.rectangle(sibr::Vector3f(0, 0, 0), imTl, imBR, false, 1.0); + } + + //utils.rectangle(sibr::Vector3f(0, 1, 0), UV01(0.25,0.25), UV01(0.75, 0.75), true, 0.15); + //utils.circle(sibr::Vector3f(0, 0, 1), UV01(0.33, 0.33), 0.1, true, 0.25); + + if (reproMesh.get()) { + utils.meshViewShader.begin(); + utils.alphaMeshGL.set(0.25f); + utils.colorMeshGL.set(sibr::Vector3f(1, 0, 1)); + + sibr::Vector2i viewPortSize(imagesView.viewport.finalWidth(), imagesView.viewport.finalHeight()); + + Eigen::AlignedBox2d winBox; + winBox.extend(sibr::Vector2d(0, 0)); + + winBox.extend(viewPortSize.cast()); + //std::cout << std::endl; + + //std::cout << " winbox " << (winBox.center()-0.5*winBox.diagonal()).transpose() << " " << (winBox.center() + 0.5*winBox.diagonal()).transpose() << std::endl; + for (int i = 0; i <(int)cams.size(); ++i) { + utils.mvp.set(cams[i]->viewproj()); + + //std::cout << i << std::endl; + glClearDepth(1.0); + glClear(GL_DEPTH_BUFFER_BIT); + + sibr::Vector2i tlImgPix = screenPosPixels(PixPos(i, sibr::Vector2i(0, cams[i]->h() - 1)), viewPortSize.cast()); + sibr::Vector2i brImgPix = screenPosPixels(PixPos(i, sibr::Vector2i(cams[i]->w() - 1, 0)), viewPortSize.cast()); + + Eigen::AlignedBox2d box; + box.extend(tlImgPix.cast()); + box.extend(brImgPix.cast()); + //std::cout << "\t box " << (box.center() - 0.5*box.diagonal()).transpose() << " " << (box.center() + 0.5*box.diagonal()).transpose() << std::endl; + + Eigen::AlignedBox2d renderBox = winBox.intersection(box); + + if (renderBox.isEmpty()) { + continue; + } + + //tlImgPix = renderBox.corner(Eigen::AlignedBox2d::CornerType::BottomLeft).cast(); + // brImgPix = renderBox.corner(Eigen::AlignedBox2d::CornerType::TopRight).cast(); + //std::cout << "\t renderBox " << (renderBox.center() - 0.5*renderBox.diagonal()).transpose() << " " << (renderBox.center() + 0.5*renderBox.diagonal()).transpose() << std::endl; + + //std::cout << tlImgPix.x() << " " << tlImgPix.y() << " " << (brImgPix - tlImgPix).x() << " " << (brImgPix - tlImgPix).y() << std::endl; + glViewport(tlImgPix.x(), tlImgPix.y(), std::abs((brImgPix - tlImgPix).x()), std::abs((brImgPix - tlImgPix).y())); + + reproMesh->render(true, reproMeshBackFace, reproMeshMode); + } + + utils.meshViewShader.end(); + } + } + + void MultiViewInterface::displayMesh(const sibr::Viewport & viewport) + { + if (meshView.isActive) { + meshViewer.render(viewport); + } + } + + void MultiViewInterface::displayZoom(const sibr::Viewport & viewport) + { + if (zoomSelection.isActive) { + viewport.bind(); + UV01 tl = UV01::from(zoomSelection.first.cast().cwiseQuotient(viewport.finalSize())); + UV01 br = UV01::from(zoomSelection.second.cast().cwiseQuotient(viewport.finalSize())); + utils.rectangle(sibr::Vector3f(1, 0, 0), tl, br, true, 0.15f); + } + } + + void MultiViewInterface::displayHighlightedPixels(const sibr::Vector3f & color, float alpha) + { + if (!highlightedPixelsMesh.get()) { + return; + } + + utils.baseShader.begin(); + + utils.scalingGL.set(1.0f); + utils.translationGL.set(sibr::Vector2f(0, 0)); + utils.colorGL.set(color); + utils.alphaGL.set(alpha); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendEquation(GL_FUNC_ADD); + + highlightedPixelsMesh->render(false, false); + + utils.alphaGL.set(1.0f); + highlightedPixelsMesh->render(false, false, sibr::Mesh::LineRenderMode); + + utils.baseShader.end(); + + highlightedPixelsMesh.reset(); + + } + + void MultiViewInterface::updateMeshView(const sibr::Input & input, sibr::Window & window) + { + + if (meshView.isActive) { + + //meshViewer.trackBall->updateAspectWithViewport(meshView.viewport); + meshViewer.interactCam->update(input, 1 / 60.f, meshView.viewport); + + if (sibr::Input::global().key().isPressed(sibr::Key::Left)) { + sibr::Vector2i oldWinSize = window.size(); + window.size(oldWinSize.x() /2, oldWinSize.y()); + imagesView.viewport = sibr::Viewport(&window.viewport(), 0, 0, 1, 1); + + meshView.isActive = false; + } + } else { + if (sibr::Input::global().key().isPressed(sibr::Key::Right)) { + sibr::Vector2i oldWinSize = window.size(); + window.size(oldWinSize.x() * 2, oldWinSize.y()); + meshView.viewport = sibr::Viewport(&window.viewport(), 0.5, 0, 1, 1); + imagesView.viewport = sibr::Viewport(&window.viewport(), 0, 0, 0.5, 1); + meshViewer.interactCam->setup(cpuMesh, meshView.viewport); + meshView.isActive = true; + } + } + } + + void MultiViewInterface::updateMeshView(const sibr::Input & input, const sibr::Viewport & viewport) + { + if (!meshView.isActive && cpuMesh.get() ) { + meshViewer.setMainMesh(*cpuMesh, sibr::Mesh::FillRenderMode, false, true); + meshViewer.interactCam->setup(cpuMesh, viewport); + meshView.isActive = true; + } + if (meshView.isActive) { + meshViewer.interactCam->update(input,1/60.0f, viewport); + } + } + + void MultiViewInterface::updateZoomBox(const sibr::Input & input, const sibr::Vector2f & winSize) + { + if (input.key().isPressed(sibr::Key::Q)) { + viewRectangle.center = sibr::Vector2f(0.5, 0.5); + viewRectangle.diagonal = sibr::Vector2f(0.5, 0.5); + } + + if (input.mouseButton().isPressed(sibr::Mouse::Code::Right) && !zoomSelection.isActive) { + zoomSelection.isActive = true; + zoomSelection.first = input.mousePosition(); + zoomSelection.first.y() = (int)winSize.y() - zoomSelection.first.y() - 1; + } + if (input.mouseButton().isActivated(sibr::Mouse::Code::Right) && zoomSelection.isActive) { + zoomSelection.second = input.mousePosition(); + zoomSelection.second.y() = (int)winSize.y() - zoomSelection.second.y() - 1; + } + if (input.mouseButton().isReleased(sibr::Mouse::Code::Right) && zoomSelection.isActive) { + sibr::Vector2f currentTL = (zoomSelection.first.cwiseMin(zoomSelection.second)).cast(); + sibr::Vector2f currentBR = (zoomSelection.first.cwiseMax(zoomSelection.second)).cast(); + + if (((currentBR - currentTL).array() > sibr::Vector2f(10, 10).array()).all()) { + + + sibr::Vector2f tlPix = viewRectangle.tl().cwiseProduct(winSize) + (viewRectangle.br() - viewRectangle.tl()).cwiseProduct(currentTL); + sibr::Vector2f brPix = viewRectangle.tl().cwiseProduct(winSize) + (viewRectangle.br() - viewRectangle.tl()).cwiseProduct(currentBR); + + sibr::Vector2f center = 0.5f*(brPix + tlPix); + sibr::Vector2f diag = 0.5f*(brPix - tlPix); + + float new_ratio = diag.x() / diag.y(); + float target_ratio = scalesData[currentScale].imRatio; + if (new_ratio > target_ratio) { + diag.y() = diag.x() / target_ratio; + } else { + diag.x() = diag.y() * target_ratio; + } + + viewRectangle.center = center.cwiseQuotient(winSize); + viewRectangle.diagonal = diag.cwiseQuotient(winSize); + + zoomSelection.isActive = false; + } + } + } + + void MultiViewInterface::updateCurrentLayer(const sibr::Input & input) + { + int i = -1; + + std::vector keys = { + sibr::Key::Num1, sibr::Key::Num2, sibr::Key::Num3, sibr::Key::Num4, sibr::Key::Num5, + sibr::Key::Num6, sibr::Key::Num7, sibr::Key::Num8, sibr::Key::Num9 + }; + + for (int k = 0; k < (int)keys.size(); ++k) { + if (input.key().isPressed(keys[k])) { + i = k; + break; + } + } + + if (i >= 0 && i < (int)imagesLayers.size()) { + currentLayer = i; + } + } + + void MultiViewInterface::updateZoomScroll(const sibr::Input & input) + { + double scroll = input.mouseScroll(); + + if (scroll != 0) { + float ratio = (scroll > 0 ? 0.75f : 1.33f); + if (input.key().isActivated(sibr::Key::LeftControl)) { + ratio *= ratio; + } + viewRectangle.diagonal *= ratio; + } + } + + void MultiViewInterface::updateCenter(const sibr::Input & input, const sibr::Vector2f & winSize) + { + if (dclick.detected(input)) { + //std::cout << "dclick : " << std::endl; + sibr::Vector2f translation = (dclick.firstPosition.cast().cwiseQuotient(winSize)-sibr::Vector2f(0.5,0.5)).cwiseProduct(viewRectangle.br() - viewRectangle.tl()); + translation.y() = -translation.y(); + viewRectangle.center += translation; + } + } + + void MultiViewInterface::updateDrag(const sibr::Input & input, const sibr::Vector2f & winSize) + { + if (input.mouseButton().isPressed(sibr::Mouse::Left)) { + drag.isActive = true; + drag.position = input.mousePosition(); + drag.center = viewRectangle.center; + } else if (drag.isActive && input.mouseButton().isReleased(sibr::Mouse::Left)) { + drag.isActive = false; + } + if (drag.isActive && input.mouseButton().isActivated(sibr::Mouse::Left)) { + sibr::Vector2f translation = (input.mousePosition() - drag.position).cast().cwiseQuotient(winSize).cwiseProduct(viewRectangle.br() - viewRectangle.tl()); + translation.y() = -translation.y(); + viewRectangle.center = drag.center - translation; + } + } + + + void MultiViewInterfaceView::onUpdate(Input & input, const sibr::Viewport & viewport) + { + if (viewType == ViewType::IMAGES) { + //i.imagesInput = input; + //i.imagesView.viewport = viewport; + interfacePtr->updateImageView(viewport, input); + } else if (viewType == ViewType::MESH) { + interfacePtr->updateMeshView(input, viewport); + } + } + + void MultiViewInterfaceView::onRender(const sibr::Viewport & viewport) + { + if (viewType == ViewType::IMAGES) { + interfacePtr->renderImageView(viewport); + interfacePtr->onGui(); + } else if (viewType == ViewType::MESH) { + interfacePtr->displayMesh(viewport); + } + } + +} //namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/interface/Interface.h b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/interface/Interface.h new file mode 100644 index 0000000000000000000000000000000000000000..8817b50210673d9d4fd2139ea9afd7742c604a53 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/interface/Interface.h @@ -0,0 +1,337 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include "../Config.hpp" +#include +#include +#include +#include +#include +#include "InterfaceUtils.h" +#include "MeshViewer.h" +#include + +#include + +//typedef void (*CallBackFunction)(int event, int x, int y, int flags, void* userdata); + +namespace sibr { + struct PixPos { + PixPos() : im(-1), isDefined(false) {} + PixPos(int i, const sibr::Vector2i & px) : im(i), pos(px), isDefined(true) {} + void cout() const { std::cout << im << " : " << pos.transpose() << std::endl; } + sibr::Vector2i pos; + int im; + bool isDefined; + }; + + struct SubView { + SubView() : isActive(false) {} + + sibr::Viewport viewport; + bool isActive; + sibr::Vector2i getViewportPosition(const sibr::Vector2i & winPos) { + return winPos - sibr::Vector2f(viewport.finalLeft(), viewport.finalTop()).cast(); + } + }; + + struct ScalingOptions { + ScalingOptions() : numScale(1), interpolation_method_cv(cv::INTER_CUBIC) {}; + int numScale; + int interpolation_method_cv; + }; + + struct LayerData { + LayerData(const std::string & name) : name(name) { } + std::string name; + }; + + struct ScaleData { + ScaleData(const sibr::Vector2i & imSizeI) { + imSize = imSizeI.cast(); + imRatio = imSize[0] / (float)imSize[1]; + } + sibr::Vector2f imSize; + float imRatio; + }; + + class MultiViewInterface; + + class SIBR_VIEW_EXPORT MultiViewInterfaceView : public sibr::ViewBase { + + public: + enum class ViewType { IMAGES, MESH }; + + SIBR_CLASS_PTR(MultiViewInterfaceView); + + MultiViewInterfaceView() {} + MultiViewInterfaceView(MultiViewInterface * interfacePtr, ViewType type) : interfacePtr(interfacePtr), viewType(type) {} + + virtual void onRenderIBR(IRenderTarget& /*dst*/, const sibr::Camera& /*eye*/) {} + + virtual void onUpdate(Input& /*input*/, const sibr::Viewport & viewport); + virtual void onRender(const sibr::Viewport & viewport); + + PixPos currentActivePos; + + protected: + MultiViewInterface * interfacePtr; + ViewType viewType; + }; + + /** + This class provides basic rendering utilities for a list of images + a mesh. + \ingroup sibr_view + */ + class SIBR_VIEW_EXPORT MultiViewInterface { + + SIBR_CLASS_PTR(MultiViewInterface); + + public: + + MultiViewInterface(); + + /** + Execute the main display loop, with an optional callback. + \param window the sibr::Window displayed into + \param f an optional callback called at the end of each frame. + */ + void displayLoop(sibr::Window & window, std::function = [](MultiViewInterface*){}); + void addCameras(const std::vector & input_cams); + void addMesh(const sibr::Mesh::Ptr & mesh); + void addMesh(const sibr::Mesh & mesh); + + virtual void update(sibr::Window & window, const sibr::Input & input); + + virtual void updateImageView(const sibr::Viewport & viewport, const sibr::Input & input); + + virtual void render(); + + void renderImageView(const sibr::Viewport & viewport); + + sibr::ViewBase::Ptr getViewBase(MultiViewInterfaceView::ViewType type = MultiViewInterfaceView::ViewType::IMAGES); + void onGui(); + + //~MultiViewInterface(); + + //virtual void loop(); + + sibr::Mesh::Ptr cpuMesh; + sibr::Mesh::Ptr reproMesh; + sibr::Mesh::RenderMode reproMeshMode; + bool reproMeshBackFace; + + sibr::Mesh::Ptr highlightedPixelsMesh; + std::vector highlightedPixels; + bool hightligthChanged; + + sibr::Vector2f imgPixelScreenSize; + + SubView imagesView; + SubView meshView; + + sibr::Input imagesInput; + sibr::Input meshInput; + + + public: + //std::unique_ptr window; + + MultiViewInterfaceView::Ptr imagesViewBase; + MultiViewInterfaceView::Ptr meshViewBase; + + InterfaceUtilities utils; + + ScalingOptions scalingOptions; + std::map name_to_layer_map; + + RectangleData viewRectangle; + DragData drag; + DoubleClick dclick; + SelectionData zoomSelection; + sibr::MeshViewer meshViewer; + + std::vector cams; + + sibr::PixPos currentActivePos; + + sibr::Vector2i grid; + sibr::Vector2f imSizeF; + sibr::Vector2f winSize; + float imRatio; + + int currentScale; + int currentLayer; + int numImgs; + std::vector> imagesLayers; //for each scale, each image layer + std::vector> imagesPtr; + std::vector > imagesFromLambdasPtr; + std::vector layersData; + std::vector scalesData; + + PixPos pixFromScreenPos(const sibr::Vector2i & pos, const sibr::Vector2f & winSize); + + UV01 screenPos(const PixPos & pix); + UV01 screenPosPixelCenter(const PixPos & pix); + + sibr::Vector2i screenPosPixels(const PixPos & pix, const sibr::Vector2f & winSize); + sibr::Vector2f screenPosPixelsFloat(const PixPos & pix, const sibr::Vector2f & winSize); + + void addHighlightPixel(const PixPos & pix, const sibr::Vector2f & winSize); + void renderHighlightPixels(); + + void highlightPixel(const PixPos & pix, const sibr::Viewport & viewport, const sibr::Vector3f & color = { 0, 1, 0 }, const sibr::Vector2f & pixScreenSize = { 5.0f,5.0f } ); + + virtual void displayImages(const sibr::Viewport & viewport); + virtual void displayMesh(const sibr::Viewport & viewport); + + void displayZoom(const sibr::Viewport & viewport); + void displayHighlightedPixels(const sibr::Vector3f & color, float alpha); + + virtual void updateMeshView(const sibr::Input & input, sibr::Window & window); + virtual void updateMeshView(const sibr::Input & input, const sibr::Viewport & viewport); + void updateZoomBox(const sibr::Input & input, const sibr::Vector2f & winSize); + void updateCurrentLayer(const sibr::Input & input); + void updateZoomScroll(const sibr::Input & input); + void updateCenter(const sibr::Input & input, const sibr::Vector2f & winSize); + void updateDrag(const sibr::Input & input, const sibr::Vector2f & winSize); + + template + bool checkNewLayer(const std::vector > & images) + { + if (imagesLayers.size() == 0) { + imagesLayers.resize(scalingOptions.numScale); + for (int scale = 0; scale < scalingOptions.numScale; ++scale) { + int w_s = static_cast(std::ceil(images[0].w()*pow(2.0f, -scale))); + int h_s = static_cast(std::ceil(images[0].h()*pow(2.0f, -scale))); + scalesData.push_back(ScaleData(sibr::Vector2i(w_s, h_s))); + } + numImgs = (int)images.size(); + } + + const auto & baseScaleImageLayer = imagesLayers[0]; + if (baseScaleImageLayer.size() > 0) { + if ((uint)images.size() != baseScaleImageLayer[0]->depth()) { + SIBR_ERR << "not enough images" << std::endl; + } + } + + if (images.size() == 0) { + SIBR_ERR << "empty image vector" << std::endl; + } + + return true; + } + + public: + + template + void addImageLayer(const std::vector > & images, const std::string & name = "") { + std::vector > imgs(images.size()); + for (int i = 0; i < (int)images.size(); ++i) { + imgs[i] = images[i]->clone(); + } + addImageLayer(imgs, name); + } + + template + void addImageLayer(const std::vector > & images, const std::string & name = "") + { + + checkNewLayer(images); + + for (int scale = 0; scale < scalingOptions.numScale; ++scale) { + std::vector > resized_imgs(images.size()); + if (scale != 0) { +#pragma omp parallel for + for (int im = 0; im < (int)images.size(); ++im) { + const sibr::Vector2i scaleSize = scalesData[scale].imSize.cast(); + resized_imgs[im] = images[im].resized(scaleSize[0], scaleSize[1], scalingOptions.interpolation_method_cv); + } + } else { + std::vector layerPtrs(images.size()); + for (int im = 0; im < (int)images.size(); ++im) { + layerPtrs[im] = &images[im]; + } + imagesPtr.push_back(layerPtrs); + } + const std::vector > & imgs = (scale == 0 ? images : resized_imgs); + auto layer = std::make_shared>(); + + layer->createFromImages(imgs); + + sibr::ITexture2DArray::Ptr layerBase(layer); + imagesLayers[scale].push_back(layerBase); + } + + std::string layerName = (name == "" ? "Layer" + std::to_string(layersData.size()) : name); + name_to_layer_map[layerName] = (int)layersData.size(); + layersData.push_back(LayerData(layerName)); + + } + + template + void addImageLayerWithLambda(const std::vector > & images, LambdaType lambda, const std::string & name = "") { + + checkNewLayer(images); + + using Lambda_Out_Image_Type = decltype(lambda(images[0])); + using Lambda_Out_Type = typename Lambda_Out_Image_Type::Type; + const int Lambda_Out_N = Lambda_Out_Image_Type::e_NumComp; + + for (int scale = 0; scale < scalingOptions.numScale; ++scale) { + std::vector > resized_imgs(images.size()); + if (scale != 0) { +#pragma omp parallel for + for (int im = 0; im < (int)images.size(); ++im) { + const sibr::Vector2i scaleSize = scalesData[scale].imSize.cast(); + resized_imgs[im] = images[im].resized(scaleSize[0], scaleSize[1], scalingOptions.interpolation_method_cv); + } + } + const std::vector > & imgs = (scale == 0 ? images : resized_imgs); + + std::vector lambdaImgs(images.size()); +#pragma omp parallel for + for (int im = 0; im < (int)images.size(); ++im) { + lambdaImgs[im] = lambda(imgs[im]); + //sibr::show(lambdaImgs[im], "test"); + } + + if (scale == 0) { + std::vector firstLayerPtrs(images.size()); + std::vector layerPtrs(images.size()); + for (int im = 0; im < (int)images.size(); ++im) { + auto lambdaImgPtr = std::make_shared(lambdaImgs[im].clone()); + + firstLayerPtrs[im] = std::static_pointer_cast(lambdaImgPtr); + layerPtrs[im] = firstLayerPtrs[im].get(); + } + imagesFromLambdasPtr.push_back(firstLayerPtrs); + imagesPtr.push_back(layerPtrs); + } + + typename sibr::Texture2DArray::Ptr layer = std::make_shared >(); + layer->createFromImages(lambdaImgs); + sibr::ITexture2DArray::Ptr layerBase(layer); + imagesLayers[scale].push_back(layerBase); + } + + std::string layerName = (name == "" ? "Layer" + std::to_string(layersData.size()) : name); + name_to_layer_map[layerName] = (int)layersData.size(); + layersData.push_back(LayerData(layerName)); + } + }; + + +} //namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/interface/InterfaceUtils.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/interface/InterfaceUtils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ee055520d2f36bdbe67e62a5e67e97da2a338872 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/interface/InterfaceUtils.cpp @@ -0,0 +1,300 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "InterfaceUtils.h" + +#include +#include + +namespace sibr { + + const std::string InterfaceUtilities::translationScalingVertexShader = + "#version 420 \n" + "layout(location = 0) in vec3 in_vertex; \n" + "uniform vec2 translation; \n" + "uniform vec2 scaling; \n" + "void main(void) { \n" + " gl_Position = vec4(scaling*in_vertex.xy+translation,0.0, 1.0); \n" + "} \n"; + + const std::string InterfaceUtilities::colorAlphaFragmentShader = + "#version 420 \n" + "uniform vec3 color; \n" + "uniform float alpha; \n" + "out vec4 out_color; \n" + "void main(void) { \n" + " out_color = vec4(color,alpha); \n" + "} \n"; + + const std::string InterfaceUtilities::meshVertexShader = + "#version 420 \n" + "layout(location = 0) in vec3 in_vertex; \n" + "uniform mat4 mvp; \n" + "void main(void) { \n" + " gl_Position = mvp*vec4(in_vertex, 1.0); \n" + "} \n"; + + const std::string InterfaceUtilities::multiViewVertexShader = + "#version 420 \n" + "layout(location = 0) in vec3 in_vertex; \n" + "out vec2 uv_coord; \n" + "uniform vec2 zoomTL; \n" + "uniform vec2 zoomBR; \n" + "void main(void) { \n" + " uv_coord = 0.5*in_vertex.xy + vec2(0.5); \n" + " uv_coord = zoomTL + (zoomBR-zoomTL)*uv_coord; \n" + " uv_coord.y = 1.0 - uv_coord.y; \n" + " gl_Position = vec4(in_vertex.xy,0.0, 1.0); \n" + "} \n"; + + + const std::string InterfaceUtilities::multiViewFragmentShader = + "#version 420 \n" + "layout(binding = 0) uniform sampler2DArray texArray; \n" + "uniform int numImgs; \n" + "uniform vec2 grid; \n" + "in vec2 uv_coord; \n" + "out vec4 out_color; \n" + "void main(void) { \n" + " vec2 uvs = uv_coord; \n" + " uvs = grid*uvs; \n" + " if( uvs.x < 0 || uvs.y < 0 ) { discard; } \n" + " vec2 fracs = fract(uvs); \n" + " vec2 mods = uvs - fracs; \n" + " int n = int(mods.x + grid.x*mods.y); \n" + " if ( n< 0 || n > numImgs || mods.x >= grid.x || mods.y >= (float(numImgs)/grid.x) + 1) { discard; } else { \n" + " out_color = texture(texArray,vec3(fracs.x,fracs.y,n)); } \n" + " //out_color = vec4(n/64.0,0.0,0.0,1.0); } \n" + " //out_color = vec4(uv_coord.x,uv_coord.y,0.0,1.0); } \n" + "} \n"; + + //sibr::GLShader InterfaceUtilities::baseShader; + + //sibr::GLParameter InterfaceUtilities::colorGL; + //sibr::GLParameter InterfaceUtilities::alphaGL; + //sibr::GLParameter InterfaceUtilities::scalingGL; + //sibr::GLParameter InterfaceUtilities::translationGL; + + //sibr::GLShader InterfaceUtilities::multiViewShader; + + //sibr::GLParameter InterfaceUtilities::numImgsGL; + //sibr::GLParameter InterfaceUtilities::gridGL; + //sibr::GLParameter InterfaceUtilities::multiViewTopLeftGL; + //sibr::GLParameter InterfaceUtilities::multiViewBottomRightGL; + + //const InterfaceUtilities::GLinitializer InterfaceUtilities::init; + + InterfaceUtilities::InterfaceUtilities() + { + + } + + void InterfaceUtilities::initAllShaders() + { + initBaseShader(); + initMultiViewShader(); + initMeshViewShader(); + CHECK_GL_ERROR; + + std::cout << " all shaders compiled" << std::endl; + } + + void InterfaceUtilities::freeAllShaders() + { + CHECK_GL_ERROR; + baseShader.terminate(); + CHECK_GL_ERROR; + multiViewShader.terminate(); + CHECK_GL_ERROR; + } + + void InterfaceUtilities::initBaseShader() + { + baseShader.init("InterfaceUtilitiesBaseShader", translationScalingVertexShader, colorAlphaFragmentShader); + colorGL.init(baseShader, "color"); + alphaGL.init(baseShader, "alpha"); + scalingGL.init(baseShader, "scaling"); + translationGL.init(baseShader, "translation"); + } + + void InterfaceUtilities::initMultiViewShader() + { + multiViewShader.init("InterfaceUtilitiesMultiViewShader", multiViewVertexShader, multiViewFragmentShader); + multiViewTopLeftGL.init(multiViewShader, "zoomTL"); + multiViewBottomRightGL.init(multiViewShader, "zoomBR"); + numImgsGL.init(multiViewShader, "numImgs"); + gridGL.init(multiViewShader, "grid"); + } + + void InterfaceUtilities::initMeshViewShader() + { + meshViewShader.init("InterfaceUtilitiesMeshViewShader", meshVertexShader, colorAlphaFragmentShader); + mvp.init(meshViewShader,"mvp"); + colorMeshGL.init(meshViewShader,"color"); + alphaMeshGL.init(meshViewShader,"alpha"); + } + + void InterfaceUtilities::rectangle(const sibr::Vector3f & color, const UV11 & tl, const UV11 & br, bool fill, float alpha) + { + + static sibr::Mesh::Ptr rectangleMesh; + static int lastContextId = -1; + + if (lastContextId != sibr::Window::contextId) { + rectangleMesh = std::make_shared(true); + }; + + + baseShader.begin(); + + scalingGL.set(sibr::Vector2f(1.0f,1.0f)); + translationGL.set(sibr::Vector2f(0, 0)); + colorGL.set(color); + + rectangleMesh->vertices({ + { tl.x(), tl.y() , 0 }, + { tl.x(), br.y() , 0 }, + { br.x(), br.y() , 0 }, + { br.x(), tl.y() , 0 } + }); + + if (fill) { + rectangleMesh->triangles({ + { 0,1,2 }, + { 0,2,3 } + }); + + alphaGL.set(alpha); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendEquation(GL_FUNC_ADD); + rectangleMesh->render(false, false); + } + + rectangleMesh->triangles({ + { 0,0,1 },{ 1,1,2 },{ 2,2,3 },{ 3,3,0 } + }); + + alphaGL.set(1.0f); + rectangleMesh->render(false, false, sibr::Mesh::LineRenderMode); + + baseShader.end(); + } + + void InterfaceUtilities::rectanglePixels(const sibr::Vector3f & color, const sibr::Vector2f & center, const sibr::Vector2f & diagonal, bool fill, float alpha, const sibr::Vector2f & winSize) + { + UV01 centerUV = UV01::from(center.cwiseQuotient(winSize)); + UV01 tl = UV01::from(centerUV - 0.5f*diagonal.cwiseQuotient(winSize)); + UV01 br = UV01::from(centerUV + 0.5f*diagonal.cwiseQuotient(winSize)); + rectangle(color, tl, br, fill, alpha); + } + + void InterfaceUtilities::circle(const sibr::Vector3f & color, const UV11 & center, float radius, bool fill, float alpha, const sibr::Vector2f & scaling, int precision) + { + + static int n; + static sibr::Mesh::Ptr circleMesh; + static sibr::Mesh::Ptr circleFilledMesh; + static sibr::Mesh::Triangles circleTriangles; + static sibr::Mesh::Triangles circleFillTriangles; + static int lastContextId = -1; + + bool updateMeshes = (lastContextId != sibr::Window::contextId) || (n != precision); + if (updateMeshes) { + lastContextId = sibr::Window::contextId; + n = precision; + circleTriangles.resize(n); + circleFillTriangles.resize(n); + for (int i = 0; i < n; ++i) { + int next = (i + 1) % n; + circleTriangles[i] = sibr::Vector3u(i, i, next); + circleFillTriangles[i] = sibr::Vector3u(i, next, n); + } + + sibr::Mesh::Vertices vertices(n + 1); + double base_angle = 2.0*M_PI / (double)n; + float rho = 0.5f*radius*(float)(1.0 + cos(0.5*base_angle)); + + for (int i = 0; i < n; ++i) { + double angle = i*base_angle; + vertices[i] = sibr::Vector3f((float)cos(angle), (float)sin(angle), (float)0.0); + } + vertices[n] = sibr::Vector3f(0, 0, 0); + + circleMesh = std::make_shared(true); + circleFilledMesh = std::make_shared(true); + circleMesh->vertices(vertices); + circleFilledMesh->vertices(vertices); + circleMesh->triangles(circleTriangles); + circleFilledMesh->triangles(circleFillTriangles); + } + + baseShader.begin(); + + translationGL.set(sibr::Vector2f(0, 0)); + + colorGL.set(color); + scalingGL.set(scaling); + translationGL.set(center); + + if (fill) { + alphaGL.set(alpha); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendEquation(GL_FUNC_ADD); + circleFilledMesh->render(false, false); + } + + alphaGL.set(1.0f); + circleMesh->render(false, false, sibr::Mesh::LineRenderMode); + + baseShader.end(); + } + + void InterfaceUtilities::circlePixels(const sibr::Vector3f & color, const sibr::Vector2f & center, float radius, bool fill, float alpha, const sibr::Vector2f & winSize, int precision) + { + UV10 centerUV = UV10::from(center.cwiseQuotient(winSize)); + sibr::Vector2f scaling = radius*sibr::Vector2f(1, 1).cwiseQuotient(winSize); + + circle(color, centerUV, 1.0f, fill, alpha, scaling, precision); + } + + void InterfaceUtilities::linePixels(const sibr::Vector3f & color, const sibr::Vector2f & ptA, const sibr::Vector2f & ptB, const sibr::Vector2f & winSize) + { + UV11 uvA = UV01::from(ptA.cwiseQuotient(winSize)); + UV11 uvB = UV01::from(ptB.cwiseQuotient(winSize)); + + sibr::Mesh line(true); + line.vertices({ + { uvA.x(), uvA.y(), 0.0f }, + { uvB.x(), uvB.y(), 0.0f } + }); + line.triangles({ + sibr::Vector3u(0,0,1) + }); + + baseShader.begin(); + + scalingGL.set(sibr::Vector2f(1.0f, 1.0f)); + translationGL.set(sibr::Vector2f(0, 0)); + colorGL.set(color); + alphaGL.set(1.0f); + + line.render(false, false, sibr::Mesh::LineRenderMode); + + baseShader.end(); + } + + + + +} //namespace sibr \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/interface/InterfaceUtils.h b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/interface/InterfaceUtils.h new file mode 100644 index 0000000000000000000000000000000000000000..e4fb63b657e563002650521c893b4cae09d11a90 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/interface/InterfaceUtils.h @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +#include "../Config.hpp" +#include +#include +#include +#include + +#include + +#include + +namespace sibr { + + /** + * \ingroup sibr_view + */ + enum UVspace { ZERO_ONE, MINUS_ONE_ONE, ONE_ZERO }; + + /** + * \ingroup sibr_view + */ + template struct UV : public sibr::Vector2f { + + static UV from(const sibr::Vector2f & v) { return UV(v.x(), v.y()); } + + UV(float u, float v) : Vector2f(u, v) {} + + //explicit UV(const sibr::Vector2f & v) : sibr::Vector2f(v) {} + + template operator UV() const; + }; + + typedef UV UV11; + typedef UV UV01; + typedef UV UV10; + + template<> template<> inline + UV11::operator UV01() const { + return UV01(0.5f*x() + 1, 0.5f*y() + 1); + } + + template<> template<> inline + UV01::operator UV11() const { + return UV11(2.0f*x() - 1, 2.0f*y() - 1); + } + + template<> template<> inline + UV01::operator UV10() const { + return UV10(x(), 1.0f - y()); + } + + template<> template<> inline + UV10::operator UV01() const { + return UV01(x(), 1.0f - y()); + } + + template<> template<> inline + UV10::operator UV11() const { + return UV11(UV01(*this)); + } + + template<> template<> inline + UV11::operator UV10() const { + return UV10(UV01(*this)); + } + + /** + * \ingroup sibr_view + */ + class SIBR_VIEW_EXPORT InterfaceUtilities + { + public: + InterfaceUtilities(); + + static const std::string translationScalingVertexShader; + static const std::string colorAlphaFragmentShader; + + sibr::GLShader baseShader; + + sibr::GLParameter colorGL; + sibr::GLParameter alphaGL; + sibr::GLParameter scalingGL; + sibr::GLParameter translationGL; + + static const std::string multiViewVertexShader; + static const std::string multiViewFragmentShader; + + static const std::string meshVertexShader; + static const std::string meshAlphaViewFragmentShader; + sibr::GLShader meshViewShader; + sibr::GLParameter mvp; + sibr::GLParameter colorMeshGL; + sibr::GLParameter alphaMeshGL; + + sibr::GLShader multiViewShader; + + sibr::GLParameter numImgsGL; + sibr::GLParameter gridGL; + sibr::GLParameter multiViewTopLeftGL; + sibr::GLParameter multiViewBottomRightGL; + + void rectangle(const sibr::Vector3f & color, const UV11 & tl, const UV11 & br, bool fill, float alpha); + void rectanglePixels(const sibr::Vector3f & color, const sibr::Vector2f & center, const sibr::Vector2f & diagonal, bool fill, float alpha, const sibr::Vector2f & winSize); + void circle(const sibr::Vector3f & color, const UV11 & center, float radius, bool fill, float alpha, const sibr::Vector2f & scaling = sibr::Vector3f(1,1), int precision = 50); + void circlePixels(const sibr::Vector3f & color, const sibr::Vector2f & center, float radius, bool fill, float alpha, const sibr::Vector2f & winSize, int precision = 50); + void linePixels(const sibr::Vector3f & color, const sibr::Vector2f & ptA, const sibr::Vector2f & ptB, const sibr::Vector2f & winSize); + + void initAllShaders(); + void freeAllShaders(); + + private: + struct GLinitializer { + GLinitializer() { + //InterfaceUtilities::initBaseShader(); + } + }; + + void initBaseShader(); + void initMultiViewShader(); + void initMeshViewShader(); + + //const static GLinitializer init; + }; + + struct RectangleData + { + RectangleData() : center({ 0.5, 0.5 }), diagonal({ 0.5, 0.5 }) {} + sibr::Vector2f center; + sibr::Vector2f diagonal; + sibr::Vector2f br() const { return center + diagonal; } + sibr::Vector2f tl() const { return center - diagonal; } + }; + + struct DragData + { + DragData() : isActive(false) {} + sibr::Vector2f center; + sibr::Vector2i position; + bool isActive; + }; + + struct SelectionData + { + SelectionData() : isActive(false) {} + sibr::Vector2i first; + sibr::Vector2i second; + bool isActive; + + }; + + template struct DoubleClick + { + DoubleClick() : detection_timing_in_ms(500) {} + + bool detected(const sibr::Input & input, bool should_be_close = true) { + if (input.mouseButton().isPressed(mKey)) { + //std::cout << "timer.deltaTimeFromLastTic() : " << timer.deltaTimeFromLastTic<>() << std::endl; + if (timer.deltaTimeFromLastTic<>() < detection_timing_in_ms && (!should_be_close || (firstPosition - input.mousePosition()).cwiseAbs().maxCoeff() < 10 ) ) { + return true; + } + firstPosition = input.mousePosition(); + timer.tic(); + } + return false; + } + + double detection_timing_in_ms; + + sibr::Timer timer; + sibr::Vector2i firstPosition; + }; + + template + static void show( + const sibr::Texture2DArray & texArray, + sibr::Window * inputWin = nullptr, + int w = -1, + int h = -1 + ) { + enum Mode { SLICE, GRID }; + + sibr::Window * win = inputWin; + const bool inChargeOfWindow = (win == nullptr); + const bool useCustomSize = (w > 0 && h > 0); + sibr::Vector2i previousSize; + + if (inChargeOfWindow) { + sibr::Vector2i winSize = (useCustomSize ? sibr::Vector2i(w, h) : sibr::Vector2i (1600, 1200)); + win = new sibr::Window(winSize[0], winSize[1], "showTexArray"); + } else if (useCustomSize) { + previousSize = win->size(); + win->size(w, h); + } + Mode mode = GRID; + + win->makeContextCurrent(); + + sibr::InterfaceUtilities utils; + utils.initAllShaders(); + + sibr::Vector2i grid(3, 3), previousGrid; + sibr::Vector2f TL(0, 0), BR(1, 1); + int slice = 1; + + bool renderLoop = true; + while (renderLoop) { + sibr::Input::poll(); + sibr::Input & input = sibr::Input::global(); + if (input.key().isPressed(sibr::Key::Escape)) { + renderLoop = false; + if (inChargeOfWindow) { + win->close(); + } + } + + ImGui::Begin("Show setting"); + if (ImGui::RadioButton("Grid", (int*)&mode, 1)) { + grid = previousGrid; + } + ImGui::SameLine(); + ImGui::RadioButton("Slice", (int*)&mode, 0); + + if (mode == GRID) { + ImGui::SliderInt("GridX", &grid[0], 1, texArray.depth()); + ImGui::SliderInt("GridY", &grid[1], 1, texArray.depth()); + previousGrid = grid; + TL = { 0, 0 }, BR = { 1,1 }; + } else if (mode == SLICE) { + grid = sibr::Vector2i(1, 1); + ImGui::SliderInt("Slice", &slice, 1, texArray.depth()); + TL[1] = -slice + 2; + BR[1] = -slice + 1; + //ImGui::SliderFloat("L", &TL[0], -3, 3); + //ImGui::SliderFloat("T", &TL[1], -3, 3); + //ImGui::SliderFloat("R", &BR[0], -3, 3); + //ImGui::SliderFloat("B", &BR[1], -3, 3); + } + + ImGui::End(); + + const auto & viewport = win->viewport(); + viewport.bind(); + viewport.clear(sibr::Vector3f(0.7, 0.7, 0.7)); + + utils.multiViewShader.begin(); + + utils.numImgsGL.set((int)texArray.depth() - 1); + sibr::Vector2f gridF = grid.cast(); + utils.gridGL.set(gridF); + + utils.multiViewTopLeftGL.set(TL); + utils.multiViewBottomRightGL.set(BR); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D_ARRAY, texArray.handle()); + sibr::RenderUtility::renderScreenQuad(); + + utils.multiViewShader.end(); + + win->swapBuffer(); + } + + if (inChargeOfWindow) { + delete win; + } else if(useCustomSize) { + win->size(previousSize[0], previousSize[1]); + } + } + + //class SIBR_VIEW_EXPORT Draw { + //public: + // static void rectangle(const sibr::Vector3f & color, const UV11 & tl, const UV11 & br, bool fill, float alpha); + // static void circle(const sibr::Vector3f & color, const UV11 & center, float radius, bool fill, float alpha, int precision = 50); + //}; + +} // namespace sibr diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/interface/MeshViewer.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/interface/MeshViewer.cpp new file mode 100755 index 0000000000000000000000000000000000000000..6b044a7166fb1b480b86986455bfd7960045f364 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/interface/MeshViewer.cpp @@ -0,0 +1,479 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "MeshViewer.h" + +#include +#include +#include +#include +#include + +const std::string sibr::MeshRenderer::meshVertexShader = +"#version 420 \n" +"uniform mat4 MVP; \n" +"layout(location = 0) in vec3 in_vertex; \n" +"layout(location = 1) in vec3 in_color; \n" +"layout(location = 3) in vec3 in_normal; \n" +"out vec3 color; \n" +"out vec3 normal; \n" +"out vec3 vertex; \n" +"void main(void) { \n" +" color = in_color; \n" +" normal = in_normal; \n" +" vertex = in_vertex; \n" +" gl_Position = MVP * vec4(in_vertex,1.0); \n" +"} \n"; + +const std::string sibr::MeshRenderer::meshFragmentShader = +"#version 420 \n" +"uniform vec3 light_pos; \n" +"uniform vec3 forcedColor = vec3(0.7f,0.7f,0.7f); \n" +"in vec3 color; \n" +"in vec3 normal; \n" +"in vec3 vertex; \n" +"out vec4 out_color; \n" +"void main(void) { \n" +" float kd = 0.3; \n" +" float ks = 0.2; \n" +" vec3 L = normalize(light_pos - vertex); \n" +" vec3 N = normalize(normal); \n" +" vec3 R = 2.0*dot(L,N)*N - N; \n" +" vec3 V = L; //light pos = eye \n" +" vec3 diffuse = max(0.0, dot(L,N))*vec3(1, 1, 1); \n" +" vec3 specular = max(0.0, dot(R,V))*vec3(1, 1, 1); \n" +" out_color = vec4((1.0 - kd -ks)*forcedColor + kd*diffuse + ks*specular , 1.0); \n" +"} \n"; + +sibr::MeshRenderer::MeshRenderer() +{ + initShaders(); + + resetLinesAndPoints(); + +} + +void sibr::MeshRenderer::render(const sibr::Camera & eye) +{ + glLineWidth(1.0f); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + for (auto & meshParam : listMeshes) { + if (meshParam.mode == sibr::Mesh::LineRenderMode) { + shaderLines.begin(); + mvpLines.set(eye.viewproj()); + lineColor.set(meshParam.color); + meshParam.mesh->render(meshParam.depthTest, false, sibr::Mesh::LineRenderMode); + shaderLines.end(); + } else { + shaderMesh.begin(); + const sibr::Vector3f lightPos = eye.position(); + light_pos.set(lightPos); + mvpMesh.set(eye.viewproj()); + forcedColor.set(meshParam.color); + meshParam.mesh->render(meshParam.depthTest, meshParam.backFaceCulling, meshParam.mode); + shaderMesh.end(); + } + } + + + if (lines.dirty) { + updateMeshLines(); + } + shaderLines.begin(); + mvpLines.set(eye.viewproj()); + lines.mesh->render(lines.depthTest, false, sibr::Mesh::LineRenderMode); + shaderLines.end(); + + float radiusW = 10.0f; + glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); + glPointSize(radiusW); + + if (points.dirty) { + updateMeshPoints(); + } + shaderPoints.begin(); + mvpPoints.set(eye.viewproj()); + radiusScreen.set(radiusW); + points.mesh->render(points.depthTest, false, sibr::Mesh::PointRenderMode); + + if (specialPoints.get() != nullptr) { + specialPoints->render(false, false, sibr::Mesh::PointRenderMode); + } + + shaderPoints.end(); + + +} + +void sibr::MeshRenderer::addMesh(std::shared_ptr meshPtr, sibr::Mesh::RenderMode mode) +{ + MeshParams mesh; + mesh.mesh = meshPtr; + mesh.mode = mode; + listMeshes.push_back(mesh); +} + +void sibr::MeshRenderer::addLines(const std::vector& listPoints, const sibr::Vector3f & color) +{ + int nLines = (int)listPoints.size() / 2; + for (int l = 0; l < nLines; ++l) { + lines.points.push_back(listPoints[2 * l]); + lines.points.push_back(listPoints[2 * l + 1]); + lines.colors.push_back(color); + } + + lines.dirty = true; +} + +void sibr::MeshRenderer::addPoint(const sibr::Vector3f & point, const sibr::Vector3f & color) +{ + points.points.push_back(point); + points.colors.push_back(color); + points.dirty = true; +} + +void sibr::MeshRenderer::addPoints(const std::vector& list_points, const sibr::Vector3f & color) +{ + std::vector colors(list_points.size(), color); + + points.points.reserve(points.points.size() + list_points.size()); + points.points.insert(points.points.end(), list_points.begin(), list_points.end()); + + points.colors.reserve(points.colors.size() + colors.size()); + points.colors.insert(points.colors.end(), colors.begin(), colors.end()); + points.dirty = true; +} + +void sibr::MeshRenderer::cleanPoints() +{ + points.points.resize(0); + points.colors.resize(0); + points.dirty = true; +} + +void sibr::MeshRenderer::cleanLines() +{ + lines.points.resize(0); + lines.colors.resize(0); + lines.dirty = true; +} + +void sibr::MeshRenderer::resetLinesAndPoints() +{ + lines.mesh = std::shared_ptr(new sibr::Mesh()); + points.mesh = std::shared_ptr(new sibr::Mesh()); + cleanLines(); + cleanPoints(); +} + +void sibr::MeshRenderer::resetMeshes() +{ + listMeshes.resize(0); +} + +void sibr::MeshRenderer::initShaders() +{ + + shaderMesh.init("meshShader", meshVertexShader, meshFragmentShader); + mvpMesh.init(shaderMesh, "MVP"); + light_pos.init(shaderMesh, "light_pos"); + forcedColor.init(shaderMesh, "forcedColor"); + + std::string lineVertexShader = + "#version 420 \n" + "uniform mat4 MVP; \n" + "layout(location = 0) in vec3 in_vertex; \n" + "layout(location = 1) in vec3 in_color; \n" + "out vec3 color_vert; \n" + "void main(void) { \n" + " gl_Position = MVP * vec4(in_vertex,1.0); \n" + " color_vert = in_color; \n" + "} \n"; + + std::string lineFragmentShader = + "#version 420 \n" + "in vec3 color_vert; \n" + "uniform vec3 color; \n" + "out vec4 out_color; \n" + "void main(void) { \n" + " out_color = vec4( color_vert, 1.0 ); \n" + "} \n"; + + shaderLines.init("LineShader", lineVertexShader, lineFragmentShader); + mvpLines.init(shaderLines, "MVP"); + lineColor.init(shaderLines, "color"); + + std::string pointVertexShader = + "#version 420 \n" + "uniform mat4 MVP; \n" + "uniform float radiusScreen; \n" + "layout(location = 0) in vec3 in_vertex; \n" + "layout(location = 1) in vec3 in_color; \n" + "out vec3 color_vert; \n" + "void main(void) { \n" + " gl_Position = MVP * vec4(in_vertex,1.0); \n" + " gl_PointSize = radiusScreen; \n" + " color_vert = in_color; \n" + "} \n"; + + std::string pointFragmentShader = + "#version 420 \n" + "in vec3 color_vert; \n" + "out vec4 out_color; \n" + "void main(void) { \n" + " out_color = vec4( color_vert, 1.0 ); \n" + "} \n"; + + shaderPoints.init("PointShader", pointVertexShader, pointFragmentShader); + mvpPoints.init(shaderPoints, "MVP"); + radiusScreen.init(shaderPoints, "radiusScreen"); +} + +void sibr::MeshRenderer::updateMeshPoints(void) +{ + std::vector vertexBuffer; + for (int vertex_id = 0; vertex_id<(int)points.points.size(); vertex_id++) { + for (int c = 0; c<3; ++c) { + vertexBuffer.push_back(points.points.at(vertex_id)[c]); + } + } + + points.mesh->vertices(vertexBuffer); + points.mesh->colors(points.colors); + + points.dirty = false; +} + +void sibr::MeshRenderer::updateMeshLines(void) +{ + std::vector vertexBuffer; + std::vector indicesBuffer(3 * (lines.points.size() / 2)); + std::vector colors(lines.points.size()); + for (int vertex_id = 0; vertex_id<(int)lines.points.size(); vertex_id += 2) { + for (int c = 0; c<3; ++c) { + vertexBuffer.push_back(lines.points.at(vertex_id)[c]); + } + for (int c = 0; c<3; ++c) { + vertexBuffer.push_back(lines.points.at(vertex_id + 1)[c]); + } + + indicesBuffer.at(3 * (vertex_id / 2)) = vertex_id; + indicesBuffer.at(3 * (vertex_id / 2) + 1) = vertex_id; + indicesBuffer.at(3 * (vertex_id / 2) + 2) = vertex_id + 1; + + colors.at(vertex_id) = lines.colors.at(vertex_id / 2); + colors.at(vertex_id + 1) = lines.colors.at(vertex_id / 2); + } + + lines.mesh->vertices(vertexBuffer); + lines.mesh->colors(colors); + lines.mesh->triangles(indicesBuffer); + + lines.dirty = false; +} + +sibr::MeshViewer::MeshViewer() +{ + renderer = std::make_shared(); + interactCam = std::make_shared(true); + interactCam->setFPSCameraSpeed(1); + interactCam->switchMode(sibr::InteractiveCameraHandler::InteractionMode::TRACKBALL); + inChargeOfWindow = false; + fpsCounter.init(sibr::Vector2f(10, 10)); +} + +sibr::MeshViewer::MeshViewer(const sibr::Vector2i & screenRes, const sibr::Mesh & mesh, bool launchRenderingLoop) +{ + window.reset(new Window(screenRes[0], screenRes[1], "MeshViewer" )); + renderer = std::make_shared(); + interactCam = std::make_shared(new sibr::InteractiveCameraHandler()); + interactCam->setFPSCameraSpeed(1); + interactCam->switchMode(sibr::InteractiveCameraHandler::InteractionMode::TRACKBALL); + inChargeOfWindow = true; + + setMainMesh(mesh); + + if (launchRenderingLoop) { + renderLoop(); + } +} + +void sibr::MeshViewer::setMainMesh(const sibr::Mesh & mesh, sibr::Mesh::RenderMode mode, bool updateCam, bool setupRaycaster) +{ + setMainMesh(*window, mesh, mode, updateCam, setupRaycaster); +} + +void sibr::MeshViewer::setMainMesh(sibr::Window & win, const sibr::Mesh & mesh, sibr::Mesh::RenderMode mode, bool updateCam, bool setupRaycaster) +{ + sibr::Mesh::Ptr meshGL = std::make_shared(true); + meshGL->vertices(mesh.vertices()); + meshGL->triangles(mesh.triangles()); + if (mesh.hasNormals()) { + meshGL->normals(mesh.normals()); + } + + renderer->resetMeshes(); + renderer->addMesh(meshGL, mode); + + if (updateCam) { + interactCam->setup(meshGL, win.viewport()); + interactCam->getTrackball().fromMesh(*meshGL, win.viewport()); + } + + if (setupRaycaster) { + raycaster = std::make_shared(); + raycaster->init(); + raycaster->addMesh(*meshGL); + } + + float radius; + sibr::Vector3f pos; + meshGL->getBoundingSphere(pos, radius); + interactCam->setFPSCameraSpeed(radius/10.0f); + +} + +void sibr::MeshViewer::render() +{ + if (window.get()) { + render(window->viewport(), interactCam->getCamera()); + window->swapBuffer(); + } +} + +void sibr::MeshViewer::renderLoop(sibr::Window & window) +{ + bool doLoop = true; + + while (doLoop && window.isOpened() ) { + sibr::Input::poll(); + + if (sibr::Input::global().key().isPressed(sibr::Key::Escape)) { + doLoop = false; + } + + interactCam->update(sibr::Input::global(), 1 / 60.0f, window.viewport()); + + window.viewport().bind(); + window.viewport().clear(sibr::Vector3f(0.9f, 0.9f, 0.9f)); + renderer->render(interactCam->getCamera()); + interactCam->onRender(window.viewport()); + + window.swapBuffer(); + } + + +} + +void sibr::MeshViewer::render(const sibr::Viewport & viewport, const sibr::Camera & eye ) +{ + viewport.bind(); + viewport.clear(sibr::Vector3f(0.9f, 0.9f, 0.9f)); + renderer->render(eye); + interactCam->onRender(viewport); + fpsCounter.update(true); +} + +void sibr::MeshViewer::render(const sibr::Viewport & viewport) +{ + render(viewport, interactCam->getCamera()); +} + +void sibr::MeshViewer::render(const sibr::Camera & eye) +{ + if (window.get()) { + render(window->viewport(), eye); + window->swapBuffer(); + } +} + +void sibr::MeshViewer::renderLoop(std::shared_ptr otherWindow) +{ + + if (!otherWindow.get() && !window->isOpened()) { + return; + } + if (otherWindow.get() && !window.get() ) { + window = otherWindow; + } + + while (window->isOpened()) { + sibr::Input::poll(); + + if (sibr::Input::global().key().isPressed(sibr::Key::Escape)) { + window->close(); + } + + interactCam->update(sibr::Input::global(), 1 / 60.0f, window->viewport()); + render(); + } + + reset(); +} + +void sibr::MeshViewer::renderLoop(const std::function & f, bool customRendering, bool doReset) +{ + bool doRender = true; + while (doRender && window->isOpened()) { + sibr::Input::poll(); + input = sibr::Input::global(); + if (input.key().isPressed(sibr::Key::Escape)) { + doRender = false; + if (inChargeOfWindow) { + window->close(); + } + } + + interactCam->update(input,1/60.0f, window->viewport()); + + f(this); + + if (!customRendering) { + render(); + } + } + if(doReset) { + reset(); + } +} + +void sibr::MeshViewer::reset() +{ + if (inChargeOfWindow) { + interactCam.reset(); + renderer.reset(); + raycaster.reset(); + window.reset(); + } + +} + +void sibr::MeshViewer::demo() +{ + sibr::Mesh::Ptr meshPtr = sibr::Mesh::getTestCube(); + + sibr::MeshViewer meshViewer(sibr::Vector2i(1600, 1200), *meshPtr); + + meshViewer.renderer->addPoints(meshPtr->vertices(), sibr::Vector3f(0, 1, 0)); + + for (const auto & tri : meshPtr->triangles()) { + for (int k = 0; k < 3; ++k) { + meshViewer.renderer->addLines( + { meshPtr->vertices()[tri[k]], meshPtr->vertices()[tri[(k + 1) % 3]] }, + sibr::Vector3f(1, 0, 0)); + } + } + + meshViewer.renderLoop(); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/interface/MeshViewer.h b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/interface/MeshViewer.h new file mode 100755 index 0000000000000000000000000000000000000000..6596b1ec4041b0f02bc65cd94f187c9af2abcb39 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/interface/MeshViewer.h @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once +#ifndef _DISABLE_EXTENDED_ALIGNED_STORAGE +# define _DISABLE_EXTENDED_ALIGNED_STORAGE +#endif +#include "../Config.hpp" +#include +#include +#include +#include +#include +#include +#include + +namespace sibr { + + class InteractiveCameraHandler; + class Raycaster; + class Camera; + + /** + * \ingroup sibr_view + */ + class SIBR_VIEW_EXPORT MeshRenderer { + + SIBR_CLASS_PTR(MeshRenderer); + + struct MeshData { + MeshData() : dirty(false), depthTest(true) {} + + std::shared_ptr mesh; + std::vector points; + std::vector colors; + bool dirty; + bool depthTest; + }; + + struct MeshParams { + MeshParams() : depthTest(true), backFaceCulling(true), color(sibr::Vector3f(0.7f,0.7f,0.7f)) {} + std::shared_ptr mesh; + sibr::Mesh::RenderMode mode; + sibr::Vector3f color; + bool depthTest; + bool backFaceCulling; + }; + + public: + MeshRenderer(); + void render(const sibr::Camera& viewproj); + + void addMesh(std::shared_ptr meshPtr, sibr::Mesh::RenderMode mode = sibr::Mesh::FillRenderMode ); + + void addLines(const std::vector & listPoints, const sibr::Vector3f & color); + + void addPoint(const sibr::Vector3f & point, const sibr::Vector3f & color); + void addPoints(const std::vector & listPoints, const sibr::Vector3f & color); + void cleanPoints(); + void cleanLines(); + + void resetLinesAndPoints(); + void resetMeshes(); + + std::vector & getMeshesParams() { return listMeshes; } + + public: + std::vector listMeshes; + + MeshData lines; + MeshData points; + sibr::Mesh::Ptr specialPoints; + + static const std::string meshVertexShader; + static const std::string meshFragmentShader; + + sibr::GLShader shaderLines; + + private: + + sibr::GLShader shaderMesh; + sibr::GLShader shaderPoints; + + sibr::GLParameter mvpLines; + sibr::GLuniform lineColor = sibr::Vector3f(1,0,0); + sibr::GLParameter mvpPoints; + sibr::GLParameter mvpMesh; + sibr::GLParameter forcedColor; + + sibr::GLParameter light_pos; + sibr::GLParameter radiusScreen; + + + + void initShaders(); + void updateMeshPoints(void); + void updateMeshLines(void); + + }; + + /** + * \ingroup sibr_view + */ + class SIBR_VIEW_EXPORT MeshViewer { + + SIBR_CLASS_PTR(MeshViewer); + + public: + MeshViewer(); + + MeshViewer( + const sibr::Vector2i & screenRes, + const sibr::Mesh & mesh = sibr::Mesh(), + bool launchRenderingLoop = false); + + virtual void setMainMesh( + const sibr::Mesh & mesh, + sibr::Mesh::RenderMode mode = sibr::Mesh::FillRenderMode, + bool updateCam = true, + bool setupRaycaster = true + ); + + virtual void setMainMesh( + sibr::Window & win, + const sibr::Mesh & mesh, + sibr::Mesh::RenderMode mode = sibr::Mesh::FillRenderMode, + bool updateCam = true, + bool setupRaycaster = true + ); + + virtual void render(const sibr::Viewport & viewport, const sibr::Camera & eye); + virtual void render(const sibr::Viewport & viewport); + virtual void render(const sibr::Camera & eye); + virtual void render(); + + virtual void renderLoop(sibr::Window & window); + + void renderLoop(std::shared_ptr window); + void renderLoop(const std::function & f = [](MeshViewer* m){} , bool customRendering = false, bool doReset = true); + + virtual void reset(); + + static void demo(); + + + + public: + sibr::Input input; + sibr::FPSCounter fpsCounter; + std::shared_ptr window; + std::shared_ptr renderer; + std::shared_ptr interactCam; + std::shared_ptr raycaster; + + bool inChargeOfWindow; + }; + +} //namespace sibr + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alpha_colored_mesh.frag b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alpha_colored_mesh.frag new file mode 100644 index 0000000000000000000000000000000000000000..abb26e6f846cc3c7b1260a13fa9568e6d1e79ac6 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alpha_colored_mesh.frag @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +layout(location = 0) out vec4 out_color; + +uniform vec3 light_position; +uniform vec3 user_color; +uniform float alpha; +uniform bool phong_shading; +uniform bool use_mesh_color; + +in vec3 color; +in vec3 normal; +in vec3 position; + +void main(void) { + + vec3 col; + if(use_mesh_color){ + col = color; + } else { + col = user_color; + } + + out_color = vec4(col, alpha); + + if(phong_shading){ + float kd = 0.2; + float ks = 0.1; + vec3 L = normalize(light_position - position); + vec3 N = normalize(normal); + vec3 R = - reflect(L,N); + vec3 V = L; //light pos = eye + float diffuse = max(0.0, dot(L,N)); + float specular = max(0.0, dot(R,V)); + out_color.xyz = (1.0 - kd - ks)*col + (kd*diffuse + ks*specular)* vec3(1, 1, 1); + } +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alpha_colored_mesh.vert b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alpha_colored_mesh.vert new file mode 100644 index 0000000000000000000000000000000000000000..feb9ef4f2d1faf15207f17521e4ca378adf13918 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alpha_colored_mesh.vert @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +layout(location = 0) in vec3 in_vertex; +layout(location = 1) in vec3 in_color; +layout(location = 3) in vec3 in_normal; + +uniform mat4 mvp; + +out vec3 color; +out vec3 normal; +out vec3 position; + +void main(void) { + gl_Position = mvp * vec4(in_vertex, 1.0); + color = in_color; + normal = in_normal; + position = in_vertex; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alpha_colored_per_triangle_normals.geom b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alpha_colored_per_triangle_normals.geom new file mode 100644 index 0000000000000000000000000000000000000000..5130841ea7910994fee90ad8e74998f5a9040228 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alpha_colored_per_triangle_normals.geom @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#version 420 + +layout(triangles) in; +layout(line_strip, max_vertices = 2) out; + +uniform mat4 mvp; +uniform float normals_size; + +out vec3 color; +out vec3 normal; +out vec3 position; + +void main(void) { + vec3 a = gl_in[0].gl_Position.xyz; + vec3 b = gl_in[1].gl_Position.xyz; + vec3 c = gl_in[2].gl_Position.xyz; + + vec3 tri_normal = normalize(cross(b-a,c-b)); + vec3 tri_center = (a+b+c)/3.0; + gl_Position = mvp*vec4(tri_center,1.0); + color = vec3(0.0); + normal = vec3(0.0); + position = vec3(0.0); + EmitVertex(); + gl_Position = mvp*vec4(tri_center + normals_size*tri_normal, 1.0); + color = vec3(0.0); + normal = vec3(0.0); + position = vec3(0.0); + EmitVertex(); + EndPrimitive(); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alpha_colored_per_triangle_normals.vert b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alpha_colored_per_triangle_normals.vert new file mode 100644 index 0000000000000000000000000000000000000000..0b05517e0b25d7a04c2b323127ecafc333b10965 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alpha_colored_per_triangle_normals.vert @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +layout(location = 0) in vec3 in_vertex; + +void main(void) { + gl_Position = vec4(in_vertex, 1.0); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alpha_colored_per_vertex_normals.geom b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alpha_colored_per_vertex_normals.geom new file mode 100644 index 0000000000000000000000000000000000000000..927be7c6264c53264a122c166196ecc4f2504858 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alpha_colored_per_vertex_normals.geom @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +layout(points) in; +layout(line_strip, max_vertices = 2) out; + +uniform mat4 mvp; +uniform float normals_size; + +in vec3 normals[]; + +out vec3 color; +out vec3 normal; +out vec3 position; + + +void main(void) { + gl_Position = mvp*(gl_in[0].gl_Position); + color = vec3(0.0); + normal = vec3(0.0); + position = vec3(0.0); + EmitVertex(); + gl_Position = mvp* vec4(gl_in[0].gl_Position.xyz + normals_size*normals[0],1.0); + color = vec3(0.0); + normal = vec3(0.0); + position = vec3(0.0); + EmitVertex(); + EndPrimitive(); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alpha_colored_per_vertex_normals.vert b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alpha_colored_per_vertex_normals.vert new file mode 100644 index 0000000000000000000000000000000000000000..b6af90008500b60b27257630015a50f00af56288 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alpha_colored_per_vertex_normals.vert @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +layout(location = 0) in vec3 in_vertex; +layout(location = 3) in vec3 in_normal; + +out vec3 normals; + +void main(void) { + gl_Position = vec4(in_vertex, 1.0); + normals = in_normal; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alpha_points.frag b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alpha_points.frag new file mode 100644 index 0000000000000000000000000000000000000000..67a9c0d559e74be7d5352f84a4635ec1d60e7364 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alpha_points.frag @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +layout(location = 0) out vec4 out_color; + +uniform vec3 user_color; +uniform float alpha; +in vec3 color; + +void main(void) { +// out_color = vec4(user_color, alpha); + out_color = vec4(color, alpha); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alpha_points.vert b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alpha_points.vert new file mode 100644 index 0000000000000000000000000000000000000000..681e21b93bcde59377204bf70504fb3aaf20db1f --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alpha_points.vert @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +layout(location = 0) in vec3 in_vertex; +layout(location = 1) in vec3 in_color; + +uniform mat4 mvp; +uniform int radius; +out vec3 color; + +void main(void) { + gl_Position = mvp * vec4(in_vertex, 1.0); + gl_PointSize = radius; + color = in_color; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alpha_uv_tex.frag b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alpha_uv_tex.frag new file mode 100644 index 0000000000000000000000000000000000000000..c71a209c5d3df5f237ed736e7099b6017504348a --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alpha_uv_tex.frag @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +layout(location = 0) out vec4 out_color; +layout(binding = 0) uniform sampler2D input_rgb; + +in vec2 out_uv; + +uniform float alpha; + +void main() { + out_color = vec4(texture(input_rgb, out_uv).xyz, alpha); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alpha_uv_tex_array.frag b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alpha_uv_tex_array.frag new file mode 100644 index 0000000000000000000000000000000000000000..eab58e47e8558458e58ca4202d2aa8df1c92158e --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alpha_uv_tex_array.frag @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +layout(location = 0) out vec4 out_color; +layout(binding = 0) uniform sampler2DArray input_rgbs; + +in vec2 out_uv; + +uniform float alpha; +uniform int slice; + +void main() { + vec3 uv_cam = vec3(out_uv, slice); + out_color = vec4(texture(input_rgbs, uv_cam).xyz, alpha); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alphaimgview.fp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alphaimgview.fp new file mode 100644 index 0000000000000000000000000000000000000000..d7c3b3fb892b8148536976cd148b60ae6ed40b95 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alphaimgview.fp @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +layout(binding = 0) uniform sampler2D tex; +layout(location= 0) out vec4 out_color; + +in vec2 tex_coord; +uniform float alpha; + +void main(void) { + vec2 texcoord = tex_coord ; + out_color = vec4(texture(tex,texcoord).rgb, alpha); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alphaimgview.vp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alphaimgview.vp new file mode 100644 index 0000000000000000000000000000000000000000..ba6679111f8b2b671f462a26cf70ea5b7f57b2d8 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/alphaimgview.vp @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +layout(location = 0) in vec2 in_vertex; +layout(location = 1) in vec2 in_texcoord; + +out vec2 tex_coord; + +uniform vec4 imagefit; + +vec2 fitTexcoord( vec2 tc ) { + tc.x = tc.x*imagefit[0] + imagefit[2+0]; + tc.y = tc.y*imagefit[1] + imagefit[2+1]; + return tc; +} + +void main(void) { + gl_Position = vec4(in_vertex, 0.0, 1.0); + tex_coord = fitTexcoord(in_texcoord); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/anaglyph.fp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/anaglyph.fp new file mode 100644 index 0000000000000000000000000000000000000000..c5b5b997d20830212f6669406658852164bb8a0c --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/anaglyph.fp @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +layout(binding = 0) uniform sampler2D left; +layout(binding = 1) uniform sampler2D right; +layout(location= 0) out vec4 out_color; + +in vec2 vertex_coord; + +void main(void) { + vec2 texcoord = (vertex_coord + vec2(1.0)) / 2.0; + vec4 cl = texture(left, texcoord); + vec4 cr = texture(right, texcoord); + out_color = vec4(cl.r, cr.g, cr.b, 1.0); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/anaglyph.vp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/anaglyph.vp new file mode 100644 index 0000000000000000000000000000000000000000..910b4f431615d786ad75d58f4590934e246bc462 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/anaglyph.vp @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +layout(location = 0) in vec2 in_vertex; + +out vec2 vertex_coord; + +void main(void) { + gl_Position = vec4(in_vertex, 0.0, 1.0); + vertex_coord = in_vertex; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/axisgizmo.fp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/axisgizmo.fp new file mode 100644 index 0000000000000000000000000000000000000000..bcaf4f5f4329e46a8a2c733464105fb863e074e2 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/axisgizmo.fp @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +in vec3 axis_color; +out vec4 out_color; + +void main(void) { + out_color = vec4(axis_color, 1.0); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/axisgizmo.vp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/axisgizmo.vp new file mode 100644 index 0000000000000000000000000000000000000000..9fd55cde8b37f44c62430a71c238c2c714e6ad9a --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/axisgizmo.vp @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +uniform mat4 MVP; + +layout(location = 0) in vec3 in_vertex; +layout(location = 1) in vec3 in_color; + +out vec3 axis_color; + +void main(void) { + axis_color = in_color; + gl_Position = MVP * vec4(in_vertex,1.0); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/camstub.fp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/camstub.fp new file mode 100644 index 0000000000000000000000000000000000000000..b4fb5bf0dcb4fe95dbbed4cef7121335c1d3ad14 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/camstub.fp @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +uniform vec3 color; + +out vec4 out_color; + +void main(void) { + out_color = vec4(color, 1.0); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/camstub.vp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/camstub.vp new file mode 100644 index 0000000000000000000000000000000000000000..9476f4f10fbc801cb4ef1add20f0b99ee5939661 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/camstub.vp @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +uniform mat4 MVP; + +layout(location = 0) in vec3 in_vertex; + +void main(void) { + gl_Position = MVP * vec4(in_vertex,1.0); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/depth.fp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/depth.fp new file mode 100644 index 0000000000000000000000000000000000000000..dbcfb3f062dc1d8a8b0e721f31c98a32b0d9408f --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/depth.fp @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +layout(location = 0) out vec4 out_color; +layout(binding = 0) uniform sampler2D image; /// \todo TODO: remove + +//in vec3 vertex_coord; +//uniform vec3 iCamPos; + +uniform vec2 size; + +void main(void) { + vec2 tC = gl_FragCoord.xy / size; + out_color.xyz = vec3(0.0);//texture(image, tC.xy).xyz; + out_color.w = gl_FragCoord.z; + //out_color.w = distance(vertex_coord, iCamPos); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/depth.vp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/depth.vp new file mode 100644 index 0000000000000000000000000000000000000000..49bb95647042225404398e8b89b2692986fd733b --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/depth.vp @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +uniform mat4 proj; + +layout(location = 0) in vec3 in_vertex; + +//out vec2 texture_coord; +//out vec3 normal_coord; + +void main(void) { + gl_Position = proj * vec4(in_vertex,1.0); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/depthonly.fp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/depthonly.fp new file mode 100644 index 0000000000000000000000000000000000000000..3c34d3ff91263d7944bac4e9340ce878a6455665 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/depthonly.fp @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +layout(location = 0) out float out_color; + +void main(void) { + out_color = gl_FragCoord.z; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/depthonly.vp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/depthonly.vp new file mode 100644 index 0000000000000000000000000000000000000000..9863f64c30e30d88e38c518895e4b53cb6c74439 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/depthonly.vp @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +uniform mat4 proj; + +layout(location = 0) in vec3 in_vertex; + +void main(void) { + gl_Position = proj * vec4(in_vertex,1.0); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/image_viewer.frag b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/image_viewer.frag new file mode 100644 index 0000000000000000000000000000000000000000..60baa6ea590f2d1dd71468f8b4ce1f94ef5abceb --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/image_viewer.frag @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +in vec2 texcoord; + +layout(binding = 0) uniform sampler2D in_texture; + +uniform vec4 minVal = vec4(0.0); +uniform vec4 maxVal = vec4(1.0); +uniform vec4 channels = vec4(1.0); + +layout(location = 0) out vec4 out_color; + +void main(void) +{ + if(any(greaterThan(texcoord, vec2(1.0))) || any(lessThan(texcoord, vec2(0.0)))){ + discard; + } + + vec4 col = texture(in_texture, texcoord); + // Rescale. + out_color = channels*(col - minVal)/(maxVal - minVal); + + // If only one channel is enabled, no alpha and B&W image. + if(dot(channels, vec4(1.0)) == 1.0){ + float val = dot(out_color, channels); + out_color.rgb = vec3(val); + out_color.a = 1.0; + } + + // Ensure visibility when alpha is disabled. + if(channels[3] == 0.0f){ + out_color.a; + } +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/image_viewer.vert b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/image_viewer.vert new file mode 100644 index 0000000000000000000000000000000000000000..d6254fee36f8d9c6d5950d983ad61b51d2e0a2ea --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/image_viewer.vert @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +layout(location = 0) in vec3 in_vertex; + +uniform float scale; +uniform vec2 pos; +uniform vec2 size; +uniform bool correctRatio; + +out vec2 texcoord; + +void main(void) { + vec2 position = scale * vec2(1.0, correctRatio ? (size.y/size.x) : 1.0) * in_vertex.xy + pos; + gl_Position = vec4(in_vertex.xy, 0.0, 1.0); + texcoord = position * 0.5 + 0.5; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/mesh_color.fp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/mesh_color.fp new file mode 100644 index 0000000000000000000000000000000000000000..7f54cde683aa71651d981ae503a5ce414174d0d6 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/mesh_color.fp @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +uniform vec3 lightDir; + +out vec4 out_color; + +in vec3 color_vert; +in vec3 vertexPos; +in vec3 normalPos; + +void main(void) { + float kd = 0.2; + vec3 normal = normalize(normalPos); + vec3 shading = max(0.0,dot(lightDir,normal))*color_vert; + + out_color = vec4( (1.0-kd)*color_vert + kd*shading, 1.0); + //out_color = vec4( normal , 1.0 ); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/mesh_color.vp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/mesh_color.vp new file mode 100644 index 0000000000000000000000000000000000000000..e120cabc2c442dcb89c5a027a0ae99d16ad5b9ab --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/mesh_color.vp @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +uniform mat4 MVP; +uniform mat4 invMV; + +layout(location = 0) in vec3 in_vertex; +layout(location = 1) in vec3 in_color; +layout(location = 3) in vec3 in_normal; + +out vec3 color_vert; +out vec3 vertexPos; +out vec3 normalPos; + +void main(void) { + gl_Position = MVP * vec4(in_vertex,1.0); + vertexPos = vec3(MVP * vec4(in_vertex,1.0)); + normalPos = vec3(invMV*vec4(in_normal,1.0)); + + color_vert = in_color; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/mesh_debugview.fp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/mesh_debugview.fp new file mode 100644 index 0000000000000000000000000000000000000000..6e5b9d366ed19eb00cae677e31443a87498d4ed1 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/mesh_debugview.fp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +uniform vec3 lightDir; + +uniform bool hasNormal = true; +out vec4 out_color; + +in vec3 color_vert; +in vec3 vertexPos; +in vec3 normalPos; + +void main(void) { + float kd = 0.8; + float ks = 0.15; + float diffuse = 1.0; + float specular = 0.0; + + if(hasNormal){ + vec3 L = normalize(lightDir); + vec3 N = normalize(normalPos); + vec3 R = reflect(L,N);//2.0*dot(L,N)*N - N; + vec3 V = L; + diffuse = max(0.0, dot(L,N)); + specular = max(0.0, dot(R,V)); + } + out_color.rgb = (1.0-kd-ks)*color_vert + kd*diffuse*color_vert + ks*specular; + out_color.a = 1.0; + +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/mesh_debugview.vp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/mesh_debugview.vp new file mode 100644 index 0000000000000000000000000000000000000000..d0a8d1ca2d757e722e94f98d226c7c22e9d70ea7 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/mesh_debugview.vp @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +uniform mat4 MVP; +uniform mat4 invMV; +uniform bool hasColor = true; +uniform vec3 defaultColor = vec3(0.9,0.9,0.9); + +layout(location = 0) in vec3 in_vertex; +layout(location = 1) in vec3 in_color; +layout(location = 3) in vec3 in_normal; + +out vec3 color_vert; +out vec3 vertexPos; +out vec3 normalPos; + +void main(void) { + gl_Position = MVP * vec4(in_vertex,1.0); + vertexPos = vec3(MVP * vec4(in_vertex,1.0)); + normalPos = vec3(vec4(in_normal,1.0)); + + color_vert = hasColor ? in_color : defaultColor; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/mesh_normal.fp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/mesh_normal.fp new file mode 100644 index 0000000000000000000000000000000000000000..3b8b52c009520112c38cba0bd404f52c06e6e720 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/mesh_normal.fp @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +layout(location = 0) out vec4 out_color; + +in vec3 normal_coord; + +void main(void) { + vec3 color = vec3(normalize(normal_coord)); + color = color * 0.5 + 0.5; + out_color = vec4(color, 1.0); + //out_color = vec4(dot(normal_coord, vec3(0.58,-0.58,0.08))); + if (length(normal_coord) == 0.0) { // no normal present + out_color = vec4(0.8); + } +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/mesh_normal.vp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/mesh_normal.vp new file mode 100644 index 0000000000000000000000000000000000000000..dba563f8f99166edca4325b6805bfd059c2b4dc2 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/mesh_normal.vp @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +uniform mat4 proj; + +layout(location = 0) in vec3 in_vertex; +//layout(location = 1) in vec2 in_texcoord; +layout(location = 1) in vec3 in_normal; + +//out vec2 texture_coord; +out vec3 normal_coord; + +void main(void) { + gl_Position = proj * vec4(in_vertex,1.0); + //texture_coord = in_texcoord; + normal_coord = in_normal; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/number.fp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/number.fp new file mode 100644 index 0000000000000000000000000000000000000000..19adc1b71ea1b7bedcb0c78843f9e74b68bf7467 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/number.fp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +in vec2 uv_coord; + +uniform float value; +uniform int count; + +out vec4 out_color; + +const float digits[10] = float[](0x69996,0x26222,0x6924F,0x69396,0x99F11,0xF861E,0x68E96,0xF1248,0x69696,0x69716); + +float printDigit(int digit, vec2 position){ + // Margin scaling/shift + position *= 1.4; + position -= 0.2; + // Early discard. + if(position.x < 0.0 || position.x > 1.0 || position.y < 0.0 || position.y > 1.0){ + return 0.0; + } + // [0,1] -> discrete[0,4]x[0,5] + vec2 newPos = floor(vec2(4.0-4.0*position.x,5.0*position.y)); + // -> corresponding bit + float index = 4*newPos.y + newPos.x; + // -> get the index-th bit + float isIn = mod(floor(digits[digit]/pow(2.0,index)),2.0); + return isIn; +} + +float printPoint(vec2 position){ + position *= 1.4; + position -= 0.02; + if(position.x < 0.0 || position.x > 1.0 || position.y < 0.0 || position.y > 1.0){ + return 0.0; + } + return length(position - vec2(0.2, 0.4)) < 0.182 ? 1.0 : 0.0; + +} + +void main(void) { + float deca = printDigit(int(mod(value/10,10)), uv_coord); + float unit = printDigit(int(mod(value,10)), uv_coord-vec2(1.0,0.0)); + float deci = printDigit(int(mod(value*10,10)), uv_coord-vec2(2.5,0.0)); + float centi = printDigit(int(mod(value*100,10)), uv_coord-vec2(3.5,0.0)); + float point = printPoint(uv_coord-vec2(2.0,0.0)); + float color = clamp(deca+unit+deci+centi+point,0.0,1.0); + out_color = vec4(color,color, color, 1.0); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/number.vp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/number.vp new file mode 100644 index 0000000000000000000000000000000000000000..e8f338eb521fce9cffdd0fc30259225da3238148 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/number.vp @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +uniform vec2 position; +uniform vec2 scale; +uniform int count; + +layout(location = 0) in vec3 in_vertex; +out vec2 uv_coord; + +void main(void) { + uv_coord = vec2(count+0.5, 1.0) * (in_vertex.xy * 0.5 + 0.5); + gl_Position = vec4(scale * vec2(count, 1.0) * (in_vertex.xy - position) + position,0.0, 1.0); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/skybox.fp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/skybox.fp new file mode 100644 index 0000000000000000000000000000000000000000..3eb2cdd9f92c41ca9b1884f4c095035b3880092e --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/skybox.fp @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#version 420 + +layout(binding = 0) uniform samplerCube in_CubeMap; +layout(location= 0) out vec4 out_Color; + +in VSOUT +{ + vec3 tc; +} in_Frag; + +void main(void) +{ + out_Color = texture(in_CubeMap, in_Frag.tc); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/skybox.vp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/skybox.vp new file mode 100644 index 0000000000000000000000000000000000000000..d7d5aacb845e2a468b43abf600e704fcb77c8b0e --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/skybox.vp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#version 420 + +out VSOUT +{ + vec3 tc; +} out_Vert; + +uniform mat4 in_View; +uniform vec2 in_Aspect; + + +const float fov = 70.0; +const float vecZ = in_Aspect.y / tan(radians(fov / 2.0)); +//const float vecZ = 0.8033332538; + +mat3 rotationMatrix(vec3 axis, float angle) +{ + axis = normalize(axis); + float s = sin(angle); + float c = cos(angle); + float oc = 1.0 - c; + return mat3(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, + oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, + oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c); +} + +void main(void) +{ + + vec2[4] vertices = vec2[4](vec2(-1.0, -1.0), + vec2( 1.0, -1.0), + vec2(-1.0, 1.0), + vec2( 1.0, 1.0)); + + + vec3 vertex = vec3(vertices[gl_VertexID], -1.0); + + // out gl_Position + gl_Position = vec4(vertex, 1.0); + + vertex.y = vertex.y * in_Aspect.y; + vertex.z = -vecZ; + + out_Vert.tc = mat3(in_View) * vertex; + //out_Vert.tc = rotationMatrix(vec3(1,0,0), -1.14) * out_Vert.tc; + out_Vert.tc.z = -out_Vert.tc.z; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/text-imgui.fp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/text-imgui.fp new file mode 100644 index 0000000000000000000000000000000000000000..72e45966ba6b7a5f9981154dd6ee8d6b901dbcfb --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/text-imgui.fp @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +layout (location = 0) out vec4 fragColor; + +in INTERFACE { + vec4 col; + vec2 uv; +} In ; + +uniform sampler2D tex; + +void main(){ + fragColor = In.col * texture(tex, In.uv); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/text-imgui.vp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/text-imgui.vp new file mode 100644 index 0000000000000000000000000000000000000000..6e67cae8d8ddf4f3817cc8edd095c64f77557095 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/text-imgui.vp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +// Attributes +layout(location = 0) in vec3 in_vertex; +layout(location = 1) in vec3 in_color; +layout(location = 2) in vec2 in_uv; +//layout(location = 3) in vec3 in_normal; + +// Uniforms +uniform vec3 position = vec3(0.0,0.0,0.0); // Position in NDC space +uniform float scale = 1.0; +uniform vec2 viewport = vec2(1.0); +uniform bool forceOpacity = true; + +out INTERFACE { + vec4 col; + vec2 uv; +} Out ; + +void main(){ + // Should be in -1,1 + // Multiply by the w component to stay at a constant screen size. + gl_Position = vec4(position.xy+scale*in_vertex.xy/viewport, 0.0, 1.0); + Out.uv = in_uv; + Out.col = vec4(in_color, forceOpacity ? 1.0 : in_vertex.z); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/texture.fp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/texture.fp new file mode 100644 index 0000000000000000000000000000000000000000..ee57f7b8ca7c033aae5811f66d9df4732b1f1b3e --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/texture.fp @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +layout(binding = 0) uniform sampler2D tex; +layout(location= 0) out vec4 out_color; + +in vec2 tex_coord; + +void main(void) { + vec2 texcoord = tex_coord ; + out_color = texture(tex,texcoord); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/texture.vp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/texture.vp new file mode 100644 index 0000000000000000000000000000000000000000..7b096189f29455e06cd8af7b93cb91bd050e2b63 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/texture.vp @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +layout(location = 0) in vec2 in_vertex; +layout(location = 1) in vec2 in_texcoord; + +out vec2 tex_coord; + +void main(void) { + gl_Position = vec4(in_vertex, 0.0, 1.0); + tex_coord = in_texcoord; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/topview.fp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/topview.fp new file mode 100644 index 0000000000000000000000000000000000000000..f085cb78af7dcb347f9af87fefd068423864a510 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/topview.fp @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +/** + * \file topview.fp + * + * Basic shader to render textured/colored geometry + */ + +#version 420 + +layout(binding = 0) uniform sampler2D tex;/**< Input texture */ +layout(location= 0) out vec4 out_color; /**< Output texture map */ + +uniform vec4 in_color; /**< Uniform color */ +in vec4 texcoord; /**< Texture coords at current pixel */ + +void main(void) { + vec4 c1 = texture(tex,texcoord.xy); + vec4 c2 = in_color; + out_color = c2.a*in_color + clamp(1.0-c2.a,0.0,1.0)*c1; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/topview.vp b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/topview.vp new file mode 100644 index 0000000000000000000000000000000000000000..f46815ec1666699bd0525408be3ee35c273b3ac5 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/topview.vp @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +/** \file topview.vp + * + * Vertex shader with projection and modelview transformations + * for rendering top view + */ + +#version 420 + +layout(location = 0) in vec4 in_vertex; /**< Input vertex coordinates */ +layout(location = 1) in vec4 in_texcoord; /**< Input texture coordinates */ + +uniform mat4 proj; /**< Projection matrix */ +out vec4 texcoord; /**< Output texture coordinates */ + +void main(void) { + gl_Position = proj * in_vertex; + texcoord = in_texcoord; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/uv_mesh.vert b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/uv_mesh.vert new file mode 100644 index 0000000000000000000000000000000000000000..2e5a9f3be70068a24f2e3cd345b17861b10b5924 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/shaders/uv_mesh.vert @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +layout(location = 0) in vec3 in_vertex; +layout(location = 2) in vec2 in_uv; + +out vec2 out_uv; + +uniform mat4 mvp; + +void main() { + out_uv = in_uv; + gl_Position = mvp * vec4(in_vertex, 1.0); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/core/view/sibr_view.dox b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/sibr_view.dox new file mode 100644 index 0000000000000000000000000000000000000000..50180dbea9844bf7e3bdc615feacd92fe7835197 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/core/view/sibr_view.dox @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +/*! + \defgroup sibr_view sibr_view + + \brief View, camera, high-level rendering utilities. + +*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/CMakeLists.txt b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..3fa2d5be6d6109a9bdad22e8735f3fef43f0f8c0 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/CMakeLists.txt @@ -0,0 +1,17 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + + +project(sibr_dataset_tools_all) + +add_subdirectory(preprocess) + +include(install_runtime) +subdirectory_target(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR} "projects/dataset_tools") diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/documentation/dataset_tools.dox b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/documentation/dataset_tools.dox new file mode 100644 index 0000000000000000000000000000000000000000..78c52603377a38f844645dd9a3a2eb3302bb7166 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/documentation/dataset_tools.dox @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +/*! +@page sibr_projects_dataset_tools Dataset Preprocessing Tools + +This page contains the documentation for various tools developed for treating multi-view datasets used for image-based rendering. These deal with calibrated cameras (typically with Structure-from-Motion / SfM), 3D meshes reconstructed with SfM and Multi-View Stereo (MVS) and various other utilities. + +For information on datasets, see the @ref howto_generate_dataset. + +We next present a set preprocessing tools used in the various toolchains to prepare data for IBR *Projects*. + +\subsection sibr_projects_dataset_tools_preprocess_tools Preprocessing tools + + +\subsubsection sibr_projects_dataset_tools_preprocess_tools_cameraConverter cameraConverter + +Utility to convert between camera path formats (blender: .lookAt, bundler: .out, colmap: .txt, internal binary format: .bin,...). This is useful for comparisons (see the \ref comparisonsPage) + +\subsubsection sibr_projects_dataset_tools_preprocess_tools_clippingPlanes clippingPlanes + +Calculates near and far planes for each image and writes to file clipping_planes.txt. This is used while creating the dataset. In some cases (e.g., [Chaurasia 13] and [Ortiz-Cayon 15] we need to have the same clipping planes for all images). + +\subsubsection sibr_projects_dataset_tools_preprocess_tools_converters converters + +Converters include python scripts to generate various files. In *install/scripts*, run +``` +python generate_list_images.py --imagesPath IMAGESPATH + +[--outputPath OUTPUTPATH ] +[--filename FILENAME ] +``` +That generates "list_images.txt" file in a directory IMAGESPATH containing images, optional arguments are the outputpath and filename. + +``` +ibr_preprocess_rc_to_sibr.py +``` +See \ref howto_generate_dataset + +``` +simplify_mesh.py +``` +Used in *fullcolmapProcess* (see below), and uses *meshlabServer* to simplify a mesh. + +``` +wedge_to_vertices_uvs.py +``` +converts a mesh from wedge uvs to vertex uvs, again using *meshlabServer*. + + +\subsubsection sibr_projects_dataset_tools_preprocess_tools_cropFromCenter cropFromCenter + +Utility to crop images so they are centered and have the same size. Used for preprocessing in [Chaurasia 13] and [Ortiz-Cayon 15]. + +\subsubsection sibr_projects_dataset_tools_preprocess_tools_distordCrop distordCrop + +Undistort images and then send to *cropFromCenter* above. + +\subpage sibr_projects_dataset_tools_preprocess_tools_fullColmapProcess fullColmapProcess: from images to a colmap dataset + + +\subsubsection sibr_projects_dataset_tools_preprocess_tools_nvmToSIBR nvmToSIBR + +Convert from VisualSFM .nvm format for calibrated cameras to SIBR format + + +\subsubsection sibr_projects_dataset_tools_preprocess_tools_unwrapMesh unwrapMesh + +``` +unwrapMesh_rwdi.exe or +unwrapMesh.exe + --appPath define a custom app path (default: "./") + --help display this help message (default: disabled) + --output path to the output mesh (default: "") + --path path to the mesh [required] + --size target UV map width (approx.) (default: 4096) + --texture-name name of the texture to reference in the output mesh (Meshlab compatible) (default: "TEXTURE_NAME_TO_PUT_IN_THE_FILE") + --visu save visualisation (default: disabled) +``` + +Calls xatlas to compute UV coordinates of a mesh (not adapted to complex meshes, works but really long); typical use involves calling simplify mesh first. + +\subsubsection sibr_projects_dataset_tools_preprocess_tools_textureMesh textureMesh + +``` +textureMesh_rwdi.exe or +textureMesh.exe + --path PATH_TO_DATASET [required] + --output PATH_TO_OUTPUT_FILE.png [required] + --size [default=8192] + --flood + --poisson +``` + +Given a mesh with UV coordinates (typically using unwrapMesh) and calibrated cameras, produces a texture atlas, with optional arguments for texture resolution, flood or poisson filling. + +\subsection Deprecated + +\subsubsection sibr_projects_dataset_tools_preprocess_tools_tonemapper tonemapper + +\subsubsection sibr_projects_dataset_tools_preprocess_tools_meshroomPythonScripts meshroomPythonScripts +Utilities for Meshroom use (untested) + +*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/documentation/dataset_tools_doc.cmake b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/documentation/dataset_tools_doc.cmake new file mode 100644 index 0000000000000000000000000000000000000000..90e37bf47c7e61c0d3b4998c4c7d23a7746288a5 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/documentation/dataset_tools_doc.cmake @@ -0,0 +1,13 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +set(PROJECT_PAGE "sibr_projects_dataset_tools") +set(PROJECT_LINK "https://gitlab.inria.fr/sibr/sibr_core") +set(PROJECT_TYPE "SAMPLES") diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/documentation/fullColmapProcess.dox b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/documentation/fullColmapProcess.dox new file mode 100644 index 0000000000000000000000000000000000000000..56126a8943498d502b1cb26c9e4bc42c42a60435 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/documentation/fullColmapProcess.dox @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +/*! +@page sibr_projects_dataset_tools_preprocess_tools_fullColmapProcess fullColmapProcess : running the full Colmap pipeline for SIBR + +\section ColmapInstallRequirements Install requirements + +- Colmap 3.6: https://demuc.de/colmap/ + +You can choose the Pre-Release of Release Version for Windows. The .bat file corresponds +to the application. Download and install it in any folder. + +- Dataset tools projects (available in sibr core) + +Install the SIBR Core on your computer : https://gitlab.inria.fr/sibr/sibr_core + +The page contains all the steps to install it. + +Choose the BUILD_IBR_DATASET_TOOLS option in CMAKE, BUILD and INSTALL the dataset_tools project (Apps and Preprocess). + + +\subsection ColmapHToPrepareDataset How to prepare the dataset +- Create the directory which will contain the future dataset +- In the dataset directory, create a new directory with the name images +- In the images directory, place your images that you want to use to create +the SIBR dataset + +Your dataset architecture should correspond to this: + +\verbatim + dataset/ # your dataset directory + images/ # your images directory + im001.jpeg + im002.jpeg + im003.jpeg + im004.jpeg + ... +\endverbatim + + +\subsection ColmapHToRunPipeline How to run the pipeline + +This section shows the different steps that you need to run to create the dataset. +The SIBR ULR project contains some applications which allows to run Colmap, generate UVs +and create a textured mesh. All the steps can be directly done through the +fullColmapProcess python script. + +You can run the script as an executable in bash-like command, or call it through python on cmd : + +\code +# from cmd +Ξ» python .\install\scripts\fullColmapProcess.py --help +# from git bash / cygwin / msys2 +❯ ./install/scripts/fullColmapProcess.py --help + +usage: fullColmapProcess.py [-h] --path PATH --colmapPath COLMAPPATH [--sibrBinariesPath SIBRBINARIESPATH] [--quality {default,low,medium,average,high,extreme}] [--with_texture] [--numGPUs NUMGPUS] + [--SiftExtraction.max_image_size SIFTEXTRACTION_IMAGESIZE] [--SiftExtraction.estimate_affine_shape SIFTEXTRACTION_ESTIMATEAFFINESHAPE] [--SiftExtraction.domain_size_pooling SIFTEXTRACTION_DOMAINSIZEPOOLING] + [--SiftExtraction.max_num_features SIFTEXTRACTION_MAXNUMFEATURES] [--ImageReader.single_camera IMAGEREADER_SINGLECAMERA] [--ExhaustiveMatching.block_size EXHAUSTIVEMATCHER_EXHAUSTIVEMATCHINGBLOCKSIZE] + [--Mapper.ba_local_max_num_iterations MAPPER_MAPPERDOTBALOCALMAXNUMITERATIONS] [--Mapper.ba_global_max_num_iterations MAPPER_MAPPERDOTBAGLOBALMAXNUMITERATIONS] + [--Mapper.ba_global_images_ratio MAPPER_MAPPERDOTBAGLOBALIMAGESRATIO] [--Mapper.ba_global_points_ratio MAPPER_MAPPERDOTBAGLOBALPOINTSRATIO] + [--Mapper.ba_global_max_refinements MAPPER_MAPPERDOTBAGLOBALMAXREFINEMENTS] [--Mapper.ba_local_max_refinements MAPPER_MAPPERDOTBALOCALMAXREFINEMENTS] + [--PatchMatchStereo.max_image_size PATCHMATCHSTEREO_PATCHMATCHSTEREODOTMAXIMAGESIZE] [--PatchMatchStereo.window_radius PATCHMATCHSTEREO_PATCHMATCHSTEREODOTWINDOWRADIUS] + [--PatchMatchStereo.window_step PATCHMATCHSTEREO_PATCHMATCHSTEREODOTWINDOWSTEP] [--PatchMatchStereo.num_samples PATCHMATCHSTEREO_PATCHMATCHSTEREODOTNUMSAMPLES] + [--PatchMatchStereo.num_iterations PATCHMATCHSTEREO_PATCHMATCHSTEREODOTNUMITERATIONS] [--PatchMatchStereo.geom_consistency PATCHMATCHSTEREO_PATCHMATCHSTEREODOTGEOMCONSISTENCY] + [--StereoFusion.check_num_images STEREOFUSION_CHECKNUMIMAGES] [--StereoFusion.max_image_size STEREOFUSION_MAXIMAGESIZE] + +optional arguments: + -h, --help show this help message and exit + --path PATH path to your dataset folder + --colmapPath COLMAPPATH + colmap path directory which contains colmap.bat / colmap.bin + --sibrBinariesPath SIBRBINARIESPATH + binaries directory of SIBR + --quality {default,low,medium,average,high,extreme} + quality of the reconstruction + --with_texture Add texture steps + --numGPUs NUMGPUS number of GPUs allocated to Colmap + --SiftExtraction.max_image_size SIFTEXTRACTION_IMAGESIZE + --SiftExtraction.estimate_affine_shape SIFTEXTRACTION_ESTIMATEAFFINESHAPE + --SiftExtraction.domain_size_pooling SIFTEXTRACTION_DOMAINSIZEPOOLING + --SiftExtraction.max_num_features SIFTEXTRACTION_MAXNUMFEATURES + --ImageReader.single_camera IMAGEREADER_SINGLECAMERA + --ExhaustiveMatching.block_size EXHAUSTIVEMATCHER_EXHAUSTIVEMATCHINGBLOCKSIZE + --Mapper.ba_local_max_num_iterations MAPPER_MAPPERDOTBALOCALMAXNUMITERATIONS + --Mapper.ba_global_max_num_iterations MAPPER_MAPPERDOTBAGLOBALMAXNUMITERATIONS + --Mapper.ba_global_images_ratio MAPPER_MAPPERDOTBAGLOBALIMAGESRATIO + --Mapper.ba_global_points_ratio MAPPER_MAPPERDOTBAGLOBALPOINTSRATIO + --Mapper.ba_global_max_refinements MAPPER_MAPPERDOTBAGLOBALMAXREFINEMENTS + --Mapper.ba_local_max_refinements MAPPER_MAPPERDOTBALOCALMAXREFINEMENTS + --PatchMatchStereo.max_image_size PATCHMATCHSTEREO_PATCHMATCHSTEREODOTMAXIMAGESIZE + --PatchMatchStereo.window_radius PATCHMATCHSTEREO_PATCHMATCHSTEREODOTWINDOWRADIUS + --PatchMatchStereo.window_step PATCHMATCHSTEREO_PATCHMATCHSTEREODOTWINDOWSTEP + --PatchMatchStereo.num_samples PATCHMATCHSTEREO_PATCHMATCHSTEREODOTNUMSAMPLES + --PatchMatchStereo.num_iterations PATCHMATCHSTEREO_PATCHMATCHSTEREODOTNUMITERATIONS + --PatchMatchStereo.geom_consistency PATCHMATCHSTEREO_PATCHMATCHSTEREODOTGEOMCONSISTENCY + --StereoFusion.check_num_images STEREOFUSION_CHECKNUMIMAGES + --StereoFusion.max_image_size STEREOFUSION_MAXIMAGESIZE +\endcode + +\image HTML colmapfullpipeline.png + +- Colmap creates a reconstruction from your images +- UnwrapMesh program gens UV coordinates on the mesh +- colmapToSibr creates the architecture and files required by a SIBR scene +- TextureMesh create a texture and bind it to the reconstruction. + +\subsubsection ColmapInputArgs Input arguments + +Required arguments: + +\code +--path YOUR_DATA_PATH +\endcode + +The path to your dataset folder. It must contain an images folder with images of your captured scene + +Optional arguments: + +\code +--colmapPath COLMAP_DIR +\endcode + +The directory containing the colmap.bat executable (if not provided, it will look for a `COLMAP_PATH` environment variable, or use `C:\Program Files\Colmap`) + +\code +--meshlabPath MESHLAB_DIR +\endcode + +The directory containing the meshlabserver executable (if not provided, it will look for a `MESHLAB_PATH` environment variable, or use `C:\Program Files\VCG\Meshlab`) + +\code +--sibrBinariesPath YOUR_SIBR_DIR\install\bin +\endcode + +That is the directory which contains the binaries of SIBR + +Those optional arguments are about the Colmap parametrization. You have several ways to +set the colmap parameters + +- Use a pre-defined configuration. You have 4 configurations : low, medium, high, extreme. +If you don't use a pre-defined configuration, all the parameters are set to the default +value ( usually it is a mix between high and extreme ). To apply it, use the +\code +--quality +\endcode option + +- Specify the parameters separately. You can set each parameters by yourself. Here is +a tab contains the default values and the values for each pre-defined configuration: + + | parameters | default | low | medium | average | high | extreme | + | ---------------------------------------------------- | ------------- | ----- | ------------- | ------------- | ------------- | ------------- | + | **colmap feature_extractor** ||||||| + | siftExtraction_ImageSize | 3200 | 1000 | 1600 | 3200 | 2400 | 3200 | + | siftExtraction_EstimateAffineShape | false | false | false | false | true | true | + | siftExtraction_DomainSizePooling | false | false | false | false | false | true | + | siftExtraction_MaxNumFeatures | 16000 | 8192 | 8192 | 8192 | 8192 | 8192 | + | imageReader_SingleCamera | false | true | true | true | true | true | + | **colmap exhaustive_matcher** ||||||| + | exhaustiveMatcher_ExhaustiveMatchingBlockSize | 50 | 50 | 50 | 50 | 50 | 50 | + | **colmap mapper** ||||||| + | mapper_MapperDotbaLocalMaxNumIterations | 25 | 12 | 16 | 25 | 30 | 40 | + | mapper_MapperDotbaGlobalMaxNumIterations | 50 | 25 | 33 | 50 | 75 | 100 | + | mapper_MapperDotbaGlobalImagesRatio | 1.100001 | 1.32 | 1.21 | 1.100001 | 1.100001 | 1.100001 | + | mapper_MapperDotbaGlobalPointsRatio | 1.100001 | 1.32 | 1.21 | 1.100001 | 1.100001 | 1.100001 | + | mapper_MapperDotbaGlobalMaxRefinements | 5 | 2 | 2 | 5 | 5 | 5 | + | mapper_MapperDotbaLocalMaxRefinements | 2 | 2 | 2 | 2 | 3 | 3 | + | **colmap patch_match_stereo** ||||||| + | patchMatchStereo_PatchMatchStereoDotMaxImageSize | -1 | 1000 | 1600 | -1 | 2400 | -1 | + | patchMatchStereo_PatchMatchStereoDotWindowRadius | 5 | 4 | 4 | 5 | 5 | 5 | + | patchMatchStereo_PatchMatchStereoDotWindowStep | 1 | 2 | 2 | 1 | 1 | 1 | + | patchMatchStereo_PatchMatchStereoDotNumSamples | 15 | 7 | 10 | 15 | 15 | 15 | + | patchMatchStereo_PatchMatchStereoDotNumIterations | 5 | 3 | 5 | 5 | 5 | 5 | + | patchMatchStereo_PatchMatchStereoDotGeomConsistency | 1 | 0 | 0 | 1 | 1 | 1 | + | **colmap stereo_fusion** ||||||| + | stereoFusion_CheckNumImages | 50 | 25 | 33 | 50 | 50 | 50 | + | stereoFusion_MaxImageSize | -1 | 1000 | 1600 | -1 | 2400 | -1 | + +- Mix a pre-defined configuration and your own parameters. First, the parameters +of the pre-defined configuration are applied. Then, your parameters are applied over them. + + + +\subsubsection ColmapInputArgsExamples Input arguments examples + +The most basic version looks like that + + +\code +--path E:\USERNAME\dataset --sibrBinariesPath E:\USERNAME\dev\sibr_basic2\install\bin --colmapPath D:\colmap +\endcode + +\note Do not forget that your dataset path has to contain an image directory with the images inside it. + +Now an example using the pre-defined configuration + +\code +--path E:\USERNAME\dataset --sibrBinariesPath E:\YOU\dev\sibr_basic2\install\bin --colmapPath D:\colmap --quality low +\endcode + +Finally, an example with the mix of the two ways + +\code +--path E:\USERNAME\dataset --sibrBinariesPath E:\YOU\dev\sibr_basic2\install\bin --colmapPath D:\colmap --quality medium --SiftExtraction.max_num_features 4096 +\endcode + +All the parameters will be set to the medium configuration except the max_num_features that +will be setted to 4096. + +*/ \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/documentation/img/colmapfullpipeline.png b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/documentation/img/colmapfullpipeline.png new file mode 100644 index 0000000000000000000000000000000000000000..807963fbb674728829ffa9906f91ff792973103a Binary files /dev/null and b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/documentation/img/colmapfullpipeline.png differ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/CMakeLists.txt b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..5d299a53f292f8f240e3cb2cb8d01ede2f7f141d --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/CMakeLists.txt @@ -0,0 +1,28 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + + +project(SIBR_dataset_tools_preprocess) + +add_subdirectory(alignMeshes) +add_subdirectory(cameraConverter) +add_subdirectory(clippingPlanes) +add_subdirectory(converters) +add_subdirectory(cropFromCenter) +add_subdirectory(distordCrop) +add_subdirectory(fullColmapProcess) +add_subdirectory(meshroomPythonScripts) +add_subdirectory(nvmToSIBR) +add_subdirectory(textureMesh) +add_subdirectory(tonemapper) +add_subdirectory(unwrapMesh) +add_subdirectory(utils) +add_subdirectory(prepareColmap4Sibr) +add_subdirectory(realityCaptureTools) diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/alignMeshes/CMakeLists.txt b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/alignMeshes/CMakeLists.txt new file mode 100755 index 0000000000000000000000000000000000000000..e19086ed67def108fb04b858fccd99841f0f67eb --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/alignMeshes/CMakeLists.txt @@ -0,0 +1,34 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +# project name +project(alignMeshes) + +# Define build output for project +add_executable(${PROJECT_NAME} main.cpp) + +target_link_libraries(${PROJECT_NAME} + ${Boost_LIBRARIES} + OpenMP::OpenMP_CXX + sibr_assets + sibr_system + sibr_graphics + sibr_renderer +) + +set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER "projects/dataset_tools/preprocess") + +## High level macro to install in an homogen way all our ibr targets +include(install_runtime) +ibr_install_target(${PROJECT_NAME} + INSTALL_PDB ## mean install also MSVC IDE *.pdb file (DEST according to target type) + STANDALONE ${INSTALL_STANDALONE} ## mean call install_runtime with bundle dependencies resolution + COMPONENT ${PROJECT_NAME}_install ## will create custom target to install only this project +) diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/alignMeshes/main.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/alignMeshes/main.cpp new file mode 100755 index 0000000000000000000000000000000000000000..d5e4b68e7562bdb15eaa543c87f89b39bf1e6887 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/alignMeshes/main.cpp @@ -0,0 +1,883 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PROGRAM_NAME "sibr_chunk2sibr" +using namespace sibr; + +const char* usage = "" +"Usage: " PROGRAM_NAME " -path -path2 -outPath " "\n" +; + +double distPatch(sibr::ImageRGB& im1, sibr::Vector2i& tpos, sibr::ImageRGB& im2, sibr::Vector2i& spos, int size) { + //only need to check boundaries for target + + + double dist = 0; + for (int i = -size; i <= size; i++) { + for (int j = -size; j <= size; j++) { + sibr::Vector2i debug(spos.x() + i, spos.y() + j); + if (!im2.isInRange(debug.x(), debug.y())) + std::cout << "Pos patch is : " << sibr::Vector2i(spos.x() + i, spos.y() + j) << std::endl; + dist += (im1(tpos.x() + i, tpos.y() + j).cast() - im2(spos.x() + i, spos.y() + j).cast()).squaredNorm(); + } + } + return dist; +} + + +// Convienience function to find the Median Absolute Deviation from a vector of deviations. +// Note that it isn't a strict median( just a quick approximation. ) +float findMAD(const Eigen::VectorXf& vec) { + Eigen::VectorXf vec_ = vec; + // Sort the data in increasing order. + std::sort(vec_.data(), vec_.data() + vec_.size()); + // Return the 'middle' element. + return vec_[((vec_.size() + 1) / 2)]; +} + +// Weight function.( Takes a list of standardized adjusted residuals and returns the square-root-weights for each one ) +// Currently, the Bisquares estimator is used. +// Note that this function should return the square root of the actual weight value since both X and Y are multiplied by this vector. +Eigen::VectorXf weight(Eigen::VectorXf v) { + Eigen::VectorXf vout = v; + + for (int i = 0; i < v.size(); i++) { + float r = v[i]; + vout[i] = ((abs(r) < 1) ? (1 - (r * r)) : 0); + } + + return vout; +} + +#define MAX_ITERS 100 +// Procedure for IRLS( Iterative Reweighted Least Squares ). +void irls(Eigen::MatrixX4f mX, Eigen::VectorXf vY, Eigen::Vector4f& mCoeffs, float tune) { + + Eigen::MatrixXf mX_ = mX; + Eigen::VectorXf vY_ = vY; + // Find the least squares coefficients. + Eigen::Vector4f vC = mX_.jacobiSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(vY); + //Log(EInfo, "Finished solving for LS solution."); + + // Form the leverage value matrix as H = X . ( X_T . X ) . X_T + // Form the leverage factor matrix as 1/sqrt(1 - diag(H)) + Eigen::VectorXf mH = (mX_ * (((mX_.transpose() * mX_).inverse()) * mX_.transpose())).diagonal(); + Eigen::MatrixXf mH_ = (Eigen::VectorXf::Constant(mH.rows(), 1, 1) - mH).cwiseSqrt().cwiseInverse().asDiagonal(); + + std::cout << vC << std::endl; + for (int i = 0; ; i++) { + std::cout << "IRLS: Iteration " << i << ":"; + + // Find residuals: + Eigen::VectorXf resid = vY - mX * vC; + + float mad = findMAD(resid.cwiseAbs()); + + // Calcualte Standardized Adjusted Residuals. + Eigen::VectorXf r = (mH_ * resid * 0.6745) / (mad * tune); + + // Find the root weight of residuals. + Eigen::VectorXf wt = weight(r); + + // Multiply X and Y with the root of the weights. + mX_ = wt.asDiagonal() * mX; + vY_ = wt.asDiagonal() * vY; + + std::cout << "MAD= " << mad << ", "; + + // Regress the weighted X and Y to find weighted least squares optimisation. + Eigen::Vector4f vC_ = mX_.jacobiSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(vY_); + + // Find mean deviation in coefficients. + float meanDiff = (vC - vC_).cwiseAbs().mean(); + std::cout << "MD=" << meanDiff << ","; + // Terminate if the deviation is too small or number of iterations has been exceeded. + if (meanDiff < 0.01f || i > MAX_ITERS) { + mCoeffs = vC_; + std::cout << "\n"; + break; + } + + vC = vC_; + std::cout << "\n"; + } + std::cout << vC << std::endl; +} + +static bool isRawRC(std::string pathRC) +{ + // do we have bundle, mesh and list images ? + sibr::Mesh mesh2Align; + if (!mesh2Align.load(pathRC + "/recon.ply")) { + SIBR_WRG << "***** No file " << pathRC + "/recon.ply ; make sure your mesh has the correct name !!"; + return false; + } + if (!fileExists(pathRC + "/bundle.out")) { + SIBR_WRG << "***** No file " << pathRC + "/bundle.out ; make sure your bundle file has the correct name !!"; + return false; + } + if (!fileExists(pathRC + "/list_images.txt")) { + SIBR_WRG << "***** No file " << pathRC + "/list_images.txt ; make sure you generate the list_images.txt file "; + return false; + } + return true; +} + +static void loadRawRC(std::string pathRC, std::vector& cams2Align, + std::vector& imgs2Align, sibr::Mesh& mesh2Align) +{ + cams2Align = sibr::InputCamera::loadBundle(pathRC + "/bundle.out", 0.01f, 1000.0f, pathRC + "/list_images.txt"); + mesh2Align.load(pathRC + "/recon.ply"); + imgs2Align.resize(cams2Align.size()); + for (int c = 0; c < cams2Align.size(); c++) { + sibr::ImageRGB::Ptr imgPtr; + sibr::ImageRGB img; + if (!img.load(pathRC + "/" + cams2Align[c]->name())) + if (!img.load(pathRC + "/" + cams2Align[c]->name() + ".png")) + if (!img.load(pathRC + "/" + cams2Align[c]->name() + ".jpg")) { + SIBR_ERR << "Error loading dataset to align from " << pathRC; + SIBR_ERR << "Problem loading images from raw RC, exiting "; + } + + imgs2Align[c] = img.clonePtr(); + } +} + +static bool isRawSynthetic(std::string pathSynthetic) +{ + // do we have bundle, mesh and list images ? + sibr::Mesh mesh2Align; + if (!fileExists(pathSynthetic + "/scene.obj")) { + SIBR_WRG << "***** No file " << pathSynthetic + "/scene.obj ; make sure your mesh has the correct name !!"; + return false; + } + if (!fileExists(pathSynthetic + "/cameras.lookat")) { + SIBR_WRG << "***** No file " << pathSynthetic + "/cameras.lookat ; make sure your bundle file has the correct name !!"; + return false; + } + if (!directoryExists(pathSynthetic + "/images")) { + SIBR_WRG << "***** No file " << pathSynthetic + "/images ; make sure you have images folder inside the scene "; + return false; + } + return true; +} + +static void loadRawSynthetic(std::string pathSynthetic, std::vector& cams2Align, + std::vector& imgs2Align, sibr::Mesh& mesh2Align) +{ + cams2Align = sibr::InputCamera::loadLookat(pathSynthetic + "/cameras.lookat", std::vector{sibr::Vector2u(1920, 1080)}, 0.01f, 1000.0f); + SIBR_WRG << "We assume a size of the synthetic images of 1920*1080. If it is not your case, this loading will not work properly"; + mesh2Align.load(pathSynthetic + "/scene.obj"); + imgs2Align.resize(cams2Align.size()); + for (int c = 0; c < cams2Align.size(); c++) { + sibr::ImageRGB::Ptr imgPtr; + sibr::ImageRGB img; + if (!img.load(pathSynthetic + "/images/" + cams2Align[c]->name())) + if (!img.load(pathSynthetic + "/images/" + cams2Align[c]->name() + ".png")) + if (!img.load(pathSynthetic + "/images/" + cams2Align[c]->name() + ".jpg")) { + SIBR_ERR << "Error loading dataset to align from " << pathSynthetic; + SIBR_ERR << "Problem loading images from raw RC, exiting "; + } + + imgs2Align[c] = img.clonePtr(); + } +} + + +int assignImages( + std::vector& imgs2Align, std::vector& imgs2AlignSmall, + std::vector& imgsRef, std::vector& imgsRefSmall, + std::map& alignCamToRef, std::vector& camsRef, std::vector cams2Align, + int resizeW, std::set& assignedCam, float threshold) +{ + int assignCnt = 0; + std::cout << "Assigning " << imgs2Align.size() << " cameras from the set to align to the fixed one: "; + //We then look for closest match and assign it only if the distance between the images is half the median distance + //This prevent issues in the case were a camera is missing from one set + for (int i = 0; i < imgs2Align.size(); i++) { + + std::cout << "Assigning camera " << i << ", "; + + sibr::ImageRGB& im2Align = imgs2AlignSmall[i]; + sibr::Vector2i pos2Align(resizeW / 2, im2Align.h() / 2); + + double minImDist = DBL_MAX; + int bestIm = -1; + + std::vector dists; + std::cerr << "2 ALIGN TESTING " << std::endl; + + cv::Rect centerROI(im2Align.w() / 8, im2Align.h() / 8, 6 * im2Align.w() / 8, 6 * im2Align.h() / 8); + + for (int j = 0; j < imgsRef.size(); j++) { + if (assignedCam.find(j) != assignedCam.end()) + continue; + + sibr::ImageRGB& imRef = imgsRefSmall[j]; + double minDist = DBL_MAX; + int wIm = imRef.w(); + int hIm = imRef.h(); + + for (int dx = -wIm / 8; dx <= wIm / 8; dx += 4) { + for (int dy = -hIm / 8; dy <= hIm / 8; dy += 4) { + cv::Rect shiftROI(dx + wIm / 8, dy + hIm / 8, 6 * wIm / 8, 6 * hIm / 8); + double d = cv::norm(imRef.toOpenCV()(shiftROI), im2Align.toOpenCV()(centerROI)); + if (d < minDist) + { + minDist = d; + } + } + } + + dists.push_back(minDist); + + if (minDist < minImDist) { + minImDist = minDist; + bestIm = j; + + //show(imRef); + //show(im2Align); + } + } + + std::sort(dists.begin(), dists.end()); + std::cerr << " SIZe " << dists.size() << " min " << minImDist << " half " << threshold * dists[dists.size() / 2] << std::endl; + if (dists.size() > 5 && minImDist < threshold * dists[dists.size() / 2]) { + alignCamToRef[i] = bestIm; + assignedCam.emplace(bestIm); + std::wcout << i << " -> " << bestIm << " -- " << cams2Align[i]->name().c_str() << " -> " << camsRef[bestIm]->name().c_str() << std::endl; + assignCnt++; + } + else { + alignCamToRef[i] = -1; + std::wcout << i << " -> " << "Not assigned " << std::endl; + std::wcout << i << " BEST MATCH -> " << bestIm << " -- " << cams2Align[i]->name().c_str() << " -> " << camsRef[bestIm]->name().c_str() << std::endl; + } + + //show(imgs2Align[i]); + //show(imgsRef[bestIm]); + + } + return assignCnt; +} + +InputCamera rot90CC(InputCamera::Ptr& in) +{ + InputCamera rotCam = *in; + rotCam.size(rotCam.h(), rotCam.w()); + rotCam.aspect(1.0f / rotCam.aspect()); + rotCam.fovy(2.0 * atan(0.5 * rotCam.h() / rotCam.focal())); + rotCam.setLookAt(rotCam.position(), rotCam.position() + rotCam.dir(), rotCam.right()); + return rotCam; +} + + +struct AlignMeshesArgs : + virtual BasicIBRAppArgs { + RequiredArg pathRef = { "pathRef", "Path to the fixed scene" }; + RequiredArg pathToAlign = { "path2Align", "Path to the scene to align" }; + RequiredArg outPath = { "out", "Path to the folder where to write the transformed mesh and the matrix" }; + Arg forceLandscape = { "forceLandscape", "Option to force all images to be in landscape orientation before image assignation and correspondances computation" }; + Arg saveScene = { "saveScene", "If true saves entire scene, else only save the transformed mesh and transform.txt file in out dir" + }; +}; + +int main(int ac, char** av) +{ + // Parse Commad-line Args + CommandLineArgs::parseMainArgs(ac, av); + AlignMeshesArgs myArgs; + + //sibr::Window window(100, 100, "Window"); + sibr::Window window(PROGRAM_NAME, sibr::Vector2i(50, 50), myArgs); + int wRender, hRender; + + std::cout << "This method relies on images, cameras and meshes of both scenes." << std::endl; + + // Here is the data strctures that we will use for this program to make it as generic as possible + std::vector imgsRef; + std::vector imgs2AlignOriginal; + std::vector imgs2Align; + + std::vector imgsRefSmall; + std::vector imgs2AlignSmall; + + std::vector camsRef; + std::vector cams2Align; + + sibr::Mesh meshRef; + sibr::Mesh mesh2Align; + //Create the two scenes + + //Load the reference data + IParseData::Type refSceneType; + if (myArgs.pathRef.get() == "") + SIBR_ERR << "Reference path empty"; + BasicIBRAppArgs argsRefScene; + argsRefScene.dataset_path = myArgs.pathRef.get(); + + try { + BasicIBRScene::Ptr sceneRef(new BasicIBRScene(argsRefScene, true)); + + if ((refSceneType = sceneRef->data()->datasetType()) != IParseData::Type::EMPTY) { + meshRef = sceneRef->proxies()->proxy(); + imgsRef = sceneRef->images()->inputImages(); + camsRef = sceneRef->cameras()->inputCameras(); + } + else + SIBR_ERR << "Error loading reference dataset from " << myArgs.pathRef.get(); + } + + catch(...) { + std::cout << "Trying to load Raw RealityCapture or Synthetic data" << std::endl; + if (isRawRC(argsRefScene.dataset_path)) { // try "raw RC" option + loadRawRC(argsRefScene.dataset_path, camsRef, imgsRef, meshRef); + } + else if (isRawSynthetic(argsRefScene.dataset_path)) { + loadRawSynthetic(argsRefScene.dataset_path, camsRef, imgsRef, meshRef); + } + else + SIBR_ERR << "Error loading reference dataset from " << myArgs.pathRef.get(); + } + + + //Load the data for the scene to align + if (myArgs.pathToAlign.get() == "") + SIBR_ERR << "Path to mesh to align empty"; + BasicIBRAppArgs argsAlignScene; + argsAlignScene.dataset_path = myArgs.pathToAlign.get(); + // + try { + BasicIBRScene::Ptr sceneAlign(new BasicIBRScene(argsAlignScene, true)); + + if (sceneAlign->data()->datasetType() != IParseData::Type::EMPTY) { + mesh2Align = sceneAlign->proxies()->proxy(); + imgs2AlignOriginal = sceneAlign->images()->inputImages(); + cams2Align = sceneAlign->cameras()->inputCameras(); + } + else { + SIBR_ERR << "Error loading dataset to align from " << myArgs.pathToAlign.get(); + } + } + + + catch(...) { + std::cout << "Trying to load Raw RealityCapture or Synthetic data" << std::endl; + if (isRawRC(argsAlignScene.dataset_path)){ // try "raw RC" option + loadRawRC(argsAlignScene.dataset_path, cams2Align, imgs2AlignOriginal, mesh2Align); + } + else if (isRawSynthetic(argsAlignScene.dataset_path)) { + loadRawSynthetic(argsAlignScene.dataset_path, cams2Align, imgs2AlignOriginal, mesh2Align); + } + else + SIBR_ERR << "Error loading dataset to align from " << myArgs.pathToAlign.get(); + } + + if (myArgs.forceLandscape) { + for (int c = 0; c < camsRef.size(); c++) { + if (imgsRef[c]->h() > imgsRef[c]->w()) { + //rotate the image + cv::rotate(imgsRef[c]->toOpenCV(), imgsRef[c]->toOpenCVnonConst(), cv::ROTATE_90_COUNTERCLOCKWISE); + //rotate the camera + *camsRef[c] = rot90CC(camsRef[c]); + } + + } + for (int c = 0; c < cams2Align.size(); c++) { + if (imgs2AlignOriginal[c]->h() > imgs2AlignOriginal[c]->w()) { + cv::rotate(imgs2AlignOriginal[c]->toOpenCV(), imgs2AlignOriginal[c]->toOpenCVnonConst(), cv::ROTATE_90_COUNTERCLOCKWISE); + //rotate the camera + *cams2Align[c] = rot90CC(cams2Align[c]); + } + } + + } + + + //We resize the input images to the same width to account for possible rescale between the two scenes +#pragma omp parallel for + for (int c = 0; c < camsRef.size(); c++) { + *imgsRef[c] = imgsRef[c]->resized(1024, 1024.0f * imgsRef[c]->h() / imgsRef[c]->w(), cv::INTER_LINEAR); + } + + for (int c = 0; c < cams2Align.size(); c++) { + imgs2Align.push_back(sibr::ImageRGB::Ptr(new sibr::ImageRGB())); + } +#pragma omp parallel for + for (int c = 0; c < cams2Align.size(); c++) { + *imgs2Align[c] = imgs2AlignOriginal[c]->resized(1024, 1024.0f * imgs2AlignOriginal[c]->h() / imgs2AlignOriginal[c]->w(), cv::INTER_LINEAR); + } + + //Create output dir + std::string outPath; + outPath = myArgs.outPath.get(); + //First create all the needed directories + sibr::makeDirectory(outPath); + + //We now match images between the two scenes as we cannot rely on correspondance between cameras + //First we make all image 512*512 + int resizeW = 512; + cv::Rect centerROI(resizeW / 4, resizeW / 4, resizeW / 2, resizeW / 2); + std::map alignCamToRef; + std::set assignedCam; + + std::cout << "Resizing images" << std::endl; + + imgs2AlignSmall.resize(imgs2Align.size()); +#pragma omp parallel for + for (int i = 0; i < imgs2Align.size(); i++) { + imgs2AlignSmall[i] = imgs2Align[i]->resized(resizeW, resizeW, cv::INTER_AREA); + imgs2AlignSmall[i].fromOpenCV(imgs2AlignSmall[i].toOpenCV()(centerROI)); + } + imgsRefSmall.resize(imgsRef.size()); +#pragma omp parallel for + for (int i = 0; i < imgsRef.size(); i++) { + imgsRefSmall[i] = imgsRef[i]->resized(resizeW, resizeW, cv::INTER_AREA); + imgsRefSmall[i].fromOpenCV(imgsRefSmall[i].toOpenCV()(centerROI)); + } + + int cnt = assignImages(imgs2Align, imgs2AlignSmall, imgsRef, imgsRefSmall, alignCamToRef, camsRef, cams2Align, resizeW, assignedCam, 0.7); + std::cout << "Assigned " << cnt << std::endl; + + ///////////////// + ///////////////// + // Now we will compute closely matched feature between pair of images + ///////////////// + ///////////////// + + std::vector listFeatPRef; + std::vector listFeatP2Align; + + std::vector dist2CamRef; + std::vector dist2Cam2Align; + + //Maximum shift for patch alignement + int shiftMax = 16; + const int patchRadius = 8; + + for (int im = 0; im < imgs2Align.size(); im++) { + + if (alignCamToRef[im] < 0) + continue; + + std::cout << "IM " << im << std::endl; + + sibr::ImageRGB& imRef = *imgsRef[alignCamToRef[im]]; + sibr::ImageRGB& im2Align = *imgs2Align[im]; + + // To see feature match in images + sibr::ImageRGB imRefCopy = imRef.clone(); + sibr::ImageRGB im2AlignCopy = im2Align.clone(); + + //Compute im center to transpose position from imref to im2Align. The center should stay aligned with the crop. + //Small errors are absorbed by the shift estimation. + sibr::Vector2i imRefCenter(imRef.w() / 2, imRef.h() / 2); + sibr::Vector2i im2AlignCenter(im2Align.w() / 2, im2Align.h() / 2); + + //Get the two cameras + sibr::InputCamera::Ptr camRef = camsRef[alignCamToRef[im]]; + sibr::InputCamera::Ptr cam2Align = cams2Align[im]; + + //Depth map for 3D position estimation + sibr::ImageL32F depthMapRef, depthMap2Align; + + //We render the two depth map of the two meshes to be able to recover 3D position from pixel position + int wCamRef, hCamRef, wCam2Align, hCam2Align; + wCamRef = camRef->w(); + hCamRef = camRef->h(); + wCam2Align = cam2Align->w(); + hCam2Align = cam2Align->h(); + + std::cout << "Rendering reference DepthMap ..." << std::endl; + sibr::DepthRenderer rendererDepthRef(wCamRef, hCamRef); + glViewport(0, 0, wCamRef, hCamRef); + rendererDepthRef.render(*camRef, meshRef); + rendererDepthRef._depth_RT->readBack(depthMapRef); + + //showFloat(depthMapRef.resized(1024, 1024 * hCamRef / wCamRef)); + std::cout << "Rendering recon DepthMap ..." << std::endl; + + sibr::DepthRenderer rendererDepth2Align(wCam2Align, hCam2Align); + glViewport(0, 0, wCam2Align, hCam2Align); + rendererDepth2Align.render(*cam2Align, mesh2Align); + rendererDepth2Align._depth_RT->readBack(depthMap2Align); + + //showFloat(depthMap2Align.resized(1024, 1024 * hCam2Align / wCam2Align)); + const int stride = std::max(16.0, sqrt(imRef.w() * imRef.h() * imgs2Align.size() / 50000.0)); + std::wcout << " Stride:" << stride << std::endl; + + float ratioRefW = (float)depthMapRef.w() / imRefCopy.w(); + float ratioRefH = (float)depthMapRef.h() / imRefCopy.h(); + float ratio2AlignW = (float)depthMap2Align.w() / im2AlignCopy.w(); + float ratio2AlignH = (float)depthMap2Align.h() / im2AlignCopy.h(); + +#pragma omp parallel for + for (int i = patchRadius; i < imRef.w(); i += stride) { + for (int j = patchRadius; j < imRef.h(); j += stride) { + + sibr::Vector2i posRef(i, j); + //Corresponding position is estimated from the center because the two center of the images should be aligned + sibr::Vector2i pos2Align = im2AlignCenter + posRef - imRefCenter; + + + if (imRef.isInRange(i, j) + && imRef(i, j) != Vector3ub(0, 0, 0) + && im2Align.isInRange(pos2Align.x(), pos2Align.y()) + && im2Align.isInRange(pos2Align.x() - (shiftMax + patchRadius), pos2Align.y() - (shiftMax + patchRadius)) + && im2Align.isInRange(pos2Align.x() + shiftMax + patchRadius + 1, pos2Align.y() + shiftMax + patchRadius + 1)) { + + // To visualize feature match in images + imRefCopy(i, j) = sibr::Vector3ub(255, 0, 0); + im2AlignCopy(pos2Align.x(), pos2Align.y()) = sibr::Vector3ub(255, 0, 0); + + double minDist = DBL_MAX; + sibr::Vector2i bestShift(0, 0); + + //We find the best shift to refine our point matching + for (int k = -shiftMax; k <= shiftMax; k++) { + for (int l = -shiftMax; l <= shiftMax; l++) { + + sibr::Vector2i shift(k, l); + sibr::Vector2i pos2AlignShifted = pos2Align + shift; + + double dist = distPatch(imRef, posRef, im2Align, pos2AlignShifted, patchRadius); + + if (dist < minDist || (dist == minDist && shift.norm() < bestShift.norm())) { + bestShift = shift; + minDist = dist; + } + } + } + + sibr::Vector2i pos2AlignShifted = pos2Align + bestShift; + sibr::Vector2i posImFullRef(posRef.x() * ratioRefW, posRef.y() * ratioRefH); + sibr::Vector2i posImFull2Align(pos2AlignShifted.x() * ratio2AlignW, pos2AlignShifted.y() * ratio2AlignH); + + if (depthMapRef(posImFullRef.x(), posImFullRef.y()).x() != 1 && + depthMap2Align(posImFull2Align.x(), posImFull2Align.y()).x() != 1) { + // To see feature match in images + im2AlignCopy(pos2Align.x() + bestShift.x(), pos2Align.y() + bestShift.y()) = sibr::Vector3ub(0, 255, 0); + + float dRef = depthMapRef(posImFullRef.x(), posImFullRef.y()).x(); + sibr::Vector3f pos3DRef = camRef->unprojectImgSpaceInvertY( + posImFullRef, dRef); + + float d2Align = depthMap2Align(posImFull2Align.x(), posImFull2Align.y()).x(); + sibr::Vector3f pos3D2Align = cam2Align->unprojectImgSpaceInvertY( + posImFull2Align, d2Align); + + //Add those feature to the list +#pragma omp critical + { + if (pos3DRef == pos3DRef && pos3D2Align == pos3D2Align) { + listFeatPRef.push_back(pos3DRef); + listFeatP2Align.push_back(pos3D2Align); + + dist2CamRef.push_back((pos3DRef - camRef->position()).norm()); + dist2Cam2Align.push_back((pos3D2Align - cam2Align->position()).norm()); + } + else { + std::cout << "Skipping bad point" << std::endl; + } + } + } + + } + + } + } + + // To see feature match in images + //show(imRefCopy); + //show(im2AlignCopy); + + } + + //Now we will remove outliers that appears for several reason, one of them is obviously the part of the images where the content changed. + //We compute the median scale factor using the distances to cameras, and we only keep matches that respect this median + std::vector scalesfromCam; + for (int i = 0; i < dist2CamRef.size(); i++) { + scalesfromCam.push_back(dist2CamRef[i] / dist2Cam2Align[i]); + } + std::sort(scalesfromCam.begin(), scalesfromCam.end()); + float medianScale = scalesfromCam[scalesfromCam.size() / 2]; + std::cout << std::endl << "Median is " << medianScale << std::endl; + + std::vector listStrongFeatPRef; + std::vector listStrongFeatP2Align; + + //5% above and under the median + for (int i = 0; i < dist2CamRef.size(); i++) { + if (dist2CamRef[i] / dist2Cam2Align[i] > 0.95 * medianScale && + dist2CamRef[i] / dist2Cam2Align[i] < 1.05 * medianScale) { + listStrongFeatPRef.push_back(listFeatPRef[i]); + listStrongFeatP2Align.push_back(listFeatP2Align[i]); + } + } + + std::cout << "Cleaned matches: " << listFeatPRef.size() << " to " << listStrongFeatPRef.size() << std::endl; + + ///////// + ///////// + //Now we will estimate the transformation using irls. + ///////// + ///////// + + //Format the data + std::vector XData; + std::vector YData0; + std::vector YData1; + std::vector YData2; + + for (int i = 0; i < listStrongFeatPRef.size(); i++) { + XData.push_back(listStrongFeatP2Align[i].x()); + XData.push_back(listStrongFeatP2Align[i].y()); + XData.push_back(listStrongFeatP2Align[i].z()); + + YData0.push_back(listStrongFeatPRef[i].x()); + YData1.push_back(listStrongFeatPRef[i].y()); + YData2.push_back(listStrongFeatPRef[i].z()); + } + + /////////////// + //SOLVING WITH IRLS + int numX = listStrongFeatP2Align.size(); + // Convert std::vector to Eigen::VectorXf + Eigen::Map evY0(YData0.data(), numX); + Eigen::Map evY1(YData1.data(), numX); + Eigen::Map evY2(YData2.data(), numX); + + Eigen::Map > mX3(XData.data(), numX, 3); + + // Convert 3-column matrix into a 4-column one using all 1s for the last column. + Eigen::MatrixX4f mX4(mX3.rows(), 4); + mX4 << mX3, Eigen::ArrayXXf::Ones(mX3.rows(), 1); + +#define TUNING_CONSTANT 4.685 + Eigen::Vector4f vCoeffs0; + Eigen::Vector4f vCoeffs1; + Eigen::Vector4f vCoeffs2; + + // Run IRLS considering each of the Y-matrix's calumns as the target Y-vector individually. + // We get one row of the solution matrix at each step which is then put together to form the + // complete solution. + //Log(EInfo, "Running IRLS on row 0"); + irls(mX4, evY0, vCoeffs0, TUNING_CONSTANT); + //Log(EInfo, "Running IRLS on row 1"); + irls(mX4, evY1, vCoeffs1, TUNING_CONSTANT); + //Log(EInfo, "Running IRLS on row 2"); + irls(mX4, evY2, vCoeffs2, TUNING_CONSTANT); + //Log(EInfo, "Finished running IRLS"); + + // Put all the rows together. + Eigen::Matrix4f mFinal; + mFinal << vCoeffs0.x(), vCoeffs0.y(), vCoeffs0.z(), vCoeffs0.w(), + vCoeffs1.x(), vCoeffs1.y(), vCoeffs1.z(), vCoeffs1.w(), + vCoeffs2.x(), vCoeffs2.y(), vCoeffs2.z(), vCoeffs2.w(), + 0, 0, 0, 1; + + std::cout << "Matrix is:" << std::endl; + std::cout << vCoeffs0.x() << " " << vCoeffs0.y() << " " << vCoeffs0.z() << " " << vCoeffs0.w() << std::endl; + std::cout << vCoeffs1.x() << " " << vCoeffs1.y() << " " << vCoeffs1.z() << " " << vCoeffs1.w() << std::endl; + std::cout << vCoeffs2.x() << " " << vCoeffs2.y() << " " << vCoeffs2.z() << " " << vCoeffs2.w() << std::endl; + std::cout << 0 << " " << 0 << " " << 0 << " " << 1 << std::endl; + std::cout << medianScale << std::endl; // for xFormScene scale factor of 1 + + std::ofstream myfile; + myfile.open(outPath + "/transform.txt"); + myfile << vCoeffs0.x() << " " << vCoeffs0.y() << " " << vCoeffs0.z() << " " << vCoeffs0.w() << std::endl; + myfile << vCoeffs1.x() << " " << vCoeffs1.y() << " " << vCoeffs1.z() << " " << vCoeffs1.w() << std::endl; + myfile << vCoeffs2.x() << " " << vCoeffs2.y() << " " << vCoeffs2.z() << " " << vCoeffs2.w() << std::endl; + myfile << 0 << " " << 0 << " " << 0 << " " << 1 << std::endl; + myfile << 1 << std::endl; // for xFormScene scale factor of 1 + myfile.close(); + + //create new mesh : + Mesh alignedMesh = mesh2Align; + std::cout << "Input vertices num : " << mesh2Align.vertices().size(); + Mesh::Vertices newVertices; + for (sibr::Vector3f v : alignedMesh.vertices()) { + sibr::Vector4f v4(v.x(), v.y(), v.z(), 1.0); + newVertices.push_back((mFinal * v4).xyz()); + } + alignedMesh.vertices(newVertices); + std::cout << " Output vertices num : " << alignedMesh.vertices().size() << std::endl; + + if (myArgs.saveScene) { + sibr::makeDirectory(outPath + "/meshes"); + sibr::makeDirectory(outPath + "/cameras"); + sibr::makeDirectory(outPath + "/images"); + + //Save the meshes + alignedMesh.save(outPath + "/meshes/recon.ply", true); + alignedMesh.save(outPath + "/meshes/recon.obj", true); + + //Save the cameras + //transform first + for (auto& cam : cams2Align) { + sibr::Vector3f pos = cam->position(); + sibr::Vector3f center = cam->position() + cam->dir(); + sibr::Vector3f up = cam->position() + cam->up(); + pos = (mFinal * pos.homogeneous()).xyz(); + center = (mFinal * center.homogeneous()).xyz(); + up = (mFinal * up.homogeneous()).xyz(); + cam->setLookAt(pos, center, (up - pos).normalized()); + } + std::vector outCams; + for (const auto& cam : cams2Align) { + outCams.push_back(std::make_shared(*cam)); + } + + sibr::InputCamera::saveAsBundle(outCams, outPath + "/cameras/bundle.out"); + + //Save the images and metadata + std::ofstream outputSceneMetadata; + outputSceneMetadata.open(outPath + "/scene_metadata.txt"); + outputSceneMetadata << "Scene Metadata File\n" << std::endl; + outputSceneMetadata << "[list_images]\n " << std::endl; + + int im = 0; + for (const auto& camIm : cams2Align) { + + //std::string extensionFile = boost::filesystem::extension(camIm->name()); + std::ostringstream ssZeroPad; + ssZeroPad << std::setw(8) << std::setfill('0') << camIm->id(); + std::string newFileName = ssZeroPad.str() + ".jpg"; + imgs2AlignOriginal[im]->save(outPath + "/images/" + newFileName); + outputSceneMetadata << newFileName << " " << camIm->w() << " " << camIm->h() << " " << camIm->znear() << " " << camIm->zfar() << std::endl; + im++; + } + outputSceneMetadata << "\n// Always specify active/exclude images after list images\n\n[exclude_images]\n ... " << std::endl; + outputSceneMetadata << "\n\n\n[other parameters]" << std::endl; + outputSceneMetadata.close(); + } + else { // just save meshes (transform.txt saved above) + std::string textureFileName; + // could preserve texture name, but is probably cleaner to have standard name + textureFileName = "textured_u1_v1.png"; + + alignedMesh.save(outPath + "/mesh.ply", true, textureFileName); + alignedMesh.save(outPath + "/mesh.obj", true); + // save the mtl file + std::string mtlFileName = outPath + "/mesh.mtl"; + std::ofstream mtlFile; + mtlFile.open(mtlFileName); + mtlFile << "# File produced by SIBR\n\nnewmtl $Material_0\nKa 1 1 1\nKd 1 1 1\nd 1\nNs 0\nillum 1\nmap_Kd " << textureFileName; + mtlFile.close(); + } + + return EXIT_SUCCESS; +} + + + +template std::vector sort_indexes(const std::vector& v) { + + // initialize original index locations + std::vector idx(v.size()); + iota(idx.begin(), idx.end(), 0); + + // sort indexes based on comparing values in v + sort(idx.begin(), idx.end(), + [&v](size_t i1, size_t i2) {return v[i1] < v[i2]; }); + + return idx; +} + + + +void computeRT(std::vector A, std::vectorB, Matrix3f S, Matrix3f& R, sibr::Vector3f& T) { + + //finding R,T such that B = RA + T; + const int numPoint = B.size(); + //Scaling the points to align + std::vector AScaled; + for (int i = 0; i < numPoint; i++) { + AScaled.push_back(S * A[i]); + } + + //Computing the centroids + sibr::Vector3f centroidB(0, 0, 0); + sibr::Vector3f centroidA(0, 0, 0); + for (int i = 0; i < numPoint; i++) { + centroidB += B[i]; + centroidA += AScaled[i]; + } + centroidB /= numPoint; + centroidA /= numPoint; + + + //Now we estimate the rotation : + Matrix3f H; + H << 0, 0, 0, + 0, 0, 0, + 0, 0, 0; + + for (int i = 0; i < numPoint; i++) { + H += (AScaled[i] - centroidA) * (B[i] - centroidB).transpose(); + } + + Eigen::JacobiSVD svd(H, Eigen::ComputeThinU | Eigen::ComputeThinV); + + R = svd.matrixV() * svd.matrixU().transpose(); + if (R.determinant() < 0) { + //R.col(2) *= -1; + //std::cout << "Warning : determinant of rotation matrix is negative, multiplying last column by -1" << std::endl; + } + + //Translation estimation : + T = -R * centroidA + centroidB; + +} + +float computeS(std::vector A, std::vectorB, float& minScale, float& maxScale) { + //findin S such that A*S has the same scale as B + sibr::Vector3f meanPosA(0, 0, 0); + sibr::Vector3f meanPosB(0, 0, 0); + + for (int i = 0; i < A.size(); i++) { + meanPosA += A[i]; + meanPosB += B[i]; + } + + meanPosA /= A.size(); + meanPosB /= A.size(); + + float scale = 0; + for (int i = 0; i < A.size(); i++) { + + float scale_i = (B[i] - meanPosB).norm() / (A[i] - meanPosA).norm(); + scale += scale_i; + + if (scale_i > maxScale) + maxScale = scale_i; + if (scale_i < minScale) + minScale = scale_i; + } + + scale /= A.size(); + + return scale; +} + + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/cameraConverter/CMakeLists.txt b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/cameraConverter/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..b500df1c4de822571a2c04354e0c929879f43200 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/cameraConverter/CMakeLists.txt @@ -0,0 +1,31 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +project(cameraConverter) + +# Define build output for project +add_executable(${PROJECT_NAME} main.cpp) + +target_link_libraries(${PROJECT_NAME} + ${Boost_LIBRARIES} + sibr_system + sibr_assets + sibr_graphics +) + +set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER "projects/dataset_tools/preprocess") + +## High level macro to install in an homogen way all our ibr targets +include(install_runtime) +ibr_install_target(${PROJECT_NAME} + INSTALL_PDB ## mean install also MSVC IDE *.pdb file (DEST according to target type) + STANDALONE ${INSTALL_STANDALONE} ## mean call install_runtime with bundle dependencies resolution + COMPONENT ${PROJECT_NAME}_install ## will create custom target to install only this project +) diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/cameraConverter/main.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/cameraConverter/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..271a26ad98dfcbc764ae07bc2deadb376d7ea1e3 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/cameraConverter/main.cpp @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "core/system/CommandLineArgs.hpp" +#include "core/assets/InputCamera.hpp" + +using namespace sibr; + +/* Camera converter args. */ +struct CameraConverterArgs : virtual AppArgs { + RequiredArg input = { "input", "input camera file" }; + RequiredArg output = { "output", "output camera file" }; + RequiredArg colmapPath = { "colmapPath", "path to colmap recon for camera file" }; + Arg transfo = { "transfo", "", "matrix file" }; + Arg inputRes = {"ires", {1920, 1080}, "input camera resolution (not required for all formats)"}; + Arg outputRes = { "ores", {1920, 1080}, "output camera resolution (not required for all formats)" }; + Arg inverse = {"inverse", "reverse the transformation"}; + Arg bundleImageList = { "images_list", "for a bundle output, output list_images.txt" }; + Arg bundleImageFiles = { "images_files", "for a bundle output, output empty images in a 'visualize' subdirectory" }; + Arg inImageFilePath = { "in_images_files", "", "for a bundle input images file directory (for list_images etc)" }; + Arg scale = { "scale", 1.0, "scale images for cameras.txt file" }; +}; + +/* SIBR binary path loader helper. + * \param filename the .path binary file + * \param cams will be populated with the loaded cameras + * \param res the image resolution (for aspect ratio) + * \return the loading status + */ +bool load(const std::string& filename, std::vector & cams, const sibr::Vector2u & res){ + sibr::ByteStream stream; + if(!stream.load(filename)) { + return false; + } + int32 num = 0; + stream >> num; + while (num > 0) { + Camera cam; + stream >> cam; + cams.push_back(std::make_shared(cam, res[0], res[1])); + --num; + } + return stream; +} + +/** SIBR binary path saver helper. + * \param filename the .path output file + * \param cams the cameras to save + */ +void save(const std::string& filename, const std::vector & cams){ + sibr::ByteStream stream; + const int32 num = int32(cams.size()); + stream << num; + for (const InputCamera::Ptr& cam : cams) { + Camera subcam(*cam); + stream << subcam; + } + stream.saveToFile(filename); +} + + + +void colmapSave(const std::string& filename, const std::vector & xformPath, float scale, float focaly, float focalx) { + // save as colmap images.txt file + sibr::Matrix3f converter; + converter << 1, 0, 0, + 0, -1, 0, + 0, 0, -1; + + std::ofstream outputColmapPath, outputColmapPathCams; + std::string colmapPathCams = parentDirectory(filename) + std::string("/cameras.txt"); + + std::cerr << std::endl; + std::cerr << std::endl; + std::cerr << "Writing colmap path to " << parentDirectory(filename) << std::endl; + + outputColmapPath.open(filename); + if(!outputColmapPath.good()) + SIBR_ERR << "Cant open output file " << filename << std::endl; + outputColmapPathCams.open(colmapPathCams); + + outputColmapPathCams << "# Camera list with one line of data per camera:" << std::endl; + outputColmapPathCams << "# CAMERA_ID, MODEL, WIDTH, HEIGHT, PARAMS[]" << std::endl; + outputColmapPathCams << "# Number of cameras: 1" << std::endl; + if (focalx == -1) { + focalx = xformPath[0]->focal() * xformPath[0]->aspect(); // use aspect ratio + SIBR_WRG << "No focal x given making it equal to focaly * aspect ratio; use result at own risk. Should have a colmap dataset as input" << std::endl; + } + else + { + std::cerr << "FX " << focalx << std::endl; + focalx = xformPath[0]->focal() * (focalx / focaly); + SIBR_WRG << "Focal x set to f / (fx/fy); f of first image :" << focalx<w()*scale << " " << xformPath[0]->h()*scale + << " " << xformPath[0]->focal()*scale << " " << focalx*scale + << " " << xformPath[0]->w()*scale * 0.5 << " " << xformPath[0]->h()*scale * 0.5 << std::endl; + } + + + outputColmapPath<< "# Image list with two lines of data per image:" << std::endl; + outputColmapPath<< "# IMAGE_ID, QW, QX, QY, QZ, TX, TY, TZ, CAMERA_ID, NAME" << std::endl; + outputColmapPath<< "# POINTS2D[] as (X, Y, POINT3D_ID)" << std::endl; + for(int i=0; irotation().toRotationMatrix() * converter; + sibr::Matrix3f Qinv = tmp.transpose(); + sibr::Quaternionf q = quatFromMatrix(Qinv); + sibr::Vector3f t = -Qinv*xformPath[i]->position(); + + outputColmapPath << i << " " << q.w() << " " << -q.x() << " " << -q.y() << " " << -q.z() << " " << + t.x() << " " << t.y() << " " << t.z() << " " << 1 << " " << "pathImage"< cams; + const std::string ext = sibr::getExtension(args.input); + if(ext == "path") { + load(args.input, cams, args.inputRes); + } else if(ext == "lookat") { + cams = InputCamera::loadLookat(args.input, { args.inputRes }); + } else if (ext == "out") { + if (std::string(args.inImageFilePath) == "") + SIBR_ERR << "Please provide image file directory for bundler input (use option -in_images_files DIRECTORY_CONTAINING_LIST_IMAGES.txt )\nIf necessary use the generate_list_images.py script to generate list_images.txt " << std::endl; + cams = InputCamera::loadBundle(args.input, 0.01, 1000, args.inImageFilePath, true); + } else if (ext == "nvm") { + cams = InputCamera::loadNVM(args.input, 0.01f, 1000.0f, {args.inputRes}); + } else if (sibr::directoryExists(args.input)) { + // If we got a directory, assume colmap sparse. + cams = InputCamera::loadColmap(args.input, 0.01, 1000, 1); + } else { + SIBR_ERR << "Unsupported path file extension: " << ext << "." << std::endl; + return EXIT_FAILURE; + } + SIBR_LOG << "Loaded " << cams.size() << " cameras." << std::endl; + + float focaly = cams[0]->focal(); // y by default + float focalx = cams[0]->focalx(); + + // if a path is given try and get focalx + std::vector camsFx; + if (args.colmapPath != "") { + std::cerr << "COLMAP " << args.colmapPath << std::endl; + std::string cm_sparse_path = args.colmapPath.get() + "/stereo/sparse"; + if (directoryExists(cm_sparse_path)) { + camsFx = InputCamera::loadColmap(cm_sparse_path, 0.01, 1000, 1); + std::cerr << "Found " << camsFx.size() << " cameras fovx " << camsFx[0]->focalx() << std::endl; + focalx = camsFx[0]->focalx(); + } + else + std::cerr << "Cant find " << cm_sparse_path << std::endl; + } + + // Load the transformation. + std::ifstream transFile(args.transfo.get()); + sibr::Matrix4f transf = sibr::Matrix4f::Identity(); + if (transFile.is_open()) { + for (int i = 0; i < 16; ++i) { + float f; + transFile >> f; + transf(i) = f; + } + transFile.close(); + } + transf.transposeInPlace(); + if (args.inverse) { + transf = transf.inverse().eval(); + } + + // Apply transformation to each camera keypoints, if it's not identity. + if(!transf.isIdentity()) { + SIBR_LOG << "Applying transformation: " << std::endl << transf << std::endl; + for (auto & cam : cams) { + sibr::Vector3f pos = cam->position(); + sibr::Vector3f center = cam->position() + cam->dir(); + sibr::Vector3f up = cam->position() + cam->up(); + pos = (transf * pos.homogeneous()).xyz(); + center = (transf * center.homogeneous()).xyz(); + up = (transf * up.homogeneous()).xyz(); + cam->setLookAt(pos, center, (up - pos).normalized()); + + } + } + + // Save cameras. + const std::string outExt = sibr::getExtension(args.output); + if (outExt == "path") { + save(args.output, cams); + } else if (outExt == "out") { // bundler + std::vector outCams; + for(const auto & cam : cams) { + const int outH = int(args.outputRes.get()[1]); + const int outW = int(std::round(cam->aspect() * float(outH))); + InputCamera::Ptr oc; + outCams.push_back(oc=std::make_shared(*cam, outW, outH)); + // reset focal + oc->setFocal(cam->focal()); + } + sibr::InputCamera::saveAsBundle(outCams, args.output, args.bundleImageList, args.bundleImageFiles, false); + } else if (outExt == "lookat") { + std::vector outCams; + for (const auto& cam : cams) { + const int outH = int(args.outputRes.get()[1]); + const int outW = int(std::round(cam->aspect() * float(outH))); + outCams.push_back(std::make_shared(*cam, outW, outH)); + } + sibr::InputCamera::saveAsLookat(outCams, args.output); + } + else if (getFileName(args.output) == "images.txt" ) { // colmap + colmapSave(args.output, cams, args.scale, focaly, focalx); + } else { + SIBR_ERR << "Unsupported output file extension: " << outExt << "." << std::endl; + return EXIT_FAILURE; + } + SIBR_LOG << "Saved transformed cameras to \"" << args.output.get() << "\"." << std::endl; + + return EXIT_SUCCESS; +} + + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/clippingPlanes/CMakeLists.txt b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/clippingPlanes/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..90e46f355bc1db5532ed65802f62ccd5ed8365aa --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/clippingPlanes/CMakeLists.txt @@ -0,0 +1,38 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +project(clippingPlanes) + +# libraries used: +# * sibr graphics (vector2i class) +# * sibr system (programArg class) +# * boost filesystem (path class) +# * openmp + +# Define build output for project +add_executable(${PROJECT_NAME} main.cpp) + +target_link_libraries(${PROJECT_NAME} + ${Boost_LIBRARIES} + sibr_graphics + sibr_assets + sibr_raycaster + sibr_system +) + +set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER "projects/dataset_tools/preprocess") + +## High level macro to install in an homogen way all our ibr targets +include(install_runtime) +ibr_install_target(${PROJECT_NAME} + INSTALL_PDB ## mean install also MSVC IDE *.pdb file (DEST according to target type) + STANDALONE ${INSTALL_STANDALONE} ## mean call install_runtime with bundle dependencies resolution + COMPONENT ${PROJECT_NAME}_install ## will create custom target to install only this project +) diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/clippingPlanes/main.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/clippingPlanes/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fad65c828c29c2b9b79b8a989a763651ebb9adb2 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/clippingPlanes/main.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include +#include +#include +#include +#include +#include + +/* +generate clipping_planes.txt file +*/ +const char* USAGE = "Usage: clippingPlanes \n"; +const char* TAG = "[clippingPlanes]"; + +using namespace sibr; + + +int main(const int argc, const char** argv) +{ + + if (argc < 1 + 1) + { + std::cout << USAGE << std::endl; + return 1; + } + + std::string datasetPath = argv[1]; + + if (directoryExists(datasetPath) == false) { + SIBR_ERR << "Wrong program options, check the usage."; + return 1; + } + + // load rest of the things + std::vector inCams = InputCamera::load(datasetPath); + ImageListFile imageListFile; + Mesh proxy(false); + + // check needed things are there + if (imageListFile.load(datasetPath + "/images/list_images.txt") == false && imageListFile.load(datasetPath + "/list_images.txt") == false) + return 1; + + if ((proxy.load(datasetPath + "/meshes/pmvs_recon.ply") == false) && (proxy.load(datasetPath + "/meshes/mesh.ply") == false) && (proxy.load(datasetPath + "/pmvs_recon.ply") == false) && (proxy.load(datasetPath + "/recon.ply") == false) && (proxy.load(datasetPath + "/meshes/recon.ply") == false)) + return 1; + + const std::string clipping_planes_file_path = datasetPath + "/clipping_planes.txt"; + if (!sibr::fileExists(clipping_planes_file_path)) { + + std::vector nearsFars; + CameraRaycaster::computeClippingPlanes(proxy, inCams, nearsFars); + + std::ofstream file(clipping_planes_file_path, std::ios::trunc | std::ios::out); + if (file) { + for (const auto & nearFar : nearsFars) { + if (nearFar[0] > 0 && nearFar[1] > 0) { + file << nearFar[0] << ' ' << nearFar[1] << std::endl; + } + else { + /** \todo [SP]Temporary fix. Ideally we should exclude these images. */ + file << "0.1 100.0" << std::endl; + } + } + file.close(); + } + else { + SIBR_WRG << " Could not save file '" << clipping_planes_file_path << "'." << std::endl; + } + } + + std::cout << TAG << " done!\n"; + return 0; +} \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/CMakeLists.txt b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..f4b6ce3f40306104fd1025d39d18da79fcf4a43c --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/CMakeLists.txt @@ -0,0 +1,19 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +project(dataset_tools_converters) + +file(GLOB_RECURSE SCRIPTS "*.py" "*.sh" "*.mlx") + +add_custom_target(${PROJECT_NAME} ALL) + +include(install_runtime) +set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER "projects/dataset_tools/preprocess") +ibr_install_rsc(${PROJECT_NAME} TYPE "scripts" FILES ${SCRIPTS} RELATIVE) diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/bundle.py b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/bundle.py new file mode 100644 index 0000000000000000000000000000000000000000..8f1f30fa0d2121f6397806c8d913471e87b56f64 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/bundle.py @@ -0,0 +1,301 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# in python, elements declared outside __init__ are static (belong to the class) +# while ones declared inside __init__ belong to the object + +import os +import get_image_size # way faster than loading images in opencv and lightweighted (not as the case with python's pillow) +from enum import IntEnum + +class InputImage: + + def __init__(self, cam_id, path_to_image): + self.id = cam_id + self.path = path_to_image # absolute path + self.filename = os.path.basename(path_to_image) + width, height = get_image_size.get_image_size(path_to_image) + self.resolution = [width, height] + + def __str__(self): + return "{0}\t{1}\t{2}".format(self.path, self.resolution[0], self.resolution[1]) + # return str(self.filename) + delimiter + str(self.resolution[0]) + delimiter + str(self.resolution[1]) + #return "{0}\t{1}\t{2}".format(self.filename, self.resolution[0], self.resolution[1]) + + +class BundleFeaturePointLine (IntEnum): + POSITION = 0 + COLOR = 1 + VIEW_LIST = 2 + + +class BundleCamera: + + def __init__(self, cam_id, focal_length, radial_dist, rotation, translation): + self.id = cam_id + self.focal_length = focal_length + self.radial_dist = radial_dist + self.rotation = rotation + self.translation = translation + + # inverse index of feature points + self.list_of_feature_points = [] + + def add_feature_point (feature_point): + pass + + def set_feature_points (list_of_feature_points): + pass + + def scale_focal_length (self, factor): + self.focal_length = self.focal_length * factor + + def __str__(self): + first_line = "{0:g} {1:g} {2:g}\n".format(self.focal_length, self.radial_dist[0], self.radial_dist[1]) + second_line = "{0:g} {1:g} {2:g}\n".format(self.rotation[0][0], self.rotation[0][1], self.rotation[0][2]) + third_line = "{0:g} {1:g} {2:g}\n".format(self.rotation[1][0], self.rotation[1][1], self.rotation[1][2]) + fourth_line = "{0:g} {1:g} {2:g}\n".format(self.rotation[2][0], self.rotation[2][1], self.rotation[2][2]) + fifth_line = "{0:g} {1:g} {2:g}".format(self.translation[0], self.translation[1], self.translation[2]) + return first_line + second_line + third_line + fourth_line + fifth_line + + +class BundleFeaturePoint: + + def __init__(self, feature_point_id, position, color, view_list): + self.id = feature_point_id + self.position = position + self.color = color # each channel between [0, 255] + + # list of cameras + # each camera has the following info: + # ( ) # (x,y) floating point value with (0,0) center of the img + self.view_list = view_list + # for colmap conversion + self.point2d_index = {} + + def remove_cam(self, cam_id): + for index in range (len(self.view_list)): + if (self.view_list[index][0] == cam_id): + del self.view_list[index] + break + # fix all subsequent indices + + newlist = [] + nr1 = len(self.view_list) + change = False + for vl_item in self.view_list: + newitem = list(vl_item) + if (vl_item[0] > cam_id): +# change = True + newitem[0] = newitem[0]-1 + newlist.append(tuple(newitem)) + else: + newlist.append(vl_item) + + if change: + print("NEW : {}\n".format( newlist )) + print("OLD : {}\n".format( self.view_list )) + + self.view_list = newlist + + def __str__(self): + first_line = "{0:g} {1:g} {2:g}\n".format(self.position[0], self.position[1], self.position[2]) + second_line = "{0} {1} {2}\n".format(self.color[0], self.color[1], self.color[2]) + third_line = str(len(self.view_list)) + " " + cam_index = 0 + for view_info in self.view_list: + third_line = third_line + "{0:g} {1:g} {2:g} {3:g}".format(view_info[0], view_info[1], view_info[2], view_info[3]) + if (cam_index != len(self.view_list) - 1): + third_line = third_line + " " + cam_index = cam_index + 1 + return first_line + second_line + third_line + +class Bundle: + + MAX_NR_FEATURE_POINTS = 8000000 # if bundle file has more than this limit, features will not be processed at all + + def __init__(self, path_to_bundle): + # read bundle file + input_file = open(path_to_bundle, "r") + + # first line is the header containing bundle version + self.header = input_file.readline().strip() + self.nr_cameras, self.nr_feature_points = map(int, input_file.readline().strip().split(" ")) + + self.using_feature_points = (self.nr_feature_points < Bundle.MAX_NR_FEATURE_POINTS) + if (not self.using_feature_points): + self.nr_feature_points = 0 + print ("[bundle.py] Warning: Too many feature points. They are going to be discarded") + + self.list_of_cameras = [] + self.list_of_feature_points = [] + + for i in range(self.nr_cameras): + # read each camera + focal_length, radial_dist_x, radial_dist_y = map(float, input_file.readline().strip().split(" ")) + r11, r12, r13 = map(float, input_file.readline().strip().split(" ")) + r21, r22, r23 = map(float, input_file.readline().strip().split(" ")) + r31, r32, r33 = map(float, input_file.readline().strip().split(" ")) + tx, ty, tz = map(float, input_file.readline().strip().split(" ")) + + camera = BundleCamera(i, focal_length, (radial_dist_x, radial_dist_y), [ [r11, r12, r13], [r21, r22, r23], [r31, r32, r33] ], [tx, ty, tz]) + + self.list_of_cameras.append(camera) + + if (self.using_feature_points): + # keep reading input file + # read feature points (sometimes there aren't as many as reported in the header) + # display a warning when this happens + type_of_line_to_read = BundleFeaturePointLine.POSITION + + feature_point_position = None + feature_point_color = None + feature_point_view_list = None + feature_point_id = 0 + + for line in input_file: + if (type_of_line_to_read == BundleFeaturePointLine.POSITION): + x, y, z = map(float, line.strip().split(" ")) + feature_point_position = [x, y, z] + elif (type_of_line_to_read == BundleFeaturePointLine.COLOR): + r, g, b = map(int, line.strip().split(" ")) + feature_point_color = [r, g, b] + elif (type_of_line_to_read == BundleFeaturePointLine.VIEW_LIST): + tokens = line.split() + nr_cams_that_see_point = int(tokens[0]) + list_of_view_info = [] + for i in range(nr_cams_that_see_point): + cam_id = int (tokens[1 + i*4+0]) + sift = int (tokens[1 + i*4+1]) + x_pos = float (tokens[1 + i*4+2]) + y_pos = float (tokens[1 + i*4+3]) + list_of_view_info.append( (cam_id, sift, x_pos, y_pos) ) + + # add feature point to the list of feature points contained in the bundle + feature_point = BundleFeaturePoint(feature_point_id, feature_point_position, feature_point_color, list_of_view_info) + + # for colmap conversion + for v in list_of_view_info: + if v[0] >= len(self.list_of_cameras): + print("ERROR ", v[0], " ", len(self.list_of_cameras)) + else: + self.list_of_cameras[v[0]].list_of_feature_points.append(feature_point) + + feature_point_id = feature_point_id + 1 + + self.list_of_feature_points.append(feature_point) + + type_of_line_to_read = (type_of_line_to_read + 1) % len (BundleFeaturePointLine) + + # done processing input file + input_file.close() + + # paths + self.path_to_bundle_file = path_to_bundle + self.root_directory = os.path.dirname(path_to_bundle) + + # get absolute path to input images + image_id = 0 + self.list_of_input_images = [] + for file_in_dir in os.listdir( self.root_directory ): + # input imgs have a [jpg|jpeg|png] extension + if (file_in_dir.lower().endswith(".jpg" ) or file_in_dir.lower().endswith(".png" ) or file_in_dir.lower().endswith(".jpeg")): + # input images must also have a numerical filename (avoid reading things as texture images that are stored in the same folder) + if (os.path.splitext(file_in_dir)[0].isdigit()): + absolute_path = os.path.join(self.root_directory, file_in_dir) + image = InputImage(image_id, absolute_path) + self.list_of_input_images.append(image) + image_id = image_id + 1 + + # additional data + self.list_of_excluded_cams = [] + self.has_right_nr_feature_pts = False + self.has_right_nr_images = (len(self.list_of_cameras) == len(self.list_of_input_images)) + + if (not self.has_right_nr_images): + print ("[bundle.py] Warning: nr cameras in bundle file (" + str(len(self.list_of_cameras)) + ") is not the same as nr of images in " + self.root_directory + " (" + str(len(self.list_of_input_images)) + ")") + + print ("[bundle.py] Message: Done reading bundle file", path_to_bundle) + print ("[bundle.py] Message: Nr cams in bundle file", len(self.list_of_cameras)) + print ("[bundle.py] Message: Nr images in root folder", len(self.list_of_input_images)) + print ("[bundle.py] Message: Nr feature points", len(self.list_of_feature_points)) + + def get_avg_resolution (self): + result = [0, 0] + for image in self.list_of_input_images: + result[0] = result[0] + image.resolution[0] + result[1] = result[1] + image.resolution[1] + if (len(self.list_of_input_images) != 0): + result[0] = (int)(result[0] / len(self.list_of_input_images)) + result[1] = (int)(result[1] / len(self.list_of_input_images)) + return result + + def generate_list_of_images_file (self, path_to_output): + output_file = open (path_to_output, "w") + for image in self.list_of_input_images: + output_file.write(str(image) + '\n') + output_file.close() + + + def scale (self, factor): + for cam in self.list_of_cameras: + cam.scale_focal_length(factor) + + def exclude_cams (self, cam_list, verbose = True): + if (verbose): + print ("[bundle.py] Message: excluding images", cam_list) + # calling this method twice doesn't make sense because + # we need to make sure the index passed refer to the right cameras to remove + + # sort list of cams to exclude by decreasing order + cam_list.sort(reverse=True) + for index in cam_list: + # don't forget to go through feature points and remove ref to cam + for feature_point in self.list_of_feature_points: + feature_point.remove_cam(index) + + # log the cam id that was removed by adding it to the internal list of excluded cams + self.list_of_excluded_cams.append(index) + + del self.list_of_cameras[index] + del self.list_of_input_images[index] + + # update nr_cameras attribute + self.nr_cameras = len (self.list_of_cameras) + + def save (self, path_to_output_file, new_res=[]): + output_file = open(path_to_output_file, "w") + + output_file.write(self.header + '\n') + output_file.write(str(self.nr_cameras) + " " + str(self.nr_feature_points) + '\n') + + if new_res == []: + for cam in self.list_of_cameras: + output_file.write(str(cam) + '\n') + else: + # not needed TODO: verify + #indx = 0 + for cam in self.list_of_cameras: + #im = self.list_of_input_images[indx] + #old_w = im.resolution[0] + #old_h = im.resolution[1] + #new_focal = cam.focal_length*(min(old_h/new_res[1], old_w/new_res[0])) + #print("Old : ", cam.focal_length, " New : " , new_focal) + #cam.focal_length = new_focal + output_file.write(str(cam) + '\n') + #indx = indx + 1 + + for feature_point in self.list_of_feature_points: +# print("Writing ", len(feature_point.view_list) , " FEATURE POINTS " ) + if len(feature_point.view_list)> 0: + output_file.write(str(feature_point) + '\n') + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/colmap2sibr.py b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/colmap2sibr.py new file mode 100755 index 0000000000000000000000000000000000000000..69f66b72a48048d604bb4d9831b6f4520d128f9d --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/colmap2sibr.py @@ -0,0 +1,99 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +#!/usr/bin/env python +#! -*- encoding: utf-8 -*- + +""" @package dataset_tools_preprocess +This script calls meshlab to simplify a mesh + +Parameters: --h help, + --path + +Usage: python colmap2sibr.py --path [required] + +""" + +import os, sys +import argparse +import os, sys, getopt +import re +from utils.commands import getProcess +from utils.paths import getBinariesPath +from utils.commands import runCommand +import subprocess +from pathlib import Path + + +def checkColmapConsistent(pathdir): + colmapDir = Path(pathdir+"/colmap") + + if not os.path.isdir(colmapDir): + return False + + # check for mesh + colmapmesh = Path(pathdir+"/colmap/stereo/meshed-delaunay.ply") + if not os.path.isfile(colmapmesh): + print("SIBR_ERROR: colmap directory exists but there is no mesh ", colmapmesh) + print("No file", colmapmesh) + return False + + return True + +def main(): + parser = argparse.ArgumentParser() + + # common arguments + parser.add_argument("--path", type=str, required=True, help="path to dataset folder") + + args = vars(parser.parse_args()) + + if not checkColmapConsistent(args['path']): + print("SIBR_ERROR Colmap hasnt been run properly; run it first (ie dont use --noColmap)") + sys.exit(1) + + # prepareColmap4Sibr: convert cameras and create bundle file put everything in sfm_mvs_cm, then run the normal preprocessing + # + prepareColmap_app = getProcess("prepareColmap4Sibr") + + prepareColmap_args = [prepareColmap_app, + "--path", args['path'], + ] + + print("Running prepareColmap4Sibr ", prepareColmap_args) + p_exit = subprocess.call(prepareColmap_args) + if p_exit != 0: + print("SIBR ERROR: prepareColmap4Sibr failed, exiting") + sys.exit(1) + + # run rc_to_sibr process to make all images have the same size and be compatible with spixelwarp pipeline + p_exit = subprocess.call(["python", "ibr_preprocess_rc_to_sibr.py", "-i", args['path']+"/sfm_mvs_cm", "-o", args['path']+"/sibr_cm"]) + if p_exit != 0: + print("SIBR_ERROR preprocess to sibr_cm failed"); + sys.exit(1) + + prepareColmap_app = getProcess("prepareColmap4Sibr") + + prepareColmap_args = [prepareColmap_app, + "--fix_metadata", + "--path", args['path'], + ] + + print("Running prepareColmap4Sibr to fix scene_dataset.txt ", prepareColmap_args) + p_exit = subprocess.call(prepareColmap_args) + if p_exit != 0: + print("SIBR ERROR: prepareColmap4Sibr failed, exiting") + sys.exit(1) + + + sys.exit(0) + +if __name__ == "__main__": + main() diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/generate_list_images.py b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/generate_list_images.py new file mode 100644 index 0000000000000000000000000000000000000000..d8c10b413415392c38d91d71c5ece005051d56ae --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/generate_list_images.py @@ -0,0 +1,72 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import argparse, sys, os +from PIL import Image, UnidentifiedImageError + +def generateListImages(imagesPath, outputPath = None, filename = "list_images.txt"): + if not os.path.exists(imagesPath): + print("Path '%s' does not exists. Aborting." % imagesPath) + sys.exit(1) + + if not outputPath: + outputPath = imagesPath + elif not os.path.exists(outputPath): + print("Path '%s' does not exists. Aborting." % outputPath) + sys.exit(1) + + files = os.listdir(imagesPath) + + if not files: + print("No files found in directory '%s'. Aborting." % imagesPath) + sys.exit(1) + + with open(os.path.join(outputPath, filename), "w") as list_images: + for file in files: + try: + if os.path.isdir(os.path.join(imagesPath, file)): + raise UnidentifiedImageError() + with Image.open(os.path.join(imagesPath, file)) as image: + list_images.write("%s %s %s\n" % (file, image.width, image.height)) + except UnidentifiedImageError: + print("File '%s' is not a recognizable image. Skipping." % file) + + + +def main(): + parser = argparse.ArgumentParser() + + # common arguments + parser.add_argument("--imagesPath", type=str, required=True, help="path to your images folder") + parser.add_argument("--outputPath", type=str, default=None, help="output path where to place the list_images.txt") + parser.add_argument("--filename", type=str, default=None, help="filename for the image list") + + args = vars(parser.parse_args()) + + if not args["outputPath"]: + args["outputPath"] = args["imagesPath"] + elif not os.path.isdir(args["outputPath"]) and os.path.basename(args["outputPath"]) and not args["filename"]: + args["outputPath"], args["filename"] = os.path.split(args["outputPath"]) + + if not args["filename"]: + args["filename"] = "list_images.txt" + + print("Generating '%s' file from images in '%s' and saving to '%s'." % (args["filename"], args["imagesPath"], args["outputPath"])) + + generateListImages(os.path.abspath(args["imagesPath"]), os.path.abspath(args["outputPath"]), args["filename"]) + + print("'%s' generated successfully." % args["filename"]) + sys.exit(0) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/get_image_size.py b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/get_image_size.py new file mode 100644 index 0000000000000000000000000000000000000000..7d4e17c636d3bb53d6815b9218dec51340022a05 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/get_image_size.py @@ -0,0 +1,399 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +#!/usr/bin/env python +# -*- coding: utf-8 -*- +from __future__ import print_function +""" + +get_image_size.py +==================== + + :Name: get_image_size + :Purpose: extract image dimensions given a file path + + :Author: Paulo Scardine (based on code from Emmanuel VAÏSSE) + + :Created: 26/09/2013 + :Copyright: (c) Paulo Scardine 2013 + :Licence: MIT + +""" +import collections +import json +import os +import struct + +FILE_UNKNOWN = "Sorry, don't know how to get size for this file." + + +class UnknownImageFormat(Exception): + pass + + +types = collections.OrderedDict() +BMP = types['BMP'] = 'BMP' +GIF = types['GIF'] = 'GIF' +ICO = types['ICO'] = 'ICO' +JPEG = types['JPEG'] = 'JPEG' +PNG = types['PNG'] = 'PNG' +TIFF = types['TIFF'] = 'TIFF' + +image_fields = ['path', 'type', 'file_size', 'width', 'height'] + + +class Image(collections.namedtuple('Image', image_fields)): + + def to_str_row(self): + return ("%d\t%d\t%d\t%s\t%s" % ( + self.width, + self.height, + self.file_size, + self.type, + self.path.replace('\t', '\\t'), + )) + + def to_str_row_verbose(self): + return ("%d\t%d\t%d\t%s\t%s\t##%s" % ( + self.width, + self.height, + self.file_size, + self.type, + self.path.replace('\t', '\\t'), + self)) + + def to_str_json(self, indent=None): + return json.dumps(self._asdict(), indent=indent) + + +def get_image_size(file_path): + """ + Return (width, height) for a given img file content - no external + dependencies except the os and struct builtin modules + """ + img = get_image_metadata(file_path) + return (img.width, img.height) + + +def get_image_metadata(file_path): + """ + Return an `Image` object for a given img file content - no external + dependencies except the os and struct builtin modules + + Args: + file_path (str): path to an image file + + Returns: + Image: (path, type, file_size, width, height) + """ + size = os.path.getsize(file_path) + + # be explicit with open arguments - we need binary mode + with open(file_path, "rb") as input: + height = -1 + width = -1 + data = input.read(26) + msg = " raised while trying to decode as JPEG." + + if (size >= 10) and data[:6] in (b'GIF87a', b'GIF89a'): + # GIFs + imgtype = GIF + w, h = struct.unpack("= 24) and data.startswith(b'\211PNG\r\n\032\n') + and (data[12:16] == b'IHDR')): + # PNGs + imgtype = PNG + w, h = struct.unpack(">LL", data[16:24]) + width = int(w) + height = int(h) + elif (size >= 16) and data.startswith(b'\211PNG\r\n\032\n'): + # older PNGs + imgtype = PNG + w, h = struct.unpack(">LL", data[8:16]) + width = int(w) + height = int(h) + elif (size >= 2) and data.startswith(b'\377\330'): + # JPEG + imgtype = JPEG + input.seek(0) + input.read(2) + b = input.read(1) + try: + while (b and ord(b) != 0xDA): + while (ord(b) != 0xFF): + b = input.read(1) + while (ord(b) == 0xFF): + b = input.read(1) + if (ord(b) >= 0xC0 and ord(b) <= 0xC3): + input.read(3) + h, w = struct.unpack(">HH", input.read(4)) + break + else: + input.read( + int(struct.unpack(">H", input.read(2))[0]) - 2) + b = input.read(1) + width = int(w) + height = int(h) + except struct.error: + raise UnknownImageFormat("StructError" + msg) + except ValueError: + raise UnknownImageFormat("ValueError" + msg) + except Exception as e: + raise UnknownImageFormat(e.__class__.__name__ + msg) + elif (size >= 26) and data.startswith(b'BM'): + # BMP + imgtype = 'BMP' + headersize = struct.unpack("= 40: + w, h = struct.unpack("= 8) and data[:4] in (b"II\052\000", b"MM\000\052"): + # Standard TIFF, big- or little-endian + # BigTIFF and other different but TIFF-like formats are not + # supported currently + imgtype = TIFF + byteOrder = data[:2] + boChar = ">" if byteOrder == "MM" else "<" + # maps TIFF type id to size (in bytes) + # and python format char for struct + tiffTypes = { + 1: (1, boChar + "B"), # BYTE + 2: (1, boChar + "c"), # ASCII + 3: (2, boChar + "H"), # SHORT + 4: (4, boChar + "L"), # LONG + 5: (8, boChar + "LL"), # RATIONAL + 6: (1, boChar + "b"), # SBYTE + 7: (1, boChar + "c"), # UNDEFINED + 8: (2, boChar + "h"), # SSHORT + 9: (4, boChar + "l"), # SLONG + 10: (8, boChar + "ll"), # SRATIONAL + 11: (4, boChar + "f"), # FLOAT + 12: (8, boChar + "d") # DOUBLE + } + ifdOffset = struct.unpack(boChar + "L", data[4:8])[0] + try: + countSize = 2 + input.seek(ifdOffset) + ec = input.read(countSize) + ifdEntryCount = struct.unpack(boChar + "H", ec)[0] + # 2 bytes: TagId + 2 bytes: type + 4 bytes: count of values + 4 + # bytes: value offset + ifdEntrySize = 12 + for i in range(ifdEntryCount): + entryOffset = ifdOffset + countSize + i * ifdEntrySize + input.seek(entryOffset) + tag = input.read(2) + tag = struct.unpack(boChar + "H", tag)[0] + if(tag == 256 or tag == 257): + # if type indicates that value fits into 4 bytes, value + # offset is not an offset but value itself + type = input.read(2) + type = struct.unpack(boChar + "H", type)[0] + if type not in tiffTypes: + raise UnknownImageFormat( + "Unkown TIFF field type:" + + str(type)) + typeSize = tiffTypes[type][0] + typeChar = tiffTypes[type][1] + input.seek(entryOffset + 8) + value = input.read(typeSize) + value = int(struct.unpack(typeChar, value)[0]) + if tag == 256: + width = value + else: + height = value + if width > -1 and height > -1: + break + except Exception as e: + raise UnknownImageFormat(str(e)) + elif size >= 2: + # see http://en.wikipedia.org/wiki/ICO_(file_format) + imgtype = 'ICO' + input.seek(0) + reserved = input.read(2) + if 0 != struct.unpack(" 1: + import warnings + warnings.warn("ICO File contains more than one image") + # http://msdn.microsoft.com/en-us/library/ms997538.aspx + w = input.read(1) + h = input.read(1) + width = ord(w) + height = ord(h) + else: + raise UnknownImageFormat(FILE_UNKNOWN) + + return Image(path=file_path, + type=imgtype, + file_size=size, + width=width, + height=height) + + +import unittest + + +class Test_get_image_size(unittest.TestCase): + data = [{ + 'path': 'lookmanodeps.png', + 'width': 251, + 'height': 208, + 'file_size': 22228, + 'type': 'PNG'}] + + def setUp(self): + pass + + def test_get_image_metadata(self): + img = self.data[0] + output = get_image_metadata(img['path']) + self.assertTrue(output) + self.assertEqual(output.path, img['path']) + self.assertEqual(output.width, img['width']) + self.assertEqual(output.height, img['height']) + self.assertEqual(output.type, img['type']) + self.assertEqual(output.file_size, img['file_size']) + for field in image_fields: + self.assertEqual(getattr(output, field), img[field]) + + def test_get_image_metadata__ENOENT_OSError(self): + with self.assertRaises(OSError): + get_image_metadata('THIS_DOES_NOT_EXIST') + + def test_get_image_metadata__not_an_image_UnknownImageFormat(self): + with self.assertRaises(UnknownImageFormat): + get_image_metadata('README.rst') + + def test_get_image_size(self): + img = self.data[0] + output = get_image_size(img['path']) + self.assertTrue(output) + self.assertEqual(output, + (img['width'], + img['height'])) + + def tearDown(self): + pass + + +def main(argv=None): + """ + Print image metadata fields for the given file path. + + Keyword Arguments: + argv (list): commandline arguments (e.g. sys.argv[1:]) + Returns: + int: zero for OK + """ + import logging + import optparse + import sys + + prs = optparse.OptionParser( + usage="%prog [-v|--verbose] [--json|--json-indent] []", + description="Print metadata for the given image paths " + "(without image library bindings).") + + prs.add_option('--json', + dest='json', + action='store_true') + prs.add_option('--json-indent', + dest='json_indent', + action='store_true') + + prs.add_option('-v', '--verbose', + dest='verbose', + action='store_true',) + prs.add_option('-q', '--quiet', + dest='quiet', + action='store_true',) + prs.add_option('-t', '--test', + dest='run_tests', + action='store_true',) + + argv = list(argv) if argv is not None else sys.argv[1:] + (opts, args) = prs.parse_args(args=argv) + loglevel = logging.INFO + if opts.verbose: + loglevel = logging.DEBUG + elif opts.quiet: + loglevel = logging.ERROR + logging.basicConfig(level=loglevel) + log = logging.getLogger() + log.debug('argv: %r', argv) + log.debug('opts: %r', opts) + log.debug('args: %r', args) + + if opts.run_tests: + import sys + sys.argv = [sys.argv[0]] + args + import unittest + return unittest.main() + + output_func = Image.to_str_row + if opts.json_indent: + import functools + output_func = functools.partial(Image.to_str_json, indent=2) + elif opts.json: + output_func = Image.to_str_json + elif opts.verbose: + output_func = Image.to_str_row_verbose + + EX_OK = 0 + EX_NOT_OK = 2 + + if len(args) < 1: + prs.print_help() + print('') + prs.error("You must specify one or more paths to image files") + + errors = [] + for path_arg in args: + try: + img = get_image_metadata(path_arg) + print(output_func(img)) + except KeyboardInterrupt: + raise + except OSError as e: + log.error((path_arg, e)) + errors.append((path_arg, e)) + except Exception as e: + log.exception(e) + errors.append((path_arg, e)) + pass + if len(errors): + import pprint + print("ERRORS", file=sys.stderr) + print("======", file=sys.stderr) + print(pprint.pformat(errors, indent=2), file=sys.stderr) + return EX_NOT_OK + return EX_OK + + +if __name__ == "__main__": + import sys + sys.exit(main(argv=sys.argv[1:])) diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/ibr_convert_old_to_new.py b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/ibr_convert_old_to_new.py new file mode 100644 index 0000000000000000000000000000000000000000..5bc5f781070960e4341b81451a039ffb66acd7a5 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/ibr_convert_old_to_new.py @@ -0,0 +1,212 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# -------------------------------------------- +""" @package dataset_tools_preprocess +This script creates a SIBR template dataset from the old SIBR dataset which can be fed to a SIBR application + +Parameters: -h help, + -i , + -o [optional], + -r use release w/ debug symbols executables + +Usage: python ibr_preprocess_rc_to_sibr.py -i \sibr\install\bin\datasets\museum_sibr_old_preproc + -d \sibr\install\bin\datasets\museum_sibr_new_preproc2 + +""" + +import subprocess +import shutil +import os, sys, getopt +import re +from utils.commands import getProcess +from utils.paths import getBinariesPath + +from os import walk + +#-------------------------------------------- + +#=============================================================================== + +import struct +import imghdr + +def get_image_size(fname): + '''Determine the image type of fhandle and return its size. + from draco''' + with open(fname, 'rb') as fhandle: + head = fhandle.read(24) + if len(head) != 24: + return + if imghdr.what(fname) == 'png': + check = struct.unpack('>i', head[4:8])[0] + if check != 0x0d0a1a0a: + return + width, height = struct.unpack('>ii', head[16:24]) + elif imghdr.what(fname) == 'gif': + width, height = struct.unpack('H', fhandle.read(2))[0] - 2 + # We are at a SOFn block + fhandle.seek(1, 1) # Skip `precision' byte. + height, width = struct.unpack('>HH', fhandle.read(4)) + except Exception: #IGNORE:W0703 + return + else: + return + return width, height + +def checkOutput( output, force_continue ): + if( output != 0): + if( not force_continue ): + sys.exit() + else: + return False + else: + return True + + +#=============================================================================== + +#-------------------------------------------- +# 0. Paths, commands and options + +def main(argv, path_dest): + opts, args = getopt.getopt(argv, "hi:ro:", ["idir=", "bin="]) + executables_suffix = "" + executables_folder = getBinariesPath() + path_data = "" + for opt, arg in opts: + if opt == '-h': + print("-i path_to_old_dataset -d path_to_new_dataset [-r (use release w/ debug symbols executables)]") + sys.exit() + elif opt == '-i': + path_data = arg + print(['Setting path_data to ', path_data]) + elif opt == '-r': + executables_suffix = "_rwdi" + print("Using rwdi executables.") + elif opt == '-o': + path_dest = arg + print(['Setting path_dest to ', path_dest]) + + return (path_data, path_dest, executables_suffix, executables_folder) + +path_dest = "" +path_data, path_dest, executables_suffix, executables_folder = main(sys.argv[1:], path_dest) + +if(path_data == ""): + path_data = os.path.abspath(os.path.join(os.path.dirname(__file__), "../datasets")) + +if(path_dest == ""): + path_dest = path_data + +path_data = os.path.abspath(path_data + "/") + "/" +path_dest = os.path.abspath(path_dest + "/") + "/" + +path_in_imgs = path_data + + +print(['Raw_data folder: ', path_data]) +print(['Path_dest: ', path_dest]) + +#path_dest_pmvs = path_dest + "pmvs/models/"; +file_nameList = path_data + "images/list_images.txt"; +# path_scene_metadata = path_data + "scene_metadata.txt" + + +#-------------------------------------------- +# Create scene metadata file from list image file +scene_metadata = "Scene Metadata File\n\n" + +# read list image file +path_list_images = os.path.join(path_in_imgs, "list_images.txt") +list_images = [] + +print(path_list_images) +if os.path.exists(path_list_images): + list_image_file = open(path_list_images, "r") + + for line in list_image_file: + list_images.append(line) + + list_image_file.close() + +# read clipping planes file +path_clipping_planes = os.path.join(path_data, "clipping_planes.txt") +clipping_planes = [] + +if os.path.exists(path_clipping_planes): + clipping_planes_file = open(path_clipping_planes, "r") + + for line in clipping_planes_file: + line = line.strip('\n') + clipping_planes.append(line) + + clipping_planes_file.close() + + +if not os.path.exists(path_dest): + os.mkdir(path_dest) + +folder_to_create = ["images","cameras","meshes","textures"] +for f in folder_to_create: + if not os.path.exists(os.path.join(path_dest,f)): + os.mkdir(os.path.join(path_dest,f)) + +scene_metadata = scene_metadata + "[list_images]\n \n" + +for im in list_images: + print("copying: "+im.split(' ', 1)[0]) + shutil.copy( + os.path.join(path_data,im.split(' ', 1)[0]), + os.path.join(path_dest,"images",im.split(' ', 1)[0]) + ) + + if len(clipping_planes) is not 0: + scene_metadata = scene_metadata + im[:-1] + " " + clipping_planes[0] + "\n" + else: + scene_metadata = scene_metadata + im[:-1] + " 0.01 100\n" + +shutil.copy( + os.path.join(path_data,"list_images.txt"), + os.path.join(path_dest,"images","list_images.txt") + ) + +shutil.copy( + os.path.join(path_data,"bundle.out"), + os.path.join(path_dest,"cameras","bundle.out") + ) + +shutil.copy( + os.path.join(path_data,"pmvs/models/pmvs_recon.ply"), + os.path.join(path_dest,"meshes/recon.ply") + ) + +scene_metadata = scene_metadata + "\n\n// Always specify active/exclude images after list images\n\n[exclude_images]\n ... \n" + + +path_scene_metadata = os.path.join(path_dest, "scene_metadata.txt") + +scene_metadata_file = open(path_scene_metadata, "w") +scene_metadata_file.write(scene_metadata) +scene_metadata_file.close() \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/ibr_preprocess_rc_to_sibr.py b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/ibr_preprocess_rc_to_sibr.py new file mode 100644 index 0000000000000000000000000000000000000000..04448a43cdd3603711d388237c2471cf66d1e242 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/ibr_preprocess_rc_to_sibr.py @@ -0,0 +1,487 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# -------------------------------------------- +""" @package dataset_tools_preprocess +This script converts a Reality Capture dataset to SIBR template dataset which can be fed to an SIBR application + +Parameters: -h help, + -i , + -o [optional], + -r use release w/ debug symbols executables + +Usage: python ibr_preprocess_rc_to_sibr.py -r + -i \sibr\install\bin\datasets\museum_sibr_new_preproc_template_RCOut + -o \sibr\install\bin\datasets\museum_sibr_new_preproc2 + +""" + +import subprocess +import shutil +import os +import re +from utils.commands import getProcess +from utils.paths import getBinariesPath +from generate_list_images import generateListImages + +from os import walk + +# -------------------------------------------- + +from tempfile import mkstemp +from shutil import move +from os import remove, close + +# =============================================================================== + +import sys, getopt +import struct +import imghdr + +# =============================================================================== +import bundle + + +def get_image_size(fname): + '''Determine the image type of fhandle and return its size. + from draco''' + with open(fname, 'rb') as fhandle: + head = fhandle.read(24) + if len(head) != 24: + return + if imghdr.what(fname) == 'png': + check = struct.unpack('>i', head[4:8])[0] + if check != 0x0d0a1a0a: + return + width, height = struct.unpack('>ii', head[16:24]) + elif imghdr.what(fname) == 'gif': + width, height = struct.unpack('H', fhandle.read(2))[0] - 2 + # We are at a SOFn block + fhandle.seek(1, 1) # Skip `precision' byte. + height, width = struct.unpack('>HH', fhandle.read(4)) + except Exception: # IGNORE:W0703 + return + else: + return + return width, height + + +# =============================================================================== + +def replace(file_path, pattern, subst): + # Create temp file + fh, abs_path = mkstemp() + with open(abs_path, 'w') as new_file: + with open(file_path) as old_file: + for line in old_file: + new_file.write(line.replace(pattern, subst)) + close(fh) + # Remove original file + remove(file_path) + # Move new file + move(abs_path, file_path) + +def checkOutput( output, force_continue ): + """Check if an external process succeeded and if we should abort if something went wrong + + Args: + output (int): output of some external launched process (0=fine, 1 or greater=error) + force_continue (bool): should we continue anyway? + + Returns: + bool: True if last process succeeded + """ + if(output != 0): + if( not force_continue ): + sys.exit() + else: + return False + else: + return True + +def get_textured_mesh_base_name (source_folder): + """Return the base name of a textured mesh obtained with RealityCapture + + Args: + source_folder (str): path to dataset (bundle file, textured and images) + + Returns: + str: base name of .obj, .mtl and _u1_v1.png + """ + default_name = "textured" + for file_in_dir in os.listdir (source_folder): + if (file_in_dir.lower().endswith(".mtl")): + return os.path.splitext( file_in_dir )[0] + return default_name + + +def get_scale_factor (current_res, target_res): + """Return the scale factor needed to go from current_res to target_res. + The value is calculated based on the idea that we don't want to crop the input dataset anymore + and that we prefer to add black borders in order to reach the target resolution + + Args: + current_res (vec2): current dataset resolution + target_res (vec2): target dataset resolution + + Returns: + float: scale factor + """ + + # to go from current to target resolution, we have to options: + # either scale down current width to match target width and modify height accordingly + # or scalen down current height to match target height and modify width accordingly. + # we take the option that doesn't crop the remaining dimension and add the least black border + + # trying scaling down width + alpha_by_width = (float)(target_res[0]) / current_res[0] + adjusted_height = (int) (alpha_by_width * current_res[1]) + delta_height = target_res[1] - adjusted_height + + # trying scaling down height + alpha_by_height = (float)(target_res[1]) / current_res[1] + adjusted_width = (int) (alpha_by_height * current_res[0]) + delta_width = target_res[0] - adjusted_width + + # since we don't want to crop the input images even more, we considerer only + # the options were black borders need to be added + + if (delta_height < 0): + # height would need to be cropped. take the other option + return alpha_by_height + elif (delta_width < 0): + # width would need to be cropped. take the other option + return alpha_by_width + else: + # none of them need to be cropped. take option that adds less black border + return alpha_by_width if (delta_height < delta_width) else alpha_by_height + + + +# =============================================================================== + +# -------------------------------------------- +# 0. Paths, commands and options + +def main(argv, path_dest): + opts, args = getopt.getopt(argv, "hi:ro:", ["idir=", "bin="]) + executables_suffix = "" + executables_folder = getBinariesPath() + path_data = "" + for opt, arg in opts: + if opt == '-h': + print("-i path_to_rc_data_dir -o path_to_destination_dir [-r (use release w/ debug symbols executables)]") + sys.exit() + elif opt == '-i': + path_data = arg + print(['Setting path_data to ', path_data]) + elif opt == '-r': + executables_suffix = "_rwdi" + print("Using rwdi executables.") + elif opt == '-o': + path_dest = arg + print(['Setting path_dest to ', path_dest]) + elif opt in ('-bin', '--bin'): + executables_folder = os.path.abspath(arg) + + return (path_data, path_dest, executables_suffix, executables_folder) + + +path_dest = "" +path_data, path_dest, executables_suffix, executables_folder = main(sys.argv[1:], path_dest) + +if(path_data == ""): + path_data = os.path.abspath(os.path.join(os.path.dirname(__file__), "../datasets")) + +if(path_dest == ""): + path_dest = path_data + +path_data = os.path.abspath(path_data + "/") + "/" +path_dest = os.path.abspath(path_dest + "/") + "/" +executables_folder = os.path.abspath(executables_folder + "/") + "/" + +path_in_imgs = path_data +path_out_imgs = path_dest + "images/" + +print(['Raw_data folder: ', path_data]) +print(['Path_dest: ', path_dest]) +print(['Executables folder: ', executables_folder]) + +# dirs to create + +raw_data = "raw/" +cameras_dir = "cameras/" +images_dir = "images/" +pmvs_model_dir = "meshes/" +parentdir = os.path.dirname(os.path.split(path_dest)[0]) +print("COMPARE " , parentdir , " AND " , os.path.dirname(os.path.split(path_data)[0])) +if( parentdir == os.path.dirname(os.path.split(path_data)[0])): + capreal_dir = os.path.join(parentdir, "capreal/") + print("CAPREAL " , capreal_dir) + if not os.path.exists(capreal_dir): + os.makedirs(capreal_dir) + +dirs_to_create = [ raw_data, cameras_dir, images_dir, pmvs_model_dir] + +for dir_to_create in dirs_to_create: + path_to_dir = os.path.join(path_dest, dir_to_create) + if not os.path.exists(path_to_dir): + os.makedirs(path_to_dir) + + +################################# GLOBALS ###################################### + +# half size parameters +width_limit = 2500 +create_temp_folders = False + +input_bundle = bundle.Bundle(path_data + "bundle.out") + + +############################# RUN DISTORDCROP ################################## +# by calling distordCrop (preprocess/distordCrop), input images that have a +# resolution completely different from the average or that have too much +# black border added by RealityCapture will be listed in a exclude_images.txt file. +# A new proposed resolution will be also output in a file called cropNewSize.txt +# In order to accelerate this process and avoid loading the images multiple times, +# make sure that average resolution was already calculated and there is file called +# resolutions.txt in the dataset source folder containing the current resolution +# of each image. + +# distordCrop executable +crop_app = getProcess("distordCrop" + executables_suffix, executables_folder) + +# query current avera resolution in dataset +avg_resolution = input_bundle.get_avg_resolution() + +# generate resolutions.txt and put it in the current dataset folder +resolutions_txt_path = os.path.join(path_data, "resolutions.txt") +input_bundle.generate_list_of_images_file(resolutions_txt_path) + +# call distordCrop +p_exit = subprocess.call([crop_app, "--path", path_data, "--ratio", "0.3", "--avg_width", str(avg_resolution[0]), "--avg_height", str(avg_resolution[1]) ]) +print(crop_app, " exited with ", p_exit); +checkOutput(p_exit, False) + +# read new proposed resolution and check if images were discarded +exclude = [] +path_to_exclude_images_txt = os.path.join(path_data, "exclude_images.txt") +if (os.path.exists(path_to_exclude_images_txt)): + # list of excluded cameras (one line having all the camera ids to exclude) + exclusion_file = open(path_to_exclude_images_txt, "r") + line = exclusion_file.readline() + tokens = line.split() + + for cam_id in tokens: + exclude.append(int(cam_id)) + exclusion_file.close() + +# exclude cams from bundle file +input_bundle.exclude_cams (exclude) + +# read proposed cropped resolution +path_to_crop_new_size_txt = os.path.join(path_data, "cropNewSize.txt") +with open(path_to_crop_new_size_txt) as crop_size_file: + line = crop_size_file.readline() + tokens = line.split() + new_width = int(tokens[0]) + new_height = int(tokens[1]) + proposed_res = [new_width, new_height] + +print("crop size:", proposed_res) + +################################################################################ + +##################### TRANSFORM IMAGES TO TARGET RESOLUTION #################### +# we need to crop images to the previous proposed resolution (crop applied from the center). +# if a target resolution was passed as parameter, we also need to scale down the images +# and pad them with black borders in order to end up with the exact target resolution. +# Before padding the images, we need to have available the temporary result of the +# dataset scaled down in order to potentially call harmonize (which doesn't work with +# images that were padded with black borders). +# Scaled down dataset will be stored inside \/scaledDown +# and we will store the scale down factor in a scale_factor.txt file +target_res = None +if (proposed_res[0] > width_limit): + half_width = (int)(proposed_res[0] * 0.5) + half_height = (int)(proposed_res[0] * 0.5) + target_res = [half_width, half_height] + +# cropFromCenter executable +crop_from_center_app = getProcess("cropFromCenter" + executables_suffix, executables_folder) + +# generate file with list of current selected images to process +path_to_transform_list_txt = os.path.join (path_data, "toTransform.txt") +input_bundle.generate_list_of_images_file(path_to_transform_list_txt) + +crop_from_center_args = [crop_from_center_app, + "--inputFile", path_to_transform_list_txt, + "--outputPath", path_out_imgs, + "--avgResolution", str(avg_resolution[0]), str(avg_resolution[1]), + "--cropResolution", str(proposed_res[0]), str(proposed_res[1]) +] + +# calculate scale factor and how to achieve target resolution +# scaled dataset will be store in destionation_folder/scaled +if (target_res is not None): + scale_factor = get_scale_factor(proposed_res, target_res) + crop_from_center_args.extend([ + "--scaleDownFactor", str(scale_factor), + "--targetResolution", str(target_res[0]), str(target_res[1]) + ]) + +# call cropFromCenter +p_exit = subprocess.call(crop_from_center_args) +print(crop_from_center_app, " exited with ", p_exit); +checkOutput(p_exit, False) + +# write bundle file in output cameras folder +path_to_output_bundle = os.path.join (path_dest, cameras_dir, "bundle.out") +input_bundle.save(path_to_output_bundle) + +# and also in scaled down output folder if needed +if (target_res is not None): + # scale bundle file for the same factor + input_bundle.scale(scale_factor) + path_to_scaled_down_output_bundle = os.path.join (os.path.join (path_dest, "images/scaled"), "bundle.out") + input_bundle.save(path_to_scaled_down_output_bundle) + +################################################################################ + +############################ MOVE REST OF ASSETS ############################### + +textured_mesh_base_name = get_textured_mesh_base_name(path_data) +print("***** TEXT * ", textured_mesh_base_name) + +# copy files +files_to_move = [ #['pmvs/models/pmvs_recon.ply',''], + ['pmvs_recon.ply', pmvs_model_dir], + ['mesh.ply', pmvs_model_dir], + ['mesh.ply', capreal_dir], + ['recon.ply', pmvs_model_dir], + ['rc_out.csv', path_dest], + ["textured.obj", capreal_dir], + ["textured.mtl", capreal_dir], + ["textured_u1_v1.png", capreal_dir], + [textured_mesh_base_name + ".obj", capreal_dir], + [textured_mesh_base_name + ".mtl", capreal_dir], + [textured_mesh_base_name + "_u1_v1.png", capreal_dir] ] +for filename, directory_name in files_to_move: + source_file = os.path.join (path_data, filename) + destination_file = os.path.join (os.path.join (path_dest, directory_name), filename) + # print("Trying ", source_folder + file , " ", destination_folder + dir + file ) + print("Trying ", source_file , "-->", destination_file ) + if (os.path.exists(source_file)): + print("Moving ", source_file , " ", destination_file ) + shutil.copy( source_file , destination_file ) + +################################################################################ + +######################## CALCULATE CLIPPING PLANES ############################# +# clippingPlanes executable +clipping_planes_app = getProcess("clippingPlanes" + executables_suffix, executables_folder) + +clipping_planes_args = [clipping_planes_app, path_dest] + +# call clippingPlanes app +p_exit = subprocess.call(clipping_planes_args) +print(clipping_planes_app, " exited with ", p_exit); +checkOutput(p_exit, False) + +################################################################################ + +########################## CREATE LIST IMAGES ################################## + +path_images = os.path.join(path_dest, images_dir) +path_list_images = os.path.join(path_images, "list_images.txt") +generateListImages(path_images) + +################################################################################ + +######################## CREATE SCENE METADATA ################################# + +# read list image file +list_images = [] + +if os.path.exists(path_list_images): + list_image_file = open(path_list_images, "r") + + for line in list_image_file: + list_images.append(line) + + list_image_file.close() + +# read clipping planes file +path_clipping_planes = os.path.join(path_dest, "clipping_planes.txt") +clipping_planes = [] + +if os.path.exists(path_clipping_planes): + clipping_planes_file = open(path_clipping_planes, "r") + + for line in clipping_planes_file: + clipping_planes.append(line) + + clipping_planes_file.close() + + +# Create scene metadata file from list image file +scene_metadata = "Scene Metadata File\n\n" + +if len(list_images) == len(clipping_planes): + scene_metadata = scene_metadata + "[list_images]\n \n" + new_list = [a[:-1] + " " + b for a, b in zip(list_images, clipping_planes)] + for line in new_list: + scene_metadata = scene_metadata + line + +scene_metadata = scene_metadata + "\n\n// Always specify active/exclude images after list images\n\n[exclude_images]\n ... \n" + +# if len(exclude) > 0: +# for line in exclude: +# scene_metadata = scene_metadata + str(line) + " " + +scene_metadata = scene_metadata + "\n\n\n[other parameters]" + + +# rename pmvs_recon.ply to recon.ply +if (os.path.exists(os.path.join(path_dest, pmvs_model_dir, "pmvs_recon.ply"))): + shutil.copy(os.path.join(path_dest, pmvs_model_dir, "pmvs_recon.ply"), os.path.join(path_dest, pmvs_model_dir, "recon.ply")) + +if (os.path.exists(os.path.join(path_dest, pmvs_model_dir, "mesh.ply"))): + shutil.copy(os.path.join(path_dest, pmvs_model_dir, "mesh.ply"), os.path.join(path_dest, pmvs_model_dir, "recon.ply")) + +path_scene_metadata = os.path.join(path_dest, "scene_metadata.txt") + +scene_metadata_file = open(path_scene_metadata, "w") +scene_metadata_file.write(scene_metadata) +scene_metadata_file.close() + +################################################################################ + +for filename in os.listdir(path_data): + src = os.path.join(path_data, filename) + dst = os.path.join(path_dest, raw_data) + if not os.path.isdir(src): + shutil.copy(src, dst) + +print("Fin.") diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/meshlab/simplify.mlx b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/meshlab/simplify.mlx new file mode 100644 index 0000000000000000000000000000000000000000..a77e796f18dd4209eb0889c9107072f1b4dc20b3 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/meshlab/simplify.mlx @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/meshlab/simplify200.mlx b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/meshlab/simplify200.mlx new file mode 100644 index 0000000000000000000000000000000000000000..e44b6c71afc7ae12af21cc4b473012d0ab5f8e62 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/meshlab/simplify200.mlx @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/meshlab/simplify250.mlx b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/meshlab/simplify250.mlx new file mode 100644 index 0000000000000000000000000000000000000000..03af02fcbf688b5e24c9e31fbbe16e7380c7aa4b --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/meshlab/simplify250.mlx @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/meshlab/simplify300.mlx b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/meshlab/simplify300.mlx new file mode 100644 index 0000000000000000000000000000000000000000..6f35b699ea7429cbcc6e98c9d578515d574266d1 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/meshlab/simplify300.mlx @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/meshlab/simplify350.mlx b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/meshlab/simplify350.mlx new file mode 100644 index 0000000000000000000000000000000000000000..03af02fcbf688b5e24c9e31fbbe16e7380c7aa4b --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/meshlab/simplify350.mlx @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/meshlab/wedge_to_vertex_uvs.mlx b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/meshlab/wedge_to_vertex_uvs.mlx new file mode 100644 index 0000000000000000000000000000000000000000..a72957a82cc8db27f30115056e85ff4d797d5b99 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/meshlab/wedge_to_vertex_uvs.mlx @@ -0,0 +1,4 @@ + + + + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/simplify_mesh.py b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/simplify_mesh.py new file mode 100644 index 0000000000000000000000000000000000000000..6e18622b10e127ef67d353db0730bcad981de7ad --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/simplify_mesh.py @@ -0,0 +1,72 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +#!/usr/bin/env python +#! -*- encoding: utf-8 -*- + +""" @package dataset_tools_preprocess +This script calls meshlab to simplify a mesh + +Parameters: -h help, + -inputMesh , + -outputMesh , + -meshlabPath + +Usage: python simplify_mesh.py --inputMesh + --outputMesh + --meshlabPath + --meshsize + +""" + +import os, sys +import argparse +from utils.commands import runCommand, getMeshlabServer +from utils.paths import getMeshlabPath + +def simplifyMesh(inputMesh, outputMesh, meshsize="", meshlabPath = getMeshlabPath()): + mlxFileEnd = 'meshlab/simplify.mlx' + + if( meshsize != "" ): + if( meshsize == "200"): + mlxFileEnd = 'meshlab/simplify200.mlx' + elif( meshsize == "250"): + mlxFileEnd = 'meshlab/simplify250.mlx' + elif( meshsize == "300"): + mlxFileEnd = 'meshlab/simplify300.mlx' + elif( meshsize == "350"): + mlxFileEnd = 'meshlab/simplify350.mlx' + elif( meshsize == "400"): + mlxFileEnd = 'meshlab/simplify400.mlx' + + + mlxFile = os.path.abspath(os.path.join(os.path.abspath(os.path.dirname(__file__)), mlxFileEnd)) + + return runCommand(getMeshlabServer(meshlabPath), ['-i', inputMesh, + '-o', outputMesh, + '-s', mlxFile]) + +def main(): + parser = argparse.ArgumentParser() + + # common arguments + parser.add_argument("--inputMesh", type=str, required=True, help="the mesh to simplify") + parser.add_argument("--outputMesh", type=str, required=True, help="the output mesh") + parser.add_argument("--meshlabPath", type=str, default=getMeshlabPath(), help="Meshlab binary directory") + parser.add_argument("--meshsize", type=str, help="size of the output mesh in K polygons (ie 200 == 200,000 polygons). Values allowed: 200, 250, 300, 350, 400") + + args = vars(parser.parse_args()) + + return simplifyMesh(args['inputMesh'], args['outputMesh'], args['meshsize'], args['meshlabPath']) + +# sys.exit(0) + +if __name__ == "__main__": + main() diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/wedge_to_vertex_uvs.py b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/wedge_to_vertex_uvs.py new file mode 100644 index 0000000000000000000000000000000000000000..bcf651c015165bf7c106223e1e25008bd4ad2950 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/converters/wedge_to_vertex_uvs.py @@ -0,0 +1,60 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +#!/usr/bin/env python +#! -*- encoding: utf-8 -*- + +""" @package dataset_tools_preprocess +This script calls meshlab to simplify a mesh + +Parameters: -h help, + -inputMesh , + -outputMesh , + -meshlabPath + +Usage: python wedge_to_vertex_uvs.py -inputMesh + -outputMesh + -meshlabPath + +""" + +import os, sys +import argparse +from utils.commands import runCommand, getMeshlabServer +from utils.paths import getMeshlabPath + +def convertUVs(inputMesh, outputMesh, meshlabPath = getMeshlabPath()): + mlxFile = os.path.abspath(os.path.join(os.path.abspath(os.path.dirname(__file__)), 'meshlab/wedge_to_vertex_uvs.mlx')) + + ret = runCommand(getMeshlabServer(meshlabPath), ['-i', inputMesh, + '-o', outputMesh, + '-m', 'vt', + '-s', mlxFile]) + return ret + +def main(): + parser = argparse.ArgumentParser() + + # common arguments + parser.add_argument("--inputMesh", type=str, required=True, help="the mesh to simplify") + parser.add_argument("--outputMesh", type=str, required=True, help="the output mesh") + parser.add_argument("--meshlabPath", type=str, default=getMeshlabPath(), help="Meshlab binary directory") + + args = vars(parser.parse_args()) + + ret = convertUVs(args['inputMesh'], args['outputMesh'], args['meshlabPath']) + if( ret.returncode != 0 ): + print("SIBR_ERROR meshlab error in converting UVs") + sys.exit(1) + + sys.exit(0) + +if __name__ == "__main__": + main() diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/cropFromCenter/CMakeLists.txt b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/cropFromCenter/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..23b57c6b95e82bbfa8dc1f7661f745be24e7ae51 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/cropFromCenter/CMakeLists.txt @@ -0,0 +1,38 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +project(cropFromCenter) + +# libraries used: +# * sibr graphics (vector2i class) +# * sibr system (programArg class) +# * boost filesystem (path class) +# * openmp + +# Define build output for project +add_executable(${PROJECT_NAME} main.cpp) + +target_link_libraries(${PROJECT_NAME} + ${Boost_LIBRARIES} + OpenMP::OpenMP_CXX + sibr_system + sibr_graphics + sibr_imgproc +) + +set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER "projects/dataset_tools/preprocess") + +## High level macro to install in an homogen way all our ibr targets +include(install_runtime) +ibr_install_target(${PROJECT_NAME} + INSTALL_PDB ## mean install also MSVC IDE *.pdb file (DEST according to target type) + STANDALONE ${INSTALL_STANDALONE} ## mean call install_runtime with bundle dependencies resolution + COMPONENT ${PROJECT_NAME}_install ## will create custom target to install only this project +) diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/cropFromCenter/main.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/cropFromCenter/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a62ef6320b82cfd37b6ef84e4d328dad0d28c547 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/cropFromCenter/main.cpp @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include +#include + + + +/* +Crop input images from center so they end up with resolution x +if scale down factor is also passed, after the image has been cropped, it will be scaled down by that value +*/ +const char* USAGE = "Usage: cropFromCenter --inputFile --outputPath --avgResolution --cropResolution [--scaleDownFactor --targetResolution ] \n"; +//const char* USAGE = "Usage: cropFromCenter --inputFile --outputPath --avgResolution --cropResolution [--scaleDownFactor --targetResolution ] \n"; +const char* TAG = "[cropFromCenter]"; +const unsigned PROCESSING_BATCH_SIZE = 150; +const char* LOG_FILE_NAME = "cropFromCenter.log"; +const char* SCALED_DOWN_SUBFOLDER = "scaled"; +const char* SCALED_DOWN_FILENAME = "scale_factor.txt"; + +struct CropAppArgs : + virtual sibr::BasicIBRAppArgs { + sibr::Arg inputFileArg = { "inputFile", "" }; + sibr::Arg outputFolderArg = { "outputPath", "" }; + sibr::Arg avgResolutionArg = { "avgResolution",{ 0, 0 } }; + sibr::Arg cropResolutionArg = { "cropResolution",{ 0, 0 } }; + sibr::Arg scaleDownFactorArg = { "scaleDownFactor", 0.0f }; + sibr::Arg targetResolutionArg = { "targetResolution",{ 0, 0 } }; +}; + +void printUsage() +{ + std::cout << USAGE << std::endl; +} + + +bool getParamas(int argc, const char ** argv, + std::string & inputFile, boost::filesystem::path & outputPath, + sibr::Vector2i & avgResolution, sibr::Vector2i & cropResolution, float & scaleDownFactor, sibr::Vector2i & targetResolution) +{ + + sibr::CommandLineArgs::parseMainArgs(argc, argv); + CropAppArgs myArgs; + + inputFile = myArgs.inputFileArg; + + std::string outputFolder = myArgs.outputFolderArg; + outputPath = outputFolder; + + avgResolution = myArgs.avgResolutionArg; + + cropResolution = myArgs.cropResolutionArg; + + // optional parameters + if (myArgs.scaleDownFactorArg != 0.0f) { + scaleDownFactor = myArgs.scaleDownFactorArg; + } + + if (myArgs.targetResolutionArg.get() != sibr::Vector2i(0, 0)) { + targetResolution = myArgs.targetResolutionArg; + } + + + if (inputFile.empty() || outputFolder.empty() || avgResolution == sibr::Vector2i(0, 0) || cropResolution == sibr::Vector2i(0, 0)) { + return false; + } + + return true; +} + + +int main(const int argc, const char** argv) +{ + // process parameters + std::string inputFileName; + boost::filesystem::path outputFolder; + boost::filesystem::path scaledDownOutputFolder; + sibr::Vector2i avgInitialResolution; // just for statistics and log file + sibr::Vector2i cropResolution; + float scaleDownFactor = 0.f; + sibr::Vector2i targetResolution; + + sibr::CropScaleImageUtility appUtility; + + if (!getParamas(argc, argv, inputFileName, outputFolder, avgInitialResolution, cropResolution, scaleDownFactor, targetResolution)) { + std::cerr << TAG << " ERROR: wrong parameters.\n"; + printUsage(); + return -1; + } + + scaledDownOutputFolder = (outputFolder / SCALED_DOWN_SUBFOLDER); + + bool scaleDown = (scaleDownFactor > 0); + //cv::Size resizedSize (finalResolution[0], cropResolution[1] * ((float)(finalResolution[0]) / cropResolution[0])); + cv::Size resizedSize(int(cropResolution[0] * scaleDownFactor), int(cropResolution[1] * scaleDownFactor)); + + + if (!boost::filesystem::exists(outputFolder)) + { + boost::filesystem::create_directory(outputFolder); + } + + if (scaleDown && !boost::filesystem::exists(scaledDownOutputFolder)) { + boost::filesystem::create_directory(scaledDownOutputFolder); + } + + // read input file + std::vector pathToImgs = appUtility.getPathToImgs(inputFileName); + std::vector listOfImages(pathToImgs.size()); + std::vector listOfImagesScaledDown(scaleDown ? pathToImgs.size() : 0); + + // calculate nr batches + const int nrBatches = static_cast(ceil((float)(pathToImgs.size()) / PROCESSING_BATCH_SIZE)); + + std::chrono::time_point start, end; + start = std::chrono::system_clock::now(); + + const int batchSize = int(PROCESSING_BATCH_SIZE); + // run batches sequentially + for (int batchId = 0; batchId < nrBatches; batchId++) { + + const int nrItems = (batchId != nrBatches - 1) ? batchSize : ((nrBatches * batchSize != int(pathToImgs.size())) ? (int(pathToImgs.size()) - (batchSize * batchId)) : batchSize); + + #pragma omp parallel for + for (int localImgIndex = 0; localImgIndex < nrItems; localImgIndex++) { + + const int globalImgIndex = (batchId * batchSize) + localImgIndex; + + // using next code will keep filename in output directory + boost::filesystem::path boostPath(pathToImgs[globalImgIndex]); + //std::string outputFileName = (outputFolder / boostPath.filename()).string(); + + std::stringstream ss; + ss << std::setfill('0') << std::setw(8) << globalImgIndex << boostPath.extension().string(); + std::string outputFileName = (outputFolder / ss.str()).string(); + std::string scaledDownOutputFileName = (scaledDownOutputFolder / ss.str()).string(); + + cv::Mat img = cv::imread(pathToImgs[globalImgIndex], 1); + + cv::Rect areOfIntererst = cv::Rect((img.cols - cropResolution[0]) / 2, (img.rows - cropResolution[1]) / 2, cropResolution[0], cropResolution[1]); + + cv::Mat croppedImg = img(areOfIntererst); + + cv::imwrite(outputFileName, croppedImg); + + listOfImages[globalImgIndex].filename = ss.str(); + listOfImages[globalImgIndex].width = croppedImg.cols; + listOfImages[globalImgIndex].height = croppedImg.rows; + + if (scaleDown) { + cv::Mat resizedImg; + cv::resize(croppedImg, resizedImg, resizedSize, 0, 0, cv::INTER_LINEAR); + + cv::imwrite(scaledDownOutputFileName, resizedImg); + + listOfImagesScaledDown[globalImgIndex].filename = ss.str(); + listOfImagesScaledDown[globalImgIndex].width = resizedImg.cols; + listOfImagesScaledDown[globalImgIndex].height = resizedImg.rows; + } + } + } + + end = std::chrono::system_clock::now(); + auto elapsedTime = std::chrono::duration_cast(end - start).count(); + + std::cout << TAG << " elapsed time=" << elapsedTime << "s.\n"; + + appUtility.logExecution(avgInitialResolution, int(pathToImgs.size()), elapsedTime, scaleDown, LOG_FILE_NAME); + + // write list_images.txt + appUtility.writeListImages((outputFolder / "list_images.txt").string(), listOfImages); + + // write list_images.txt and scale_factor in scaled down directoy if needed + if (scaleDown) { + appUtility.writeListImages((scaledDownOutputFolder / "list_images.txt").string(), listOfImagesScaledDown); + appUtility.writeScaleFactor((scaledDownOutputFolder / SCALED_DOWN_FILENAME).string(), scaleDownFactor); + + if (targetResolution != sibr::Vector2i(0, 0)) { + appUtility.writeTargetResolution((scaledDownOutputFolder / "target_resolution.txt").string(), targetResolution); + } + } + + return 0; +} \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/distordCrop/CMakeLists.txt b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/distordCrop/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..2431d73795c477ffedc5472ca5ddd165d9f09dbe --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/distordCrop/CMakeLists.txt @@ -0,0 +1,39 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +# project name +project(distordCrop) + +file(GLOB SOURCES "*.cpp" "*.h" "*.hpp") + +# Define build output for project +add_executable(${PROJECT_NAME} ${SOURCES}) + +target_link_libraries(${PROJECT_NAME} + ${Boost_LIBRARIES} + OpenMP::OpenMP_CXX + sibr_system + sibr_graphics + sibr_imgproc +) + +set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER "projects/dataset_tools/preprocess") +if (WIN32) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4251") +endif() + + +## High level macro to install in an homogen way all our ibr targets +include(install_runtime) +ibr_install_target(${PROJECT_NAME} + INSTALL_PDB ## mean install also MSVC IDE *.pdb file (DEST according to target type) + STANDALONE ${INSTALL_STANDALONE} ## mean call install_runtime with bundle dependencies resolution + COMPONENT ${PROJECT_NAME}_install ## will create custom target to install only this project +) diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/distordCrop/main.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/distordCrop/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..637760d386e4f8338b2d96ab579aff4655ef544b --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/distordCrop/main.cpp @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include +#include + +typedef boost::filesystem::path Path; +using namespace boost::filesystem; + +int threshold_black_color = 10; //10 +int thinest_bounding_box_size = 5; +int threshold_bounding_box_size = 500; +float threshold_ratio_bounding_box_size = 0.2f; + +const int PROCESSING_BATCH_SIZE = 150; // process PROCESSING_BATCH_SIZE images together + +sibr::Vector3i backgroundColor = sibr::Vector3i(0, 0, 0); + +/* + if input image resolution is too different from the avg, it will be discarded automatically at the beginning +*/ +float resolutionThreshold = 0.15f; + +/* + tolerance factor is used to allow somehow some black borders in the final images. + if tolerance factor is zero, then all black borders are remove. + if tolerance factor is one, then the image keeps its original resolution +*/ +float toleranceFactor = 0.0f; + +bool debug_viz = false; + +struct DistordCropAppArgs : + virtual sibr::BasicIBRAppArgs { + sibr::Arg black_threshold = { "black", threshold_black_color }; + sibr::Arg minSizeThresholdArg = { "min", threshold_bounding_box_size}; + sibr::Arg minRatioThresholdArg = { "ratio", threshold_ratio_bounding_box_size }; + sibr::Arg resThreshold = { "resolution_threshold", 0.15f }; + sibr::Arg toleranceArg = { "tolerance", toleranceFactor }; + sibr::Arg vizArg = { "debug" }; + sibr::ArgSwitch modeArg = { "modesame", true }; + sibr::Arg avgWidthArg = { "avg_width", 0 }; + sibr::Arg avgHeightArg = { "avg_height", 0 }; + sibr::Arg backgroundColor = { "backgroundColor", sibr::Vector3i(0, 0, 0) }; +}; + + +/* +utility program that determines a new resolution taking into account that some input images have black borders added by reality capture. +the second output of the program [optional] is a excludeImages.txt file containing the id of the images that didn't pass the threshold test +(they would have to be cropped to much). current pipeline (IBR_recons_RC.py) doesn't used that file properly. + +we might need to call process_cam_selection manually passing as argument the excludeImages.txt in order to actually remove the cameras that +didn't pass the threshold test + +update: reality capture (using the 'fit' option when exporting bundle) sometimes produces datasets that have images not only with black borders +but also with a completely different resolution. We need to take into account those datasets too. +*/ + + +using namespace sibr; + + +int main(const int argc, const char* const* argv) +{ + // parameters stuff + sibr::CommandLineArgs::parseMainArgs(argc, argv); + DistordCropAppArgs myArgs; + + DistordCropUtility appUtils; + + std::string datasetPath = myArgs.dataset_path; + + threshold_black_color = myArgs.black_threshold; + threshold_bounding_box_size = myArgs.minSizeThresholdArg; + threshold_ratio_bounding_box_size = myArgs.minRatioThresholdArg; + toleranceFactor = myArgs.toleranceArg; + backgroundColor = myArgs.backgroundColor; + resolutionThreshold = myArgs.resThreshold; + + if( myArgs.vizArg.get()) { + debug_viz = true; + } + + int avgWidth = myArgs.avgWidthArg; + int avgHeight = myArgs.avgHeightArg; + + bool sameSize = myArgs.modeArg; + // end parameters stuff + + Path root(datasetPath); + + std::cout << "[distordCrop] looking for input images : " << std::endl; + std::vector< Path > imagePaths; + directory_iterator it(root), eod; + std::vector resolutions; + + BOOST_FOREACH(Path const &p, std::make_pair(it, eod)) { + if (is_regular_file(p) && ( p.extension() == ".jpg" || p.extension() == ".JPG" || p.extension() == ".PNG" || p.extension() == ".png" ) && appUtils.is_number(p.stem().string())) { + + std::cout << "\t " << p.filename().string() << std::endl; + imagePaths.push_back(p); + } + else if (is_regular_file(p) && p.extension() == ".txt" && p.stem().string() == "resolutions") { + + // read resolutions file + ifstream inputFile(p.string()); + + std::string line; + while (getline(inputFile, line)) { + std::stringstream iss(line); + std::string pathToImg; + std::string widthStr; + std::string heightStr; + + getline(iss, pathToImg, '\t'); + getline(iss, widthStr, '\t'); + getline(iss, heightStr, '\n'); + + sibr::Vector2i res(std::stoi(widthStr), std::stoi(heightStr)); + + resolutions.push_back(res); + + } + + inputFile.close(); + } + } + + if (resolutions.size() == 0) { + std::cout << "[distordCrop] WARNING : no resolution.txt file found" << std::endl; + return 0; + } + + if (imagePaths.size() == 0) { + std::cout << "[distordCrop] WARNING: no images found: need .jpg,.JPG,.png,.PNG " << std::endl; + return 0; + } + + if (resolutions.size() != imagePaths.size()) { + std::cout << "[distordCrop] WARNING : different number of input images and resolutions written in resolutions.txt" << std::endl; + return 0; + } + + int minWidth, minHeight, new_half_w, new_half_h; + + if (sameSize) { + std::cout << " ALL IMG SHOULD HAVE SAME SIZE " << std::endl; + sibr::Vector2i minSize = appUtils.findBiggestImageCenteredBox(root, imagePaths, resolutions, avgWidth, avgHeight, + PROCESSING_BATCH_SIZE, resolutionThreshold, threshold_ratio_bounding_box_size, backgroundColor, + threshold_black_color, thinest_bounding_box_size, toleranceFactor); + + std::cout << "[distordCrop] minSize " << minSize[0] << "x" << minSize[1] << std::endl; + minWidth = minSize[0]; + minHeight = minSize[1]; + } else { + std::cout << " ALL IMG SHOULD NOT HAVE SAME SIZE " << std::endl; + sibr::Vector2i minSize = appUtils.findMinImageSize(root, imagePaths); + minWidth = minSize[0]; + minHeight = minSize[1]; + } + + new_half_w = (minWidth % 2 == 0) ? (minWidth / 2) : (--minWidth / 2); + new_half_h = (minHeight % 2 == 0) ? (minHeight / 2) : (--minHeight / 2); + + while ((new_half_w % 4) != 0) { --new_half_w; } + while ((new_half_h % 4) != 0) { --new_half_h; } + + std::string outputFilePath = root.string() + "/cropNewSize.txt"; + std::ofstream file(outputFilePath, std::ios::trunc); + if (file) { + file << 2 * new_half_w << " " << 2 * new_half_h; + file.close(); + } + else { + std::cout << "[distordCrop] ERROR cant open file : " << outputFilePath << std::endl; + return 1; + } + + std::cout << "[distordCrop] done, new size is " << 2 * new_half_w << " x " << 2 * new_half_h << std::endl; + + return 0; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/fullColmapProcess/CMakeLists.txt b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/fullColmapProcess/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..fde4398683f7256e91cdb3b210ff2e0872cbcb62 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/fullColmapProcess/CMakeLists.txt @@ -0,0 +1,19 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +project(fullColmapProcess) + +file(GLOB SCRIPTS "*.py" "*.json") + +add_custom_target(${PROJECT_NAME} ALL) + +include(install_runtime) +set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER "projects/dataset_tools/preprocess") +ibr_install_rsc(${PROJECT_NAME} TYPE "scripts" FILES ${SCRIPTS}) diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/fullColmapProcess/ColmapProcessSteps.json b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/fullColmapProcess/ColmapProcessSteps.json new file mode 100644 index 0000000000000000000000000000000000000000..3ea917aa1c0bd195b2de2b22b9aa8e3b4f49a164 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/fullColmapProcess/ColmapProcessSteps.json @@ -0,0 +1,182 @@ +{ + "steps" : [ + { + "name": "build_dataset_structure", + "function": "utils.datasets.buildDatasetStructure", + "function_args": { + "path" : "${path}", + "types" : ["colmap", "capreal"] + } + }, + { + "name": "colmap_feature_extractor", + "app": "colmap", + "command_args": [ + "feature_extractor", + "--database_path", "${path}/colmap/dataset.db", + "--image_path", "${path}/images/", + "--ImageReader.camera_model", "OPENCV", + "--SiftExtraction.max_image_size", "${siftExtraction_ImageSize}", + "--SiftExtraction.estimate_affine_shape", "${siftExtraction_EstimateAffineShape}", + "--SiftExtraction.domain_size_pooling", "${siftExtraction_DomainSizePooling}", + "--SiftExtraction.max_num_features", "${siftExtraction_MaxNumFeatures}", + "--ImageReader.single_camera", "${imageReader_SingleCamera}", + "--SiftExtraction.gpu_index", "${gpusIndices}" + ] + }, + { + "name": "colmap_exhaustive_matcher", + "app": "colmap", + "command_args": [ + "exhaustive_matcher", + "--database_path", "${path}/colmap/dataset.db", + "--SiftMatching.guided_matching", "1", + "--ExhaustiveMatching.block_size", "${exhaustiveMatcher_ExhaustiveMatchingBlockSize}", + "--SiftMatching.gpu_index", "${gpusIndices}" + ] + }, + { + "name": "colmap_mapper", + "app": "colmap", + "command_args": [ + "mapper", + "--database_path", "${path}/colmap/dataset.db", + "--image_path", "${path}/images/", + "--output_path", "${path}/colmap/sparse/", + "--Mapper.ba_local_max_num_iterations", "${mapper_MapperDotbaLocalMaxNumIterations}", + "--Mapper.ba_global_max_num_iterations", "${mapper_MapperDotbaGlobalMaxNumIterations}", + "--Mapper.ba_global_images_ratio", "${mapper_MapperDotbaGlobalImagesRatio}", + "--Mapper.ba_global_points_ratio", "${mapper_MapperDotbaGlobalPointsRatio}", + "--Mapper.ba_global_max_refinements", "${mapper_MapperDotbaGlobalMaxRefinements}", + "--Mapper.ba_local_max_refinements", "${mapper_MapperDotbaLocalMaxRefinements}" + ] + }, + { + "name": "colmap_image_undistorter_colmap", + "app": "colmap", + "command_args": [ + "image_undistorter", + "--image_path", "${path}/images/", + "--input_path", "${path}/colmap/sparse/0", + "--output_path", "${path}/colmap/stereo/", + "--output_type", "COLMAP" + ] + }, + { + "name": "colmap_image_undistorter_capreal", + "app": "colmap", + "command_args": [ + "image_undistorter", + "--image_path", "${path}/images/", + "--input_path", "${path}/colmap/sparse/0/", + "--output_path", "${path}/capreal/undistorted/", + "--output_type", "CMP-MVS" + ] + }, + { + "name": "colmap_patch_match_stereo", + "app": "colmap", + "command_args": [ + "patch_match_stereo", + "--workspace_path", "${path}/colmap/stereo", + "--workspace_format", "COLMAP", + "--PatchMatchStereo.max_image_size", "${patchMatchStereo_PatchMatchStereoDotMaxImageSize}", + "--PatchMatchStereo.window_radius", "${patchMatchStereo_PatchMatchStereoDotWindowRadius}", + "--PatchMatchStereo.window_step", "${patchMatchStereo_PatchMatchStereoDotWindowStep}", + "--PatchMatchStereo.num_samples", "${patchMatchStereo_PatchMatchStereoDotNumSamples}", + "--PatchMatchStereo.num_iterations", "${patchMatchStereo_PatchMatchStereoDotNumIterations}", + "--PatchMatchStereo.geom_consistency", "${patchMatchStereo_PatchMatchStereoDotGeomConsistency}", + "--PatchMatchStereo.gpu_index", "${gpusIndices}" + ] + }, + { + "name": "colmap_stereo_fusion", + "app": "colmap", + "command_args": [ + "stereo_fusion", + "--workspace_path", "${path}/colmap/stereo/", + "--workspace_format", "COLMAP", + "--input_type", "geometric", + "--output_path", "${path}/colmap/stereo/fused.ply", + "--StereoFusion.max_image_size", "${stereoFusion_MaxImageSize}", + "--StereoFusion.check_num_images", "${stereoFusion_CheckNumImages}" + ] + }, + { + "name": "colmap_delaunay_mesher", + "app": "colmap", + "command_args": [ + "delaunay_mesher", + "--input_path", "${path}/colmap/stereo/", + "--output_path", "${path}/colmap/stereo/meshed-delaunay.ply", + "--input_type", "dense" + ] + }, + { + "name": "colmap_model_converter", + "app": "colmap", + "command_args": [ + "model_converter", + "--input_path", "${path}/colmap/stereo/sparse/", + "--output_path", "${path}/colmap/stereo/sparse/", + "--output_type", "TXT" + ] + }, + { + "name": "fix_mesh_eol", + "function": "utils.convert.fixMeshEol", + "function_args": { + "meshPath" : "${path}/colmap/stereo/meshed-delaunay.ply", + "newMeshPath" : "${path}/colmap/stereo/unix-meshed-delaunay.ply" + } + }, + { + "if": "${with_texture}", + "name": "simplify_mesh", + "function": "simplify_mesh.simplifyMesh", + "function_args": { + "inputMesh" : "${path}/colmap/stereo/unix-meshed-delaunay.ply", + "outputMesh" : "${path}/colmap/stereo/unix-meshed-delaunay-simplified.ply", + "meshlabPath" : "${meshlabPath}", + "meshsize" : "${meshsize}" + } + }, + { + "if": "${with_texture}", + "name": "unwrap_mesh", + "app": "unwrapMesh", + "command_args": [ + "--path", "${path}/colmap/stereo/unix-meshed-delaunay-simplified.ply", + "--output", "${path}/capreal/mesh.ply", + "--texture-name", "texture.png" + ] + }, + { + "if": "${with_texture}", + "name": "texture_mesh", + "app": "textureMesh", + "command_args": [ + "--path", "${path}", + "--output", "${path}/capreal/texture.png", + "--size", "8192", + "--flood" + ] + }, + { + "name": "move_eol_dirty_mesh", + "function": "shutil.copy", + "function_args": { + "src" : "${path}/colmap/stereo/meshed-delaunay.ply", + "dst" : "${path}/colmap/stereo/meshed-delaunay-eolpb.ply" + } + }, + { + "name": "use_eol_fixed_mesh", + "function": "shutil.copy", + "function_args": { + "src" : "${path}/colmap/stereo/unix-meshed-delaunay.ply", + "dst" : "${path}/colmap/stereo/meshed-delaunay.ply" + } + } + ] +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/fullColmapProcess/ColmapQualityParameters.json b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/fullColmapProcess/ColmapQualityParameters.json new file mode 100644 index 0000000000000000000000000000000000000000..e7989fb833e24a974a0dbfa71e83376ac6ec0969 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/fullColmapProcess/ColmapQualityParameters.json @@ -0,0 +1,162 @@ +{ + "siftExtraction_ImageSize": { + "default": 3200, + "low": 1000, + "medium": 1600, + "average": 3200, + "high": 2400, + "extreme": 3200 + }, + "siftExtraction_EstimateAffineShape": { + "default": false, + "low": false, + "medium": false, + "average": false, + "high": true, + "extreme": true + }, + "siftExtraction_DomainSizePooling": { + "default": false, + "low": false, + "medium": false, + "average": false, + "high": false, + "extreme": true + }, + "siftExtraction_MaxNumFeatures": { + "default": 16000, + "low": 8192, + "medium": 8192, + "average": 8192, + "high": 8192, + "extreme": 8192 + }, + "imageReader_SingleCamera": { + "default": false, + "low": true, + "medium": true, + "average": true, + "high": true, + "extreme": true + }, + "exhaustiveMatcher_ExhaustiveMatchingBlockSize": { + "default": 50, + "low": 50, + "medium": 50, + "average": 50, + "high": 50, + "extreme": 50 + }, + "mapper_MapperDotbaLocalMaxNumIterations": { + "default": 25, + "low": 12, + "medium": 16, + "average": 25, + "high": 30, + "extreme": 40 + }, + "mapper_MapperDotbaGlobalMaxNumIterations": { + "default": 50, + "low": 25, + "medium": 33, + "average": 50, + "high": 75, + "extreme": 100 + }, + "mapper_MapperDotbaGlobalImagesRatio": { + "default": 1.100001, + "low": 1.32, + "medium": 1.21, + "average": 1.100001, + "high": 1.100001, + "extreme": 1.100001 + }, + "mapper_MapperDotbaGlobalPointsRatio": { + "default": 1.100001, + "low": 1.32, + "medium": 1.21, + "average": 1.100001, + "high": 1.100001, + "extreme": 1.100001 + }, + "mapper_MapperDotbaGlobalMaxRefinements": { + "default": 5, + "low": 2, + "medium": 2, + "average": 5, + "high": 5, + "extreme": 5 + }, + "mapper_MapperDotbaLocalMaxRefinements": { + "default": 2, + "low": 2, + "medium": 2, + "average": 2, + "high": 3, + "extreme": 3 + }, + "patchMatchStereo_PatchMatchStereoDotMaxImageSize": { + "default": -1, + "low": 1000, + "medium": 1600, + "average": -1, + "high": 2400, + "extreme": -1 + }, + "patchMatchStereo_PatchMatchStereoDotWindowRadius": { + "default": 5, + "low": 4, + "medium": 4, + "average": 5, + "high": 5, + "extreme": 5 + }, + "patchMatchStereo_PatchMatchStereoDotWindowStep": { + "default": 1, + "low": 2, + "medium": 2, + "average": 1, + "high": 1, + "extreme": 1 + }, + "patchMatchStereo_PatchMatchStereoDotNumSamples": { + "default": 15, + "low": 7, + "medium": 10, + "average": 15, + "high": 15, + "extreme": 15 + }, + "patchMatchStereo_PatchMatchStereoDotNumIterations": { + "default": 5, + "low": 3, + "medium": 5, + "average": 5, + "high": 5, + "extreme": 5 + }, + "patchMatchStereo_PatchMatchStereoDotGeomConsistency": { + "default": 1, + "low": 0, + "medium": 0, + "average": 1, + "high": 1, + "extreme": 1 + }, + "stereoFusion_CheckNumImages": { + "default": 50, + "low": 25, + "medium": 33, + "average": 50, + "high": 50, + "extreme": 50 + }, + "stereoFusion_MaxImageSize": { + "default": -1, + "low": 1000, + "medium": 1600, + "average": -1, + "high": 2400, + "extreme": -1 + } +} \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/fullColmapProcess/SelectiveColmapProcessSteps.json b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/fullColmapProcess/SelectiveColmapProcessSteps.json new file mode 100644 index 0000000000000000000000000000000000000000..b722fdcbbb35e01dd47eea4c396c63188f87e046 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/fullColmapProcess/SelectiveColmapProcessSteps.json @@ -0,0 +1,234 @@ +{ + "steps" : [ + { + "name": "build_dataset_structure", + "function": "utils.datasets.buildDatasetStructure", + "function_args": { + "path" : "${path}", + "types" : ["colmap"] + } + }, + { + "name": "extract_video_frames", + "function": "selective_colmap_process.extract_video_frames", + "function_args": { + "pathIn": "${path}/videos", + "pathOut": "${path}/images" + } + }, + { + "name": "colmap_feature_extractor", + "app": "colmap", + "command_args": [ + "feature_extractor", + "--database_path", "${path}/colmap/dataset.db", + "--image_path", "${path}/images/", + "--ImageReader.camera_model", "OPENCV", + "--SiftExtraction.max_image_size", "${siftExtraction_ImageSize}", + "--SiftExtraction.estimate_affine_shape", "${siftExtraction_EstimateAffineShape}", + "--SiftExtraction.domain_size_pooling", "${siftExtraction_DomainSizePooling}", + "--SiftExtraction.max_num_features", "${siftExtraction_MaxNumFeatures}", + "--ImageReader.single_camera", "${imageReader_SingleCamera}", + "--SiftExtraction.gpu_index", "${gpusIndices}" + ] + }, + { + "name": "colmap_exhaustive_matcher", + "app": "colmap", + "command_args": [ + "exhaustive_matcher", + "--database_path", "${path}/colmap/dataset.db", + "--SiftMatching.gpu_index", "${gpusIndices}" + ] + }, + { + "name": "colmap_mapper", + "app": "colmap", + "command_args": [ + "mapper", + "--database_path", "${path}/colmap/dataset.db", + "--image_path", "${path}/images/", + "--output_path", "${path}/colmap/sparse/", + "--Mapper.num_threads", "16", + "--Mapper.init_min_tri_angle", "4", + "--Mapper.multiple_models", "0", + "--Mapper.extract_colors", "0", + "--Mapper.ba_global_images_ratio", "1.2", + "--Mapper.ba_global_points_ratio", "1.2", + "--Mapper.ba_global_max_num_iterations", "20", + "--Mapper.ba_global_max_refinements", "3", + "--Mapper.ba_global_points_freq", "200000" + ] + }, + { + "name": "colmap_model_converter_sparse_0", + "app": "colmap", + "command_args": [ + "model_converter", + "--input_path", "${path}/colmap/sparse/0", + "--output_path", "${path}/colmap/sparse/", + "--output_type", "TXT" + ] + }, + { + "name": "fix_cameras", + "function": "selective_colmap_process.fix_cameras", + "function_args": { + "path": "${path}", + "photoName": "MG_", + "sparseSubdir": "" + } + }, + { + "name": "colmap_image_undistorter_colmap", + "app": "colmap", + "command_args": [ + "image_undistorter", + "--image_path", "${path}/images/", + "--input_path", "${path}/colmap/sparse/", + "--output_path", "${path}/colmap/stereo", + "--output_type", "COLMAP" + ] + }, + { + "name": "colmap_model_converter_stereo_sparse", + "app": "colmap", + "command_args": [ + "model_converter", + "--input_path", "${path}/colmap/stereo/sparse", + "--output_path", "${path}/colmap/stereo/sparse/", + "--output_type", "TXT" + ] + }, + { + "name": "build_dataset_structure", + "function": "utils.datasets.buildDatasetStructure", + "function_args": { + "path" : "${path}", + "types" : ["capreal"] + } + }, + { + "name": "colmap_image_deleter_colmap", + "app": "colmap", + "command_args": [ + "image_deleter", + "--input_path", "${path}/colmap/sparse/", + "--output_path", "${path}/colmap/sparse/", + "--image_names_path", "${path}/videos/Video_frames.txt" + ] + }, + { + "name": "remove_video_images", + "function": "selective_colmap_process.remove_video_images", + "function_args": { + "path": "${path}" + } + }, + { + "name": "colmap_patch_match_stereo", + "app": "colmap", + "command_args": [ + "patch_match_stereo", + "--workspace_path", "${path}/colmap/stereo", + "--workspace_format", "COLMAP", + "--PatchMatchStereo.max_image_size", "${patchMatchStereo_PatchMatchStereoDotMaxImageSize}", + "--PatchMatchStereo.window_radius", "${patchMatchStereo_PatchMatchStereoDotWindowRadius}", + "--PatchMatchStereo.window_step", "${patchMatchStereo_PatchMatchStereoDotWindowStep}", + "--PatchMatchStereo.num_samples", "${patchMatchStereo_PatchMatchStereoDotNumSamples}", + "--PatchMatchStereo.num_iterations", "${patchMatchStereo_PatchMatchStereoDotNumIterations}", + "--PatchMatchStereo.geom_consistency", "${patchMatchStereo_PatchMatchStereoDotGeomConsistency}", + "--PatchMatchStereo.gpu_index", "${gpusIndices}" + ] + }, + { + "name": "colmap_stereo_fusion", + "app": "colmap", + "command_args": [ + "stereo_fusion", + "--workspace_path", "${path}/colmap/stereo/", + "--workspace_format", "COLMAP", + "--input_type", "geometric", + "--output_path", "${path}/colmap/stereo/fused.ply", + "--StereoFusion.max_image_size", "${stereoFusion_MaxImageSize}", + "--StereoFusion.check_num_images", "${stereoFusion_CheckNumImages}" + ] + }, + { + "name": "colmap_delaunay_mesher", + "app": "colmap", + "command_args": [ + "delaunay_mesher", + "--input_path", "${path}/colmap/stereo/", + "--output_path", "${path}/colmap/stereo/meshed-delaunay.ply", + "--input_type", "dense" + ] + }, + { + "name": "colmap_model_converter", + "app": "colmap", + "command_args": [ + "model_converter", + "--input_path", "${path}/colmap/stereo/sparse/", + "--output_path", "${path}/colmap/stereo/sparse/", + "--output_type", "TXT" + ] + }, + { + "name": "fix_mesh_eol", + "function": "utils.convert.fixMeshEol", + "function_args": { + "meshPath" : "${path}/colmap/stereo/meshed-delaunay.ply", + "newMeshPath" : "${path}/colmap/stereo/unix-meshed-delaunay.ply" + } + }, + { + "if": "${with_texture}", + "name": "simplify_mesh", + "function": "simplify_mesh.simplifyMesh", + "function_args": { + "inputMesh" : "${path}/colmap/stereo/unix-meshed-delaunay.ply", + "outputMesh" : "${path}/colmap/stereo/unix-meshed-delaunay-simplified.ply", + "meshlabPath" : "${meshlabPath}", + "meshsize" : "${meshsize}" + } + }, + { + "if": "${with_texture}", + "name": "unwrap_mesh", + "app": "unwrapMesh", + "command_args": [ + "--path", "${path}/colmap/stereo/unix-meshed-delaunay-simplified.ply", + "--output", "${path}/capreal/mesh.ply", + "--texture-name", "texture.png" + ] + }, + { + "if": "${with_texture}", + "name": "texture_mesh", + "app": "textureMesh", + "command_args": [ + "--path", "${path}", + "--output", "${path}/capreal/texture.png", + "--size", "8192", + "--flood" + ] + }, + { + "name": "move_eol_dirty_mesh", + "function": "shutil.copy", + "function_args": { + "src" : "${path}/colmap/stereo/meshed-delaunay.ply", + "dst" : "${path}/colmap/stereo/meshed-delaunay-eolpb.ply" + } + }, + { + "name": "use_eol_fixed_mesh", + "function": "shutil.copy", + "function_args": { + "src" : "${path}/colmap/stereo/unix-meshed-delaunay.ply", + "dst" : "${path}/colmap/stereo/meshed-delaunay.ply" + } + } + ] +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/fullColmapProcess/colmap2nerf.py b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/fullColmapProcess/colmap2nerf.py new file mode 100644 index 0000000000000000000000000000000000000000..e9c6e1068f018dbf04cb626989fc4cfc1d07a34b --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/fullColmapProcess/colmap2nerf.py @@ -0,0 +1,359 @@ +#!/usr/bin/env python3 + +# Copyright (c) 2020-2022, NVIDIA CORPORATION. All rights reserved. +# +# NVIDIA CORPORATION and its licensors retain all intellectual property +# and proprietary rights in and to this software, related documentation +# and any modifications thereto. Any use, reproduction, disclosure or +# distribution of this software and related documentation without an express +# license agreement from NVIDIA CORPORATION is strictly prohibited. + +import argparse +import os +from pathlib import Path, PurePosixPath + +import numpy as np +import json +import sys +import math +import cv2 +import os +import shutil + +def parse_args(): + parser = argparse.ArgumentParser(description="convert a text colmap export to nerf format transforms.json; optionally convert video to images, and optionally run colmap in the first place") + + parser.add_argument("--video_in", default="", help="run ffmpeg first to convert a provided video file into a set of images. uses the video_fps parameter also") + parser.add_argument("--video_fps", default=2) + parser.add_argument("--run_colmap", action="store_true", help="run colmap first on the image folder") + parser.add_argument("--colmap_matcher", default="sequential", choices=["exhaustive","sequential","spatial","transitive","vocab_tree"], help="select which matcher colmap should use. sequential for videos, exhaustive for adhoc images") + parser.add_argument("--colmap_db", default="colmap.db", help="colmap database filename") + parser.add_argument("--images", default="images", help="input path to the images") + parser.add_argument("--text", default="colmap_text", help="input path to the colmap text files (set automatically if run_colmap is used)") + parser.add_argument("--aabb_scale", default=16, choices=["1","2","4","8","16"], help="large scene scale factor. 1=scene fits in unit cube; power of 2 up to 16") + parser.add_argument("--skip_early", default=0, help="skip this many images from the start") + parser.add_argument("--out", default="transforms.json", help="output path") + parser.add_argument("--path", default="", help="top level dataset") + args = parser.parse_args() + return args + +def do_system(arg): + print(f"==== running: {arg}") + err=os.system(arg) + if err: + print("FATAL: command failed") + sys.exit(err) + + +def run_ffmpeg(args): + if not os.path.isabs(args.images): + args.images = os.path.join(os.path.dirname(args.video_in), args.images) + images=args.images + video=args.video_in + fps=float(args.video_fps) or 1.0 + print(f"running ffmpeg with input video file={video}, output image folder={images}, fps={fps}.") + if (input(f"warning! folder '{images}' will be deleted/replaced. continue? (Y/n)").lower().strip()+"y")[:1] != "y": + sys.exit(1) + try: + shutil.rmtree(images) + except: + pass + do_system(f"mkdir {images}") + do_system(f"ffmpeg -i {video} -qscale:v 1 -qmin 1 -vf \"fps={fps}\" {images}/%04d.jpg") + +def run_colmap(args): + db=args.colmap_db + images=args.images + db_noext=str(Path(db).with_suffix("")) + + if args.text=="text": + args.text=db_noext+"_text" + text=args.text + sparse=db_noext+"_sparse" + print(f"running colmap with:\n\tdb={db}\n\timages={images}\n\tsparse={sparse}\n\ttext={text}") + if (input(f"warning! folders '{sparse}' and '{text}' will be deleted/replaced. continue? (Y/n)").lower().strip()+"y")[:1] != "y": + sys.exit(1) + if os.path.exists(db): + os.remove(db) + do_system(f"colmap feature_extractor --ImageReader.camera_model OPENCV --ImageReader.single_camera 1 --database_path {db} --image_path {images}") + do_system(f"colmap {args.colmap_matcher}_matcher --database_path {db}") + try: + shutil.rmtree(sparse) + except: + pass + do_system(f"mkdir {sparse}") + do_system(f"colmap mapper --database_path {db} --image_path {images} --output_path {sparse}") + do_system(f"colmap bundle_adjuster --input_path {sparse}/0 --output_path {sparse}/0 --BundleAdjustment.refine_principal_point 1") + try: + shutil.rmtree(text) + except: + pass + do_system(f"mkdir {text}") + do_system(f"colmap model_converter --input_path {sparse}/0 --output_path {text} --output_type TXT") + +def variance_of_laplacian(image): + return cv2.Laplacian(image, cv2.CV_64F).var() + +def sharpness(imagePath): + image = cv2.imread(imagePath) + gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) + fm = variance_of_laplacian(gray) + return fm + +def qvec2rotmat(qvec): + return np.array([ + [ + 1 - 2 * qvec[2]**2 - 2 * qvec[3]**2, + 2 * qvec[1] * qvec[2] - 2 * qvec[0] * qvec[3], + 2 * qvec[3] * qvec[1] + 2 * qvec[0] * qvec[2] + ], [ + 2 * qvec[1] * qvec[2] + 2 * qvec[0] * qvec[3], + 1 - 2 * qvec[1]**2 - 2 * qvec[3]**2, + 2 * qvec[2] * qvec[3] - 2 * qvec[0] * qvec[1] + ], [ + 2 * qvec[3] * qvec[1] - 2 * qvec[0] * qvec[2], + 2 * qvec[2] * qvec[3] + 2 * qvec[0] * qvec[1], + 1 - 2 * qvec[1]**2 - 2 * qvec[2]**2 + ] + ]) + +def rotmat(a, b): + a, b = a / np.linalg.norm(a), b / np.linalg.norm(b) + v = np.cross(a, b) + c = np.dot(a, b) + s = np.linalg.norm(v) + kmat = np.array([[0, -v[2], v[1]], [v[2], 0, -v[0]], [-v[1], v[0], 0]]) + return np.eye(3) + kmat + kmat.dot(kmat) * ((1 - c) / (s ** 2 + 1e-10)) + +def closest_point_2_lines(oa, da, ob, db): # returns point closest to both rays of form o+t*d, and a weight factor that goes to 0 if the lines are parallel + da=da/np.linalg.norm(da) + db=db/np.linalg.norm(db) + c=np.cross(da,db) + denom=(np.linalg.norm(c)**2) + t=ob-oa + ta=np.linalg.det([t,db,c])/(denom+1e-10) + tb=np.linalg.det([t,da,c])/(denom+1e-10) + if ta>0: + ta=0 + if tb>0: + tb=0 + return (oa+ta*da+ob+tb*db)*0.5,denom + + + +def convert(AABB_SCALE, SKIP_EARLY, IMAGE_FOLDER, TEXT_FOLDER, OUT_PATH, totp=-1, totw=-1, avglen = -1, rMat = np.array([])): + print(f"outputting to {OUT_PATH}...") + with open(os.path.join(TEXT_FOLDER,"cameras.txt"), "r") as f: + angle_x=math.pi/2 + for line in f: + # 1 SIMPLE_RADIAL 2048 1536 1580.46 1024 768 0.0045691 + # 1 OPENCV 3840 2160 3178.27 3182.09 1920 1080 0.159668 -0.231286 -0.00123982 0.00272224 + # 1 RADIAL 1920 1080 1665.1 960 540 0.0672856 -0.0761443 + # + if line[0]=="#": + continue + els=line.split(" ") + w = float(els[2]) + h = float(els[3]) + fl_x = float(els[4]) + fl_y = float(els[4]) + k1 = 0 + k2 = 0 + p1 = 0 + p2 = 0 + cx = w/2 + cy = h/2 + if (els[1]=="SIMPLE_RADIAL"): + cx = float(els[5]) + cy = float(els[6]) + k1 = float(els[7]) + elif (els[1]=="RADIAL"): + cx = float(els[5]) + cy = float(els[6]) + k1 = float(els[7]) + k2 = float(els[8]) + elif (els[1]=="OPENCV"): + fl_y = float(els[5]) + cx = float(els[6]) + cy = float(els[7]) + k1 = float(els[8]) + k2 = float(els[9]) + p1 = float(els[10]) + p2 = float(els[11]) + elif (els[1]=="PINHOLE"): + cx = float(els[6]) + cy = float(els[7]) + else: + print("unknown camera model ", els[1]) + # fl = 0.5 * w / tan(0.5 * angle_x); + angle_x= math.atan(w/(fl_x*2))*2 + angle_y= math.atan(h/(fl_y*2))*2 + fovx=angle_x*180/math.pi + fovy=angle_y*180/math.pi + + #print(f"camera:\n\tres={w,h}\n\tcenter={cx,cy}\n\tfocal={fl_x,fl_y}\n\tfov={fovx,fovy}\n\tk={k1,k2} p={p1,p2} ") + + with open(os.path.join(TEXT_FOLDER,"images.txt"), "r") as f: + i=0 + bottom = np.array([0,0,0,1.]).reshape([1,4]) + out={ + "camera_angle_x":angle_x, + "camera_angle_y":angle_y, + "fl_x":fl_x, + "fl_y":fl_y, + "k1":k1, + "k2":k2, + "p1":p1, + "p2":p2, + "cx":cx, + "cy":cy, + "w":w, + "h":h, + "aabb_scale":AABB_SCALE,"frames":[] + } + + up=np.zeros(3) + for line in f: + line=line.strip() + if len(line)!=0 and line[0]=="#": + continue + i=i+1 + if i < SKIP_EARLY*2: + continue + if i%2==1 : + elems=line.split(" ") # 1-4 is quat, 5-7 is trans, 9 is filename + #name = str(PurePosixPath(Path(IMAGE_FOLDER, elems[9]))) + # why is this requireing a relitive path while using ^ + image_rel = os.path.relpath(IMAGE_FOLDER) + name = str(f"./{image_rel}/{elems[9]}") + if not os.path.exists(name): + name = name + ".png" + print("opening ", name) + b=sharpness(name) + #print(name, "sharpness=",b) + image_id = int(elems[0]) + qvec = np.array(tuple(map(float, elems[1:5]))) + tvec = np.array(tuple(map(float, elems[5:8]))) + R = qvec2rotmat(-qvec) + t = tvec.reshape([3,1]) + m = np.concatenate([np.concatenate([R, t], 1), bottom], 0) + c2w = np.linalg.inv(m) + c2w[0:3,2] *= -1 # flip the y and z axis + c2w[0:3,1] *= -1 + c2w=c2w[[1,0,2,3],:] # swap y and z + c2w[2,:] *= -1 # flip whole world upside down + + up += c2w[0:3,1] + + #s=str(os.path.splitext(os.path.basename(elems[9]))[0]) + s=str(os.path.basename(elems[9])) + #print("BASENAME ", s) + name = "images/"+ s # os.path.join("images", s) + frame={"file_path":name,"sharpness":b,"transform_matrix": c2w} + #print("OUTPUT ", name) + out["frames"].append(frame) + nframes = len(out["frames"]) + if len(rMat) == 0: + up = up / np.linalg.norm(up) + print("rMat is None up vector was ", up) + R=rotmat(up,[0,0,1]) # rotate up vector to [0,0,1] + R=np.pad(R,[0,1]) + R[-1,-1]=1 + rMat = R + else: + R = rMat + + + for f in out["frames"]: + f["transform_matrix"]=np.matmul(R,f["transform_matrix"]) # rotate up to be the z axis + + # find a central point they are all looking at + print("computing center of attention...") + + print("TOTP {} TOTW {}".format(totp, totw)) + if totw < 0 : + totw=0 + totp=[0,0,0] + for f in out["frames"]: + mf=f["transform_matrix"][0:3,:] + for g in out["frames"]: + mg=g["transform_matrix"][0:3,:] + p,w=closest_point_2_lines(mf[:,3],mf[:,2],mg[:,3],mg[:,2]) + if w>0.01: + totp+=p*w + totw+=w + if totw >0: + totp/=totw + + print("AFTER TOTP {} TOTW {}".format(totp, totw)) + print(totp) # the cameras are looking at totp + for f in out["frames"]: + f["transform_matrix"][0:3,3]-=totp + + if avglen < 0: + avglen=0. + for f in out["frames"]: + avglen+=np.linalg.norm(f["transform_matrix"][0:3,3]) + avglen/=nframes + + print("avg camera distance from origin ", avglen) + for f in out["frames"]: + f["transform_matrix"][0:3,3]*=4./avglen # scale to "nerf sized" + + for f in out["frames"]: + f["transform_matrix"]=f["transform_matrix"].tolist() + print(nframes,"frames") + print(f"writing {OUT_PATH}") + with open(OUT_PATH, "w") as outfile: + json.dump(out, outfile, indent=2) + + return totp, totw, avglen, rMat + +def createNerf(path, hires=False): + AABB_SCALE=int(16) + SKIP_EARLY=int(0) + print("Path is ", path, str(path)) + if hires: + print("DOING HIRES !!") + colmappath = os.path.join(os.path.join(str(path), "sibr"), "colmap") + else: + colmappath = os.path.join(os.path.join(str(path), "colmap_1000"), "colmap") + TEXT_FOLDER=os.path.join(os.path.join(colmappath, "stereo"), "sparse") + IMAGE_FOLDER=os.path.join(os.path.join(colmappath, "stereo"), "images") + OUT_PATH= os.path.join(os.path.join(colmappath, "stereo"), "transforms.json") + + totp, totw, avglen, rMat = convert(AABB_SCALE, SKIP_EARLY, IMAGE_FOLDER, TEXT_FOLDER, OUT_PATH, -1, -1, -1, np.array([])) + + colmappath = os.path.join(os.path.join(str(path), "colmap_1000"), "validation_colmap") + TEXT_FOLDER=os.path.join(os.path.join(colmappath, "stereo"), "sparse") + IMAGE_FOLDER=os.path.join(os.path.join(colmappath, "stereo"), "images") + OUT_PATH= os.path.join(os.path.join(colmappath, "stereo"), "transforms.json") + totp, totw, avglen, rMat = convert(AABB_SCALE, SKIP_EARLY, IMAGE_FOLDER, TEXT_FOLDER, OUT_PATH, totp, totw, avglen, rMat) + + colmappath = os.path.join(os.path.join(str(path), "colmap_1000"), "test_path_colmap") + TEXT_FOLDER=os.path.join(os.path.join(colmappath, "stereo"), "sparse") + IMAGE_FOLDER=os.path.join(os.path.join(colmappath, "stereo"), "images") + OUT_PATH= os.path.join(os.path.join(colmappath, "stereo"), "transforms.json") + totp, totw, avglen, rMat = convert(AABB_SCALE, SKIP_EARLY, IMAGE_FOLDER, TEXT_FOLDER, OUT_PATH, totp, totw, avglen, rMat) + + # if test2_path exists + colmappath = os.path.join(os.path.join(str(path), "colmap_1000"), "test_path2") + + if os.path.exists(colmappath): + TEXT_FOLDER=os.path.join(os.path.join(colmappath, "stereo"), "sparse") + IMAGE_FOLDER=os.path.join(os.path.join(colmappath, "stereo"), "images") + OUT_PATH= os.path.join(os.path.join(colmappath, "stereo"), "transforms.json") + totp, totw, avglen, rMat = convert(AABB_SCALE, SKIP_EARLY, IMAGE_FOLDER, TEXT_FOLDER, OUT_PATH, totp, totw, avglen, rMat) + +if __name__ == "__main__": + args = parse_args() + if args.video_in != "": + run_ffmpeg(args) + if args.run_colmap: + run_colmap(args) + AABB_SCALE=int(args.aabb_scale) + SKIP_EARLY=int(args.skip_early) + IMAGE_FOLDER=args.images + TEXT_FOLDER=args.text + OUT_PATH=args.out + convert(AABB_SCALE, SKIP_EARLY, IMAGE_FOLDER, TEXT_FOLDER, OUT_PATH, -1, -1) diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/fullColmapProcess/fullColmapProcess.py b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/fullColmapProcess/fullColmapProcess.py new file mode 100644 index 0000000000000000000000000000000000000000..da9391a31197820ed0c522eafbe4c165f81b20e5 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/fullColmapProcess/fullColmapProcess.py @@ -0,0 +1,126 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +#!/usr/bin/env python +#! -*- encoding: utf-8 -*- + +""" @package dataset_tools_preprocess +This script runs a pipeline to create Colmap reconstruction data + +Parameters: -h help, + -path , + -sibrBinariesPath , + -colmapPath , + -quality , + +Usage: python fullColmapProcess.py -path + -sibrBinariesPath + -colmapPath + -quality + +""" + +import os, sys, shutil +import json +import argparse +from utils.paths import getBinariesPath, getColmapPath, getMeshlabPath +from utils.commands import getProcess, getColmap +from utils.TaskPipeline import TaskPipeline + +def main(): + parser = argparse.ArgumentParser() + + # common arguments + parser.add_argument("--path", type=str, required=True, help="path to your dataset folder") + parser.add_argument("--sibrBinariesPath", type=str, default=getBinariesPath(), help="binaries directory of SIBR") + parser.add_argument("--colmapPath", type=str, default=getColmapPath(), help="path to directory colmap.bat / colmap.bin directory") + parser.add_argument("--meshlabPath", type=str, default=getMeshlabPath(), help="path to meshlabserver directory") + parser.add_argument("--quality", type=str, default='default', choices=['default', 'low', 'medium', 'average', 'high', 'extreme'], + help="quality of the reconstruction") + parser.add_argument("--dry_run", action='store_true', help="run without calling commands") + parser.add_argument("--with_texture", action='store_true', help="Add texture steps") + parser.add_argument("--create_sibr_scene", action='store_true', help="Create SIBR scene") + parser.add_argument("--meshsize", type=str, help="size of the output mesh in K polygons (ie 200 == 200,000 polygons). Values allowed: 200, 250, 300, 350, 400") + + #colmap performance arguments + parser.add_argument("--numGPUs", type=int, default=2, help="number of GPUs allocated to Colmap") + + # Feature extractor + parser.add_argument("--SiftExtraction.max_image_size", type=int, dest="siftExtraction_ImageSize") + parser.add_argument("--SiftExtraction.estimate_affine_shape", type=int, dest="siftExtraction_EstimateAffineShape") + parser.add_argument("--SiftExtraction.domain_size_pooling", type=int, dest="siftExtraction_DomainSizePooling") + parser.add_argument("--SiftExtraction.max_num_features", type=int, dest="siftExtraction_MaxNumFeatures") + parser.add_argument("--ImageReader.single_camera", type=int, dest="imageReader_SingleCamera") + + # Exhaustive matcher + parser.add_argument("--ExhaustiveMatching.block_size", type=int, dest="exhaustiveMatcher_ExhaustiveMatchingBlockSize") + + # Mapper + parser.add_argument("--Mapper.ba_local_max_num_iterations", type=int, dest="mapper_MapperDotbaLocalMaxNumIterations") + parser.add_argument("--Mapper.ba_global_max_num_iterations", type=int, dest="mapper_MapperDotbaGlobalMaxNumIterations") + parser.add_argument("--Mapper.ba_global_images_ratio", type=float, dest="mapper_MapperDotbaGlobalImagesRatio") + parser.add_argument("--Mapper.ba_global_points_ratio", type=float, dest="mapper_MapperDotbaGlobalPointsRatio") + parser.add_argument("--Mapper.ba_global_max_refinements", type=int, dest="mapper_MapperDotbaGlobalMaxRefinements") + parser.add_argument("--Mapper.ba_local_max_refinements", type=int, dest="mapper_MapperDotbaLocalMaxRefinements") + + # Patch match stereo + parser.add_argument("--PatchMatchStereo.max_image_size", type=int, dest="patchMatchStereo_PatchMatchStereoDotMaxImageSize") + parser.add_argument("--PatchMatchStereo.window_radius", type=int, dest="patchMatchStereo_PatchMatchStereoDotWindowRadius") + parser.add_argument("--PatchMatchStereo.window_step", type=int, dest="patchMatchStereo_PatchMatchStereoDotWindowStep") + parser.add_argument("--PatchMatchStereo.num_samples", type=int, dest="patchMatchStereo_PatchMatchStereoDotNumSamples") + parser.add_argument("--PatchMatchStereo.num_iterations", type=int, dest="patchMatchStereo_PatchMatchStereoDotNumIterations") + parser.add_argument("--PatchMatchStereo.geom_consistency", type=int, dest="patchMatchStereo_PatchMatchStereoDotGeomConsistency") + + # Stereo fusion + parser.add_argument("--StereoFusion.check_num_images", type=int, dest="stereoFusion_CheckNumImages") + parser.add_argument("--StereoFusion.max_image_size", type=int, dest="stereoFusion_MaxImageSize") + + args = vars(parser.parse_args()) + + # Update args with quality values + with open(os.path.join(os.path.abspath(os.path.dirname(__file__)), "ColmapQualityParameters.json"), "r") as qualityParamsFile: + qualityParams = json.load(qualityParamsFile) + + for key, value in qualityParams.items(): + if not key in args or args[key] is None: + args[key] = qualityParams[key][args["quality"]] if args["quality"] in qualityParams[key] else qualityParams[key]["default"] + + # Get process steps + with open(os.path.join(os.path.abspath(os.path.dirname(__file__)), "ColmapProcessSteps.json"), "r") as processStepsFile: + steps = json.load(processStepsFile)["steps"] + + # Fixing path values + args["path"] = os.path.abspath(args["path"]) + args["sibrBinariesPath"] = os.path.abspath(args["sibrBinariesPath"]) + args["colmapPath"] = os.path.abspath(args["colmapPath"]) + + args["gpusIndices"] = ','.join([str(i) for i in range(args["numGPUs"])]) + + programs = { + "colmap": { + "path": getColmap(args["colmapPath"]) + }, + "unwrapMesh": { + "path": getProcess("unwrapMesh", args["sibrBinariesPath"]) + }, + "textureMesh": { + "path": getProcess("textureMesh", args["sibrBinariesPath"]) + }, + } + + pipeline = TaskPipeline(args, steps, programs) + + pipeline.runProcessSteps() + + print("fullColmapProcess has finished successfully.") + sys.exit(0) + +if __name__ == "__main__": + main() diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/fullColmapProcess/read_write_model.py b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/fullColmapProcess/read_write_model.py new file mode 100644 index 0000000000000000000000000000000000000000..fe5da2421cc844ad451af8b4fd8a0b7b58cfde5b --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/fullColmapProcess/read_write_model.py @@ -0,0 +1,502 @@ +# Copyright (c) 2018, ETH Zurich and UNC Chapel Hill. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of +# its contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de) + +import os +import collections +import numpy as np +import struct +import argparse + + +CameraModel = collections.namedtuple( + "CameraModel", ["model_id", "model_name", "num_params"]) +Camera = collections.namedtuple( + "Camera", ["id", "model", "width", "height", "params"]) +BaseImage = collections.namedtuple( + "Image", ["id", "qvec", "tvec", "camera_id", "name", "xys", "point3D_ids"]) +Point3D = collections.namedtuple( + "Point3D", ["id", "xyz", "rgb", "error", "image_ids", "point2D_idxs"]) + + +class Image(BaseImage): + def qvec2rotmat(self): + return qvec2rotmat(self.qvec) + + +CAMERA_MODELS = { + CameraModel(model_id=0, model_name="SIMPLE_PINHOLE", num_params=3), + CameraModel(model_id=1, model_name="PINHOLE", num_params=4), + CameraModel(model_id=2, model_name="SIMPLE_RADIAL", num_params=4), + CameraModel(model_id=3, model_name="RADIAL", num_params=5), + CameraModel(model_id=4, model_name="OPENCV", num_params=8), + CameraModel(model_id=5, model_name="OPENCV_FISHEYE", num_params=8), + CameraModel(model_id=6, model_name="FULL_OPENCV", num_params=12), + CameraModel(model_id=7, model_name="FOV", num_params=5), + CameraModel(model_id=8, model_name="SIMPLE_RADIAL_FISHEYE", num_params=4), + CameraModel(model_id=9, model_name="RADIAL_FISHEYE", num_params=5), + CameraModel(model_id=10, model_name="THIN_PRISM_FISHEYE", num_params=12) +} +CAMERA_MODEL_IDS = dict([(camera_model.model_id, camera_model) + for camera_model in CAMERA_MODELS]) +CAMERA_MODEL_NAMES = dict([(camera_model.model_name, camera_model) + for camera_model in CAMERA_MODELS]) + + +def read_next_bytes(fid, num_bytes, format_char_sequence, endian_character="<"): + """Read and unpack the next bytes from a binary file. + :param fid: + :param num_bytes: Sum of combination of {2, 4, 8}, e.g. 2, 6, 16, 30, etc. + :param format_char_sequence: List of {c, e, f, d, h, H, i, I, l, L, q, Q}. + :param endian_character: Any of {@, =, <, >, !} + :return: Tuple of read and unpacked values. + """ + data = fid.read(num_bytes) + return struct.unpack(endian_character + format_char_sequence, data) + + +def write_next_bytes(fid, data, format_char_sequence, endian_character="<"): + """pack and write to a binary file. + :param fid: + :param data: data to send, if multiple elements are sent at the same time, + they should be encapsuled either in a list or a tuple + :param format_char_sequence: List of {c, e, f, d, h, H, i, I, l, L, q, Q}. + should be the same length as the data list or tuple + :param endian_character: Any of {@, =, <, >, !} + """ + if isinstance(data, (list, tuple)): + bytes = struct.pack(endian_character + format_char_sequence, *data) + else: + bytes = struct.pack(endian_character + format_char_sequence, data) + fid.write(bytes) + + +def read_cameras_text(path): + """ + see: src/base/reconstruction.cc + void Reconstruction::WriteCamerasText(const std::string& path) + void Reconstruction::ReadCamerasText(const std::string& path) + """ + cameras = {} + with open(path, "r") as fid: + while True: + line = fid.readline() + if not line: + break + line = line.strip() + if len(line) > 0 and line[0] != "#": + elems = line.split() + camera_id = int(elems[0]) + model = elems[1] + width = int(elems[2]) + height = int(elems[3]) + params = np.array(tuple(map(float, elems[4:]))) + cameras[camera_id] = Camera(id=camera_id, model=model, + width=width, height=height, + params=params) + return cameras + + +def read_cameras_binary(path_to_model_file): + """ + see: src/base/reconstruction.cc + void Reconstruction::WriteCamerasBinary(const std::string& path) + void Reconstruction::ReadCamerasBinary(const std::string& path) + """ + cameras = {} + with open(path_to_model_file, "rb") as fid: + num_cameras = read_next_bytes(fid, 8, "Q")[0] + for _ in range(num_cameras): + camera_properties = read_next_bytes( + fid, num_bytes=24, format_char_sequence="iiQQ") + camera_id = camera_properties[0] + model_id = camera_properties[1] + model_name = CAMERA_MODEL_IDS[camera_properties[1]].model_name + width = camera_properties[2] + height = camera_properties[3] + num_params = CAMERA_MODEL_IDS[model_id].num_params + params = read_next_bytes(fid, num_bytes=8*num_params, + format_char_sequence="d"*num_params) + cameras[camera_id] = Camera(id=camera_id, + model=model_name, + width=width, + height=height, + params=np.array(params)) + assert len(cameras) == num_cameras + return cameras + + +def write_cameras_text(cameras, path): + """ + see: src/base/reconstruction.cc + void Reconstruction::WriteCamerasText(const std::string& path) + void Reconstruction::ReadCamerasText(const std::string& path) + """ + HEADER = "# Camera list with one line of data per camera:\n" + \ + "# CAMERA_ID, MODEL, WIDTH, HEIGHT, PARAMS[]\n" + \ + "# Number of cameras: {}\n".format(len(cameras)) + with open(path, "w") as fid: + fid.write(HEADER) + for _, cam in cameras.items(): + to_write = [cam.id, cam.model, cam.width, cam.height, *cam.params] + line = " ".join([str(elem) for elem in to_write]) + fid.write(line + "\n") + + +def write_cameras_binary(cameras, path_to_model_file): + """ + see: src/base/reconstruction.cc + void Reconstruction::WriteCamerasBinary(const std::string& path) + void Reconstruction::ReadCamerasBinary(const std::string& path) + """ + with open(path_to_model_file, "wb") as fid: + write_next_bytes(fid, len(cameras), "Q") + for _, cam in cameras.items(): + model_id = CAMERA_MODEL_NAMES[cam.model].model_id + camera_properties = [cam.id, + model_id, + cam.width, + cam.height] + write_next_bytes(fid, camera_properties, "iiQQ") + for p in cam.params: + write_next_bytes(fid, float(p), "d") + return cameras + + +def read_images_text(path): + """ + see: src/base/reconstruction.cc + void Reconstruction::ReadImagesText(const std::string& path) + void Reconstruction::WriteImagesText(const std::string& path) + """ + images = {} + with open(path, "r") as fid: + while True: + line = fid.readline() + if not line: + break + line = line.strip() + if len(line) > 0 and line[0] != "#": + elems = line.split() + image_id = int(elems[0]) + qvec = np.array(tuple(map(float, elems[1:5]))) + tvec = np.array(tuple(map(float, elems[5:8]))) + camera_id = int(elems[8]) + image_name = elems[9] + elems = fid.readline().split() + xys = np.column_stack([tuple(map(float, elems[0::3])), + tuple(map(float, elems[1::3]))]) + point3D_ids = np.array(tuple(map(int, elems[2::3]))) + images[image_id] = Image( + id=image_id, qvec=qvec, tvec=tvec, + camera_id=camera_id, name=image_name, + xys=xys, point3D_ids=point3D_ids) + return images + + +def read_images_binary(path_to_model_file): + """ + see: src/base/reconstruction.cc + void Reconstruction::ReadImagesBinary(const std::string& path) + void Reconstruction::WriteImagesBinary(const std::string& path) + """ + images = {} + with open(path_to_model_file, "rb") as fid: + num_reg_images = read_next_bytes(fid, 8, "Q")[0] + for _ in range(num_reg_images): + binary_image_properties = read_next_bytes( + fid, num_bytes=64, format_char_sequence="idddddddi") + image_id = binary_image_properties[0] + qvec = np.array(binary_image_properties[1:5]) + tvec = np.array(binary_image_properties[5:8]) + camera_id = binary_image_properties[8] + image_name = "" + current_char = read_next_bytes(fid, 1, "c")[0] + while current_char != b"\x00": # look for the ASCII 0 entry + image_name += current_char.decode("utf-8") + current_char = read_next_bytes(fid, 1, "c")[0] + num_points2D = read_next_bytes(fid, num_bytes=8, + format_char_sequence="Q")[0] + x_y_id_s = read_next_bytes(fid, num_bytes=24*num_points2D, + format_char_sequence="ddq"*num_points2D) + xys = np.column_stack([tuple(map(float, x_y_id_s[0::3])), + tuple(map(float, x_y_id_s[1::3]))]) + point3D_ids = np.array(tuple(map(int, x_y_id_s[2::3]))) + images[image_id] = Image( + id=image_id, qvec=qvec, tvec=tvec, + camera_id=camera_id, name=image_name, + xys=xys, point3D_ids=point3D_ids) + return images + + +def write_images_text(images, path): + """ + see: src/base/reconstruction.cc + void Reconstruction::ReadImagesText(const std::string& path) + void Reconstruction::WriteImagesText(const std::string& path) + """ + if len(images) == 0: + mean_observations = 0 + else: + mean_observations = sum((len(img.point3D_ids) for _, img in images.items()))/len(images) + HEADER = "# Image list with two lines of data per image:\n" + \ + "# IMAGE_ID, QW, QX, QY, QZ, TX, TY, TZ, CAMERA_ID, NAME\n" + \ + "# POINTS2D[] as (X, Y, POINT3D_ID)\n" + \ + "# Number of images: {}, mean observations per image: {}\n".format(len(images), mean_observations) + + with open(path, "w") as fid: + fid.write(HEADER) + for _, img in images.items(): + image_header = [img.id, *img.qvec, *img.tvec, img.camera_id, img.name] + first_line = " ".join(map(str, image_header)) + fid.write(first_line + "\n") + + points_strings = [] + for xy, point3D_id in zip(img.xys, img.point3D_ids): + points_strings.append(" ".join(map(str, [*xy, point3D_id]))) + fid.write(" ".join(points_strings) + "\n") + + +def write_images_binary(images, path_to_model_file): + """ + see: src/base/reconstruction.cc + void Reconstruction::ReadImagesBinary(const std::string& path) + void Reconstruction::WriteImagesBinary(const std::string& path) + """ + with open(path_to_model_file, "wb") as fid: + write_next_bytes(fid, len(images), "Q") + for _, img in images.items(): + write_next_bytes(fid, img.id, "i") + write_next_bytes(fid, img.qvec.tolist(), "dddd") + write_next_bytes(fid, img.tvec.tolist(), "ddd") + write_next_bytes(fid, img.camera_id, "i") + for char in img.name: + write_next_bytes(fid, char.encode("utf-8"), "c") + write_next_bytes(fid, b"\x00", "c") + write_next_bytes(fid, len(img.point3D_ids), "Q") + for xy, p3d_id in zip(img.xys, img.point3D_ids): + write_next_bytes(fid, [*xy, p3d_id], "ddq") + + +def read_points3D_text(path): + """ + see: src/base/reconstruction.cc + void Reconstruction::ReadPoints3DText(const std::string& path) + void Reconstruction::WritePoints3DText(const std::string& path) + """ + points3D = {} + with open(path, "r") as fid: + while True: + line = fid.readline() + if not line: + break + line = line.strip() + if len(line) > 0 and line[0] != "#": + elems = line.split() + point3D_id = int(elems[0]) + xyz = np.array(tuple(map(float, elems[1:4]))) + rgb = np.array(tuple(map(int, elems[4:7]))) + error = float(elems[7]) + image_ids = np.array(tuple(map(int, elems[8::2]))) + point2D_idxs = np.array(tuple(map(int, elems[9::2]))) + points3D[point3D_id] = Point3D(id=point3D_id, xyz=xyz, rgb=rgb, + error=error, image_ids=image_ids, + point2D_idxs=point2D_idxs) + return points3D + + +def read_points3D_binary(path_to_model_file): + """ + see: src/base/reconstruction.cc + void Reconstruction::ReadPoints3DBinary(const std::string& path) + void Reconstruction::WritePoints3DBinary(const std::string& path) + """ + points3D = {} + with open(path_to_model_file, "rb") as fid: + num_points = read_next_bytes(fid, 8, "Q")[0] + for _ in range(num_points): + binary_point_line_properties = read_next_bytes( + fid, num_bytes=43, format_char_sequence="QdddBBBd") + point3D_id = binary_point_line_properties[0] + xyz = np.array(binary_point_line_properties[1:4]) + rgb = np.array(binary_point_line_properties[4:7]) + error = np.array(binary_point_line_properties[7]) + track_length = read_next_bytes( + fid, num_bytes=8, format_char_sequence="Q")[0] + track_elems = read_next_bytes( + fid, num_bytes=8*track_length, + format_char_sequence="ii"*track_length) + image_ids = np.array(tuple(map(int, track_elems[0::2]))) + point2D_idxs = np.array(tuple(map(int, track_elems[1::2]))) + points3D[point3D_id] = Point3D( + id=point3D_id, xyz=xyz, rgb=rgb, + error=error, image_ids=image_ids, + point2D_idxs=point2D_idxs) + return points3D + + +def write_points3D_text(points3D, path): + """ + see: src/base/reconstruction.cc + void Reconstruction::ReadPoints3DText(const std::string& path) + void Reconstruction::WritePoints3DText(const std::string& path) + """ + if len(points3D) == 0: + mean_track_length = 0 + else: + mean_track_length = sum((len(pt.image_ids) for _, pt in points3D.items()))/len(points3D) + HEADER = "# 3D point list with one line of data per point:\n" + \ + "# POINT3D_ID, X, Y, Z, R, G, B, ERROR, TRACK[] as (IMAGE_ID, POINT2D_IDX)\n" + \ + "# Number of points: {}, mean track length: {}\n".format(len(points3D), mean_track_length) + + with open(path, "w") as fid: + fid.write(HEADER) + for _, pt in points3D.items(): + point_header = [pt.id, *pt.xyz, *pt.rgb, pt.error] + fid.write(" ".join(map(str, point_header)) + " ") + track_strings = [] + for image_id, point2D in zip(pt.image_ids, pt.point2D_idxs): + track_strings.append(" ".join(map(str, [image_id, point2D]))) + fid.write(" ".join(track_strings) + "\n") + + +def write_points3D_binary(points3D, path_to_model_file): + """ + see: src/base/reconstruction.cc + void Reconstruction::ReadPoints3DBinary(const std::string& path) + void Reconstruction::WritePoints3DBinary(const std::string& path) + """ + with open(path_to_model_file, "wb") as fid: + write_next_bytes(fid, len(points3D), "Q") + for _, pt in points3D.items(): + write_next_bytes(fid, pt.id, "Q") + write_next_bytes(fid, pt.xyz.tolist(), "ddd") + write_next_bytes(fid, pt.rgb.tolist(), "BBB") + write_next_bytes(fid, pt.error, "d") + track_length = pt.image_ids.shape[0] + write_next_bytes(fid, track_length, "Q") + for image_id, point2D_id in zip(pt.image_ids, pt.point2D_idxs): + write_next_bytes(fid, [image_id, point2D_id], "ii") + + +def detect_model_format(path, ext): + if os.path.isfile(os.path.join(path, "cameras" + ext)) and \ + os.path.isfile(os.path.join(path, "images" + ext)) and \ + os.path.isfile(os.path.join(path, "points3D" + ext)): + print("Detected model format: '" + ext + "'") + return True + + return False + + +def read_model(path, ext=""): + # try to detect the extension automatically + if ext == "": + if detect_model_format(path, ".bin"): + ext = ".bin" + elif detect_model_format(path, ".txt"): + ext = ".txt" + else: + print("Provide model format: '.bin' or '.txt'") + return + + if ext == ".txt": + cameras = read_cameras_text(os.path.join(path, "cameras" + ext)) + images = read_images_text(os.path.join(path, "images" + ext)) + points3D = read_points3D_text(os.path.join(path, "points3D") + ext) + else: + cameras = read_cameras_binary(os.path.join(path, "cameras" + ext)) + images = read_images_binary(os.path.join(path, "images" + ext)) + points3D = read_points3D_binary(os.path.join(path, "points3D") + ext) + return cameras, images, points3D + + +def write_model(cameras, images, points3D, path, ext=".bin"): + if ext == ".txt": + write_cameras_text(cameras, os.path.join(path, "cameras" + ext)) + write_images_text(images, os.path.join(path, "images" + ext)) + write_points3D_text(points3D, os.path.join(path, "points3D") + ext) + else: + write_cameras_binary(cameras, os.path.join(path, "cameras" + ext)) + write_images_binary(images, os.path.join(path, "images" + ext)) + write_points3D_binary(points3D, os.path.join(path, "points3D") + ext) + return cameras, images, points3D + + +def qvec2rotmat(qvec): + return np.array([ + [1 - 2 * qvec[2]**2 - 2 * qvec[3]**2, + 2 * qvec[1] * qvec[2] - 2 * qvec[0] * qvec[3], + 2 * qvec[3] * qvec[1] + 2 * qvec[0] * qvec[2]], + [2 * qvec[1] * qvec[2] + 2 * qvec[0] * qvec[3], + 1 - 2 * qvec[1]**2 - 2 * qvec[3]**2, + 2 * qvec[2] * qvec[3] - 2 * qvec[0] * qvec[1]], + [2 * qvec[3] * qvec[1] - 2 * qvec[0] * qvec[2], + 2 * qvec[2] * qvec[3] + 2 * qvec[0] * qvec[1], + 1 - 2 * qvec[1]**2 - 2 * qvec[2]**2]]) + + +def rotmat2qvec(R): + Rxx, Ryx, Rzx, Rxy, Ryy, Rzy, Rxz, Ryz, Rzz = R.flat + K = np.array([ + [Rxx - Ryy - Rzz, 0, 0, 0], + [Ryx + Rxy, Ryy - Rxx - Rzz, 0, 0], + [Rzx + Rxz, Rzy + Ryz, Rzz - Rxx - Ryy, 0], + [Ryz - Rzy, Rzx - Rxz, Rxy - Ryx, Rxx + Ryy + Rzz]]) / 3.0 + eigvals, eigvecs = np.linalg.eigh(K) + qvec = eigvecs[[3, 0, 1, 2], np.argmax(eigvals)] + if qvec[0] < 0: + qvec *= -1 + return qvec + + +def main(): + parser = argparse.ArgumentParser(description="Read and write COLMAP binary and text models") + parser.add_argument("--input_model", help="path to input model folder") + parser.add_argument("--input_format", choices=[".bin", ".txt"], + help="input model format", default="") + parser.add_argument("--output_model", + help="path to output model folder") + parser.add_argument("--output_format", choices=[".bin", ".txt"], + help="outut model format", default=".txt") + args = parser.parse_args() + + cameras, images, points3D = read_model(path=args.input_model, ext=args.input_format) + + print("num_cameras:", len(cameras)) + print("num_images:", len(images)) + print("num_points3D:", len(points3D)) + + if args.output_model is not None: + write_model(cameras, images, points3D, path=args.output_model, ext=args.output_format) + + +if __name__ == "__main__": + main() diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/fullColmapProcess/selectiveColmapProcess.py b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/fullColmapProcess/selectiveColmapProcess.py new file mode 100644 index 0000000000000000000000000000000000000000..c236cec7e040f59858466f98f7552f3de19f60bb --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/fullColmapProcess/selectiveColmapProcess.py @@ -0,0 +1,194 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +#!/usr/bin/env python +#! -*- encoding: utf-8 -*- + +""" @package dataset_tools_preprocess +This script runs a pipeline to create Colmap reconstruction data; you can choose which steps to do and it also handles test path data which are only calibrated + +Parameters: -h help, + -path , + -sibrBinariesPath , + -colmapPath , + -quality , + +Usage: python selectiveColmapProcess.py -path + -sibrBinariesPath + -colmapPath + -quality + +""" + +import os, sys, shutil +import json +import argparse +from utils.paths import getBinariesPath, getColmapPath, getMeshlabPath +from utils.commands import getProcess, getColmap +from utils.TaskPipeline import TaskPipeline +import selective_colmap_process + +def main(): + parser = argparse.ArgumentParser() + + # common arguments + parser.add_argument("--path", type=str, required=True, help="path to your dataset folder") + parser.add_argument("--sibrBinariesPath", type=str, default=getBinariesPath(), help="binaries directory of SIBR") + parser.add_argument("--colmapPath", type=str, default=getColmapPath(), help="path to directory colmap.bat / colmap.bin directory") + parser.add_argument("--meshlabPath", type=str, default=getMeshlabPath(), help="path to meshlabserver directory") + parser.add_argument("--quality", type=str, default='default', choices=['default', 'low', 'medium', 'average', 'high', 'extreme'], + help="quality of the reconstruction") + parser.add_argument("--dry_run", action='store_true', help="run without calling commands") + parser.add_argument("--with_texture", action='store_true', help="Add texture steps") + parser.add_argument("--create_sibr_scene", action='store_true', help="Create SIBR scene") + parser.add_argument("--meshsize", type=str, help="size of the output mesh in K polygons (ie 200 == 200,000 polygons). Values allowed: 200, 250, 300, 350, 400") + + # additional step choice presets + parser.add_argument("--from_step", type=str, default='default', help="Run from this step to --to_step") + parser.add_argument("--to_step", type=str, default='default', help="up to but *excluding* this step (from --from_step); must be unique steps") + parser.add_argument("--exclude_steps", type=str, default='default', help="Ignore these steps (string with space separated names of steps)") + parser.add_argument("--calibrate_only", action='store_true', help="Do calibration only (from dataset_build_structure to before colmap_path_match_stereo with no special test frame processing") + parser.add_argument("--calibrate_only_process_test", action='store_true', help="Do calibration only (from dataset_build_structure to before colmap_path_match_stereo with test frame processing") + parser.add_argument("--mvs_only", action='store_true', help="Do mvs only (from colmap_path_match_stereo onwards without test frame processing") + parser.add_argument("--fix_cameras", action='store_true', help="Do fix camera step only") + parser.add_argument("--fix_cameras_stereo", action='store_true', help="Do fix camera step only for stereo/sparse") + + #colmap performance arguments + parser.add_argument("--numGPUs", type=int, default=2, help="number of GPUs allocated to Colmap") + + # Feature extractor + parser.add_argument("--SiftExtraction.max_image_size", type=int, dest="siftExtraction_ImageSize") + parser.add_argument("--SiftExtraction.estimate_affine_shape", type=int, dest="siftExtraction_EstimateAffineShape") + parser.add_argument("--SiftExtraction.domain_size_pooling", type=int, dest="siftExtraction_DomainSizePooling") + parser.add_argument("--SiftExtraction.max_num_features", type=int, dest="siftExtraction_MaxNumFeatures") + parser.add_argument("--ImageReader.single_camera", type=int, dest="imageReader_SingleCamera") + + # Exhaustive matcher + parser.add_argument("--ExhaustiveMatching.block_size", type=int, dest="exhaustiveMatcher_ExhaustiveMatchingBlockSize") + + # Mapper + parser.add_argument("--Mapper.ba_local_max_num_iterations", type=int, dest="mapper_MapperDotbaLocalMaxNumIterations") + parser.add_argument("--Mapper.ba_global_max_num_iterations", type=int, dest="mapper_MapperDotbaGlobalMaxNumIterations") + parser.add_argument("--Mapper.ba_global_images_ratio", type=float, dest="mapper_MapperDotbaGlobalImagesRatio") + parser.add_argument("--Mapper.ba_global_points_ratio", type=float, dest="mapper_MapperDotbaGlobalPointsRatio") + parser.add_argument("--Mapper.ba_global_max_refinements", type=int, dest="mapper_MapperDotbaGlobalMaxRefinements") + parser.add_argument("--Mapper.ba_local_max_refinements", type=int, dest="mapper_MapperDotbaLocalMaxRefinements") + + + # Patch match stereo + parser.add_argument("--PatchMatchStereo.max_image_size", type=int, dest="patchMatchStereo_PatchMatchStereoDotMaxImageSize") + parser.add_argument("--PatchMatchStereo.window_radius", type=int, dest="patchMatchStereo_PatchMatchStereoDotWindowRadius") + parser.add_argument("--PatchMatchStereo.window_step", type=int, dest="patchMatchStereo_PatchMatchStereoDotWindowStep") + parser.add_argument("--PatchMatchStereo.num_samples", type=int, dest="patchMatchStereo_PatchMatchStereoDotNumSamples") + parser.add_argument("--PatchMatchStereo.num_iterations", type=int, dest="patchMatchStereo_PatchMatchStereoDotNumIterations") + parser.add_argument("--PatchMatchStereo.geom_consistency", type=int, dest="patchMatchStereo_PatchMatchStereoDotGeomConsistency") + + # Stereo fusion + parser.add_argument("--StereoFusion.check_num_images", type=int, dest="stereoFusion_CheckNumImages") + parser.add_argument("--StereoFusion.max_image_size", type=int, dest="stereoFusion_MaxImageSize") + + args = vars(parser.parse_args()) + + # Update args with quality values + with open(os.path.join(os.path.abspath(os.path.dirname(__file__)), "ColmapQualityParameters.json"), "r") as qualityParamsFile: + qualityParams = json.load(qualityParamsFile) + + for key, value in qualityParams.items(): + if not key in args or args[key] is None: + args[key] = qualityParams[key][args["quality"]] if args["quality"] in qualityParams[key] else qualityParams[key]["default"] + + # Get process steps + with open(os.path.join(os.path.abspath(os.path.dirname(__file__)), "SelectiveColmapProcessSteps.json"), "r") as processStepsFile: + steps = json.load(processStepsFile)["steps"] + + # apply selective processing + exclude_steps = [] + if( args["exclude_steps"] != 'default' ): + exclude_steps = args["exclude_steps"].split() + + from_step = args["from_step"] + to_step = args["to_step"] + + # treat pre-defined cases + if( args["fix_cameras"] or args["fix_cameras_stereo"]): + new_steps = [] + for s in steps: + if( s['name'] == "fix_cameras" ): + print(s) + (s['function_args'])['photoName'] = "00" + if args["fix_cameras_stereo"]: + (s['function_args'])['sparse_subdir'] = os.path.join(os.path.join("colmap", "stereo"), "sparse") + new_steps.append(s) + break + steps = new_steps + + if( args["calibrate_only"] or args["calibrate_only_process_test"] ): + from_step = "build_dataset_structure" + to_step = "colmap_patch_match_stereo" + if( args["calibrate_only"] ): + exclude_steps = [ "extract_video_frames", "fix_cameras", "colmap_image_deleter_colmap", "remove_video_images" ] + + if( args["mvs_only"] ): + from_step = "colmap_patch_match_stereo" + to_step = "use_eol_fixed_mesh" + + + if( from_step != 'default' ): + # check if to_step exists + if( to_step != 'default' ): + # select steps + newsteps = [] + adding_steps = False + for s in steps: + if( s['name'] == from_step ): + adding_steps = True + # special case for last step that should be added + if( s['name'] == to_step and s['name'] != "use_eol_fixed_mesh" ): + break + if adding_steps : + if not (s['name'] in exclude_steps): + newsteps.append(s) + steps = newsteps + else: + print("--from_step given without --to_step; ignoring") + + if args["dry_run"]: + print("Keeping only following steps: ") + for s in steps: + print (s['name']) + + # Fixing path values + args["path"] = os.path.abspath(args["path"]) + args["sibrBinariesPath"] = os.path.abspath(args["sibrBinariesPath"]) + args["colmapPath"] = os.path.abspath(args["colmapPath"]) + + args["gpusIndices"] = ','.join([str(i) for i in range(args["numGPUs"])]) + + programs = { + "colmap": { + "path": getColmap(args["colmapPath"]) + }, + "unwrapMesh": { + "path": getProcess("unwrapMesh", args["sibrBinariesPath"]) + }, + "textureMesh": { + "path": getProcess("textureMesh", args["sibrBinariesPath"]) + }, + } + + pipeline = TaskPipeline(args, steps, programs) + + pipeline.runProcessSteps() + + print("selectiveColmapProcess has finished successfully.") + sys.exit(0) + +if __name__ == "__main__": + main() diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/fullColmapProcess/selective_colmap_process.py b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/fullColmapProcess/selective_colmap_process.py new file mode 100644 index 0000000000000000000000000000000000000000..39b36a5641f60feb7c5f04b64adb5b6f4ec69116 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/fullColmapProcess/selective_colmap_process.py @@ -0,0 +1,390 @@ +import os +import os.path +import sys +import argparse +import shutil +import sqlite3 +import read_write_model as rwm + + +import cv2 +print(cv2.__version__) + + +def extract_images(pathIn, pathOut, videoName, maxNumFrames = -1, resize=False): + EVERY_NTH = 2 + count = 0 + vidcap = cv2.VideoCapture(pathIn) + fps = round(vidcap.get(cv2.CAP_PROP_FPS)) + total_frames = vidcap.get(7)/EVERY_NTH + print("FPS = ", fps) + success,image = vidcap.read() + success = True + print("Extracting ", total_frames, " Frames" ) + fileNames = [] + newFolder = pathOut + "\\%s" % (videoName) + if not os.path.exists(newFolder): + print( "Creating: ", newFolder) + os.makedirs(newFolder, exist_ok=True) + + for frame in range(round(total_frames)): + # every Nth frame + vidcap.set(cv2.CAP_PROP_POS_FRAMES,(EVERY_NTH*frame)) + success,image = vidcap.read() + if not success: + break + resized = image + if resize : + #print('Original Dimensions : ',image.shape) + scale_percent = 52 # percent of original size + width = int(image.shape[1] * scale_percent / 100) + height = int(image.shape[0] * scale_percent / 100) + dim = (width, height) + resized = cv2.resize(image, dim, interpolation = cv2.INTER_AREA) + + print( "Writing: frame # ", EVERY_NTH*frame, " " , pathOut + "\\%s\\frame%04d.png" % (videoName, count)) + fileNames.append("%s\\frame%04d.png" % (videoName, count)) + cv2.imwrite( pathOut + "\\%s\\frame%04d.png" % (videoName, count), resized) # save frame as PNG file + + if maxNumFrames == count: + break; + + count = count + 1 + + return fileNames + +def extract_images_with_name(imageName, images_data, new_images_data): + add_next = False + new_images_data.append(images_data[0]) + new_images_data.append(images_data[1]) + new_images_data.append(images_data[2]) + new_images_data.append(images_data[3]) + + img_cnt = 0 + # create list with photo-only images + for line in images_data: + if line.split(): + if imageName in line.split()[-1]: + new_images_data.append(line) + img_cnt = img_cnt+1 + add_next = True + elif add_next: + new_images_data.append(line) + add_next = False + else: + add_next = False + + return new_images_data, img_cnt + +def remove_lines_from_file(fname, match, nextDel=False): + newdata = [] + prevMatch = False + with open(fname, 'r') as imagesfile: + data = imagesfile.read().splitlines() + for line in data: + if match in line: + if nextDel: + prevMatch = True + elif (not match in line) and (not prevMatch): + newdata.append(line) + prevMatch = False + else: + prevMatch = False + + # overwrite + with open(fname, 'w') as outfile: + for line in newdata: + outfile.write(line + "\n") + + + +def remove_video_images(path, photoName="MG_"): + # make backups + oldb = os.path.abspath(os.path.join(path, "colmap\\dataset.db" )) # will be modified + backuppath = dstpath = os.path.join(path, "backups\\two_cams_all_images\\") + if not os.path.exists(dstpath): + os.makedirs(dstpath, exist_ok=True) + + dbfile = os.path.abspath(os.path.join(dstpath,"dataset.db")) + oldb = os.path.abspath(os.path.join(path, "colmap\\dataset.db" )) # will be modified + if not os.path.exists(dbfile): + shutil.copyfile(oldb, dbfile) + + + # Read images.txt & cameras.txt + backup_images = os.path.abspath(os.path.join(dstpath,"images.txt")) + images_fname = os.path.abspath(os.path.join(path, "colmap\\sparse\\")) + "\\images.txt" + if not os.path.exists(backup_images): + shutil.copyfile(images_fname, backup_images) + + backup_cameras = os.path.abspath(os.path.join(dstpath,"cameras.txt")) + cameras_fname = os.path.abspath(os.path.join(path, "colmap\\sparse\\")) + "\\cameras.txt" + if not os.path.exists(backup_cameras): + shutil.copyfile(cameras_fname, backup_cameras) + + # extract photos only for images.txt + with open(images_fname, 'r') as imagesfile: + images_data = imagesfile.read().splitlines() + + videoDirList = [] + imagespath = os.path.abspath(os.path.join(path, "images")) + for filename in os.listdir(imagespath): + if "Video" in filename: + videoDirList.append(filename) + + new_images_data = [] + new_images_data, img_cnt = extract_images_with_name(photoName, images_data, new_images_data) + + # remaining images + print("Remaining images ", img_cnt) + + new_images_data[3] = ' '.join(images_data[3].split()[0:4]) + " " + str(img_cnt) +" " + ' '.join(images_data[3].split()[5:-1] ) + + # overwrite current calibration + dstpath = os.path.abspath(os.path.join(path, "colmap\\sparse")) + with open(dstpath+"\\images.txt", 'w') as outfile: + for line in new_images_data: + outfile.write(str(line) + "\n") + + outfile.close() + print("Writing fixed images ", dstpath + "\\images.txt") + ims = rwm.read_images_text(dstpath + "\\images.txt") + rwm.write_images_binary(ims, dstpath + "\\images.bin") + + # fix the database + + # open the database + db = sqlite3.connect(oldb) + cursor = db.cursor() + cursor.execute("SELECT name FROM sqlite_master WHERE type='table';") + tables = cursor.fetchall() + # debug + delImagesQuery = """DELETE from images WHERE name LIKE '%Video%'""" + cursor.execute(delImagesQuery) + + db.commit() + + # write out database + db.close() + + # create GT path directories + dstpath = os.path.abspath(os.path.join(path, "paths_GT")) + + if not os.path.exists(dstpath): + print("Creating ", dstpath) + os.makedirs(dstpath) + + + # backup original (distorted) video images & move undistorted images to special directories + # then create the colmap data for each + + for currVideoName in videoDirList: + # move the original videos to backup + imagespath = os.path.abspath(os.path.join(path, "images")) + shutil.move(imagespath + "\\" + currVideoName, backuppath+ "\\" + currVideoName) + + # create GT_path dir + dstpath = os.path.abspath(os.path.join(path, "paths_GT")) + curr_GTpath_dir = dstpath + "\\" + currVideoName + print("Creating ", curr_GTpath_dir) + os.makedirs(curr_GTpath_dir) + os.makedirs(curr_GTpath_dir+"\\images") + + # move undistorted mages to GT_path dir + imagespath = path + "\\colmap\\stereo\\images\\"+ currVideoName + shutil.move(imagespath, curr_GTpath_dir + "\\images") + + video_images_list = [] + video_images_list, img_cnt = extract_images_with_name(currVideoName, images_data, video_images_list) + video_images_list[2] = ' '.join(images_data[2].split()[0:4]) + " " + str(img_cnt) +" " + ' '.join(images_data[2].split()[5:-1] ) + + # create colmap data + dstpath = os.path.abspath(os.path.join(curr_GTpath_dir, "text")) + os.makedirs(dstpath) + + with open(dstpath+"\\images.txt", 'w') as outfile: + for line in video_images_list: + outfile.write(str(line) + "\n") + + cameras_fname = os.path.abspath(os.path.join(path, "colmap\\sparse\\")) + "\\cameras.txt" + shutil.copyfile(cameras_fname, dstpath+"\\cameras.txt") + + points_fname = os.path.abspath(os.path.join(path, "colmap\\sparse\\")) + "\\points3D.txt" + shutil.copyfile(points_fname, dstpath+"\\points3D.txt") + + fname = os.path.abspath(os.path.join(path, "colmap\\stereo\\stereo\\fusion.cfg")) + remove_lines_from_file(fname, "Video", False) + fname = os.path.abspath(os.path.join(path, "colmap\\stereo\\stereo\\patch-match.cfg")) + remove_lines_from_file(fname, "Video", True) + # all done + + +def fix_cameras(path, photoName="MG_", sparseSubdir=""): + if sparseSubdir == "": + sparse_subdir = os.path.join("colmap", "sparse") + else: + sparse_subdir = sparseSubdir + + # Read images.txt + images_fname = os.path.abspath(os.path.join(path, sparse_subdir)) + "\\images.txt" + with open(images_fname, 'r') as imagesfile: + images_data = imagesfile.read().splitlines() + + # Read cameras.txt + cameras_fname = os.path.abspath(os.path.join(path, sparse_subdir)) + "\\cameras.txt" + with open(cameras_fname, 'r') as camerasfile: + cameras_data = camerasfile.read().splitlines() + + # find the first camera index for a photo + photoCamIndex = -1 + for line in images_data: + if line.split(): + if (photoName in line.split()[-1]) and (int(line.split()[0]) > 2): + photoCamIndex = line.split()[0] + print("Found Photo Camera Index ", photoCamIndex, " for camera ", line.split()[-1]) + break + + # find the first camera index for a video + videoCamIndex = -1 + for line in images_data: + if line.split(): + if ("Video" in line.split()[-1]) and ( int(line.split()[0]) > 2): + videoCamIndex = line.split()[0] + print("Found Video Camera Index ", videoCamIndex, " for camera ", line.split()[-1]) + break + + # make backups of original files + dstpath = os.path.join(path, "backups\\") + if not os.path.exists(dstpath): + os.makedirs(dstpath, exist_ok=True) + # + dstpath = os.path.join(path, "backups\\orig\\") + if not os.path.exists(dstpath): + os.makedirs(dstpath, exist_ok=True) + + # make backups of original files + if not os.path.exists(dstpath+"\\images.txt"): + shutil.copyfile(images_fname, dstpath +"\\images.txt") + if not os.path.exists(dstpath+"\\cameras.txt"): + shutil.copyfile(cameras_fname, dstpath +"\\cameras.txt") + + dbfile = os.path.abspath(os.path.join(dstpath,"dataset.db")) + oldb = os.path.abspath(os.path.join(path, "colmap\\dataset.db" )) # will be modified + if os.path.exists(oldb): # only do DB processing if it exists + print("Old ", oldb, " new ", dbfile, " path ", path) + if not os.path.exists(dbfile): + shutil.copyfile(oldb, dbfile) + + # open the database + db = sqlite3.connect(oldb) + cursor = db.cursor() + cursor.execute("SELECT name FROM sqlite_master WHERE type='table';") + tables = cursor.fetchall() + # debug + # table = pd.read_sql_query("SELECT * from %s" % 'images', db) + + # delete all cameras except videoCamEntry and photoCamEntry from database + delCamQuery = """DELETE from cameras WHERE camera_id != '%s' and camera_id != '%s'""" % (videoCamIndex, photoCamIndex) + cursor.execute(delCamQuery ) + + # change photo cam id to 1 and video cam id to 2 + setQuery = "UPDATE cameras SET camera_id = '%s' WHERE camera_id = '%s'" % ("1", photoCamIndex) + cursor.execute(setQuery) + + setQuery = "UPDATE cameras SET camera_id = '%s' WHERE camera_id = '%s'" % ("2", videoCamIndex) + cursor.execute(setQuery) + + # change photo cam id to 1 for all images of photos + setQuery = "UPDATE images SET camera_id = '1' WHERE name LIKE '%MG_%'" + cursor.execute(setQuery) + + # change video cam id to 2 for all images + setQuery = "UPDATE images SET camera_id = '2' WHERE name LIKE '%Video%'" + cursor.execute(setQuery) + + db.commit() + + # write out database ; next step re-exports the result to TXT and BIN + db.close() + + # replace all camera indices in images.txt + new_images_data = images_data + cnt = 0 + for line in new_images_data: + if line.split(): + if photoName in line.split()[-1]: + new_images_data[cnt] = ' '.join(line.split()[0:-2]) + " 1 " + line.split()[-1] + print("replace ", line.split()[0], " by 1 in ", new_images_data[cnt] ) + elif "Video" in line.split()[-1]: + new_images_data[cnt] = ' '.join(line.split()[0:-2]) + " 2 " + line.split()[-1] + + cnt = cnt + 1 + + videoCamEntry = "" + for line in cameras_data: + if line.split(): + if photoCamIndex == line.split()[0]: + photoCamEntry = "1 " + ' '.join(line.split()[1:]) + if videoCamIndex == line.split()[0]: + videoCamEntry = "2 " + ' '.join(line.split()[1:]) + + # create two element camera file one for photos one for video + dstpath = os.path.abspath(os.path.join(path, "colmap\\sparse\\")) + dst = dstpath + "\\cameras_two.txt" + with open(dst, 'w') as outfile: + outfile.write(photoCamEntry + "\n") + if( videoCamEntry != "" ): + outfile.write(videoCamEntry + "\n") + outfile.close() + + # write out new file + dst = dstpath + "\\images_two.txt" + with open(dst, 'w') as outfile: + for line in new_images_data: + outfile.write(line + "\n") + outfile.close() + + # replace files + dstpath = os.path.abspath(os.path.join(path, "colmap\\sparse\\")) + shutil.move(dstpath + "\\images_two.txt", images_fname) + shutil.move(dstpath + "\\cameras_two.txt", cameras_fname) + + dstpath = os.path.abspath(os.path.join(path, "colmap\\sparse\\")) + print("Writing cam/im binary ", dstpath + "\\cameras.bin") + cams = rwm.read_cameras_text(dstpath + "\\cameras.txt") + ims = rwm.read_images_text(dstpath + "\\images.txt") + rwm.write_cameras_binary(cams, dstpath + "\\cameras.bin") + rwm.write_images_binary(ims, dstpath + "\\images.bin") + + ptsbin = dstpath+"\\0\\points3D.bin" + print("Pts bin ", ptsbin, " Exists " ,os.path.exists(ptsbin)) + if os.path.exists(ptsbin): + shutil.copyfile(ptsbin, dstpath+"\\points3D.bin") + + # overwrite 0 as well + dstpath = os.path.abspath(os.path.join(path, "colmap\\sparse\\0\\")) + print("Writing cam/im binary ", dstpath + "\\cameras.bin") + rwm.write_cameras_binary(cams, dstpath + "\\cameras.bin") + rwm.write_images_binary(ims, dstpath + "\\images.bin") + rwm.write_cameras_text(cams, dstpath + "\\cameras.txt") + rwm.write_images_text(ims, dstpath + "\\images.txt") + + return True + +def extract_video_frames(pathIn, pathOut): + cnt = 0 + fileNames = [] + for filename in os.listdir(pathIn): + if ("MP4" in filename) or ("mp4" in filename): + with open(os.path.join(pathIn, filename), 'r') as f: + print("Extracting Video from File: ", f.name) +# fileNames = fileNames + extract_images(f.name, pathOut, "Video%d" % cnt, maxNumFrames=3, resize=True) + fileNames = fileNames + extract_images(f.name, pathOut, "Video%d" % cnt, resize=True) +# extract_images(f.name, pathOut, videoName="Video%d" % cnt) + cnt = cnt+1 + + with open(os.path.dirname(pathIn) + "\\videos\\Video_Frames.txt", 'w') as f: + for item in fileNames: + f.write("%s\n" % item.replace("\\", "/")) + f.close() + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/fullColmapProcess/textureOnly.py b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/fullColmapProcess/textureOnly.py new file mode 100644 index 0000000000000000000000000000000000000000..f9fd2603ea106475a37b425830f0e519e697a62b --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/fullColmapProcess/textureOnly.py @@ -0,0 +1,89 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +#!/usr/bin/env python +#! -*- encoding: utf-8 -*- + +""" @package dataset_tools_preprocess +This script runs a pipeline to texture a mesh after colmap has been run + +Parameters: -h help, + -path , + -sibrBinariesPath , + +Usage: python textureOnly.py -path + -sibrBinariesPath + +""" + +import subprocess +import os, sys, getopt +import os, sys, shutil +import json +import argparse +from utils.paths import getBinariesPath +from utils.commands import getProcess +from utils.TaskPipeline import TaskPipeline +from simplify_mesh import simplifyMesh + +def main(): + parser = argparse.ArgumentParser() + + # common arguments + parser.add_argument("--path", type=str, required=True, help="path to your dataset folder") + parser.add_argument("--sibrBinariesPath", type=str, default=getBinariesPath(), help="binaries directory of SIBR") + parser.add_argument("--dry_run", action='store_true', help="run without calling commands") + + + args = vars(parser.parse_args()) + + + # Fixing path values + args["path"] = os.path.abspath(args["path"]) + args["sibrBinariesPath"] = os.path.abspath(args["sibrBinariesPath"]) + + ret = simplifyMesh( args["path"] + "/colmap/stereo/unix-meshed-delaunay.ply", args["path"] + "/colmap/stereo/unix-meshed-delaunay-simplified.ply") + print("RET ", ret) + if( ret.returncode != 0 ): + print("SIBR ERROR: meshlab simplify failed, exiting") + sys.exit(1) + + unwrap_app = getProcess("unwrapMesh") + unwrap_args = [unwrap_app, + "--path", args["path"] + "/colmap/stereo/unix-meshed-delaunay-simplified.ply", + "--output", args["path"] + "/capreal/mesh.ply", + ] + + print("Running unwrap mesh ", unwrap_args) + p_exit = subprocess.call(unwrap_args) + if p_exit != 0: + print("SIBR ERROR: unwrap failed, exiting") + sys.exit(1) + + texturemesh_app = getProcess("textureMesh") + texturemesh_args = [texturemesh_app, + "--path", args["path"], + "--output", args["path"] + "/capreal/texture.png", + "--size", "8192", + "--flood" + ] + + print("Texturing mesh ", texturemesh_args) + p_exit = subprocess.call(texturemesh_args) + if p_exit != 0: + print("SIBR ERROR: mesh texturing failed, exiting") + sys.exit(1) + + + print("textureonly has finished successfully.") + sys.exit(0) + +if __name__ == "__main__": + main() diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/meshroomPythonScripts/CMakeLists.txt b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/meshroomPythonScripts/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..67ce9af31ed5e850d5b2d3a2dc3903ed22bbf130 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/meshroomPythonScripts/CMakeLists.txt @@ -0,0 +1,19 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +project(meshroomPythonScripts) + +file(GLOB SCRIPTS "*.py") + +add_custom_target(${PROJECT_NAME} ALL) + +include(install_runtime) +set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER "projects/dataset_tools/preprocess") +ibr_install_rsc(${PROJECT_NAME} TYPE "scripts" FILES ${SCRIPTS}) diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/meshroomPythonScripts/ULR.py b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/meshroomPythonScripts/ULR.py new file mode 100644 index 0000000000000000000000000000000000000000..6c67b7706e89111df6b5df13939b10857264fd11 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/meshroomPythonScripts/ULR.py @@ -0,0 +1,50 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +#!/usr/bin/env python +#! -*- encoding: utf-8 -*- +__version__ = "3.0" + +from meshroom.core import desc +import os + +class ULR(desc.CommandLineNode): + commandLine = 'SIBR_ulrv2_app_rwdi {allParams}' + + print(os.path.abspath('.')) + cpu = desc.Level.INTENSIVE + ram = desc.Level.INTENSIVE + + inputs = [ + desc.ListAttribute( + elementDesc = desc.File( + name = "path", + label = "Cache folder", + description = "", + value = desc.Node.internalFolder + "../..", + uid=[0], + ), + name='path', + label='Input Folder', + description='MeshroomCache folder containing the StructureFromMotion folder, PrepareDenseScene folder, and Texturing folder.' + ), + desc.ChoiceParam( + name='texture-width', + label='Texture Width', + description='''Output texture size''', + value=1024, + values=(256, 512, 1024, 2048, 4096), + exclusive=True, + uid=[0], + ), + ] + + outputs = [ + ] diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/nvmToSIBR/CMakeLists.txt b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/nvmToSIBR/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..bb6d264881a0cdedbc41d5c9cc7248c5b20aebef --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/nvmToSIBR/CMakeLists.txt @@ -0,0 +1,33 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +project(nvmToSIBR) + +# Define build output for project +add_executable(${PROJECT_NAME} main.cpp) + +target_link_libraries(${PROJECT_NAME} + ${Boost_LIBRARIES} + sibr_graphics + sibr_assets + sibr_raycaster + sibr_system + sibr_view +) + +set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER "projects/dataset_tools/preprocess") + +## High level macro to install in an homogen way all our ibr targets +include(install_runtime) +ibr_install_target(${PROJECT_NAME} + INSTALL_PDB ## mean install also MSVC IDE *.pdb file (DEST according to target type) + STANDALONE ${INSTALL_STANDALONE} ## mean call install_runtime with bundle dependencies resolution + COMPONENT ${PROJECT_NAME}_install ## will create custom target to install only this project +) diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/nvmToSIBR/main.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/nvmToSIBR/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3fc6bef9adbf7915d3ca4e98b89c1eaa34f6eb00 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/nvmToSIBR/main.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include +#include +#include +#include +#include +#include +#include + + +#define PROGRAM_NAME "sibr_nvm_to_sibr" +using namespace sibr; + +const char* usage = "" +"Usage: " PROGRAM_NAME " -path " "\n" +; + +struct ColmapPreprocessArgs : + virtual BasicIBRAppArgs { +}; + +int main(const int argc, const char** argv) +{ + + CommandLineArgs::parseMainArgs(argc, argv); + ColmapPreprocessArgs myArgs; + + std::string pathScene = myArgs.dataset_path; + + std::vector dirs = { "cameras", "images", "meshes"}; + + std::cout << "Generating SIBR scene." << std::endl; + BasicIBRScene scene(myArgs, true); + + // load the cams + std::vector cams = scene.cameras()->inputCameras(); + const int maxCam = int(cams.size()); + const int minCam = 0; + + for (auto dir : dirs) { + std::cout << dir << std::endl; + if (!directoryExists(pathScene + "/" + dir.c_str())) { + makeDirectory(pathScene + "/" + dir.c_str()); + } + } + + std::ofstream outputBundleCam; + std::ofstream outputListIm; + std::ofstream outputSceneMetadata; + + outputBundleCam.open(pathScene + "/cameras/bundle.out"); + outputListIm.open(pathScene + "/images/list_images.txt"); + outputSceneMetadata.open(pathScene + "/scene_metadata.txt"); + outputBundleCam << "# Bundle file v0.3" << std::endl; + outputBundleCam << maxCam << " " << 0 << std::endl; + outputSceneMetadata << "Scene Metadata File\n" << std::endl; + outputSceneMetadata << "[list_images]\n " << std::endl; + + std::sort(cams.begin(), cams.end(), [](const InputCamera::Ptr & a, const InputCamera::Ptr & b) { + return a->id() < b->id(); + }); + + for (int c = minCam; c < maxCam; c++) { + InputCamera & camIm = *cams[c]; + + std::string extensionFile = boost::filesystem::extension(camIm.name()); + std::ostringstream ssZeroPad; + ssZeroPad << std::setw(8) << std::setfill('0') << camIm.id(); + std::string newFileName = ssZeroPad.str() + extensionFile; + + boost::filesystem::copy_file(pathScene + "/nvm/" + camIm.name(), pathScene + "/images/" + newFileName, boost::filesystem::copy_option::overwrite_if_exists); + outputBundleCam << camIm.toBundleString(); + outputListIm << newFileName << " " << camIm.w() << " " << camIm.h() << std::endl; + outputSceneMetadata << newFileName << " " << camIm.w() << " " << camIm.h() << " " << camIm.znear() << " " << camIm.zfar() << std::endl; + } + + + outputSceneMetadata << "\n// Always specify active/exclude images after list images\n\n[exclude_images]\n ... " << std::endl; + + for (int i = 0; i < scene.data()->activeImages().size(); i++) { + if (!scene.data()->activeImages()[i]) + outputSceneMetadata << i << " "; + } + + outputSceneMetadata << "\n\n\n[other parameters]" << std::endl; + + outputBundleCam.close(); + outputListIm.close(); + outputSceneMetadata.close(); + + const std::string meshPath = pathScene + "/capreal/mesh.ply"; + sibr::copyFile(meshPath, pathScene + "/meshes/recon.ply", true); + + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/prepareColmap4Sibr/CMakeLists.txt b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/prepareColmap4Sibr/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..fc2fb3ed59c83a6486233526329c7fdf7a141052 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/prepareColmap4Sibr/CMakeLists.txt @@ -0,0 +1,33 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +project(prepareColmap4Sibr) + +# Define build output for project +add_executable(${PROJECT_NAME} main.cpp) + +target_link_libraries(${PROJECT_NAME} + ${Boost_LIBRARIES} + sibr_graphics + sibr_assets + sibr_raycaster + sibr_system + sibr_view +) + +set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER "projects/dataset_tools/preprocess") + +## High level macro to install in an homogen way all our ibr targets +include(install_runtime) +ibr_install_target(${PROJECT_NAME} + INSTALL_PDB ## mean install also MSVC IDE *.pdb file (DEST according to target type) + STANDALONE ${INSTALL_STANDALONE} ## mean call install_runtime with bundle dependencies resolution + COMPONENT ${PROJECT_NAME}_install ## will create custom target to install only this project +) diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/prepareColmap4Sibr/main.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/prepareColmap4Sibr/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ae44c53dd15fc3b1f739cbeedef9d10e79ced98a --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/prepareColmap4Sibr/main.cpp @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include +#include +#include +#include +#include +#include +#include + + +#define PROGRAM_NAME "prepareColmap4Sibr" +using namespace sibr; + +const char* usage = "" +"Usage: " PROGRAM_NAME " -path " "\n" +; + +struct ColmapPreprocessArgs : public BasicIBRAppArgs { + Arg fix_metadata = { "fix_metadata", "Fix scene_metadata after crop and distort " }; +}; + +int main(const int argc, const char** argv) +{ + + CommandLineArgs::parseMainArgs(argc, argv); + ColmapPreprocessArgs myArgs; + + std::string pathScene = myArgs.dataset_path; + + std::vector dirs = { "sfm_mvs_cm" , "sibr_cm" }; + + std::ofstream outputSceneMetadata; + + if( myArgs.fix_metadata ) { + std::string cm_path = myArgs.dataset_path.get() + "/sibr_cm"; + myArgs.dataset_path = cm_path; + + BasicIBRScene cm_scene(myArgs, true, true); + + std::vector cams = cm_scene.cameras()->inputCameras(); + + std::string tmpFileName = cm_path + "/scene_metadata_tmp.txt"; + // done in a second pass, when everything has been created. + outputSceneMetadata.open(tmpFileName); + + // overwrite previous version since image sizes have changed when running sibr preprocessing + outputSceneMetadata << "Scene Metadata File\n" << std::endl; + + if (outputSceneMetadata.bad()) + SIBR_ERR << "Problem writing new metadata file" << std::endl; + + SIBR_LOG << "Writing new scene_metadata.txt file " << cm_path + "/scene_metadata.txt" << std::endl; + + outputSceneMetadata << "[list_images]\n " << std::endl; + + for (int c = 0; c < cams.size(); c++) { + InputCamera & camIm = *cams[c]; + + std::string extensionFile = boost::filesystem::extension(camIm.name()); + std::ostringstream ssZeroPad; + ssZeroPad << std::setw(8) << std::setfill('0') << camIm.id(); + std::string newFileName = ssZeroPad.str() + extensionFile; + // load image + std::string imgpath = cm_path + "/images/" + camIm.name(); + sibr::ImageRGB im; + if (!im.load(imgpath, false)) + SIBR_ERR << "Cant open image " << imgpath << std::endl; + + std::cerr << newFileName << " " << im.w() << " " << im.h() << " " << camIm.znear() << " " << camIm.zfar() << std::endl; + outputSceneMetadata << newFileName << " " << im.w() << " " << im.h() << " " << camIm.znear() << " " << camIm.zfar() << std::endl; + } + + outputSceneMetadata << "\n// Always specify active/exclude images after list images\n\n[exclude_images]\n ... " << std::endl; + + for (int i = 0; i < cm_scene.data()->activeImages().size(); i++) { + if (!cm_scene.data()->activeImages()[i]) + outputSceneMetadata << i << " "; + } + outputSceneMetadata << "\n\n\n[other parameters]" << std::endl; + outputSceneMetadata.close(); + + std::string SMName = cm_path + "/scene_metadata.txt"; + + SIBR_LOG << "Copying " << tmpFileName << " to " << SMName << std::endl; + boost::filesystem::copy_file( tmpFileName, SMName, boost::filesystem::copy_option::overwrite_if_exists); + boost::filesystem::remove(tmpFileName); + + exit(0); + } + std::cout << "Creating bundle file for SIBR scene." << std::endl; + BasicIBRScene scene(myArgs, true, true); + + // load the cams + std::vector cams = scene.cameras()->inputCameras(); + const int maxCam = int(cams.size()); + const int minCam = 0; + + for (auto dir : dirs) { + std::cout << dir << std::endl; + if (!directoryExists(pathScene + "/" + dir.c_str())) { + makeDirectory(pathScene + "/" + dir.c_str()); + } + } + + std::ofstream outputBundleCam; + std::ofstream outputListIm; + + outputBundleCam.open(pathScene + "/sfm_mvs_cm/bundle.out"); + outputListIm.open(pathScene + "/sfm_mvs_cm/list_images.txt"); + outputBundleCam << "# Bundle file v0.3" << std::endl; + outputBundleCam << maxCam << " " << 0 << std::endl; + + outputSceneMetadata.open(pathScene + "/sibr_cm/scene_metadata.txt"); + outputSceneMetadata << "Scene Metadata File\n" << std::endl; + outputSceneMetadata << "[list_images]\n " << std::endl; + + std::sort(cams.begin(), cams.end(), [](const InputCamera::Ptr & a, const InputCamera::Ptr & b) { + return a->id() < b->id(); + }); + + for (int c = minCam; c < maxCam; c++) { + InputCamera & camIm = *cams[c]; + + std::string extensionFile = boost::filesystem::extension(camIm.name()); + std::ostringstream ssZeroPad; + ssZeroPad << std::setw(8) << std::setfill('0') << camIm.id(); + std::string newFileName = ssZeroPad.str() + extensionFile; + + boost::filesystem::copy_file(pathScene + "/colmap/stereo/images/" + camIm.name(), pathScene + "/sfm_mvs_cm/" + newFileName, boost::filesystem::copy_option::overwrite_if_exists); + // keep focal + outputBundleCam << camIm.toBundleString(false, true); + outputListIm << newFileName << " " << camIm.w() << " " << camIm.h() << std::endl; + outputSceneMetadata << newFileName << " " << camIm.w() << " " << camIm.h() << " " << camIm.znear() << " " << camIm.zfar() << std::endl; + } + + outputSceneMetadata << "\n// Always specify active/exclude images after list images\n\n[exclude_images]\n ... " << std::endl; + + for (int i = 0; i < scene.data()->activeImages().size(); i++) { + if (!scene.data()->activeImages()[i]) + outputSceneMetadata << i << " "; + } + outputSceneMetadata << "\n\n\n[other parameters]" << std::endl; + + + outputBundleCam.close(); + outputListIm.close(); + outputSceneMetadata.close(); + + std::vector> meshPathList = { + { "/capreal/mesh.ply", "/sfm_mvs_cm/recon.ply"}, + { "/capreal/mesh.obj", "/sfm_mvs_cm/recon.ply"}, + { "/capreal/mesh.mtl", "/sfm_mvs_cm/"}, + { "/capreal/texture.png", "/sfm_mvs_cm/"}, + { "/capreal/mesh_u1_v1.png", "/sfm_mvs_cm/"}, + { "/colmap/stereo/meshed-delaunay.ply", "/sfm_mvs_cm/recon.ply"}, + }; + + bool success = false; + for(const std::vector & meshPaths : meshPathList) { + if(boost::filesystem::exists(pathScene + meshPaths[0])) { + sibr::copyFile(pathScene + meshPaths[0], pathScene + meshPaths[1], true); + success = true; + } + } + if (!success) { + std::cerr << "Couldnt file proxy geometry in any of the following places "; + for (const std::vector& meshPaths : meshPathList) + std::cerr << pathScene + meshPaths[0] << std::endl; + SIBR_ERR << "No proxy geometry, exiting" << std::endl; + + } + + return EXIT_SUCCESS; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/realityCaptureTools/CMakeLists.txt b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/realityCaptureTools/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..bd77dc9963eae2bc7c1faca0fe447df179be715e --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/realityCaptureTools/CMakeLists.txt @@ -0,0 +1,19 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +project(realityCaptureTools) + +file(GLOB SCRIPTS "*.py" "*.json" ".bat" ".xml") + +add_custom_target(${PROJECT_NAME} ALL) + +include(install_runtime) +set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER "projects/dataset_tools/preprocess") +ibr_install_rsc(${PROJECT_NAME} TYPE "scripts" FILES ${SCRIPTS}) diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/realityCaptureTools/SetVariables.bat b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/realityCaptureTools/SetVariables.bat new file mode 100644 index 0000000000000000000000000000000000000000..1178242c57def7d72764548a73495161f47e5ab1 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/realityCaptureTools/SetVariables.bat @@ -0,0 +1,9 @@ +::CapturingReality +:: switch off console output +::@echo off + + +:: root path to work folders where the dataset is stored +set RootFolder=E:\datasets\Yorgos\Reflections\KitchenRCTest\ +set Video="%RootFolder%\videos\MVI_3030.MP4" +set FPS=0.2 diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/realityCaptureTools/exportModel.xml b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/realityCaptureTools/exportModel.xml new file mode 100755 index 0000000000000000000000000000000000000000..3eb2b11daa2c9af602b84d448c0a3568e7e88570 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/realityCaptureTools/exportModel.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/realityCaptureTools/fixup.bat b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/realityCaptureTools/fixup.bat new file mode 100644 index 0000000000000000000000000000000000000000..8787279ae4d22bbd743f951d73290522c6d01178 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/realityCaptureTools/fixup.bat @@ -0,0 +1,27 @@ +::CapturingReality + +:: switch off console output +::@echo off +@echo on +set RootFolder=%1 + +:: path to RealityCapture application +set RealityCaptureExe="C:\Program Files\Capturing Reality\RealityCapture\RealityCapture.exe" + +:: variable storing path to images for texturing model +set Project="%RootFolder%\rcProj\RCproject.rcproj" + +:: run RealityCapture +:: test and fix video import when RC working again + +%RealityCaptureExe% -load %Project% ^ + -selectAllImages ^ + -enableAlignment false ^ + -selectImage *test_* ^ + -enableAlignment true ^ + + + + + + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/realityCaptureTools/processRCSteps.json b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/realityCaptureTools/processRCSteps.json new file mode 100644 index 0000000000000000000000000000000000000000..41e653ae1f34c5e7e1c26dfc24d154823245aac5 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/realityCaptureTools/processRCSteps.json @@ -0,0 +1,228 @@ +{ + "steps" : [ + { + "if": "${car_data}", + "name": "car_data_process", + "function": "rc_tools.car_data_process", + "function_args": { + "path": "${path}" + } + }, + { + "name": "preprocess_for_rc", + "function": "rc_tools.preprocess_for_rc", + "function_args": { + "path": "${path}", + "video_name": "${video_name}", + "do_validation_split": "${do_validation_split}", + "valid_skip": "${valid_skip}" + } + }, + { + "if" : "${calib_only}", + "name": "calib_only", + "app": "RC", + "optional_arg1": [ + "${do_train}", + "-addFolder", "${path}/input/train/" + ], + "optional_arg2": [ "${do_validation}", + "-addFolder", "${path}/input/validation/" + ], + "optional_arg3": [ "${do_video}", + "-importVideo", "${video_filename}", "${path}/input/test_video_frames/", "${one_over_fps}" + ], + "optional_arg4": [ "${do_test}", + "-addFolder", "${path}/input/test/" + ], + "command_args": [ + "-align" , + "-selectMaximalComponent" , + "-selectAllImages" , + "-enableAlignment", "false" , + "-selectImage", "*validation_*" , + "-enableAlignment", "true" , + "-exportRegistration", "${path}/rcScene/validation_cameras/bundle.out", "${config_folder}/registrationConfig.xml" , + "-selectAllImages" , + "-enableAlignment", "false" , + "-selectImage", "*${path_prefix}*", + "-enableAlignment", "true" , + "-exportRegistration", "${path}/rcScene/test_path_cameras/bundle.out", "${config_folder}/registrationConfig.xml" , + "-selectAllImages" , + "-enableAlignment", "false" , + "-selectImage", "*train_*" , + "-enableAlignment", "true" , + "-exportRegistration", "${path}/rcScene/train_cameras/bundle.out", "${config_folder}/registrationConfig.xml" , + "-save", "${path}/rcProj/RCproject.rcproj" , + "-quit" + ] + }, + { + "if": "${video_only}", + "name": "fix_video_only", + "function": "rc_tools.fix_video_only", + "function_args": { + "path": "${path}" + } + }, + { + "if" : "${do_mvs}", + "name": "run_rc", + "app": "RC", + "optional_arg1": [ + "${do_train}", + "-addFolder", "${path}/input/train/" + ], + "optional_arg2": [ "${do_validation}", + "-addFolder", "${path}/input/validation/" + ], + "optional_arg3": [ "${do_video}", + "-importVideo", "${video_filename}", "${path}/input/test_video_frames/", "${one_over_fps}" + ], + "optional_arg4": [ "${do_test}", + "-addFolder", "${path}/input/test/" + ], + "command_args": [ + "-align" , + "-selectMaximalComponent" , + "-selectAllImages" , + "-enableAlignment", "false" , + "-selectImage", "*validation_*" , + "-enableAlignment", "true" , + "-exportRegistration", "${path}/rcScene/validation_cameras/bundle.out", "${config_folder}/registrationConfig.xml" , + "-selectAllImages" , + "-enableAlignment", "false" , + "-selectImage", "*${path_prefix}*" , + "-enableAlignment", "true" , + "-exportRegistration", "${path}/rcScene/test_path_cameras/bundle.out", "${config_folder}/registrationConfig.xml" , + "-selectAllImages" , + "-enableAlignment", "false" , + "-selectImage", "*train_*" , + "-enableAlignment", "true" , + "-exportRegistration", "${path}/rcScene/train_cameras/bundle.out", "${config_folder}/registrationConfig.xml", + "-setReconstructionRegionAuto" , + "-scaleReconstructionRegion", "1.4", "1.4", "2.5", "center", "factor" , + "-selectAllImages" , + "-enableAlignment", "false" , + "-selectImage", "*${path_prefix}*" , + "-enableAlignment", "true" , + "-save", "${path}/rcProj/RCproject.rcproj" + ], + "optional_final_arg": [ "${auto_recon_area}", + "-quit" + ] + }, + { + "if" : "${do_mvs}", + "name": "run_rc_mvs", + "app": "RC", + "command_args": [ + "-load", "${path}/rcProj/RCproject.rcproj" , + "-selectMaximalComponent" , + "-selectAllImages" , + "-enableAlignment", "false" , + "-selectImage", "*train_*" , + "-enableAlignment", "true" , + "-calculateNormalModel" , + "-calculateTexture" , + "-selectMarginalTriangles" , + "-removeSelectedTriangles" , + "-save", "${path}/rcProj/RCproject.rcproj" , + "-renameSelectedModel", "${model_name}" , + "-exportModel", "${model_name}", "${mesh_obj_filename}", "${config_folder}/exportModel.xml" , + "-deselectModelTriangles" , + "-exportModel", "${model_name}", "${mesh_ply_filename}", "${config_folder}/exportModel.xml" , + "-quit" + ] + }, + { + "name": "densify_mesh", + "function": "rc_tools.densify_mesh", + "function_args": { + "mesh_path": "${path}/rcScene/meshes/mesh.obj" + } + }, + { + "name": "dense_mesh", + "app": "RC", + "command_args": [ + "-load", "${path}/rcProj/RCProject.rcproj", + "-selectMaximalComponent", + "-importModel" , "${path}/rcScene/meshes/dense_mesh.obj", + "-renameSelectedModel", "RCTest", + "-exportModel", "RCTest", "${path}/rcScene/meshes/dense_point_cloud.xyz", "${config_folder}/exportModel.xml" , + "-quit" + ] + }, + { + "name": "rc_to_colmap_validation_cameras", + "function": "rc_tools.rc_to_colmap", + "function_args": { + "rc_path": "${path}/rcScene/validation_cameras", + "out_path": "${path}/colmap_1000/validation_colmap", + "create_colmap": "0", + "target_width": "${target_width}" + } + }, + { + "name": "rc_to_colmap_path_cameras", + "function": "rc_tools.rc_to_colmap", + "function_args": { + "rc_path": "${path}/rcScene/test_path_cameras", + "out_path": "${path}/colmap_1000/test_path_colmap", + "create_colmap": "0", + "target_width": "${target_width}" + } + }, + { + "name": "crop_cameras", + "function": "rc_tools.crop_images", + "function_args": { + "path_data": "${path}/rcScene/train_cameras/", + "path_dest": "${path}/rcScene/cropped_train_cameras/" + } + }, + { + "name": "rc_to_colmap_1000_cropped_cameras", + "function": "rc_tools.rc_to_colmap", + "function_args": { + "rc_path": "${path}/rcScene/cropped_train_cameras", + "out_path": "${path}/colmap_1000/colmap", + "create_colmap": "1", + "target_width": "${target_width}" + } + }, + { + "name": "rc_to_colmap_cropped_cameras", + "function": "rc_tools.rc_to_colmap", + "function_args": { + "rc_path": "${path}/rcScene/cropped_train_cameras", + "out_path": "${path}/sibr/colmap", + "create_colmap": "1" + } + }, + { + "name": "create_nerf", + "function": "colmap2nerf.createNerf", + "function_args": { + "path": "${path}" + } + }, + { + "if": "${hires_nerf}", + "name": "create_hi_nerf", + "function": "colmap2nerf.createNerf", + "function_args": { + "path": "${path}", + "hires": "True" + } + }, + { + "name": "convert_sibr_mesh", + "function": "rc_tools.convert_sibr_mesh", + "function_args": { + "path": "${path}" + } + } + ] +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/realityCaptureTools/rc_tools.py b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/realityCaptureTools/rc_tools.py new file mode 100644 index 0000000000000000000000000000000000000000..cc5a21d7295f0e57b2ae24493d8928d3d3ce08c7 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/realityCaptureTools/rc_tools.py @@ -0,0 +1,526 @@ +# +# RealityCapture tools +# +import os +import os.path +import sys +import argparse +import shutil +import sqlite3 +import read_write_model as rwm +import pymeshlab + + +import cv2 +print(cv2.__version__) + + +""" @package dataset_tools_preprocess +Library for RealityCapture treatment + + +""" + +import bundle +import os, sys, shutil +import json +import argparse +import scipy +import numpy as np +from scipy.spatial.transform import Rotation as R +from utils.paths import getBinariesPath, getColmapPath, getMeshlabPath +from utils.commands import getProcess, getColmap, getRCprocess, runCommand + +def preprocess_for_rc(path, video_name='default', do_validation_split=True, valid_skip='10'): + # create train/validation split (every 10 images by default now) + print("VALID SKIP ", valid_skip) + int_valid_skip = int(valid_skip) + + # Should exist + rawpath = os.path.join(path, "raw") + if not os.path.exists(rawpath): + os.makedirs(os.path.join(path, "raw")) + + imagespath = os.path.abspath(os.path.join(rawpath, "images")) + testpath = os.path.abspath(os.path.join(rawpath, "test")) + videopath = os.path.abspath(os.path.join(rawpath, "videos")) + do_test = False + inputpath = os.path.join(path, "input") + + # If not, move around + if not os.path.exists(imagespath): + if os.path.exists(os.path.join(path, "images")): + shutil.move(os.path.join(path, "images"), imagespath) + elif not os.path.exists(os.path.join(path, "videos")) and not os.path.exists(videopath): + print("ERROR: No images nor video, exiting. Images should be in $path/raw/images") + exit(-1) + # videos are optional + if os.path.exists(os.path.join(path, "videos")): + shutil.move(os.path.join(path, "videos"), videopath) + # test images (stills for path) + test_orig = os.path.join(path, "test") +# print("TEST ", test_orig, " " , os.path.exists(test_orig) , " > ", testpath) + if os.path.exists(test_orig): + do_test = True + shutil.move(test_orig, testpath) + else: + print("Found images {}".format(imagespath)) + if os.path.exists(videopath): + print("Found video {}".format(videopath)) + if os.path.exists(testpath): + print("Found test {}".format(testpath)) + do_test = True + + cnt = 0 + validation_path = os.path.abspath(os.path.join(inputpath, "validation")) + train_path = os.path.abspath(os.path.join(inputpath, "train")) + if not os.path.exists(train_path): + os.makedirs(train_path) + if not os.path.exists(validation_path): + os.makedirs(validation_path) + input_test_path = os.path.abspath(os.path.join(inputpath, "test")) + if not os.path.exists(input_test_path): + os.makedirs(input_test_path) + + # rcScene -- will contain full bundle files from RC + rcscenepath = os.path.join(path, "rcScene") + if not os.path.exists(rcscenepath): + os.makedirs(rcscenepath) + + # rcProj -- RC project save + rcprojpath = os.path.join(path, "rcProj") + if not os.path.exists(rcprojpath): + os.makedirs(rcprojpath) + + + # sibr -- will contain full size colmap + sibrpath = os.path.join(path, "sibr") + if not os.path.exists(sibrpath): + os.makedirs(sibrpath) + caprealpath = os.path.join(sibrpath, "capreal") + os.makedirs(caprealpath) + + # BUG: do_validation_split is a string + if do_validation_split != 'False': + print("Train/Validation", train_path , " : ", validation_path) + for filename in os.listdir(imagespath): + ext = os.path.splitext(filename)[1] + if ext == ".JPG" or ext == ".jpg" or ext == ".PNG" or ext == ".png" : + image = os.path.join(imagespath, filename) +# print("IM ", image) + if not(cnt % int_valid_skip ): + filename = "validation_"+filename + fname = os.path.join(validation_path, filename) +# print("Copying ", image, " to ", fname , " in validation") + shutil.copyfile(image, fname) + else: + filename = "train_"+filename + fname = os.path.join(train_path, filename) +# print("Copying ", image, " to ", fname , " in train") + shutil.copyfile(image, fname) + + cnt = cnt + 1 + else: + print("Not doing validation") + for filename in os.listdir(imagespath): + ext = os.path.splitext(filename)[1] + if ext == ".JPG" or ext == ".jpg" or ext == ".PNG" or ext == ".png" : + image = os.path.join(imagespath, filename) +# print("IM ", image) + + filename = "train_"+filename + fname = os.path.join(train_path, filename) +# print("Copying ", image, " to ", fname , " in train") + shutil.copyfile(image, fname) + + cnt = cnt + 1 + + if do_test: + for filename in os.listdir(testpath): + ext = os.path.splitext(filename)[1] + if ext == ".JPG" or ext == ".jpg" or ext == ".PNG" or ext == ".jpg" : + image = os.path.join(testpath, filename) + filename = "test_"+filename + fname = os.path.join(input_test_path, filename) +# print("Copying ", image, " to ", fname , " in test") + shutil.copyfile(image, fname) + else: + print ("****************** NOT DOING TEST !!!") + + + # extract video name -- if not given, take first + if video_name == 'default': + if os.path.exists(videopath): + for filename in os.listdir(videopath): +# print("Checking ", filename) + if ("MP4" in filename) or ("mp4" in filename): + video_name = filename + video_filename = os.path.join(path, os.path.join("raw", os.path.join("videos", video_name))) + print("Full video path:", video_filename) + + return "video_filename", video_filename + +def convert_sibr_mesh(path): + ms = pymeshlab.MeshSet() + mesh_path = os.path.join(os.path.join(os.path.join(path, "rcScene"), "meshes"), "mesh.obj") + print("Loading mesh (slow...)", mesh_path) + ms.load_new_mesh(mesh_path) + meshply_path = out_mesh_path = os.path.join(os.path.join(os.path.join(path, "sibr"), "capreal"), "mesh.ply") + print("Saving mesh (slow...)", out_mesh_path) + ms.save_current_mesh(out_mesh_path, save_wedge_texcoord=False, binary=False) + print("Done saving mesh (slow...)", out_mesh_path) + texture_path = os.path.join(os.path.join(os.path.join(path, "sibr"), "capreal"), "mesh_u1_v1.png") + out_texture_path = os.path.join(os.path.join(os.path.join(path, "sibr"), "capreal"), "texture.png") + print("Copying (to allow meshlab to work) {} to {}".format(texture_path, out_texture_path)) + shutil.copyfile(texture_path, out_texture_path) + out_mesh_path = os.path.join(os.path.join(os.path.join(os.path.join(path, "sibr"), "colmap"), "stereo"), "meshed-delaunay.ply") + print("Copying {} to {}".format(meshply_path, out_mesh_path)) + shutil.copyfile(meshply_path, out_mesh_path) + + +def densify_mesh(mesh_path): + ms = pymeshlab.MeshSet() + subdiv_threshold = pymeshlab.Percentage(0.09) + ms.load_new_mesh(mesh_path) + print("Loaded mesh ", mesh_path, " Subdividing (this can take some time)...") + ms.subdivision_surfaces_butterfly_subdivision(threshold=subdiv_threshold) + path_split = os.path.split(mesh_path) + dense_mesh_fname = "dense_" + path_split[1] + fname, fname_ext = os.path.splitext(dense_mesh_fname) + dense_mesh_fname = fname + ".obj" + dense_mesh_path = os.path.join(path_split[0], dense_mesh_fname) + print("Writing dense mesh ", dense_mesh_path) + ms.save_current_mesh(dense_mesh_path) + +def rc_to_colmap(rc_path, out_path, create_colmap=False, target_width=-1): + + input_bundle = bundle.Bundle(os.path.join(rc_path , "bundle.out")) + input_bundle.generate_list_of_images_file (os.path.join(rc_path , "list_images.txt")) + + dst_image_path = os.path.join(out_path, "images") + + # create entire colmap structure + if create_colmap: + dir_name = os.path.join(out_path, "stereo") + if not os.path.exists(dir_name): + os.makedirs(dir_name) + + stereo_stereo_dir = os.path.join(dir_name, "stereo") + if not os.path.exists(stereo_stereo_dir): + os.makedirs(stereo_stereo_dir) + + dst_image_path = os.path.join(dir_name, "images") + + sparse_stereo_dir = dir_name = os.path.join(dir_name, "sparse") + if not os.path.exists(dir_name): + os.makedirs(dir_name) + + + else: + sparse_stereo_dir = out_path + + if not os.path.exists(dst_image_path): + os.makedirs(dst_image_path) + + # create cameras.txt + fname = os.path.join(sparse_stereo_dir, "cameras.txt") + print("Creating ", fname) + numcams = len(input_bundle.list_of_input_images) + + camera_id = 1 + scale = 1. + with open(fname, 'w') as outfile: + outfile.write("# Camera list with one line of data per camera:\n") + outfile.write("# CAMERA_ID, MODEL, WIDTH, HEIGHT, PARAMS[]\n") + outfile.write("# Number of cameras: {}\n".format(numcams)) + for im in input_bundle.list_of_input_images: + width = im.resolution[0] + height = im.resolution[1] + focal_length = input_bundle.list_of_cameras[camera_id-1].focal_length + + # resize images if required + if target_width != -1: + orig_width = width + width = float(target_width) + scale = float(target_width) / orig_width + aspect = height / orig_width + height = width * aspect + focal_length = scale * focal_length + + outfile.write("{} PINHOLE {} {} {} {} {} {}\n".format(camera_id, int(width), int(height), focal_length, focal_length, width/2.0, height/2.0)) + camera_id = camera_id + 1 + outfile.close() + + # create images.txt + fname = os.path.join(sparse_stereo_dir, "images.txt") + + print("Creating ", fname) + camera_id = 1 + with open(fname, 'w') as outfile: + outfile.write( "# Image list with two lines of data per image:\n" ) + outfile.write( "# IMAGE_ID, QW, QX, QY, QZ, TX, TY, TZ, CAMERA_ID, NAME\n" ) + outfile.write( "# POINTS2D[] as (X, Y, POINT3D_ID)\n" ) + point2d_index = 0 + for cam in input_bundle.list_of_cameras: + in_im = input_bundle.list_of_input_images[camera_id-1] + imname = in_im.path + name = os.path.basename(imname) + im = cv2.imread(imname, cv2.IMREAD_UNCHANGED) + w = im.shape[1] + h = im.shape[0] + + # to sibr internal + br = np.matrix(cam.rotation).transpose() + t = -np.matmul(br , np.matrix([cam.translation[0], cam.translation[1], cam.translation[2]]).transpose()) + + # sibr save to colmap + br = np.matmul(br, np.matrix([[1, 0, 0], [0, -1, 0], [0, 0, -1]])) + br = br.transpose() + + sci_rot = R.from_matrix(br) + sci_quat = sci_rot.as_quat() + + t = -np.matmul(br, t) + + outfile.write("{} {} {} {} {} {} {} {} {} {}\n".format(camera_id, -sci_quat[3], -sci_quat[0], -sci_quat[1], -sci_quat[2], t[0,0], t[1,0], t[2,0], camera_id, name)) + # write out points + first = False + scale = 1.0 + if target_width !=1 : + scale = float(target_width) / float(in_im.resolution[0]) + for p in cam.list_of_feature_points: + for v in p.view_list: + if v[0] == camera_id-1: + outfile.write( str(scale*(2.*v[2]+w)) + " " + str(scale*(2.*v[3]+h))+ " -1" ) # TODO: not sure about this, seems to be -1 in all existing files + if not first: + outfile.write(" ") + else: + first = False + + p.point2d_index[v[0]] = point2d_index + point2d_index = point2d_index + 1 + + outfile.write("\n") + camera_id = camera_id + 1 + outfile.close() + + # create points3D.txt + fname = os.path.join(sparse_stereo_dir, "points3D.txt") + + print("Creating ", fname) + camera_id = 1 + with open(fname, 'w') as outfile: + num_points = len(input_bundle.list_of_feature_points) +# FIX mean_track_length = sum((len(pt.image_ids) for _, pt in points3D.items()))/len(points3D) + mean_track_length = 10 # 10 is a placeholder value + outfile.write("# 3D point list with one line of data per point:\n" ) + outfile.write("# POINT3D_ID, X, Y, Z, R, G, B, ERROR, TRACK[] as (IMAGE_ID, POINT2D_IDX)\n") + outfile.write("# Number of points: {}, mean track length: {}\n".format(num_points, mean_track_length)) + for p in input_bundle.list_of_feature_points: + # error set to 0.1 for all + outfile.write(str(p.id+1)+ " " + str(p.position[0]) + " " + str(p.position[1]) + " " + str(p.position[2]) + " " + str( p.color[0])+ " " + str( p.color[1])+ " " + str( p.color[2])+ " 0.1") + for v in p.view_list: +# print("Cam id ", v[0], " P= ", p.id+1 , " p2dind " , p.point2d_index ) + outfile.write(" " + str(v[0]+1)+ " " + str(p.point2d_index[v[0]]) ) + outfile.write("\n") + + + if create_colmap: + fname = os.path.join(stereo_stereo_dir, "fusion.cfg") + outfile_fusion = open(fname, 'w') + fname = os.path.join(stereo_stereo_dir, "patch-match.cfg") + outfile_patchmatch = open(fname, 'w') + outdir = os.path.join(stereo_stereo_dir, "normal_maps") + if not os.path.exists(outdir): + os.makedirs(outdir) + outdir = os.path.join(stereo_stereo_dir, "depth_maps") + if not os.path.exists(outdir): + os.makedirs(outdir) + outdir = os.path.join(stereo_stereo_dir, "consistency_graphs") + if not os.path.exists(outdir): + os.makedirs(outdir) + + # copy images + for fname in os.listdir(rc_path): + if fname.endswith(".jpg") or fname.endswith(".JPG") or fname.endswith(".png") or fname.endswith(".PNG") : + src_image_fname = os.path.join(rc_path, fname) + dst_image_fname = os.path.join(dst_image_path, os.path.basename(fname)) +# print("Copying ", src_image_fname, "to ", dst_image_fname) + + if create_colmap: + outfile_fusion.write(fname+"\n") + outfile_patchmatch.write(fname+"\n") + outfile_patchmatch.write("__auto__, 20\n") + + # resize if necessary + if target_width != -1: + im = cv2.imread(src_image_fname, cv2.IMREAD_UNCHANGED) + orig_width = im.shape[1] + orig_height = im.shape[0] + width = float(target_width) + scale = float(target_width)/ orig_width + aspect = orig_height / orig_width + height = width * aspect + dim = (int(width), int(height)) + im = cv2.resize(im, dim, interpolation = cv2.INTER_AREA) + cv2.imwrite(dst_image_fname, im) + else: + shutil.copyfile(src_image_fname, dst_image_fname) + + # copy mesh; fake it + if create_colmap: + outfile_patchmatch.close() + outfile_fusion.close() + +# taken from ibr_preprocess_rc_to_sibr +# TODO: pretty ugly needs rethink and cleanup +def crop_images(path_data, path_dest): + # open calibration data + input_bundle = bundle.Bundle(os.path.join(path_data , "bundle.out")) + # query current average resolution of these cameras + avg_resolution = input_bundle.get_avg_resolution() + print("AVG resolution ", avg_resolution) + + # special case: validation_cameras take size/crop data from train cameras so they are all the same + if "validation_" not in path_data: + + # generate resolutions.txt and put it in the current dataset folder + resolutions_txt_path = os.path.join(path_data, "resolutions.txt") + input_bundle.generate_list_of_images_file(resolutions_txt_path) + + # setup avg_resolution parameters for distordCrop + print("Command: run distordCrop ARGS: ", "--path", path_data, "--ratio", "0.3", "--avg_width", str(avg_resolution[0]), "--avg_height", str(avg_resolution[1]), ")") + retcode = runCommand(getProcess("distordCrop"), [ "--path", path_data, "--ratio", "0.3", "--avg_width", str(avg_resolution[0]), "--avg_height", str(avg_resolution[1]) ]) + if retcode.returncode != 0: + print("Command: distordCrop failed, exiting (ARGS: ", "--path", path_data, "--ratio", "0.3", "--avg_width", str(avg_resolution[0]), "--avg_height", str(avg_resolution[1]), ")") + #exit(1) + + # read new proposed resolution and check if images were discarded + exclude = [] + path_to_exclude_images_txt = os.path.join(path_data, "exclude_images.txt") + if (os.path.exists(path_to_exclude_images_txt)): + # list of excluded cameras (one line having all the camera ids to exclude) + exclusion_file = open(path_to_exclude_images_txt, "r") + line = exclusion_file.readline() + tokens = line.split() + + for cam_id in tokens: + exclude.append(int(cam_id)) + exclusion_file.close() + + # exclude cams from bundle file + if len(exclude) > 0: + print("Excluding ", exclude) + input_bundle.exclude_cams (exclude) + + # read proposed cropped resolution + path_to_crop_new_size_txt = os.path.join(path_data, "cropNewSize.txt") + else: + train_path_data = str.replace(path_data, "validation_", "") + path_to_crop_new_size_txt = os.path.join(train_path_data, "cropNewSize.txt") + print("Reading crop size from ", path_to_crop_new_size_txt ) + + with open(path_to_crop_new_size_txt) as crop_size_file: + line = crop_size_file.readline() + tokens = line.split() + new_width = int(tokens[0]) + new_height = int(tokens[1]) + proposed_res = [new_width, new_height] + + print("Crop size found:", proposed_res) + # generate file with list of current selected images to process + + path_to_transform_list_txt = os.path.join (path_data, "toTransform.txt") + input_bundle.generate_list_of_images_file(path_to_transform_list_txt) + + if not os.path.exists(path_dest): + os.makedirs(path_dest) + + + path_to_output_bundle = os.path.join (path_dest, "bundle.out") + # write bundle file in output cameras folder + new_width = None + input_bundle.save(path_to_output_bundle, proposed_res) + + # setup avg_resolution and proposed_resolution parameters for distordCrop + print("Command: run cropFromCenter ARGS:", "--inputFile", path_to_transform_list_txt, "--outputPath", path_dest, "--avgResolution", str(avg_resolution[0]), str(avg_resolution[1]), "--cropResolution", str(proposed_res[0]), str(proposed_res[1])) + retcode = runCommand(getProcess("cropFromCenter"), [ "--inputFile", path_to_transform_list_txt, "--outputPath", path_dest, "--avgResolution", str(avg_resolution[0]), str(avg_resolution[1]), "--cropResolution", str(proposed_res[0]), str(proposed_res[1]) ]) + if retcode.returncode != 0: + print("Command: cropFromCenter failed, exiting (ARGS:", "--inputFile", path_to_transform_list_txt, "--outputPath", path_dest, "--avgResolution", str(avg_resolution[0]), str(avg_resolution[1]), "--cropResolution", str(proposed_res[0]), str(proposed_res[1])) + exit(1) + + +def fix_video_only(path): + # TODO: currently only works for video_only + calib_only; doesnt do video only with MVS + # verify that train is actually empty + train_dir = os.path.join(path, os.path.join("rcScene", "train_cameras")) + test_dir = os.path.join(path, os.path.join("rcScene", "test_path_cameras")) + files = os.listdir(train_dir) + if len(files) == 1: # empty bundle file + shutil.move(train_dir, train_dir+"_save") + print("MOVING {} to {}".format(test_dir, train_dir)) + shutil.move(test_dir, train_dir) + else: + print("FATAL ERROR: trying to overwrite existing train images") + exit(1) + +def car_data_process(path): + # Contains: CAM_{BACK,FRONT}[_]{LEFT, RIGHT} + rawpath = os.path.join(path, "raw") + if not os.path.exists(rawpath): + os.makedirs(rawpath) + + imagespath = os.path.abspath(os.path.join(rawpath, "images")) + if not os.path.exists(imagespath): + os.makedirs(imagespath) + + # read all the sets of cameras + + dirlist = [ "CAM_BACK", "CAM_BACK_LEFT", "CAM_BACK_RIGHT", "CAM_FRONT", "CAM_FRONT_LEFT", "CAM_FRONT_RIGHT" ] + imlists = {} + global_im_counter = 0 + + for dirname in dirlist: + campath = os.path.join(path, dirname) + first = True +# basic version + for filename in os.listdir(campath): + shutil.copyfile(os.path.join(campath, filename), os.path.join(imagespath, "{:06d}".format(global_im_counter)+".jpg")) + global_im_counter += 1 + +""" +# code below useless + for filename in os.listdir(campath): + ext = os.path.splitext(filename)[1] + if ext == ".JPG" or ext == ".jpg" or ext == ".PNG" or ext == ".png" : + if first: + imlists[dirname] = [filename] + first = False + else: + imlists[dirname].append(filename) + +# print("Adding ", filename , " to list " , dirname) + for i in range(len(imlists["CAM_BACK"])): + imname = imlists[ "CAM_BACK_LEFT"][i] + shutil.copyfile(os.path.join(path, os.path.join( "CAM_BACK_LEFT", imname)), os.path.join(imagespath, "{:06d}".format(global_im_counter)+".jpg")) + global_im_counter += 1 + imname = imlists[ "CAM_FRONT_LEFT"][i] + shutil.copyfile(os.path.join(path, os.path.join( "CAM_FRONT_LEFT", imname)), os.path.join(imagespath, "{:06d}".format(global_im_counter)+".jpg")) + global_im_counter += 1 + if i > 2: + imname = imlists[ "CAM_FRONT"][i-2] + shutil.copyfile(os.path.join(path, os.path.join( "CAM_FRONT", imname)), os.path.join(imagespath, "{:06d}".format(global_im_counter)+".jpg")) + global_im_counter += 1 + + for i in range(len(imlists["CAM_BACK"])): + imname = imlists[ "CAM_FRONT_RIGHT"][i] + shutil.copyfile(os.path.join(path, os.path.join( "CAM_FRONT_RIGHT", imname)), os.path.join(imagespath, "{:06d}".format(global_im_counter)+ ".jpg")) + global_im_counter += 1 + imname = imlists[ "CAM_BACK_RIGHT"][i] + shutil.copyfile(os.path.join(path, os.path.join( "CAM_BACK_RIGHT", imname)), os.path.join(imagespath, "{:06d}".format(global_im_counter)+ ".jpg")) + global_im_counter += 1 + if i < len(imlists["CAM_BACK"])-2: + imname = imlists[ "CAM_BACK"][i+2] + shutil.copyfile(os.path.join(path, os.path.join( "CAM_BACK", imname)), os.path.join(imagespath, "{:06d}".format(global_im_counter)+ ".jpg")) + global_im_counter += 1 +""" diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/realityCaptureTools/registrationConfig.xml b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/realityCaptureTools/registrationConfig.xml new file mode 100644 index 0000000000000000000000000000000000000000..416c3284224747a0fca6c3bfdf4ccefe0c01001e --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/realityCaptureTools/registrationConfig.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/realityCaptureTools/runRC.bat b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/realityCaptureTools/runRC.bat new file mode 100644 index 0000000000000000000000000000000000000000..6c0b506f7ae630c6647d0e845b52260a5fa430cc --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/realityCaptureTools/runRC.bat @@ -0,0 +1,71 @@ +::CapturingReality + +:: switch off console output +::@echo off +@echo on +set RootFolder=%1 +set Video="%RootFolder%\videos\video.mp4" +set FPS=%2 + +set ConfigFolder=D:\Users\gdrett\src\sibr_core\install\scripts +:: path to RealityCapture application +set RealityCaptureExe="C:\Program Files\Capturing Reality\RealityCapture\RealityCapture.exe" + +:: variable storing path to images for creating model +set Images="%RootFolder%\images" +set TestImages="%RootFolder%\test" +set TrainImages="%RootFolder%\train" +set PathImages="%RootFolder%\train" + +:: set a new name for calculated model +set ModelName="RCTest" + +:: set the path, where model is going to be saved, and its name +set ModelObj="%RootFolder%\rcScene\meshes\mesh.obj" +set ModelXYZ="%RootFolder%\rcScene\meshes\point_cloud.xyz" + +:: variable storing path to images for texturing model +set Project="%RootFolder%\rcproj\mesh.rcproj" + +:: run RealityCapture +:: test and fix video import when RC working again + +echo %@Images% + +%RealityCaptureExe% -addFolder %TrainImages% ^ + -addFolder %TestImages% ^ + -importVideo %Video% %RootFolder%\video_frames\ %FPS% ^ + -align ^ + -selectMaximalComponent ^ + -selectAllImages ^ + -enableAlignment false ^ + -selectImage *test_* ^ + -enableAlignment true ^ + -exportRegistration %RootFolder%\rcScene\test_cameras\bundle.out %ConfigFolder%\registrationConfig.xml ^ + -selectAllImages ^ + -enableAlignment false ^ + -selectImage *frame* ^ + -enableAlignment true ^ + -exportRegistration %RootFolder%\rcScene\path_cameras\bundle.out %ConfigFolder%\registrationConfig.xml ^ + -selectAllImages ^ + -enableAlignment false ^ + -selectImage *train_* ^ + -enableAlignment true ^ + -exportRegistration %RootFolder%\rcScene\cameras\bundle.out %ConfigFolder%\registrationConfig.xml ^ + -setReconstructionRegionAuto ^ + -scaleReconstructionRegion 1.4 1.4 2.5 center factor ^ + -calculateNormalModel ^ + -selectMarginalTriangles ^ + -removeSelectedTriangles ^ + -calculateTexture ^ + -save %Project% ^ + -renameSelectedModel %ModelName% ^ + -exportModel %ModelName% %ModelObj% ^ + -exportModel %ModelName% %ModelXYZ% ^ + -quit + + + + + + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/textureMesh/CMakeLists.txt b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/textureMesh/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..37dd8a3d315fe738d0f4c1a5e1ff35f99ce90236 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/textureMesh/CMakeLists.txt @@ -0,0 +1,34 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +project(textureMesh) + +# Define build output for project +add_executable(${PROJECT_NAME} main.cpp) + +target_link_libraries(${PROJECT_NAME} + ${Boost_LIBRARIES} + sibr_system + sibr_assets + sibr_graphics + sibr_raycaster + sibr_imgproc + sibr_view +) + +set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER "projects/dataset_tools/preprocess") + +## High level macro to install in an homogen way all our ibr targets +include(install_runtime) +ibr_install_target(${PROJECT_NAME} + INSTALL_PDB ## mean install also MSVC IDE *.pdb file (DEST according to target type) + STANDALONE ${INSTALL_STANDALONE} ## mean call install_runtime with bundle dependencies resolution + COMPONENT ${PROJECT_NAME}_install ## will create custom target to install only this project +) diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/textureMesh/main.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/textureMesh/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c608540d633937087cd9b4b1b93fd7f404578fd2 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/textureMesh/main.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "core/system/CommandLineArgs.hpp" +#include "core/assets/InputCamera.hpp" +#include "core/graphics/Image.hpp" +#include "core/graphics/Mesh.hpp" +#include "core/imgproc/MeshTexturing.hpp" +#include "core/scene/BasicIBRScene.hpp" + +using namespace sibr; + + +struct TexturingAppArgs : virtual BasicIBRAppArgs { + Arg meshPath = { "mesh", "" }; + RequiredArg output_path = { "output", "output texture path" }; + Arg output_size = { "size", 8192, "texture side" }; + Arg flood_fill = { "flood", "perform flood fill" }; + Arg poisson_fill = { "poisson", "perform Poisson filling (slow on large images)" }; + Arg samples = { "samples", 1.0, "%ge of total samples to be used for texturing" }; +}; + +int main(int ac, char** av) { + + // Parse Command-line Args + sibr::CommandLineArgs::parseMainArgs(ac, av); + + TexturingAppArgs args; + + // Display help. + if(!args.dataset_path.isInit() || !args.output_path.isInit()) { + std::cout << "Usage: " << std::endl; + std::cout << "\tRequired: --path path/to/dataset --output path/to/output/file.png" << std::endl; + std::cout << "\tOptional: --size 8192 --flood (flood fill) --poisson (poisson fill)" << std::endl; + return 0; + } + + BasicIBRScene::SceneOptions opts; + opts.renderTargets = false; + if (!args.meshPath.get().empty()) { + opts.mesh = false; + } + opts.texture = false; + + SIBR_LOG << "[Texturing] Loading data..." << std::endl; + + BasicIBRScene scene(args, opts); + + if (!scene.proxies()->hasProxy()) { + sibr::Mesh::Ptr customMesh; + customMesh.reset(new Mesh()); + customMesh->load(args.meshPath); + scene.proxies()->replaceProxyPtr(customMesh); + } + + MeshTexturing texturer(args.output_size); + texturer.setMesh(scene.proxies()->proxyPtr()); + texturer.reproject(scene.cameras()->inputCameras(), scene.images()->inputImages(), args.samples); + + // Export options. + // UVs start at the bottom of the image, we have to flip. + uint options = MeshTexturing::FLIP_VERTICAL; + if (args.flood_fill) { + options = options | MeshTexturing::FLOOD_FILL; + } + if (args.poisson_fill) { + options = options | MeshTexturing::POISSON_FILL; + } + + sibr::ImageRGB::Ptr result = texturer.getTexture(options); + result->save(args.output_path); + + return 0; +} + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/tonemapper/CMakeLists.txt b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/tonemapper/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..5db33d7c55e14361f5adc4936fc03f4b275f15d2 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/tonemapper/CMakeLists.txt @@ -0,0 +1,32 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +project(tonemapper) + +# Define build output for project +add_executable(${PROJECT_NAME} main.cpp) + +target_link_libraries(${PROJECT_NAME} + ${Boost_LIBRARIES} + sibr_system + sibr_assets + sibr_graphics + sibr_imgproc +) + +set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER "projects/dataset_tools/preprocess") + +## High level macro to install in an homogen way all our ibr targets +include(install_runtime) +ibr_install_target(${PROJECT_NAME} + INSTALL_PDB ## mean install also MSVC IDE *.pdb file (DEST according to target type) + STANDALONE ${INSTALL_STANDALONE} ## mean call install_runtime with bundle dependencies resolution + COMPONENT ${PROJECT_NAME}_install ## will create custom target to install only this project +) diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/tonemapper/main.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/tonemapper/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0a3c8f262cbfd3080d2740dd9bfce90caa48d734 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/tonemapper/main.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include "core/system/CommandLineArgs.hpp" +#include "core/assets/InputCamera.hpp" +#include "core/graphics/Image.hpp" +#include "core/graphics/Mesh.hpp" +#include "core/imgproc/MeshTexturing.hpp" +#include "core/scene/BasicIBRScene.hpp" + +using namespace sibr; + + +struct TonemapperAppArgs : virtual AppArgs { + RequiredArg path = { "path", "path to the EXR images directory" }; + Arg output = { "output", "", "output directory path" }; + Arg outputExtension = { "ext", "png", "output files extension" }; + Arg exposure = { "exposure", 1.0f, "exposure value" }; + Arg gamma = { "gamma", 2.2f, "gamma value" }; +}; + +void tonemap(const sibr::ImageRGB32F& hdrImg, sibr::ImageRGB& ldrImg, float exposure, float gamma) { + const cv::Mat & tonemaped = hdrImg.toOpenCV(); + const cv::Mat exposed = -exposure * tonemaped; + cv::Mat tonemaped2; + cv::exp(exposed, tonemaped2); + tonemaped2 = cv::Scalar(1.0f, 1.0f, 1.0f) - tonemaped2; + if (gamma > 0.0f) { + cv::pow(tonemaped2, 1.0f / gamma, tonemaped2); + } + cv::Mat tonemapedRGB; + tonemaped2.convertTo(tonemapedRGB, CV_8UC3, 255.0f); + ldrImg.fromOpenCV(tonemapedRGB); +} + +int main(int ac, char** av) { + + // Parse Command-line Args + sibr::CommandLineArgs::parseMainArgs(ac, av); + + TonemapperAppArgs args; + + // Add the extension dot if needed. + std::string extension = args.outputExtension; + if (!extension.empty() && extension[0] != '.') { + extension = "." + extension; + } + + // Input/output paths. + const std::string inputPath = args.path; + std::string outputPath = args.output; + // If we output in the same dir, we want to avoid collisions. + if (outputPath.empty()) { + outputPath = inputPath; + extension = "_ldr" + extension; + } else { + sibr::makeDirectory(outputPath); + } + + const auto files = sibr::listFiles(inputPath, false, false, { "exr" }); + + for (const auto& file : files) { + const std::string src = inputPath + "/" + file; + const std::string dst = outputPath + "/" + sibr::removeExtension(file) + extension; + + sibr::ImageRGB32F hdrImg; + sibr::ImageRGB ldrImg; + hdrImg.load(src); + tonemap(hdrImg, ldrImg, args.exposure, args.gamma); + ldrImg.save(dst); + } + + return 0; +} + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/unwrapMesh/CMakeLists.txt b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/unwrapMesh/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..10dfa9feb26be2df707ac37391892d8785215ca7 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/unwrapMesh/CMakeLists.txt @@ -0,0 +1,31 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +project(unwrapMesh) + +# Define build output for project +add_executable(${PROJECT_NAME} main.cpp) + +target_link_libraries(${PROJECT_NAME} + ${Boost_LIBRARIES} + sibr_system + sibr_assets + sibr_graphics +) + +set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER "projects/dataset_tools/preprocess") + +## High level macro to install in an homogen way all our ibr targets +include(install_runtime) +ibr_install_target(${PROJECT_NAME} + INSTALL_PDB ## mean install also MSVC IDE *.pdb file (DEST according to target type) + STANDALONE ${INSTALL_STANDALONE} ## mean call install_runtime with bundle dependencies resolution + COMPONENT ${PROJECT_NAME}_install ## will create custom target to install only this project +) diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/unwrapMesh/main.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/unwrapMesh/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6e59fa86988a3637c94e36c2d8999c6595161348 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/unwrapMesh/main.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + + + +#include +#include +#include +#include + + +using namespace sibr; + +/** Options for mesh unwrapping. */ +struct UVMapperArgs : public AppArgs { + RequiredArg path = { "path", "path to the mesh" }; + Arg output = { "output", "", "path to the output mesh" }; + Arg size = { "size", 4096, "target UV map width (approx.)" }; + Arg visu = { "visu", "save visualisation" }; + Arg textureName = { "texture-name", "TEXTURE_NAME_TO_PUT_IN_THE_FILE", "name of the texture to reference in the output mesh (Meshlab compatible)" }; +}; + +int main(int ac, char ** av){ + + CommandLineArgs::parseMainArgs(ac, av); + UVMapperArgs args; + std::string outputFile = args.output; + if(outputFile.empty()) { + outputFile = sibr::removeExtension(args.path.get()) + "_output.obj"; + } + sibr::makeDirectory(sibr::parentDirectory(outputFile)); + + // Load object file. + Mesh mesh(false); + if(sibr::getExtension(args.path) == "xml") { + mesh.loadMtsXML(args.path); + } else { + mesh.load(args.path); + } + + UVUnwrapper unwrapper(mesh, uint32_t(args.size)); + auto finalMesh = unwrapper.unwrap(); + finalMesh->save(outputFile, true, args.textureName); + + // Output debug vis. + if (args.visu) { + const std::string baseName = sibr::removeExtension(outputFile); + const auto visuImgs = unwrapper.atlasVisualization(); + for (uint32_t i = 0; i < visuImgs.size(); i++) { + const std::string fileName = baseName + "_charts_atlas_" + std::to_string(i) + ".png"; + visuImgs[i]->save(fileName); + } + } + return EXIT_SUCCESS; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/utils/CMakeLists.txt b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/utils/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..ba6a1d8b6e6e982fdd3e1d0ac2ca263dc598b40c --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/utils/CMakeLists.txt @@ -0,0 +1,19 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +project(dataset_tools_utils) + +file(GLOB SCRIPTS "*.py") + +add_custom_target(${PROJECT_NAME} ALL) + +include(install_runtime) +set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER "projects/dataset_tools/preprocess") +ibr_install_rsc(${PROJECT_NAME} TYPE "scripts" FOLDER "utils" FILES ${SCRIPTS}) diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/utils/TaskPipeline.py b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/utils/TaskPipeline.py new file mode 100644 index 0000000000000000000000000000000000000000..28999a40301fce4b2c454a792ca29b9e184f7445 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/utils/TaskPipeline.py @@ -0,0 +1,101 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +#!/usr/bin/env python +#! -*- encoding: utf-8 -*- + +import subprocess +import os, sys +import re +import shutil +from importlib import import_module +from utils.convert import updateStringFromDict +from utils.commands import runCommand + +class TaskPipeline: + def __init__(self, args, steps, programs): + self.args = args + self.steps = steps + self.programs = programs + + def isExpressionValid(self, expression): + if not re.match(r"^((?:not|and|or|is|in|\$\{\w+\})+\s*)+$", expression): + print("Invalid expression '%s'." % expression) + + return eval(updateStringFromDict(expression, self.args)) + + def runProcessSteps(self): + for step in self.steps: +# print("RUN STEP ", step) + if "if" in step and not self.isExpressionValid(step["if"]): + print("Nothing to do on step %s. Skipping." % (step["name"])) + continue + + print("Running step %s..." % step["name"]) + command_args = [] + for i in range(5): + if "app" in step and "optional_arg"+str(i) in step and self.isExpressionValid(step["optional_arg"+str(i)][0]): + optional_arg = [] + for optional_arg in step["optional_arg"+str(i)][1:]: +# print("Parsing... ", optional_arg, " ", updateStringFromDict(optional_arg, self.args)) + command_args.append(updateStringFromDict(optional_arg, self.args)) + + if "app" in step: +# print("Parsing command args...") + for command_arg in step["command_args"]: +# print("Parsing... ", command_arg, " ", updateStringFromDict(command_arg, self.args)) + command_args.append(updateStringFromDict(command_arg, self.args)) + + # for optionally quitting + if "app" in step and "optional_final_arg" in step and self.isExpressionValid(step["optional_final_arg"][0]): + for command_arg in step["optional_final_arg"][1:]: +# print("Parsing... ", command_arg, " ", updateStringFromDict(command_arg, self.args)) + command_args.append(updateStringFromDict(command_arg, self.args)) + + if self.args["dry_run"]: + success = True + else: + completedProcess = runCommand(self.programs[step["app"]]["path"], command_args) + success = completedProcess.returncode == 0 + + elif "function" in step: + if '.' in step["function"]: + currentModuleName, currentFunctionName = step["function"].rsplit('.', 1) + currentFunction = getattr(import_module(currentModuleName), currentFunctionName) + else: + print("Missing module name for function %s. Aborting." % (step["function"])) + sys.exit(1) + + if self.args["dry_run"]: + print('function : %s(%s)' % (step["function"], ', '.join([ "%s=%s" % (key, ([updateStringFromDict(item, self.args) for item in val] + if type(val) is list else + updateStringFromDict(val, self.args))) + for key, val in step["function_args"].items()]))) + else: + ret = currentFunction(**{ key: ([updateStringFromDict(item, self.args) for item in val] + if type(val) is list else + updateStringFromDict(val, self.args)) + for key, val in step["function_args"].items() }) + if ret != None: + self.args[ret[0]] = ret[1] + print ("After step {}: Setting args[{}]={}".format( step["function"], ret[0] , ret[1], ret[0], self.args[ret[0]])) + + success = True + else: + print("Nothing to do on step %s. Skipping." % (step["name"])) + continue + + if success: + print("Step %s successful." % (step["name"])) + else: + sys.stdout.flush() + sys.stderr.flush() + print("Error on step %s. Aborting." % (step["name"])) + sys.exit(1) diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/utils/color.py b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/utils/color.py new file mode 100755 index 0000000000000000000000000000000000000000..f6226392a5062d176d859301cfa5599ef82a8927 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/utils/color.py @@ -0,0 +1,22 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +import os +os.system("color") + +COLOR = { + "HEADER": "\033[95m", + "BLUE": "\033[94m", + "GREEN": "\033[92m", + "RED": "\033[91m", + "ENDC": "\033[0m", +} + +#print(COLOR["GREEN"], "Testing Green!!", COLOR["ENDC"]) diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/utils/commands.py b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/utils/commands.py new file mode 100644 index 0000000000000000000000000000000000000000..50025055cd362c9b569f59ae645898a158be31ca --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/utils/commands.py @@ -0,0 +1,71 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +#!/usr/bin/env python +#! -*- encoding: utf-8 -*- + +import subprocess +import os, sys +from shutil import which +from utils.paths import getBinariesPath, getColmapPath, getMeshlabPath, getRCPath + +def getProcess(programName, binaryPath = getBinariesPath()): + suffixes = [ '', '_msr', '_rwdi', '_d'] + + print("BINARIES ", binaryPath) + for suffix in suffixes: + binary = os.path.join(binaryPath, programName + suffix + (".exe" if os.name == 'nt' else '')) + + if os.path.isfile(binary) or which(binary) is not None: + print("Program '%s' found in '%s'." % (programName, binary)) + return binary + +def getRCprocess(binaryPath = getRCPath()): + programName = "RealityCapture" + binary = os.path.join(binaryPath, programName + ".exe") + + if os.path.isfile(binary): + print("Program '%s' found in '%s'." % (programName, binary)) + return binary + + +def runCommand(binary, command_args): +# print("Running process '%s'" % (' '.join([binary, *command_args]))) + sys.stdout.flush() + completedProcess = subprocess.run([binary, *command_args]) + + if completedProcess.returncode == 0: + print("Process %s completed." % binary) + else: + sys.stdout.flush() + sys.stderr.flush() + print("Process %s failed with code %d." % (binary, completedProcess.returncode)) + + return completedProcess + +def getColmap(colmapPath = getColmapPath()): + colmapBinary = os.path.join(colmapPath, "COLMAP.bat" if os.name == 'nt' else 'colmap') + + if os.path.isfile(colmapBinary) or which(colmapBinary) is not None: + print("Program '%s' found in '%s'." % (colmapBinary, colmapPath)) + return colmapBinary + else: + print("Program '%s' not found in '%s'. Aborting." % (colmapBinary, colmapPath)) + return None + +def getMeshlabServer(meshlabPath = getMeshlabPath()): + meshlabserverBinary = os.path.join(meshlabPath, "meshlabserver" + ('.exe' if os.name == 'nt' else '')) + + if os.path.isfile(meshlabserverBinary) or which(meshlabserverBinary) is not None: + print("Program '%s' found in '%s'." % (meshlabserverBinary, meshlabPath)) + return meshlabserverBinary + else: + print("Program '%s' not found in '%s'. Aborting." % (meshlabserverBinary, meshlabPath)) + return None diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/utils/convert.py b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/utils/convert.py new file mode 100644 index 0000000000000000000000000000000000000000..a754e95751dfc5e235314d077fc215ed02d6b8d8 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/utils/convert.py @@ -0,0 +1,40 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +#!/usr/bin/env python +#! -*- encoding: utf-8 -*- + +import os +import re + +def updateStringFromDict(string, map, format='${%s}', fix_paths=True): + newstring = string + + for keyword, value in map.items(): + newstring = newstring.replace(format % keyword, str(value)) + # if it's a path, get absolute path + if fix_paths and re.match(r"^(?:\w:[\\\/]*|[@A-Za-z_.0-9-]*[\\\/]+|\.{1,2}[\\\/])(?:[\\\/]|[@A-Za-z_.0-9-]+)*$", newstring): + newstring = os.path.abspath(newstring) + + return newstring + +def fixMeshEol(meshPath, newMeshPath): + with open(meshPath,"rb") as meshFile, open(newMeshPath, "wb") as newMeshFile: + meshBytes = meshFile.read() + endBytes = b"end_header" + badEol = b"\r\n" + newEol = b"\n" + + index = meshBytes.find(endBytes) + len(endBytes) + len(badEol) + + newMeshBytes = meshBytes[0:index].replace(badEol, newEol) + newMeshBytes += meshBytes[index:] + + newMeshFile.write(newMeshBytes) \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/utils/datasets.py b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/utils/datasets.py new file mode 100644 index 0000000000000000000000000000000000000000..b7fd5b35263d10021dbde0e0ee063e94339e01b2 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/utils/datasets.py @@ -0,0 +1,33 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +#!/usr/bin/env python +#! -*- encoding: utf-8 -*- + +import os +from enum import Enum, unique + +@unique +class DatasetType(Enum): + SIBR = 'sibr' + COLMAP = 'colmap' + CAPREAL = 'capreal' + +datasetStructure = { + "colmap": [ "colmap", "colmap/stereo", "colmap/sparse" ], + "capreal": [ "capreal", "capreal/undistorted" ], + "sibr": [ "cameras", "images", "meshes" ] +} + +def buildDatasetStructure(path, types): + for folder in [folder for type in types for folder in datasetStructure[type]]: + new_folder = os.path.abspath(os.path.join(path, folder)) + print("Creating folder %s..." % new_folder) + os.makedirs(new_folder, exist_ok=True) \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/utils/paths.py b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/utils/paths.py new file mode 100644 index 0000000000000000000000000000000000000000..4b822ae595ee09c71c6b14a9d6bcfbd8a2fb30bf --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/preprocess/utils/paths.py @@ -0,0 +1,29 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +#!/usr/bin/env python +#! -*- encoding: utf-8 -*- + +import os + +def getBinariesPath(): + if os.path.exists(os.path.join(os.path.dirname(__file__), "../../bin")): + return os.path.abspath(os.path.join(os.path.dirname(__file__), "../../bin")) + else: + return os.path.abspath(os.path.join(os.path.dirname(__file__), "../../../../../install/bin")) + +def getColmapPath(): + return os.environ['COLMAP_PATH'] if 'COLMAP_PATH' in os.environ else ("C:\\Program Files\\Colmap" if os.name == 'nt' else '') + +def getMeshlabPath(): + return os.environ['MESHLAB_PATH'] if 'MESHLAB_PATH' in os.environ else ("C:\\Program Files\\VCG\\Meshlab" if os.name == 'nt' else '') + +def getRCPath(): + return os.environ['RC_PATH'] if 'RC_PATH' in os.environ else "C:\\Program Files\\Capturing Reality\\RealityCapture\\" diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/scripts/processRC.py b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/scripts/processRC.py new file mode 100644 index 0000000000000000000000000000000000000000..a6d6e95cb58d438f02295ce0bb15757af07b81e4 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/dataset_tools/scripts/processRC.py @@ -0,0 +1,244 @@ + +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr +# + + +#!/usr/bin/env python +#! -*- encoding: utf-8 -*- + +""" @package dataset_tools_preprocess +This script processes images and creates an RealityCapture (RC) reconstruction, then creates a colmap version using the RC camera registration + +Parameters: -h help, + -path , + +Usage: python processRC.py -path + +""" + +import os, sys, shutil +os.sys.path.append('../preprocess/') +os.sys.path.append('../preprocess/realityCaptureTools') +os.sys.path.append('../preprocess/fullColmapProcess') +os.sys.path.append('../preprocess/converters') + +import json +import argparse +from utils.paths import getBinariesPath, getColmapPath, getMeshlabPath +from utils.commands import getProcess, getColmap, getRCprocess +from utils.TaskPipeline import TaskPipeline +import rc_tools +import colmap2nerf +import selective_colmap_process + +def find_file(filename): + fname = os.path.join(os.path.abspath(os.path.dirname(__file__)), filename) + if not os.path.exists(fname): + fname = os.path.join("../preprocess/fullColmapProcess", filename) + if not os.path.exists(fname): + fname = os.path.join("../preprocess/realityCaptureTools", filename) + if not os.path.exists(fname): + fname = os.path.join("../preprocess/converters", filename) + return fname + + +def main(): + parser = argparse.ArgumentParser() + + # common arguments + parser.add_argument("--sibrBinariesPath", type=str, default=getBinariesPath(), help="binaries directory of SIBR") + parser.add_argument("--colmapPath", type=str, default=getColmapPath(), help="path to directory colmap.bat / colmap.bin directory") + parser.add_argument("--quality", type=str, default='default', choices=['default', 'low', 'medium', 'average', 'high', 'extreme'], + help="quality of the reconstruction") + parser.add_argument("--path", type=str, required=True, help="path to your dataset folder") + parser.add_argument("--dry_run", action='store_true', help="run without calling commands") + parser.add_argument("--rc_path", type=str, required=False, help="path to rc dataset, containing bundle.out and images") + parser.add_argument("--out_path", type=str, required=False, help = "output path ") + parser.add_argument("--video_name", type=str, default='default', required=False, help = "name of video file to load") + parser.add_argument("--create_colmap", action='store_true', help="create colmap hierarchy") + parser.add_argument("--target_width", type=str, default='default', help="colmap_target_width") + parser.add_argument("--from_step", type=str, default='default', help="Run from this step to --to_step (or end if no to_step") + parser.add_argument("--to_step", type=str, default='default', help="up to but *excluding* this step (from --from_step); must be unique steps") + + # RC arguments + parser.add_argument("--do_mvs", action='store_false', help="use train folder") + parser.add_argument("--calib_only", action='store_true', help="only do calibration") + parser.add_argument("--hires_nerf", action='store_true', help="create hi res nerf") + parser.add_argument("--car_data", action='store_true', help="pre(pre)process car camera data ") + parser.add_argument("--do_train", action='store_false', help="use train folder") + parser.add_argument("--do_validation", action='store_false', help="use validation folder") + parser.add_argument("--no_validation_split", action='store_true', help="dont do validation split") + parser.add_argument("--do_video", action='store_true', help="use video folder (mp4)") + parser.add_argument("--do_test", action='store_true', help="use test folder (stills path)") + parser.add_argument("--auto_recon_area", action='store_true', help="automatically set recon area (no user intervention)") + + parser.add_argument("--config_folder", type=str, default='default', help="folder containing configuration files; usually cwd") + parser.add_argument("--model_name", type=str, default='default', help="Internal name of RC model") + parser.add_argument("--path_prefix", type=str, default='default', help="Internal prefix of path images") + parser.add_argument("--one_over_fps", type=str, default='default', help="Sampling rate for the video") + parser.add_argument("--valid_skip", type=str, default='default', help="skip every nth image for validation") + # "presets" + parser.add_argument("--images_only", action='store_false', help="just process images: no validation, no test") + parser.add_argument("--video_only", action='store_true', help="just process video: no photos, no test") + + parser.add_argument("--no_refl", action='store_true', help="dont densify mesh, dont convert_sibr, dont create nerf (def: false)") + + + # needed to avoid parsing issue for passing arguments to next command (TODO) + parser.add_argument("--video_filename", type=str, default='default', help="full path of video file (internal argument; do not set)") + parser.add_argument("--mesh_obj_filename", type=str, default='default', help="full path of obj mesh file (internal argument; do not set)") + parser.add_argument("--mesh_xyz_filename", type=str, default='default', help="full path of xyz point cloud file (internal argument; do not set)") + parser.add_argument("--mesh_ply_filename", type=str, default='default', help="full path of ply mesh file (internal argument; do not set)") + + # colmap + #colmap performance arguments + parser.add_argument("--numGPUs", type=int, default=2, help="number of GPUs allocated to Colmap") + + # Patch match stereo + parser.add_argument("--PatchMatchStereo.max_image_size", type=int, dest="patchMatchStereo_PatchMatchStereoDotMaxImageSize") + parser.add_argument("--PatchMatchStereo.window_radius", type=int, dest="patchMatchStereo_PatchMatchStereoDotWindowRadius") + parser.add_argument("--PatchMatchStereo.window_step", type=int, dest="patchMatchStereo_PatchMatchStereoDotWindowStep") + parser.add_argument("--PatchMatchStereo.num_samples", type=int, dest="patchMatchStereo_PatchMatchStereoDotNumSamples") + parser.add_argument("--PatchMatchStereo.num_iterations", type=int, dest="patchMatchStereo_PatchMatchStereoDotNumIterations") + parser.add_argument("--PatchMatchStereo.geom_consistency", type=int, dest="patchMatchStereo_PatchMatchStereoDotGeomConsistency") + + # Stereo fusion + parser.add_argument("--StereoFusion.check_num_images", type=int, dest="stereoFusion_CheckNumImages") + parser.add_argument("--StereoFusion.max_image_size", type=int, dest="stereoFusion_MaxImageSize") + + + args = vars(parser.parse_args()) + + from_step = args["from_step"] + to_step = args["to_step"] + + # Update args with quality values + fname = find_file("ColmapQualityParameters.json") + with open(fname, "r") as qualityParamsFile: + qualityParams = json.load(qualityParamsFile) + + for key, value in qualityParams.items(): + if not key in args or args[key] is None: + args[key] = qualityParams[key][args["quality"]] if args["quality"] in qualityParams[key] else qualityParams[key]["default"] + + # Get process steps + fname = find_file("processRCSteps.json") + with open(fname, "r") as processStepsFile: + steps = json.load(processStepsFile)["steps"] + + # Fixing path values + args["path"] = os.path.abspath(args["path"]) + args["sibrBinariesPath"] = os.path.abspath(args["sibrBinariesPath"]) + args["colmapPath"] = os.path.abspath(args["colmapPath"]) + args["gpusIndices"] = ','.join([str(i) for i in range(args["numGPUs"])]) + + args["mesh_obj_filename"] = os.path.join(args["path"], os.path.join("rcScene", os.path.join("meshes", "mesh.obj"))) + args["mesh_xyz_filename"] = os.path.join(args["path"], os.path.join("rcScene", os.path.join("meshes", "point_cloud.xyz"))) + args["mesh_ply_filename"] = os.path.join(args["path"], os.path.join("sibr", os.path.join("capreal", "mesh.ply"))) + + args["path_prefix"] = "test_" + + # fixed in preprocess + args["video_filename"] = os.path.join(args["path"], os.path.join("raw", os.path.join("videos", "XXX.mp4"))) + if args["config_folder"] == 'default': + if os.path.exists("registrationConfig.xml"): + args["config_folder"] = "." + elif os.path.exists("../preprocess/realityCaptureTools/registrationConfig.xml"): + args["config_folder"] = "../preprocess/realityCaptureTools/" + + if args["valid_skip"] == 'default' : + args["valid_skip"] = "10" + + if args["one_over_fps"] == 'default': + args["one_over_fps"] = "0.02" + + if args["target_width"] == 'default': + args["target_width"] = "1000" + print("TARGET WIDTH ", args["target_width"]) + + if args["no_validation_split"]: + args["do_validation_split"] = False + else: + args["do_validation_split"] = True + + # presets + + exclude_steps = [] + + if args["no_refl"] == True: + exclude_steps = [ "densify_mesh", "dense_mesh", "create_nerf", "convert_sibr_mesh" ] + print("No densification, no sibr, no nerf, exclude:", exclude_steps) + + if args["car_data"]: + print("Doing car data") + else: + print("No car data") + + if args["calib_only"]: + to_step = "colmap_patch_match_stereo" + args["do_mvs"] = False + exclude_steps = [ "densify_mesh", "dense_mesh" ] + + # either do video or do_test + if args["do_video"]: + args["path_prefix"] = "frame" + + if args["video_only"]: + args["do_train"] = False + args["do_validation"] = False + args["do_test"] = False + args["do_video"] = True + + if args["do_test"]: + args["path_prefix"] = "test_" + args["do_video"] = False + + + if args["video_only"] and args["calib_only"]: + exclude_steps = [ "densify_mesh", "dense_mesh", "rc_to_colmap_path_cameras", "rc_to_colmap_validation_cameras" ] + + programs = { + "colmap": { + "path": getColmap(args["colmapPath"]) + }, + "RC": { + "path": getRCprocess() + } + } + + # TODO: move to generic taskpipeline code; + if( from_step != 'default' or to_step != 'default' or exclude_steps != []): + # check if to_step exists + # select steps + newsteps = [] + if from_step != 'default': + adding_steps = False + else: + adding_steps = True + + for s in steps: + if s['name'] == from_step : + adding_steps = True + if s['name'] == to_step : + break + if adding_steps and (not (s['name'] in exclude_steps)): + newsteps.append(s) + + steps = newsteps + + pipeline = TaskPipeline(args, steps, programs) + + pipeline.runProcessSteps() + + print("selectiveColmapProcess has finished successfully.") + sys.exit(0) + +if __name__ == "__main__": + main() diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/CMakeLists.txt b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..741699a584c113031f4bf403711b25f6a1aa6943 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/CMakeLists.txt @@ -0,0 +1,18 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + + +project(sibr_ulr_all) + +add_subdirectory(apps) +add_subdirectory(renderer) + +include(install_runtime) +subdirectory_target(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR} "projects/ulr") diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/apps/CMakeLists.txt b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/apps/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..7f1ce1a8ce69a35901578a053ea5f49f1091342e --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/apps/CMakeLists.txt @@ -0,0 +1,15 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + + +project(SIBR_ulr_apps) + +add_subdirectory(ulr/) +add_subdirectory(ulrv2/) diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/apps/ulr/CMakeLists.txt b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/apps/ulr/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..c96496a3b3d504c109321b1ca081efa1d52d3b68 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/apps/ulr/CMakeLists.txt @@ -0,0 +1,43 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + + +project(SIBR_ulr_app) + +file(GLOB SOURCES "*.cpp" "*.h" "*.hpp") +source_group("Source Files" FILES ${SOURCES}) + +file(GLOB RESOURCES "resources/*.ini") +source_group("Resources Files" FILES ${RESOURCES}) + +add_executable(${PROJECT_NAME} ${SOURCES}) +target_link_libraries(${PROJECT_NAME} + + ${Boost_LIBRARIES} + ${ASSIMP_LIBRARIES} + ${GLEW_LIBRARIES} + ${OPENGL_LIBRARIES} + ${OpenCV_LIBRARIES} + sibr_view + sibr_assets + sibr_ulr + sibr_graphics +) +set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER "projects/ulr/apps") + +## High level macro to install in an homogen way all our ibr targets +include(install_runtime) +ibr_install_target(${PROJECT_NAME} + INSTALL_PDB ## mean install also MSVC IDE *.pdb file (DEST according to target type) + RESOURCES ${RESOURCES} + RSC_FOLDER "ulr" + STANDALONE ${INSTALL_STANDALONE} ## mean call install_runtime with bundle dependencies resolution + COMPONENT ${PROJECT_NAME}_install ## will create custom target to install only this project +) diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/apps/ulr/main.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/apps/ulr/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..761ca4070927faf13ed3311dbc67f69e145ef81d --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/apps/ulr/main.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include +#include +#include +#include +#include +#include +#include + +#define PROGRAM_NAME "sibr_ulr_app" +using namespace sibr; + +const char* usage = "" + "Usage: " PROGRAM_NAME " -path " "\n" + ; + + + +int main( int ac, char** av ) +{ + { + + // Parse Commad-line Args + CommandLineArgs::parseMainArgs(ac, av); + BasicIBRAppArgs myArgs; + + const bool doVSync = !myArgs.vsync; + // rendering size + uint rendering_width = myArgs.rendering_size.get()[0]; + uint rendering_height = myArgs.rendering_size.get()[1]; + // window size + uint win_width = myArgs.win_width; + uint win_height = myArgs.win_height; + + // Window setup + sibr::Window window(PROGRAM_NAME, sibr::Vector2i(50, 50), myArgs, getResourcesDirectory() + "/ulr/" + PROGRAM_NAME + ".ini"); + + // Setup IBR + BasicIBRScene::Ptr scene(new BasicIBRScene(myArgs)); + + // check rendering size + rendering_width = (rendering_width <= 0) ? scene->cameras()->inputCameras()[0]->w() : rendering_width; + rendering_height = (rendering_height <= 0) ? scene->cameras()->inputCameras()[0]->h() : rendering_height; + Vector2u usedResolution(rendering_width, rendering_height); + + const unsigned int sceneResWidth = usedResolution.x(); + const unsigned int sceneResHeight = usedResolution.y(); + + ULRView::Ptr ulrView(new ULRView(scene, sceneResWidth, sceneResHeight)); + ulrView->setNumBlend(50, 50); + + // Raycaster. + std::shared_ptr raycaster = std::make_shared(); + raycaster->init(); + raycaster->addMesh(scene->proxies()->proxy()); + + // Camera handler for main view. + sibr::InteractiveCameraHandler::Ptr generalCamera(new InteractiveCameraHandler()); + generalCamera->setup(scene->cameras()->inputCameras(), Viewport(0, 0, (float)usedResolution.x(), (float)usedResolution.y()), raycaster); + + + // Add views to mvm. + MultiViewManager multiViewManager(window, false); + multiViewManager.addIBRSubView("ULR view", ulrView, usedResolution, ImGuiWindowFlags_ResizeFromAnySide); + multiViewManager.addCameraForView("ULR view", generalCamera); + + // Top view + const std::shared_ptr topView(new sibr::SceneDebugView(scene, generalCamera, myArgs)); + multiViewManager.addSubView("Top view", topView, usedResolution); + + if (myArgs.pathFile.get() != "" ) { + generalCamera->getCameraRecorder().loadPath(myArgs.pathFile.get(), usedResolution.x(), usedResolution.y()); + generalCamera->getCameraRecorder().recordOfflinePath(myArgs.outPath, multiViewManager.getIBRSubView("ULR view"), "ulr"); + if( !myArgs.noExit ) + exit(0); + } + + while (window.isOpened()) + { + sibr::Input::poll(); + window.makeContextCurrent(); + if (sibr::Input::global().key().isPressed(sibr::Key::Escape)) + window.close(); + + multiViewManager.onUpdate(sibr::Input::global()); + multiViewManager.onRender(window); + window.swapBuffer(); + CHECK_GL_ERROR + } + + } + + return EXIT_SUCCESS; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/apps/ulr/resources/sibr_ulr_app.ini b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/apps/ulr/resources/sibr_ulr_app.ini new file mode 100644 index 0000000000000000000000000000000000000000..88a09fd74e0cc999788de9cc1802fbbba9e10e26 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/apps/ulr/resources/sibr_ulr_app.ini @@ -0,0 +1,26 @@ + +[Window][Camera ULR view] +Pos=50,50 +Size=900,300 +Collapsed=0 + +[Window][Top view settings] +Pos=950,50 +Size=450,300 +Collapsed=0 + +[Window][Metrics##0] +Pos=1400,50 +Size=450,300 +Collapsed=0 + +[Window][ULR view] +Pos=50,350 +Size=900,600 +Collapsed=0 + +[Window][Top view] +Pos=950,350 +Size=900,600 +Collapsed=0 + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/apps/ulrv2/CMakeLists.txt b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/apps/ulrv2/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..47dfde990d7fbce1db9699a197f70dfb31334d41 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/apps/ulrv2/CMakeLists.txt @@ -0,0 +1,45 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + + +project(SIBR_ulrv2_app) + +file(GLOB SOURCES "*.cpp" "*.h" "*.hpp") +source_group("Source Files" FILES ${SOURCES}) + +file(GLOB RESOURCES "resources/*.ini") +source_group("Resources Files" FILES ${RESOURCES}) + +add_executable(${PROJECT_NAME} ${SOURCES}) +target_link_libraries(${PROJECT_NAME} + + ${Boost_LIBRARIES} + ${ASSIMP_LIBRARIES} + ${GLEW_LIBRARIES} + ${OPENGL_LIBRARIES} + ${OpenCV_LIBRARIES} + OpenMP::OpenMP_CXX + sibr_view + sibr_assets + sibr_ulr + sibr_renderer + sibr_graphics +) +set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER "projects/ulr/apps") + +## High level macro to install in an homogen way all our ibr targets +include(install_runtime) +ibr_install_target(${PROJECT_NAME} + INSTALL_PDB ## mean install also MSVC IDE *.pdb file (DEST according to target type) + RESOURCES ${RESOURCES} + RSC_FOLDER "ulr" + STANDALONE ${INSTALL_STANDALONE} ## mean call install_runtime with bundle dependencies resolution + COMPONENT ${PROJECT_NAME}_install ## will create custom target to install only this project +) diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/apps/ulrv2/main.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/apps/ulrv2/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0ae0bb8b961302c5c6b65a120b3e7599aeac0ecd --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/apps/ulrv2/main.cpp @@ -0,0 +1,411 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include + +#include +#include +#include + +#include "projects/ulr/renderer/ULRView.hpp" +#include +#include + +#include +#include +#include + +#define PROGRAM_NAME "sibr_ulrv2_app" +using namespace sibr; + +const char* usage = "" +"Usage: " PROGRAM_NAME " -path " "\n" +; + + +int legacyV1main(ULRAppArgs & myArgs); +int legacyV2main(ULRAppArgs & myArgs); + + +int main(int ac, char** av) { + + // Parse Command-line Args + CommandLineArgs::parseMainArgs(ac, av); + ULRAppArgs myArgs; + myArgs.displayHelpIfRequired(); + + if (myArgs.version == 2) { + return legacyV2main(myArgs); + } + if (myArgs.version == 1) { + return legacyV1main(myArgs); + } + + const bool doVSync = !myArgs.vsync; + // rendering size + uint rendering_width = myArgs.rendering_size.get()[0]; + uint rendering_height = myArgs.rendering_size.get()[1]; + + // window size + uint win_width = myArgs.win_width; + uint win_height = myArgs.win_height; + + + // Window setup + sibr::Window window(PROGRAM_NAME, sibr::Vector2i(50, 50), myArgs, getResourcesDirectory() + "/ulr/" + PROGRAM_NAME + ".ini"); + + BasicIBRScene::Ptr scene(new BasicIBRScene(myArgs, true)); + + // Setup the scene: load the proxy, create the texture arrays. + const uint flags = SIBR_GPU_LINEAR_SAMPLING | SIBR_FLIP_TEXTURE; + + // Fix rendering aspect ratio if user provided rendering size + uint scene_width = scene->cameras()->inputCameras()[0]->w(); + uint scene_height = scene->cameras()->inputCameras()[0]->h(); + float scene_aspect_ratio = scene_width * 1.0f / scene_height; + float rendering_aspect_ratio = rendering_width * 1.0f / rendering_height; + + if ((rendering_width > 0) && !myArgs.force_aspect_ratio ) { + if (abs(scene_aspect_ratio - rendering_aspect_ratio) > 0.001f) { + if (scene_width > scene_height) { + rendering_height = rendering_width / scene_aspect_ratio; + } + else { + rendering_width = rendering_height * scene_aspect_ratio; + } + } + } + + + // check rendering size + rendering_width = (rendering_width <= 0) ? scene->cameras()->inputCameras()[0]->w() : rendering_width; + rendering_height = (rendering_height <= 0) ? scene->cameras()->inputCameras()[0]->h() : rendering_height; + Vector2u usedResolution(rendering_width, rendering_height); + std::cerr << " USED RES " << usedResolution << " scene w h " << scene_width << " : " << scene_height << + " NAME " << scene->cameras()->inputCameras()[0]->name() << std::endl; + + const unsigned int sceneResWidth = usedResolution.x(); + const unsigned int sceneResHeight = usedResolution.y(); + + + scene->renderTargets()->initRGBandDepthTextureArrays(scene->cameras(), scene->images(), scene->proxies(), flags, true, myArgs.force_aspect_ratio); + + // Create the ULR view. + ULRV3View::Ptr ulrView(new ULRV3View(scene, sceneResWidth, sceneResHeight)); + + // Check if masks are provided and enabled. + if (myArgs.masks) { + if (!myArgs.maskParams.get().empty()) { + if (!myArgs.maskParamsExtra.get().empty()) { + ulrView->getULRrenderer()->loadMasks(scene, myArgs.maskParams.get(), "", myArgs.maskParamsExtra.get()); + } + else { + ulrView->getULRrenderer()->loadMasks(scene, myArgs.maskParams.get(), "", ".png"); + } + } + else { + ulrView->getULRrenderer()->loadMasks(scene); + } + ulrView->getULRrenderer()->useMasks() = true; + } + + // Raycaster. + std::shared_ptr raycaster = std::make_shared(); + raycaster->init(); + raycaster->addMesh(scene->proxies()->proxy()); + + // Camera handler for main view. + sibr::InteractiveCameraHandler::Ptr generalCamera(new InteractiveCameraHandler()); + generalCamera->setup(scene->cameras()->inputCameras(), Viewport(0, 0, (float)usedResolution.x(), (float)usedResolution.y()), raycaster); + + // Add views to mvm. + MultiViewManager multiViewManager(window, false); + multiViewManager.addIBRSubView("ULR view", ulrView, usedResolution, ImGuiWindowFlags_ResizeFromAnySide); + multiViewManager.addCameraForView("ULR view", generalCamera); + + CHECK_GL_ERROR; + + if (myArgs.offscreen || myArgs.pathFile.get() != "" ) { + generalCamera->getCameraRecorder().loadPath(myArgs.pathFile.get(), usedResolution.x(), usedResolution.y()); + generalCamera->getCameraRecorder().recordOfflinePath(myArgs.outPath, multiViewManager.getIBRSubView("ULR view"), ""); + if( !myArgs.noExit ) + exit(0); + } + + // Top view + const std::shared_ptr topView(new sibr::SceneDebugView(scene, generalCamera, myArgs)); + multiViewManager.addSubView("Top view", topView, usedResolution); + + CHECK_GL_ERROR; + + // Main looooooop. + while (window.isOpened()) { + + sibr::Input::poll(); + window.makeContextCurrent(); + if (sibr::Input::global().key().isPressed(sibr::Key::Escape)) { + window.close(); + } + + multiViewManager.onUpdate(sibr::Input::global()); + multiViewManager.onRender(window); + + window.swapBuffer(); + CHECK_GL_ERROR; + } + + return EXIT_SUCCESS; +} + +/// Use ULRV2 view and renderer. +int legacyV2main(ULRAppArgs & myArgs) +{ + + { + + const bool doVSync = !myArgs.vsync; + // rendering size + uint rendering_width = myArgs.rendering_size.get()[0]; + uint rendering_height = myArgs.rendering_size.get()[1]; + // window size + uint win_width = myArgs.win_width; + uint win_height = myArgs.win_height; + + // Window setup + sibr::Window window(PROGRAM_NAME, sibr::Vector2i(50, 50), myArgs); + + BasicIBRScene::Ptr scene(new BasicIBRScene(myArgs)); + + + // check rendering size + rendering_width = (rendering_width <= 0) ? scene->cameras()->inputCameras()[0]->w() : rendering_width; + rendering_height = (rendering_height <= 0) ? scene->cameras()->inputCameras()[0]->h() : rendering_height; + Vector2u usedResolution(rendering_width, rendering_height); + + const unsigned int sceneResWidth = usedResolution.x(); + const unsigned int sceneResHeight = usedResolution.y(); + + ULRV2View::Ptr ulrView(new ULRV2View(scene, sceneResWidth, sceneResHeight)); + ulrView->setNumBlend(40, 40); + + // Raycaster. + std::shared_ptr raycaster = std::make_shared(); + raycaster->init(); + raycaster->addMesh(scene->proxies()->proxy()); + + // Camera handler for main view. + sibr::InteractiveCameraHandler::Ptr generalCamera(new InteractiveCameraHandler()); + generalCamera->setup(scene->cameras()->inputCameras(), Viewport(0, 0, (float)usedResolution.x(), (float)usedResolution.y()), raycaster); + + + // Add views to mvm. + MultiViewManager multiViewManager(window, false); + multiViewManager.addIBRSubView("ULR view", ulrView, usedResolution, ImGuiWindowFlags_ResizeFromAnySide); + multiViewManager.addCameraForView("ULR view", generalCamera); + + // Top view + const std::shared_ptr topView(new sibr::SceneDebugView(scene, generalCamera, myArgs)); + multiViewManager.addSubView("Top view", topView, usedResolution); + + // Soft Visibility masks + std::vector depths3D(scene->cameras()->inputCameras().size()); + if (myArgs.softVisibility) { + + int numImages = (int)scene->cameras()->inputCameras().size(); + + for (int imId = 0; imId < numImages; ++imId) { + + sibr::InputCamera cam = *scene->cameras()->inputCameras()[imId]; + sibr::Vector3f camPos = cam.position(); + int w = cam.w(); + int h = cam.h(); + + sibr::DepthRenderer rendererDepth(cam.w(), cam.h()); + + sibr::ImageL32F depthMapSIBR(w, h); + + rendererDepth.render(cam, scene->proxies()->proxy()); + rendererDepth._depth_RT->readBack(depthMapSIBR); + + depths3D[imId] = sibr::ImageL32F(w, h, 0); + + for (int i = 0; i < w; i++) { + for (int j = 0; j < h; j++) { + sibr::Vector2i pixelPos(i, j); + sibr::Vector3f pos3dMesh(cam.unprojectImgSpaceInvertY(pixelPos, depthMapSIBR(i, j).x())); + depths3D[imId](i, j).x() = (camPos - pos3dMesh).norm(); + } + } + //showFloat(depthMapSIBR); + //showFloat(depths3D[imId]); + } + } + + + if (myArgs.masks) { + if (!myArgs.maskParams.get().empty()) { + ulrView->loadMasks(scene, usedResolution.x(), usedResolution.y(), myArgs.maskParams.get(), "", ".png"); + } + else { + ulrView->loadMasks(scene, usedResolution.x(), usedResolution.y()); + } + + } + if (myArgs.invert) { + ulrView->_ulr->setDoInvertMasks(true); + } + if (myArgs.alphas) { + ulrView->_ulr->setAreMasksBinary(false); + } + if (myArgs.poisson) { + ulrView->noPoissonBlend(true); + } + + Texture2DArrayLum32F soft_visibility_textures; + if (myArgs.softVisibility) { + int numImages = (int)scene->cameras()->inputCameras().size(); + std::vector softVisibilities(numImages); + + int wSoft = depths3D[0].w(); + int hSoft = depths3D[0].h(); +#pragma omp parallel for + for (int imId = 0; imId < numImages; ++imId) { + + sibr::ImageRGBA tempVisibility; + ulrView->computeVisibilityMap(depths3D[imId], tempVisibility); + softVisibilities[imId] = std::move(sibr::convertRGBAtoL32F(tempVisibility)); + cv::Mat temp; + cv::resize(softVisibilities[imId].toOpenCV(), temp, cv::Size(wSoft, hSoft), 0, 0, cv::INTER_NEAREST); + softVisibilities[imId].fromOpenCV(temp); + } + + soft_visibility_textures.createFromImages(softVisibilities, SIBR_GPU_LINEAR_SAMPLING | SIBR_FLIP_TEXTURE); + + ulrView->_ulr->getSoftVisibilityMaps() = &soft_visibility_textures; + ulrView->_ulr->getSoftVisibilityThreshold() = 20.0f; + //ulrView->noPoissonBlend(true); + + } + + if (myArgs.pathFile.get() != "" ) { + generalCamera->getCameraRecorder().loadPath(myArgs.pathFile.get(), usedResolution.x(), usedResolution.y()); + generalCamera->getCameraRecorder().recordOfflinePath(myArgs.outPath, multiViewManager.getIBRSubView("ULR view"), "ulr"); + if( !myArgs.noExit ) + exit(0); + } + + CHECK_GL_ERROR; + while (window.isOpened()) + { + + + sibr::Input::poll(); + window.makeContextCurrent(); + if (sibr::Input::global().key().isPressed(sibr::Key::Escape)) + window.close(); + + if (sibr::Input::global().key().isPressed(sibr::Key::Z)) { + if (ulrView->_ulr->getSoftVisibilityMaps()) { + std::cout << " disabling soft visibility" << std::endl; + ulrView->_ulr->getSoftVisibilityMaps() = nullptr; + } + else { + std::cout << " enabling soft visibility" << std::endl; + ulrView->_ulr->getSoftVisibilityMaps() = &soft_visibility_textures; + } + } + + multiViewManager.onUpdate(sibr::Input::global()); + multiViewManager.onRender(window); + window.swapBuffer(); + CHECK_GL_ERROR; + } + } + + + return EXIT_SUCCESS; +} + +/// Use ULRV1 view and renderer. +int legacyV1main(ULRAppArgs & myArgs) +{ + + { + + const bool doVSync = !myArgs.vsync; + // rendering size + uint rendering_width = myArgs.rendering_size.get()[0]; + uint rendering_height = myArgs.rendering_size.get()[1]; + // window size + uint win_width = myArgs.win_width; + uint win_height = myArgs.win_height; + + // Window setup + sibr::Window window(PROGRAM_NAME, sibr::Vector2i(50, 50), myArgs); + + // Setup IBR + BasicIBRScene::Ptr scene(new BasicIBRScene(myArgs)); + + // check rendering size + rendering_width = (rendering_width <= 0) ? scene->cameras()->inputCameras()[0]->w() : rendering_width; + rendering_height = (rendering_height <= 0) ? scene->cameras()->inputCameras()[0]->h() : rendering_height; + Vector2u usedResolution(rendering_width, rendering_height); + + const unsigned int sceneResWidth = usedResolution.x(); + const unsigned int sceneResHeight = usedResolution.y(); + + ULRView::Ptr ulrView(new ULRView(scene, sceneResWidth, sceneResHeight)); + ulrView->setNumBlend(50, 50); + + // Raycaster. + std::shared_ptr raycaster = std::make_shared(); + raycaster->init(); + raycaster->addMesh(scene->proxies()->proxy()); + + // Camera handler for main view. + sibr::InteractiveCameraHandler::Ptr generalCamera(new InteractiveCameraHandler()); + generalCamera->setup(scene->cameras()->inputCameras(), Viewport(0, 0, (float)usedResolution.x(), (float)usedResolution.y()), raycaster); + + + // Add views to mvm. + MultiViewManager multiViewManager(window, false); + multiViewManager.addIBRSubView("ULR view", ulrView, usedResolution, ImGuiWindowFlags_ResizeFromAnySide); + multiViewManager.addCameraForView("ULR view", generalCamera); + + // Top view + const std::shared_ptr topView(new sibr::SceneDebugView(scene, generalCamera, myArgs)); + multiViewManager.addSubView("Top view", topView); + + if (myArgs.pathFile.get() != "" ) { + generalCamera->getCameraRecorder().loadPath(myArgs.pathFile.get(), usedResolution.x(), usedResolution.y()); + generalCamera->getCameraRecorder().recordOfflinePath(myArgs.outPath, multiViewManager.getIBRSubView("ULR view"), "ulr"); + if( !myArgs.noExit ) + exit(0); + } + + + while (window.isOpened()) + { + sibr::Input::poll(); + window.makeContextCurrent(); + if (sibr::Input::global().key().isPressed(sibr::Key::Escape)) + window.close(); + + multiViewManager.onUpdate(sibr::Input::global()); + multiViewManager.onRender(window); + window.swapBuffer(); + CHECK_GL_ERROR + } + + } + return EXIT_SUCCESS; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/apps/ulrv2/resources/sibr_ulrv2_app.ini b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/apps/ulrv2/resources/sibr_ulrv2_app.ini new file mode 100644 index 0000000000000000000000000000000000000000..82428eae329121dbdbce386994b17a223a0e20df --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/apps/ulrv2/resources/sibr_ulrv2_app.ini @@ -0,0 +1,36 @@ + +[Window][ULRV2 Settings (ULR view)] +Pos=50,50 +Size=350,300 +Collapsed=0 + +[Window][ULRV3 Settings (ULR view)] +Pos=50,50 +Size=350,300 +Collapsed=0 + +[Window][Camera ULR view] +Pos=400,50 +Size=550,300 +Collapsed=0 + +[Window][Top view settings] +Pos=950,50 +Size=450,300 +Collapsed=0 + +[Window][Metrics##0] +Pos=1400,50 +Size=450,300 +Collapsed=0 + +[Window][ULR view] +Pos=50,350 +Size=900,600 +Collapsed=0 + +[Window][Top view] +Pos=950,350 +Size=900,600 +Collapsed=0 + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/documentation/IBR_ULR.dox b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/documentation/IBR_ULR.dox new file mode 100644 index 0000000000000000000000000000000000000000..96a28f5cc3506c5f6f079594004710d544fee13f --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/documentation/IBR_ULR.dox @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +/*! +@page ulrPage Unstructured Lumigraph Rendering (ULR) + +\section ulr_intro Introduction + +This *Project* contains three specialized implementations of Unstructured Lumigraph Rendering \[Buelher 2001\]; we refer the reader to that paper for technical details. In contrast to the original paper, our method blends input images on a *per-pixel* basis. In a nutshell the rendering apps in this *Project* first render a depth buffer for the novel (current) view, then for a subset *S* of input images reproject each visible 3D point into each image in *S*, and then blend the result according to the blending weights as defined in the original paper. + +This *Project* contains two renderings apps: `SIBR_ulr_app` which is the original (slow) version, `SIBR_ulrv2_app` that contains the second and third versions of the ULR. + +The original version of ULR first selects a subset of the original images using angle and position criteria on the CPU, then uses a multi-pass ping-pong shader to rank the 4 best-cost images for each pixel, by storing these four color values and their weights in rendertargets and iteratively updating them while keeping them sorted. + +Version 2 removes the need for the ping-pong best-cost image update, by iterating on the selected cameras in one shader. The corresponding images and depth maps are passed as a list of textures. The maximum supported number of cameras is determined by the maximum texture slot count in fragment shaders. + +Version 3 stores images and depth maps as texture 2D arrays, and pack all cameras in a uniform buffer object. This allows all cameras to be considered and do the selection entirely on the GPU. The maximum supported number of cameras is determined by the maximum texture array layer count and uniform buffer object size. + +\subsection ulr_authors Authors + +This *Project* was written by: Gaurav Chaurasia, Sebastien Bonopera, Theo Thonat, Simon Rodriguez, Sebastien Bonopera, Jerome Esnault, Siddhant Prakashand George Drettakis, who also supervised the entire *Project*. + +
+ +\section ulr_howToUse How to use + +\subsection ulr_binary Use the binary distribution + +The easiest way to use *SIBR* to run ULR is to download the binary distribution. All steps described below, including all preprocessing for your datasets will work using this code. +Download the distribution from the page: https://sibr.gitlabpages.inria.fr/download.html (Core, 57Mb); unzip the file and rename the directory "install". + + +\subsection ulr_howToUse_checkout Checkout the code + +ULR is already available as part of the SIBR Core code. You will need to checkout SIBR Core as mentioned in \ref sibr_checkout . + +\subsection ulr_howToUse_configure Configuration + +As for most of the projects, ULR can be configured through SIBR Core CMake configuration by selecting `SIBR_IBR_ULR` variable before running the configuration (see \ref sibr_configure_cmake). + +\subsection ulr_howToUse_build Build & Install + +You can build and install ULR via running ALL_BUILD and/or INSTALL in sibr_projects.sln solution (as mentioned in \ref sibr_compile Compiling +) or through `sibr_ulr*` specific targets in sibr_projects.sln solution. +Dont forget to build INSTALL if you use ALL_BUILD. + +\subsection ulr_howToUse_run Run + +After installing ULR, several apps should be available in `install\bin`, notably : + +- sibr_ulr_app.exe (or sibr_ulr_app_d.exe / sibr_ulr_app_rwdi.exe depending on the configuration of the target) : this is the legacy version of ULR +- sibr_ulrv2_app.exe (or sibr_ulrv2_app_d.exe / sibr_ulrv2_app_rwdi.exe depending on the configuration of the target) : this updated version gives you the choice between three different implementations of ULR (with GPU optimization and other tweaks) + +Both can be run by running the executable with a path to a working dataset: + + sibr_ulrv2_app.exe --path PATH_TO_DATASET + +Our interactive viewer has a main view running the algorithm and a top view to visualize the position of the calibrated cameras. By default you are in WASD mode, and can toggle to trackball using the "y" key. Please see the page [Interface](https://sibr.gitlabpages.inria.fr/docs/develop/howto_sibr_useful_objects.html) for more details on the interface. + +For example datasets see below \ref ulr_howToUse_example_datasets. + +\subsection Playing paths from the command line + +Paths can be played by the ulr renderers by running the renderer in offscreen mode: +``` +SIBR_ulrv2_app.exe --path PATH_TO_DATASET --offscreen --pathFile path.(out|lookat|tst|path) [--outPath optionalOutputPath --noExit] +``` +By default, the application exits when this operation is performed. This is the easiest way to compare algorithms, although interactive options exist for some *Projects*. + +
+ +\subsection ulr_howToUse_dataset Datasets + +\subsubsection ulr_howToUse_dataset_structure Dataset structure + +A ULR dataset only requires standard SfM/MVS data to function: to generate such a dataset from your input images see: + +\ref howto_generate_dataset + +A standard SIBR dataset contains *cameras* and the *mesh* required for the algorithm to run; no additional preprocessing is required. + +\subsubsection ulr_howToUse_example_datasets Example Datasets + +Some example datasets can be found here: + https://repo-sam.inria.fr/fungraph/sibr-datasets/datasets.html + +You dan download the ULR only package for each dataset. +Feel free to download and experiment, for example with (now famous) Museum Front 27 dataset. Goto the install\bin directory: + +``` + wget https://repo-sam.inria.fr/fungraph/sibr-datasets/museum_front27_ulr.zip + sibr_ulrv2_app.exe --path museum_front27\sibr_cm +``` + +
+ +\subsubsection ulr_howToUse_run_cliOptions CLI options + + | name | type | Required | default value | description | + | -------------------- | --------- | --------- | ------------------------- | --------------------------------------------- | + | **Basic app options** ||||| + | appPath | string | false | "./" | define a custom app path | + | help | bool | false | false | display this help message | + | **Basic window options** ||||| + | width | int | false | 720 | initial window width | + | height | int | false | 480 | initial window height | + | vsync | int | false | 1 | enable vertical sync | + | fullscreen | bool | false | false | set the window to fullscreen | + | hd | bool | false | false | rescale UI elements for high-density screens | + | nogui | bool | false | false | do not use ImGui | + | gldebug | bool | false | false | enable OpenGL error callback | + | **Basic rendering options** ||||| + | scene | string | false | "scene_metadata.txt" | scene metadata file | + | rendering-size | Vector2i | false | { 0, 0 } | size at which rendering is performed | + | texture-width | int | false | 0 | size of the input data in memory | + | texture-ratio | float | false | 1.0f | | + | rendering-mode | int | false | RENDERMODE_MONO | select mono (0) or stereo (1) rendering mode | + | focal-pt | Vector3f | false | { 0.0f, 0.0f, 0.0f } | | + | colmap_fovXfovY_flag | Switch | false | false | | + | **Basic dataset options** ||||| + | path | string | true | | path to the dataset root | + | dataset_type | string | false | "" | type of dataset | + | **ULR specific options** ||||| + | v | int | false | 3 | ULR implementation version | + | soft-visibility | bool | false | false | generate and use soft visibility masks | + | masks | bool | false | false | use binary masks | + | masks-param | string | false | "" | | + | masks-param-extra | string | false | "" | | + | invert | bool | false | false | invert the masks | + | alphas | bool | false | false | | + | poisson-blend | bool | false | false | apply Poisson-filling to the ULR result | + + +\subsection ulr_references References +\[Buehler 2001\] C. Buehler, M. Bosse, L. McMillan, S. Gortler, and M. Cohen. "Unstructured lumigraph +rendering." In Proceedings SIGGRAPH 2001, pp. 425-432. ACM, 2001. https://www.ics.uci.edu/~gopi/ICS280Win02/UnstructuredLumigraph.pdf +*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/documentation/ulr_doc.cmake b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/documentation/ulr_doc.cmake new file mode 100644 index 0000000000000000000000000000000000000000..d384ea0075381b5c15182e929f6fee9be658df7b --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/documentation/ulr_doc.cmake @@ -0,0 +1,13 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +set(PROJECT_PAGE "ulrPage") +set(PROJECT_LINK "https://gitlab.inria.fr/sibr/sibr_core") +set(PROJECT_TYPE "SAMPLES") \ No newline at end of file diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/CMakeLists.txt b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..6ee753b298d4448a2cf09bfde366b7402c93ad81 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/CMakeLists.txt @@ -0,0 +1,68 @@ +# Copyright (C) 2020, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + + +set(SIBR_PROJECT "ulr") +project(sibr_${SIBR_PROJECT}) + +file(GLOB SOURCES "*.cpp" "*.h" "*.hpp") +source_group("Source Files" FILES ${SOURCES}) + +file(GLOB SHADERS "shaders/*.frag" "shaders/*.vert" "shaders/*.geom") +source_group("Source Files\\shaders" FILES ${SHADERS}) + +file(GLOB SOURCES "*.cpp" "*.h" "*.hpp" "shaders/*.frag" "shaders/*.vert" "shaders/*.geom") + + +## Specify target rules +add_library(${PROJECT_NAME} SHARED ${SOURCES}) + +include_directories(${Boost_INCLUDE_DIRS} .) +if(WIN32) +target_link_libraries(${PROJECT_NAME} + ${Boost_LIBRARIES} + ${ASSIMP_LIBRARIES} + ${GLEW_LIBRARIES} + ${OPENGL_LIBRARIES} + ${OpenCV_LIBRARIES} + glfw3 + sibr_system + sibr_view + sibr_assets + sibr_renderer +) +else() +target_link_libraries(${PROJECT_NAME} + ${Boost_LIBRARIES} + ${ASSIMP_LIBRARIES} + ${GLEW_LIBRARIES} + ${OPENGL_LIBRARIES} + ${OpenCV_LIBRARIES} + ${GLFW_LIBRARY} + sibr_system + sibr_view + sibr_assets + sibr_renderer +) +endif + +add_definitions( -DSIBR_EXP_ULR_EXPORTS -DBOOST_ALL_DYN_LINK ) + +set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER "projects/${SIBR_PROJECT}/renderer") + +## High level macro to install in an homogen way all our ibr targets +include(install_runtime) +ibr_install_target(${PROJECT_NAME} + INSTALL_PDB ## mean install also MSVC IDE *.pdb file (DEST according to target type) + SHADERS ${SHADERS} + RSC_FOLDER ${SIBR_PROJECT} + + #STANDALONE ${INSTALL_STANDALONE} ## mean call install_runtime with bundle dependencies resolution + COMPONENT ${PROJECT_NAME}_install ## will create custom target to install only this project +) diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/Config.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/Config.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a4faaa8a57ba6ab9c04e7d076b4eb1210a46f65a --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/Config.hpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include +# include + +# ifdef SIBR_OS_WINDOWS +# ifdef SIBR_STATIC_DEFINE +# define SIBR_EXPORT +# define SIBR_NO_EXPORT +# else +# ifndef SIBR_EXP_ULR_EXPORT +# ifdef SIBR_EXP_ULR_EXPORTS +/* We are building this library */ +# define SIBR_EXP_ULR_EXPORT __declspec(dllexport) +# else +/* We are using this library */ +# define SIBR_EXP_ULR_EXPORT __declspec(dllimport) +# endif +# endif +# ifndef SIBR_NO_EXPORT +# define SIBR_NO_EXPORT +# endif +# endif +# else +# define SIBR_EXP_ULR_EXPORT +# endif + +namespace sibr { + + /// Arguments for all ULR applications. + struct ULRAppArgs : + virtual BasicIBRAppArgs { + Arg version = { "v", 3, "ULR implementation version" }; + ArgSwitch softVisibility = { "soft-visibility", false, "generate and use soft visibility masks" }; + Arg masks = { "masks" , "use binary masks" }; + Arg maskParams = { "masks-param" , "" }; + Arg maskParamsExtra = { "masks-param-extra" , "" }; + Arg invert = { "invert", "invert the masks" }; + Arg alphas = { "alphas", "" }; + Arg poisson = { "poisson-blend", "apply Poisson-filling to the ULR result" }; + }; + +} + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRRenderer.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRRenderer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9f0a327e1786725e4e30548159a694389479ba76 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRRenderer.cpp @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +# include "Config.hpp" +# include +# include + +namespace sibr { +ULRRenderer::ULRRenderer(const uint w, const uint h) +{ + + std::cerr << "\n[ULRenderer] initializing" << std::endl; + std::cerr << "\n[ULRenderer] loading shaders" << std::endl; + _ulrShaderPass1 .init("ULR1", + sibr::loadFile(sibr::getShadersDirectory("ulr") + "/ulr.vert"), + sibr::loadFile(sibr::getShadersDirectory("ulr") + "/ulr1.frag")); + _ulrShaderPass2 .init("ULR2", + sibr::loadFile(sibr::getShadersDirectory("ulr") + "/ulr.vert"), + sibr::loadFile(sibr::getShadersDirectory("ulr") + "/ulr2.frag")); + _depthShader.init("Depth", + sibr::loadFile(sibr::getShadersDirectory("ulr") + "/ulr_intersect.vert"), + sibr::loadFile(sibr::getShadersDirectory("ulr") + "/ulr_intersect.frag")); + + _ulrShaderPass1_nCamPos .init(_ulrShaderPass1, "nCamPos"); + _ulrShaderPass1_iCamPos .init(_ulrShaderPass1, "iCamPos"); + _ulrShaderPass1_iCamDir .init(_ulrShaderPass1, "iCamDir"); + _ulrShaderPass1_iCamProj.init(_ulrShaderPass1, "iCamProj"); + _ulrShaderPass1_occlTest .init(_ulrShaderPass1, "occlTest"); + _ulrShaderPass1_masking .init(_ulrShaderPass1, "doMasking"); + _depthShader_proj.init(_depthShader,"proj"); + + std::cerr << "\n[ULRenderer] creating render targets" << std::endl; + + _ulr0_RT .reset(new sibr::RenderTargetRGBA32F(w,h,0,4)); + _ulr1_RT .reset(new sibr::RenderTargetRGBA32F(w,h,0,4)); + _depth_RT.reset(new sibr::RenderTargetRGBA32F(w,h)); + + _doOccl = true; +} + +void +ULRRenderer::process(std::vector& imgs_ulr, const sibr::Camera& eye, + const sibr::BasicIBRScene::Ptr scene, + std::shared_ptr& altMesh, + const std::vector >& inputRTs, + IRenderTarget& dst) +{ + // Get a new camera with z_near ~ 0 + sibr::Camera new_cam = eye; + new_cam.znear( 0.001f ); + + // render geometry to depth map + + glViewport(0,0, _depth_RT->w(), _depth_RT->h()); + _depth_RT->clear(); + _depth_RT->bind(); + + _depthShader.begin(); + _depthShader_proj.set(new_cam.viewproj()); + + glClear(GL_DEPTH_BUFFER_BIT); + + if( altMesh != nullptr ) + altMesh->render( true, true); // enable depth test - disable back culling + else + scene->proxies()->proxy().render( true, true); // enable depth test - disable back culling + + _depthShader.end(); + _depth_RT->unbind(); + + // ULR pass 1 + _ulr0_RT->clear(sibr::Vector4f(0,0,0,1e5)); + _ulr1_RT->clear(sibr::Vector4f(0,0,0,1e5)); + for (uint i=0; icameras()->inputCameras()[imgs_ulr[i]]->isActive()) { + const sibr::InputCamera& cam = *scene->cameras()->inputCameras()[imgs_ulr[i]]; + std::swap(_ulr0_RT, _ulr1_RT); + _ulrShaderPass1.begin(); + _ulr0_RT->bind(); + glViewport(0,0, _ulr0_RT->w(), _ulr0_RT->h()); + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, inputRTs[imgs_ulr[i]]->texture()); + glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, _depth_RT->texture()); + glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, _ulr1_RT->texture(0)); + glActiveTexture(GL_TEXTURE3); glBindTexture(GL_TEXTURE_2D, _ulr1_RT->texture(1)); + glActiveTexture(GL_TEXTURE4); glBindTexture(GL_TEXTURE_2D, _ulr1_RT->texture(2)); + glActiveTexture(GL_TEXTURE5); glBindTexture(GL_TEXTURE_2D, _ulr1_RT->texture(3)); + if (useMasks()){ + glActiveTexture(GL_TEXTURE6); + glBindTexture(GL_TEXTURE_2D, getMasks()[imgs_ulr[i]]->texture()); + } + _ulrShaderPass1_masking.set(useMasks()); + _ulrShaderPass1_nCamPos.set(eye.position()); + _ulrShaderPass1_iCamPos.set(cam.position()); + _ulrShaderPass1_iCamDir.set(cam.dir()); + _ulrShaderPass1_iCamProj.set(cam.viewproj()); + _ulrShaderPass1_occlTest.set(_doOccl); + sibr::RenderUtility::renderScreenQuad(); + _ulr0_RT->unbind(); + _ulrShaderPass1.end(); + +#if 0 + { + sibr::ImageRGBA32F img2; + _ulr0_RT->readBack(img2); + show(img2); // DEBUG + } +#endif + } + } + + // ULR pass 2 + // enable depth test to ensure depth of proxy is written to + // depth buffer by the shader +// glEnable(GL_DEPTH_TEST); /// \todo TODO -- breaks with fences -- check + _ulrShaderPass2.begin(); + dst.clear(); + dst.bind(); + glViewport(0,0, dst.w(), dst.h()); + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, _depth_RT->texture()); + glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, _ulr0_RT->texture(0)); + glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, _ulr0_RT->texture(1)); + glActiveTexture(GL_TEXTURE3); glBindTexture(GL_TEXTURE_2D, _ulr0_RT->texture(2)); + glActiveTexture(GL_TEXTURE4); glBindTexture(GL_TEXTURE_2D, _ulr0_RT->texture(3)); + sibr::RenderUtility::renderScreenQuad(); + dst.unbind(); + _ulrShaderPass2.end(); + +#if 0 + sibr::ImageRGB img; + dst.readBack(img); + show(img); // DEBUG +#endif + +} + +} /*namespace sibr*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRRenderer.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRRenderer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a1154d264d1c5938163b064adaf780daacd7ebc2 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRRenderer.hpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include "Config.hpp" +# include +# include +# include +# include +# include +# include + +namespace sibr { + + /** Legacy ULR renderer. Process each input image separately and accumulate them. + **/ + class SIBR_EXP_ULR_EXPORT ULRRenderer : public RenderMaskHolder + { + SIBR_CLASS_PTR(ULRRenderer); + + /** Constructor. + *\param w rendering width + *\param h rendering height + */ + ULRRenderer(const uint w, const uint h); + + /** Render. + *\param imgs_ulr vector of selected image IDs + *\param eye novel viewpoint + *\param scene the scene to render + *\param altMesh optional alternative mesh + *\param inputRTs the RGBD input images + *\param output destination target + */ + void process(std::vector& imgs_ulr, const sibr::Camera& eye, + const sibr::BasicIBRScene::Ptr scene, + std::shared_ptr& altMesh, + const std::vector >& inputRTs, + IRenderTarget& output); + + /** Toggle occlusion testing. + *\param val should occlusion testing be performed + */ + void doOccl(bool val) { _doOccl = val; } + + private: + sibr::RenderTargetRGBA32F::Ptr _ulr0_RT; + sibr::RenderTargetRGBA32F::Ptr _ulr1_RT; + sibr::RenderTargetRGBA32F::Ptr _depth_RT; + + sibr::GLShader _ulrShaderPass1; + sibr::GLShader _ulrShaderPass2; + sibr::GLShader _depthShader; + + sibr::GLParameter _ulrShaderPass1_nCamPos; + sibr::GLParameter _ulrShaderPass1_iCamPos; + sibr::GLParameter _ulrShaderPass1_iCamDir; + sibr::GLParameter _ulrShaderPass1_iCamProj; + sibr::GLParameter _ulrShaderPass1_occlTest; + sibr::GLParameter _ulrShaderPass1_masking; + sibr::GLParameter _depthShader_proj; + + bool _doOccl; + + }; + +} /*namespace sibr*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRV2Renderer.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRV2Renderer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..df0cdce6fbe98b1d01097e15c05b1d0a637f91a2 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRV2Renderer.cpp @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +# include "Config.hpp" +# include +# include +# include "ULRV2Renderer.hpp" +#include "core/system/String.hpp" + +namespace sibr { + ULRV2Renderer::ULRV2Renderer(const std::vector & cameras, const uint w, const uint h, const unsigned int maxCams, const std::string & fShader, const std::string & vShader, const bool facecull) + { + + // Count how many cameras are active in the scene. + unsigned int numActiveCams = 0; + for (auto & cam : cameras) { + if (cam->isActive()) { + ++numActiveCams; + } + } + _numCams = maxCams == 0 ? numActiveCams : std::min(maxCams, numActiveCams); + + setupULRshader(fShader,vShader); + + _depthRT.reset(new sibr::RenderTargetRGBA32F(w, h)); + + _doOccl = true; + _areMasksBinary = true; + _doInvertMasks = false; + _discardBlackPixels = true; + _shouldCull = facecull; + _epsilonOcclusion = 1e-2f; + _soft_visibility_threshold = 30.0f; + soft_visibility_maps = nullptr; + } + + void ULRV2Renderer::setupULRshader(const std::string & fShader, const std::string & vShader) + { + std::cerr << "[ULRV2Renderer] Trying to initialize shaders for at most " << _numCams << " cameras." << std::endl; + /// \todo TODO SR: handle the case were we require more shader texture slots than we are allowed too. + /// Seems to be around 90 on Quadro K4200. We can either do multiple passes (fi 40 cams per pass), + /// or try to use texture arrays to avoid this problem. + /// If this happens to you, lower the maximum number of cameras picked by the ulr algo. + + GLShader::Define::List defines; + defines.emplace_back("NUM_CAMS", _numCams); + _ulrShader.init("ULRV2", + sibr::loadFile(sibr::getShadersDirectory("") + "/" + vShader + ".vert"), + sibr::loadFile(sibr::getShadersDirectory("") + "/" + fShader + ".frag", defines)); + _depthShader.init("ULRV2Depth", + sibr::loadFile(sibr::getShadersDirectory("ulr") + "/ulr_intersect.vert"), + sibr::loadFile(sibr::getShadersDirectory("ulr") + "/ulr_intersect.frag", defines)); + + _proj.init(_depthShader, "proj"); + _ncamPos.init(_ulrShader, "ncam_pos"); + _occTest.init(_ulrShader, "occ_test"); + _areMasksBinaryGL.init(_ulrShader, "is_binary_mask"); + _doInvertMasksGL.init(_ulrShader, "invert_mask"); + _discardBlackPixelsGL.init(_ulrShader, "discard_black_pixels"); + _doMask.init(_ulrShader, "doMasking"); + _camCount.init(_ulrShader, "camsCount"); + _use_soft_visibility.init(_ulrShader, "useSoftVisibility"); + _soft_visibility_threshold.init(_ulrShader, "softVisibilityThreshold"); + _epsilonOcclusion.init(_ulrShader, "epsilonOcclusion"); + + _icamProj.resize(_numCams); + _icamPos.resize(_numCams); + _icamDir.resize(_numCams); + _inputRGB.resize(_numCams); + _masks.resize(_numCams); + _selected_cams.resize(_numCams); + + _ulrShader.begin(); + for (uint i = 0; i<(uint)_numCams; i++) + { + _icamProj[i].init(_ulrShader, sibr::sprint("icam_proj[%d]", i)); + _icamPos[i].init(_ulrShader, sibr::sprint("icam_pos[%d]", i)); + _icamDir[i].init(_ulrShader, sibr::sprint("icam_dir[%d]", i)); + _selected_cams[i].init(_ulrShader, sibr::sprint("selected_cams[%d]", i)); + _inputRGB[i].init(_ulrShader, sibr::sprint("input_rgb[%d]", i)); + _inputRGB[i].set(i + 2); // location 0 and 1 reserved.s + _masks[i].init(_ulrShader, sibr::sprint("masks[%d]", i)); + _masks[i].set(GLuint(_numCams + i + 2)); + + } + _ulrShader.end(); + + } + + void + ULRV2Renderer::process(const std::vector& imgs_ulr, const sibr::Camera& eye, + const sibr::BasicIBRScene::Ptr& scene, + std::shared_ptr& altMesh, + const std::vector >& inputRTs, + IRenderTarget& dst) + { + // Get a new camera with z_near ~ 0 + sibr::Camera new_cam = eye; + //new_cam.znear(0.001f); + + + glViewport(0, 0, _depthRT->w(), _depthRT->h()); + _depthRT->bind(); + glClearColor(0, 0, 0, 1); + glClearDepth(1.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + _depthShader.begin(); + _proj.set(new_cam.viewproj()); + if (altMesh != nullptr) { + altMesh->render(true, _shouldCull); // enable depth test - disable back culling + } else { + scene->proxies()->proxy().render(true, _shouldCull); + } + _depthShader.end(); + _depthRT->unbind(); + + glViewport(0, 0, dst.w(), dst.h()); + dst.clear(); + dst.bind(); + + _ulrShader.begin(); + + _ncamPos.set(eye.position()); + _occTest.set(_doOccl); + _areMasksBinaryGL.set(_areMasksBinary); + _doInvertMasksGL.set(_doInvertMasks); + _discardBlackPixelsGL.set(_discardBlackPixels); + _doMask.set(useMasks()); + _epsilonOcclusion.send(); + + CHECK_GL_ERROR + + _use_soft_visibility.set(soft_visibility_maps != nullptr && soft_visibility_maps->handle()); + + CHECK_GL_ERROR + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, _depthRT->texture()); + + CHECK_GL_ERROR + + if (_use_soft_visibility) { + //std::cout << "using soft visib" << std::endl; + _soft_visibility_threshold.send(); + + CHECK_GL_ERROR; + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D_ARRAY, soft_visibility_maps->handle()); + + CHECK_GL_ERROR; + } + + CHECK_GL_ERROR; + + int usedCamerasCount = 0; + + for (int i = 0; i < std::min(imgs_ulr.size(), _numCams); ++i) { + + if (!scene->cameras()->inputCameras()[imgs_ulr[i]]->isActive()) { + continue; + } + + auto& cam = *scene->cameras()->inputCameras()[imgs_ulr[i]]; + _icamPos[usedCamerasCount].set(cam.position()); + _icamDir[usedCamerasCount].set(cam.dir()); + _icamProj[usedCamerasCount].set(cam.viewproj()); + _selected_cams[usedCamerasCount].set((int)imgs_ulr[i]); + glActiveTexture(GL_TEXTURE0 + usedCamerasCount + 2); + glBindTexture(GL_TEXTURE_2D, inputRTs[imgs_ulr[i]]->texture()); + + if (useMasks()) { + glActiveTexture(GL_TEXTURE0 + (int)_numCams + usedCamerasCount + 2); + glBindTexture(GL_TEXTURE_2D, getMasks()[imgs_ulr[i]]->texture()); + } + ++usedCamerasCount; + } + + CHECK_GL_ERROR; + + _camCount.set(usedCamerasCount); + + CHECK_GL_ERROR; + + //glDisable(GL_DEPTH_TEST); + RenderUtility::renderScreenQuad(); + + CHECK_GL_ERROR; + + _ulrShader.end(); + dst.unbind(); + + } + + + + } /*namespace sibr*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRV2Renderer.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRV2Renderer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..812b3de12a3a74a4b1590fce470eb65edce3a47b --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRV2Renderer.hpp @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include "Config.hpp" +# include +# include +# include +# include +# include + +namespace sibr { + + /** Second version of the ULR render. use separate samplers for each input image. + */ + class SIBR_EXP_ULR_EXPORT ULRV2Renderer : public RenderMaskHolder + { + SIBR_CLASS_PTR(ULRV2Renderer); + + /** Constructor. + *\param cameras input cameras + *\param w rendering width + *\param h rendering height + *\param maxCams maximum number of cameras selcted for rendering a frame + *\param fShader name of the fragment shader + *\param vShader name of the vertex shader + *\param facecull should backface culling be performed during the prepass. + **/ + ULRV2Renderer(const std::vector & cameras, const uint w, const uint h, const unsigned int maxCams = 0, const std::string & fShader = "ulr/ulr_v2", const std::string & vShader = "ulr/ulr_v2", const bool facecull = true); + + /** Setup the ULR shaders. + *\param fShader name of the fragment shader + *\param vShader name of the vertex shader + **/ + void setupULRshader(const std::string & fShader = "ulr/ulr_v2", const std::string & vShader = "ulr/ulr_v2"); + + /** Render. + *\param imgs_ulr vector of selected image IDs + *\param eye novel viewpoint + *\param scene the scene to render + *\param altMesh optional alternative mesh + *\param inputRTs the RGBD input images + *\param dst destination target + */ + void process(const std::vector& imgs_ulr, const sibr::Camera& eye, + const sibr::BasicIBRScene::Ptr& scene, + std::shared_ptr& altMesh, + const std::vector >& inputRTs, + IRenderTarget& dst); + + /** Should occlusion testing be performed. + *\param val true if testing should occur + */ + void doOccl(bool val) { _doOccl = val; } + + /** \return a reference to the occlusion threshold */ + float & epsilonOcclusion() { return _epsilonOcclusion; } + + /** Are the mask smooth values or binary. + *\param val true if they are binary + */ + void setAreMasksBinary(bool val) { _areMasksBinary = val; } + + /** Should the masks be inverted. + *\param val true if they should + */ + void setDoInvertMasks(bool val) { _doInvertMasks = val; } + + /** Should black pixels be ignored when accumulating colors. + *\param val true if they should be ignored + */ + void setDiscardBlackPixels(bool val) { _discardBlackPixels = val; } + + /** Should backface culling be performed. + *\param val true if it should + */ + void setCulling(bool val) { _shouldCull = val; } + + /** \return a pointer to the soft visibility texture array if it exists */ + Texture2DArrayLum32F * & getSoftVisibilityMaps(void) { return soft_visibility_maps; } + + /** \return a reference to the soft visibility threshold. */ + sibr::GLuniform & getSoftVisibilityThreshold() { return _soft_visibility_threshold; } + + /** \return a pointer to the ULR OpenGL program. */ + sibr::GLShader * getProgram() { return &_ulrShader; } + + /** \return the number of cameras */ + size_t getNumCams() { return _numCams; } + + public: + sibr::RenderTargetRGBA32F::Ptr _depthRT; ///< the prepass render target. + + private: + + sibr::GLShader _ulrShader; + sibr::GLShader _depthShader; + + std::vector _icamProj; + std::vector _icamPos; + std::vector _icamDir; + std::vector _inputRGB; + std::vector _masks; + std::vector > _selected_cams; + + Texture2DArrayLum32F * soft_visibility_maps; + sibr::GLuniform _soft_visibility_threshold; + sibr::GLuniform _use_soft_visibility; + + sibr::GLParameter _occTest; + sibr::GLParameter _areMasksBinaryGL; + sibr::GLParameter _doInvertMasksGL; + sibr::GLParameter _discardBlackPixelsGL; + sibr::GLParameter _doMask; + sibr::GLParameter _ncamPos; + sibr::GLParameter _camCount; + sibr::GLParameter _proj; + sibr::GLuniform _epsilonOcclusion; + + bool _doOccl; + bool _areMasksBinary; + bool _doInvertMasks; + bool _discardBlackPixels; + bool _shouldCull; + size_t _numCams; + + }; + +} /*namespace sibr*/ + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRV2View.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRV2View.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a89f664d1fcf87ce18ba7a21818d208a55216a4f --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRV2View.cpp @@ -0,0 +1,317 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +/// \todo TODO: make shorter +#include "Config.hpp" +#include +#include +#include +#include +#include +#include + +namespace sibr { + ULRV2View::~ULRV2View( ) +{ + _altMesh.reset(); +} + +ULRV2View::ULRV2View( const sibr::BasicIBRScene::Ptr& ibrScene, uint render_w, uint render_h ) : + _scene(ibrScene), + sibr::ViewBase(render_w, render_h), + _renderMode(ULRV2View::RenderMode::NORMAL), _singleCamId(0) +{ + _altMesh.reset(); + _altMesh = nullptr; + _numDistUlr = 4, _numAnglUlr = 0; + std::cerr << "[ULR] setting number of images to blend "<< _numDistUlr << " " << _numAnglUlr << std::endl; + + _ulr.reset(new ULRV2Renderer(ibrScene->cameras()->inputCameras(), render_w, render_h, _numDistUlr + _numAnglUlr)); + uint w = render_w; + uint h = render_h; + _poissonRT.reset(new RenderTargetRGBA(w, h, SIBR_CLAMP_UVS)); + _blendRT.reset(new RenderTargetRGBA(w, h, SIBR_CLAMP_UVS)); + _poisson.reset(new PoissonRenderer(w,h)); + _poisson->enableFix() = true; + _inputRTs = ibrScene->renderTargets()->inputImagesRT(); + + testAltlULRShader = false; +} + +void ULRV2View::onRenderIBR( sibr::IRenderTarget& dst, const sibr::Camera& eye ) { + // Select subset of input images for ULR + //std::vector imgs_ulr = chosen_cameras(eye); + std::vector imgs_ulr = chosen_cameras_angdist(eye); + _scene->cameras()->debugFlagCameraAsUsed(imgs_ulr); + //std::cout << imgs_ulr.size() << " " << std::flush; + + if (_renderMode == RenderMode::ONLY_ONE_CAM) { + for (auto i : imgs_ulr) { + //std::cout << i << " "; + } + int id_cam = std::max(0, std::min((int)imgs_ulr.size()-1, _singleCamId)); + int cam = imgs_ulr[id_cam]; + imgs_ulr = std::vector(1, cam); + //std::cout << " -> ulr debug single cam, id : " << _singleCamId << ", cam : "; + //for (auto i : imgs_ulr) { + //std::cout << i << " "; + //} + //std::cout << std::endl; + } else if(_renderMode == RenderMode::LEAVE_ONE_OUT) { + std::vector new_imgs_ulr; + for(const auto & i : imgs_ulr) { + if(int(i) != _singleCamId) { + new_imgs_ulr.emplace_back(i); + } + } + imgs_ulr = new_imgs_ulr; + } + + if (_noPoissonBlend) { + _ulr->process( + imgs_ulr, + eye, + _scene, + _altMesh, + _inputRTs, + dst); + + } else { + _ulr->process( + /* input -- images chosen */ imgs_ulr, + /* input -- camera position */ eye, + /* input -- scene */ _scene, + /* input -- alt mesh if available */ _altMesh, + /* input -- input RTs -- can be RGB or alpha */ _inputRTs, + /* output */ *_blendRT); + + _poisson->process( + _blendRT, + _poissonRT); + + + blit(*_poissonRT, dst); + } +} + +void ULRV2View::onUpdate(Input & input) +{ + if (input.key().isReleased(sibr::Key::Tab)) { + testAltlULRShader = !testAltlULRShader; + if (testAltlULRShader) { + _ulr->setupULRshader("ulr_v2_alt"); + } else { + _ulr->setupULRshader(); + } + std::cout << "ULR using " << (testAltlULRShader ? "all cams" : "standard ulr") << std::endl; + } +} + +void ULRV2View::onGUI() { + const std::string guiName = "ULRV2 Settings (" + name() + ")"; + if(ImGui::Begin(guiName.c_str())) { + + ImGui::PushScaledItemWidth(80); + const bool v1_changed = ImGui::InputInt("#Dist", &_numDistUlr, 1, 10); + ImGui::SameLine(); + const bool v2_changed = ImGui::InputInt("#Angle", &_numAnglUlr, 1, 10); + ImGui::PopItemWidth(); + + if (v1_changed || v2_changed) { + setNumBlend(_numDistUlr, _numAnglUlr); + } + + + + ImGui::Checkbox("Disable Poisson", &_noPoissonBlend); + ImGui::Checkbox("Poisson fix", &_poisson->enableFix()); + + ImGui::PushScaledItemWidth(120); + ImGui::InputFloat("Epsilon occlusion", &_ulr->epsilonOcclusion(), 0.001f, 0.01f); + ImGui::Combo("Rendering mode", (int*)(&_renderMode), "Standard\0One image\0Leave one out\0\0"); + if (ImGui::InputInt("Selected image", &_singleCamId, 1, 10)) { + _renderMode = RenderMode::ONLY_ONE_CAM; + } + _singleCamId = sibr::clamp(_singleCamId, 0, (int)_scene->cameras()->inputCameras().size() - 1); + //ImGui::SliderInt("Selected image", &_singleCamId, 0, scene().inputCameras().size() - 1); + ImGui::PopItemWidth(); + + } + ImGui::End(); +} + +void ULRV2View::computeVisibilityMap(const sibr::ImageL32F & depthMap, sibr::ImageRGBA & out) +{ + const float threshold_3d = 2.5f; + const std::vector shifts = { { 1,0 },{ 0,1 },{ -1,0 },{ 0,-1 } }; + + sibr::ImageL8 edgeMap(depthMap.w(), depthMap.h(), 255); + for (uint i = 0; i < depthMap.h(); i++) { + for (uint j = 0; j < depthMap.w(); j++) { + sibr::Vector2i pos(j, i); + float currentDepth = depthMap(pos).x(); + for (const auto & shift : shifts) { + Vector2i npos = pos + shift; + if (!depthMap.isInRange(npos)) { continue; } + if (std::abs(depthMap(npos).x() - currentDepth) > threshold_3d) { + edgeMap(pos).x() = 0; + break; + } + } + } + } + + cv::Mat distance(depthMap.h(), depthMap.w(), CV_32FC1); + cv::distanceTransform(edgeMap.toOpenCVnonConst(), distance, cv::DIST_L2, cv::DIST_MASK_PRECISE); + + sibr::ImageL32F outF; + outF.fromOpenCV(distance); + out = sibr::convertL32FtoRGBA(outF); + +} + + // ----------------------------------------------------------------------- + +std::vector ULRV2View::chosen_cameras(const sibr::Camera& eye) { + std::vector imgs_id; + std::multimap distMap; // distance wise closest input cameras + std::multimap dang; // angular distance from inputs to novel camera + for (uint i=0; i< _scene->cameras()->inputCameras().size(); i++ ) { + const sibr::InputCamera& inputCam = *_scene->cameras()->inputCameras()[i]; + if (inputCam.isActive()) { + // Convert following to Eigen versions + float dist = sibr::distance(inputCam.position(), eye.position()); + float angle = sibr::dot(inputCam.dir(),eye.dir()); + distMap.insert(std::make_pair(dist,i)); // sort distances in increasing order + dang.insert(std::make_pair( acos(angle),i)); // sort angles in increasing order + } + } + for (uint i=0; i< _scene->cameras()->inputCameras().size(); i++) { + const sibr::InputCamera& inputCam = *_scene->cameras()->inputCameras()[i]; + if (inputCam.isActive() && distMap.size() <= (_numDistUlr+_numAnglUlr)/2 ) { + float dist = sibr::distance(inputCam.position(),eye.position()); + distMap.insert(std::make_pair(dist,i)); // sort distances in increasing order + } + } + + std::multimap::const_iterator d_it(distMap.begin()); // select the _numDistUlr closest cameras + for (int i=0; d_it!=distMap.end() && i<_numDistUlr; d_it++,i++) { + imgs_id.push_back(d_it->second); + } + + std::multimap::const_iterator a_it(dang.begin()); // select the NUM_ANG_ULR closest cameras + for (int i=0; a_it!=dang.end() && i<_numAnglUlr; a_it++,i++) { + imgs_id.push_back(a_it->second); + } + + std::sort( imgs_id.begin(), imgs_id.end() ); // Avoid repetitions + imgs_id.erase( std::unique( imgs_id.begin(), imgs_id.end() ), imgs_id.end() ); + + SIBR_ASSERT(imgs_id.size() <= _numDistUlr + _numAnglUlr); + return imgs_id; +} + +std::vector ULRV2View::chosen_cameras_angdist(const sibr::Camera & eye) +{ + const auto & cams = _scene->cameras()->inputCameras(); + std::vector out; + + // sort angle / dist combined + struct camAng + { + camAng() {} + camAng(float a, float d, int i) : ang(a), dist(d), id(i) {} + float ang, dist; + int id; + static bool compare(const camAng & a, const camAng & b) { return a.ang / a.dist > b.ang / b.dist; } + }; + + int total_size = _numAnglUlr + _numDistUlr; + + std::vector allAng; + for (int id = 0; id < (int)cams.size(); ++id) { + const auto & cam = *cams[id]; + float angle = sibr::dot(cam.dir(),eye.dir()); + // reject back facing + if( angle > 0.001 && cam.isActive()) { + float dist = (cam.position() - eye.position()).norm(); + allAng.push_back(camAng(angle, dist, id)); + } + } + + std::vector wasChosen(cams.size(), false); + + std::sort(allAng.begin(), allAng.end(), camAng::compare); + for (int id = 0; id < std::min((int)allAng.size(), total_size); ++id) { + out.push_back(allAng[id].id); + wasChosen[allAng[id].id] = true; + } + + for (int id = 0; id < (int)cams.size(); ++id) { + if (!wasChosen[id] && out.size() < total_size && cams[id]->isActive()) { + out.push_back(id); + } + } + + return out; +} + +std::vector ULRV2View::chosen_camerasNew(const sibr::Camera & eye) +{ + const auto & cams = _scene->cameras()->inputCameras(); + + struct camDist + { + camDist() {} + camDist(float d, int i) : dist(d), id(i) {} + float dist; + int id; + static bool compare(const camDist & a, const camDist & b) { return a.dist < b.dist; } + }; + + std::vector allDist; + for (int id = 0; id < (int)cams.size(); ++id) { + const auto & cam = *cams[id]; + allDist.push_back(camDist((cam.position() - eye.position()).norm(), id)); + } + std::sort(allDist.begin(), allDist.end(), camDist::compare); + std::vector out; + for (int id = 0; id < std::min((int)cams.size(),(int)_numDistUlr); ++id) { + out.push_back(allDist[id].id); + } + return out; +} + +void ULRV2View::setNumBlend(short int dist, short int angle) +{ + // Backup masks. + auto copyMasks = _ulr->getMasks(); + + _numDistUlr = dist, _numAnglUlr = angle; + std::cerr << "[ULR] setting number of images to blend " << _numDistUlr << " " << _numAnglUlr << std::endl; + _ulr.reset(new ULRV2Renderer(_scene->cameras()->inputCameras(), _scene->cameras()->inputCameras()[0]->w(), _scene->cameras()->inputCameras()[0]->h(), _numDistUlr + _numAnglUlr)); + _ulr->setMasks(copyMasks); + +} + +void ULRV2View::loadMasks(const sibr::BasicIBRScene::Ptr& ibrScene, int w, int h, const std::string& maskDir, const std::string& preFileName, const std::string& postFileName +) { + std::string finalMaskDir = (maskDir == "" ? ibrScene->data()->basePathName() + "/masks/" : maskDir); + std::string finalPostFileName = (postFileName == "" ? "-mask.jpg" : postFileName); + _ulr->loadMasks(ibrScene, finalMaskDir, preFileName, finalPostFileName, w, h); +} + +void ULRV2View::setMasks( const std::vector& masks ) { + _ulr->setMasks(masks); +} + +} /*namespace sibr*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRV2View.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRV2View.hpp new file mode 100644 index 0000000000000000000000000000000000000000..574322e96d80bdf8a287b018ab98bcb03578dae5 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRV2View.hpp @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include "Config.hpp" +# include +# include +# include +# include "core/scene/BasicIBRScene.hpp" +# include +# include +# include + +namespace sibr { + + /** View associated to ULRRenderer v2, providing interface and options. */ + class SIBR_EXP_ULR_EXPORT ULRV2View : public sibr::ViewBase + { + SIBR_CLASS_PTR(ULRV2View); + + /** Camera selection mode. */ + enum class RenderMode { NORMAL = 0, ONLY_ONE_CAM = 1, LEAVE_ONE_OUT = 2 }; + + public: + + /** Constructor. + *\param ibrScene the scene + *\param render_w rendering width + *\param render_h rendering height + **/ + ULRV2View( const sibr::BasicIBRScene::Ptr& ibrScene, uint render_w, uint render_h ); + + /** Destructor. */ + ~ULRV2View(); + + /** Render using the ULR algorithm. + *\param dst destination target + *\param eye novel viewpoint + **/ + virtual void onRenderIBR( sibr::IRenderTarget& dst, const sibr::Camera& eye ); + + /** Update state absed on user inputs. + *\param input the view input + **/ + virtual void onUpdate(Input& input); + + /** Display GUI. */ + virtual void onGUI() override; + + /** Select input cameras to use for rendering. + *\param eye the current viewpoint + *\return a list of camera indices. + **/ + virtual std::vector chosen_cameras(const sibr::Camera& eye) ; + + /** Select input cameras to use for rendering, based only on distance. + *\param eye the current viewpoint + *\return a list of camera indices. + **/ + virtual std::vector chosen_camerasNew(const sibr::Camera& eye); + + /** Select input cameras to use for rendering. + *\param eye the current viewpoint + *\return a list of camera indices. + **/ + virtual std::vector chosen_cameras_angdist(const sibr::Camera& eye); + + /** Set the altMesh and use instead of scene proxy. + *\param m mesh to use + **/ + void altMesh(std::shared_ptr m) { _altMesh = m; } + + /** Toggle occlusion testing. + *\param val should occlusion testing be performed + */ + void doOccl(bool val) { _ulr->doOccl(val); } + + /** \return a pointer to the alt mesh if it exists */ + std::shared_ptr altMesh() { return _altMesh; } + + /** Set the number of cmaeras to select for blending. + *\param dist number of cameras for the distance criterion + *\param angle number of cameras for the angle criterion + **/ + void setNumBlend(short int dist, short int angle); + + /** Set the input RGBD textures. + *\param iRTs the new textures to use. + */ + void inputRTs(const std::vector >& iRTs) { _inputRTs = iRTs;} + + /** Set the masks for ignoring some regions of the input images. + *\param masks the new masks + **/ + void setMasks( const std::vector& masks ); + + /** Load masks from disk. + *\param ibrScene the scene + *\param w resolution width + *\param h resolution height + *\param maskDir masks directory path + *\param preFileName mask files prefix + *\param postFileName mask files suffix and extension + */ + void loadMasks( + const sibr::BasicIBRScene::Ptr& ibrScene, int w, int h, + const std::string& maskDir = "", + const std::string& preFileName = "", + const std::string& postFileName = "" + ); + + /** Set the camera selection mode. + *\param mode the new mode. + */ + void setRenderMode(RenderMode mode) { _renderMode = mode; } + /** \return the camera selection mode. */ + RenderMode getRenderMode() const { return _renderMode; } + + /** Set the view ID when in single view mode. + *\param id the camera id to use + */ + void setSingleViewId(int id) { _singleCamId = id; } + /** \return the current selected camera ID in single view mode. */ + int getSingleViewId(void) const { return _singleCamId; } + + /** Toggle poisson blending. + *\param val if true, Poisson blending is disabled. + */ + void noPoissonBlend(bool val) { _noPoissonBlend = val; } + /** \return true if pOisson blending is disabled. */ + bool noPoissonBlend() const { return _noPoissonBlend; } + + /** Compute soft visibility map. + *\param depthMap view depth map + *\param out will contain the soft visibility map + */ + void computeVisibilityMap(const sibr::ImageL32F & depthMap, sibr::ImageRGBA & out); + + /** \return a pointer to the scene */ + const std::shared_ptr & getScene() const { return _scene; } + + public: + ULRV2Renderer::Ptr _ulr; ///< ULRV2 renderer. + PoissonRenderer::Ptr _poisson; ///< Poisson filling renderer. + + protected: + + std::shared_ptr _scene; ///< the current scene. + std::shared_ptr _altMesh; ///< For the cases when using a different mesh than the scene + int _numDistUlr, _numAnglUlr; ///< Number of cameras to select for each criterion. + + std::vector > _inputRTs; ///< input RTs -- usually RGB but can be alpha or other + + bool _noPoissonBlend = false; ///< Runtime status of the poisson blend. + + RenderTargetRGBA::Ptr _blendRT; ///< ULR destination RT. + RenderTargetRGBA::Ptr _poissonRT; ///< Poisson filling destination RT. + + RenderMode _renderMode; ///< Current camera selection mode. + int _singleCamId; ///< Selected camera in single view mode. + + bool testAltlULRShader; ///< TT: to switch with alternate shader with tab + }; + +} /*namespace sibr*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRV3Renderer.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRV3Renderer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aa8df0322c3517c6ef9537c4694113013f41bb18 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRV3Renderer.cpp @@ -0,0 +1,274 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include + + + +sibr::ULRV3Renderer::ULRV3Renderer(const std::vector & cameras, const uint w, const uint h, const std::string & fShader, const std::string & vShader, const bool facecull) +{ + _backFaceCulling = facecull; + fragString = fShader; + vertexString = vShader; + _maxNumCams = cameras.size(); + _camsCount = int(_maxNumCams); + + // Populate the cameraInfos array (will be uploaded to the GPU). + _cameraInfos.clear(); + _cameraInfos.resize(_maxNumCams); + for (size_t i = 0; i < _maxNumCams; ++i) { + const auto & cam = *cameras[i]; + _cameraInfos[i].vp = cam.viewproj(); + _cameraInfos[i].pos = cam.position(); + _cameraInfos[i].dir = cam.dir(); + _cameraInfos[i].selected = cam.isActive(); + } + + // Compute the max number of cameras allowed. + GLint maxBlockSize = 0, maxSlicesSize = 0; + glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &maxBlockSize); + glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &maxSlicesSize); + // For each camera we store a matrix, 2 vecs3, 2 floats (including padding). + const unsigned int bytesPerCamera = 4 * (16 + 2 * 3 + 2); + const unsigned int maxCamerasAllowed = std::min((unsigned int)maxSlicesSize, (unsigned int)(maxBlockSize / bytesPerCamera)); + std::cout << "[ULRV3Renderer] " << "MAX_UNIFORM_BLOCK_SIZE: " << maxBlockSize << ", MAX_ARRAY_TEXTURE_LAYERS: " << maxSlicesSize << ", meaning at most " << maxCamerasAllowed << " cameras." << std::endl; + + // Create UBO. + _uboIndex = 0; + glGenBuffers(1, &_uboIndex); + glBindBuffer(GL_UNIFORM_BUFFER, _uboIndex); + glBufferData(GL_UNIFORM_BUFFER, sizeof(CameraUBOInfos)*_maxNumCams, &_cameraInfos[0], GL_DYNAMIC_DRAW); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + + // Setup shaders and uniforms. + setupShaders(fragString, vertexString); + + // Create the intermediate rendertarget. + _depthRT.reset(new sibr::RenderTargetRGBA32F(w, h)); + + CHECK_GL_ERROR; +} + + +void sibr::ULRV3Renderer::setupShaders(const std::string & fShader, const std::string & vShader) +{ + // Create shaders. + std::cout << "[ULRV3Renderer] Setting up shaders for " << _maxNumCams << " cameras." << std::endl; + GLShader::Define::List defines; + defines.emplace_back("NUM_CAMS", _maxNumCams); + defines.emplace_back("ULR_STREAMING", 0); + + _ulrShader.init("ULRV3", + sibr::loadFile(sibr::getShadersDirectory("") + "/" + vShader + ".vert"), + sibr::loadFile(sibr::getShadersDirectory("") + "/" + fShader + ".frag", defines)); + _depthShader.init("ULRV3Depth", + sibr::loadFile(sibr::getShadersDirectory("ulr") + "/ulr_intersect.vert"), + sibr::loadFile(sibr::getShadersDirectory("ulr") + "/ulr_intersect.frag", defines)); + + // Setup uniforms. + _nCamProj.init(_depthShader, "proj"); + _nCamPos.init(_ulrShader, "ncam_pos"); + _occTest.init(_ulrShader, "occ_test"); + _useMasks.init(_ulrShader, "doMasking"); + _discardBlackPixels.init(_ulrShader, "discard_black_pixels"); + _epsilonOcclusion.init(_ulrShader, "epsilonOcclusion"); + _areMasksBinary.init(_ulrShader, "is_binary_mask"); + _invertMasks.init(_ulrShader, "invert_mask"); + _flipRGBs.init(_ulrShader, "flipRGBs"); + _showWeights.init(_ulrShader, "showWeights"); + _winnerTakesAll.init(_ulrShader, "winner_takes_all"); + _camsCount.init(_ulrShader, "camsCount"); + _gammaCorrection.init(_ulrShader, "gammaCorrection"); + + CHECK_GL_ERROR; +} + +void sibr::ULRV3Renderer::process( + const sibr::Mesh & mesh, + const sibr::Camera & eye, + IRenderTarget & dst, + const sibr::Texture2DArrayRGB::Ptr & inputRGBs, + const sibr::Texture2DArrayLum32F::Ptr & inputDepths, + bool passthroughDepth +) { + // Render the proxy positions in world space. + process(mesh, eye, dst, inputRGBs->handle(), inputDepths, passthroughDepth); +} + +void sibr::ULRV3Renderer::process( + const sibr::Mesh & mesh, + const sibr::Camera & eye, + IRenderTarget & dst, + uint inputRGBHandle, + const sibr::Texture2DArrayLum32F::Ptr & inputDepths, + bool passthroughDepth +) { + if (_profiling) { + _depthPassTimer.tic(); + } + // Render the proxy positions in world space. + renderProxyDepth(mesh, eye); + if (_profiling) { + glFinish(); + //std::cout << "\nDepth Pass: " << _depthPassTimer.deltaTimeFromLastTic() << " ms" << std::endl; + _depthCost.push_back(_depthPassTimer.deltaTimeFromLastTic()); + } + if (_profiling) { + _blendPassTimer.tic(); + } + // Perform ULR blending. + renderBlending(eye, dst, inputRGBHandle, inputDepths, passthroughDepth); + if (_profiling) { + glFinish(); + //std::cout << "\nBlend Pass: " << _blendPassTimer.deltaTimeFromLastTic() << " ms" << std::endl; + _blendCost.push_back(_blendPassTimer.deltaTimeFromLastTic()); + } +} + +void sibr::ULRV3Renderer::updateCameras(const std::vector & camIds) { + // Reset all cameras. + for(auto & caminfos : _cameraInfos) { + caminfos.selected = 0; + } + // Enabled the ones passed as indices. + for (const auto & camId : camIds) { + _cameraInfos[camId].selected = 1; + } + + // Update the content of the UBO. + glBindBuffer(GL_UNIFORM_BUFFER, _uboIndex); + glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(CameraUBOInfos)*_maxNumCams, &_cameraInfos[0]); + glBindBuffer(GL_UNIFORM_BUFFER, 0); +} + +void sibr::ULRV3Renderer::stopProfile() +{ + const std::vector names = { "Depth Cost: ", "Blend Cost: "}; + const std::vector> counts = { + _depthCost, _blendCost}; + std::string profileStr = ""; + //profileStr = ""; + + for (int i = 0; i < names.size(); ++i) { + // Compute metrics: min, max, avg, variance. + double miniF = std::numeric_limits::max(); + double maxiF = 0.0; + double avgF = 0.0; + for (size_t tid = 0; tid < counts[i].size(); ++tid) { + const double ft = double(counts[i][tid]); + avgF += ft; + miniF = std::min(miniF, ft); + maxiF = std::max(maxiF, ft); + } + avgF /= double(counts[i].size()); + double varF = 0.0; + for (size_t tid = 0; tid < counts[i].size(); ++tid) { + const double residualF = double(counts[i][tid]) - avgF; + varF += residualF * residualF; + } + varF /= double(int(counts[i].size()) - 1); + profileStr += "-----------\n"; + profileStr += names[i] + " num frames: " + std::to_string(counts[i].size()) + "\n"; + profileStr += names[i] + " min/max: " + std::to_string(miniF) + "/" + std::to_string(maxiF) + "\n"; + profileStr += names[i] + " avg/stddev: " + std::to_string(avgF) + "/" + std::to_string(std::sqrt(varF)) + "\n"; + } + + std::cout << profileStr << std::endl; +} + +void sibr::ULRV3Renderer::renderProxyDepth(const sibr::Mesh & mesh, const sibr::Camera & eye) +{ + // Bind and clear RT. + _depthRT->bind(); + glViewport(0, 0, _depthRT->w(), _depthRT->h()); + glClearColor(0, 0, 0, 1); + glClearDepth(1.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // Render the mesh from the current viewpoint, output positions. + _depthShader.begin(); + _nCamProj.set(eye.viewproj()); + + mesh.render(true, _backFaceCulling); + + _depthShader.end(); + _depthRT->unbind(); +} + +void sibr::ULRV3Renderer::renderBlending( + const sibr::Camera & eye, + IRenderTarget & dst, + uint inputRGBHandle, + const sibr::Texture2DArrayLum32F::Ptr & inputDepths, + bool passthroughDepth +) { + // Bind and clear destination rendertarget. + glViewport(0, 0, dst.w(), dst.h()); + if (_clearDst) { + dst.clear(); + } + dst.bind(); + + _ulrShader.begin(); + + // Uniform values. + _nCamPos.set(eye.position()); + _occTest.send(); + _areMasksBinary.send(); + _invertMasks.send(); + _discardBlackPixels.send(); + _useMasks.send(); + _epsilonOcclusion.send(); + _flipRGBs.send(); + _showWeights.send(); + _camsCount.send(); + _winnerTakesAll.send(); + _gammaCorrection.send(); + + // Textures. + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, _depthRT->handle()); + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D_ARRAY, inputRGBHandle); + + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D_ARRAY, inputDepths->handle()); + + // Pass the masks if enabled and available. + if (_useMasks && _masks.get()) { + glActiveTexture(GL_TEXTURE3); + glBindTexture(GL_TEXTURE_2D_ARRAY, _masks->handle()); + } + + // Bind UBO to shader, after all possible textures. + glBindBuffer(GL_UNIFORM_BUFFER, _uboIndex); + glBindBufferBase(GL_UNIFORM_BUFFER, 4, _uboIndex); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + + if (passthroughDepth) { + glEnable(GL_DEPTH_TEST); + } else { + glDisable(GL_DEPTH_TEST); + } + + // Perform ULR rendering. + RenderUtility::renderScreenQuad(); + glDisable(GL_DEPTH_TEST); + + _ulrShader.end(); + dst.unbind(); +} + +void sibr::ULRV3Renderer::resize(const unsigned w, const unsigned h) { + _depthRT.reset(new sibr::RenderTargetRGBA32F(w, h)); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRV3Renderer.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRV3Renderer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..58b0feb0ae31c84106271161b2848e62d5859954 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRV3Renderer.hpp @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include "Config.hpp" +# include +# include +# include +# include +# include +# include +# include + +namespace sibr { + + /** + * \class ULRV3Renderer + * \brief Perform per-pixel Unstructured Lumigraph Rendering (Buehler et al., 2001). No selection is done on the CPU side. + * Relies on texture arrays and uniform buffer objects to support a high number of cameras. + */ + class SIBR_EXP_ULR_EXPORT ULRV3Renderer : public RenderMaskHolderArray + { + SIBR_CLASS_PTR(ULRV3Renderer); + + public: + + /** + * Constructor. + * \param cameras The input cameras to use. + * \param w The width of the internal rendertargets. + * \param h The height of the internal rendertargets. + * \param fShader An optional name of the fragment shader to use (default to ulr_v3). + * \param vShader An optional name of the vertex shader to use (default to ulr_v3). + * \param facecull Should the mesh be renderer with backface culling. + */ + ULRV3Renderer(const std::vector & cameras, + const uint w, const uint h, + const std::string & fShader = "ulr/ulr_v3", + const std::string & vShader = "ulr/ulr_v3", + const bool facecull = true + ); + + /** + * Change the shaders used by the ULR renderer. + * \param fShader The name of the fragment shader to use. + * \param vShader The name of the vertex shader to use. + */ + virtual void setupShaders( + const std::string & fShader = "ulr/ulr_v3", + const std::string & vShader = "ulr/ulr_v3" + ); + + /** + * Performs ULR rendering to a given destination rendertarget. + * \param mesh The mesh to use as geometric proxy. + * \param eye The novel viewpoint. + * \param dst The destination rendertarget. + * \param inputRGBs A texture array containing the input RGB images. + * \param inputDepths A texture array containing the input depth maps. + * \param passthroughDepth If true, depth from the position map will be output to the depth buffer for ulterior passes. + */ + virtual void process( + const sibr::Mesh & mesh, + const sibr::Camera& eye, + IRenderTarget& dst, + const sibr::Texture2DArrayRGB::Ptr & inputRGBs, + const sibr::Texture2DArrayLum32F::Ptr & inputDepths, + bool passthroughDepth = false + ); + + /** + * Performs ULR rendering to a given destination rendertarget. + * \param mesh The mesh to use as geometric proxy. + * \param eye The novel viewpoint. + * \param dst The destination rendertarget. + * \param inputRGBHandle The handle of a texture array containing the input RGB images. + * \param inputDepths A texture array containing the input depth maps. + * \param passthroughDepth If true, depth from the position map will be output to the depth buffer for ulterior passes. + */ + virtual void process( + const sibr::Mesh & mesh, + const sibr::Camera& eye, + IRenderTarget& dst, + uint inputRGBHandle, + const sibr::Texture2DArrayLum32F::Ptr & inputDepths, + bool passthroughDepth = false + ); + + /** + * Update which cameras should be used for rendering, based on the indices passed. + * \param camIds The indices to enable. + **/ + void updateCameras(const std::vector & camIds); + + /// Set the epsilon occlusion threshold. + float & epsilonOcclusion() { return _epsilonOcclusion.get(); } + + /// Enable or disable the masks. + bool & useMasks() { return _useMasks.get(); } + + /// Flip the RGB images before using them. + bool & flipRGBs() { return _flipRGBs.get(); } + + /// Enable or diable occlusion testing. + bool& occTest() { return _occTest.get(); } + + /// Show debug weights. + bool & showWeights() { return _showWeights.get(); } + + /// Set winner takes all weights strategy + bool & winnerTakesAll() { return _winnerTakesAll.get(); } + + /// Apply gamma correction to the output. + bool & gammaCorrection() { return _gammaCorrection.get(); } + + /// Apply backface culling to the mesh. + bool & backfaceCull() { return _backFaceCulling; } + + /** Resize the internal rendertargets. + *\param w the new width + *\param h the new height + **/ + void resize(const unsigned int w, const unsigned int h); + + /// Should the final RT be cleared or not. + bool & clearDst() { return _clearDst; } + + /// \return The ID of the first pass position map texture. + uint depthHandle() const { return _depthRT->texture(); } + + void startProfile() { + _profiling = true; + _depthCost.clear(); + _blendCost.clear(); + } + + void stopProfile(); + + /** + * Render the world positions of the proxy points in an intermediate rendertarget. + * \param mesh the proxy mesh. + * \param eye The novel viewpoint. + */ + virtual void renderProxyDepth(const sibr::Mesh & mesh, const sibr::Camera& eye); + + /** + * Perform ULR blending. + * \param eye The novel viewpoint. + * \param dst The destination rendertarget. + * \param inputRGBHandle The handle to a texture array containing the input RGB images. + * \param inputDepths A texture array containing the input depth maps. + * \param passthroughDepth If true, depth from the position map will be output to the depth buffer for ulterior passes. + */ + virtual void renderBlending( + const sibr::Camera& eye, + IRenderTarget& dst, + uint inputRGBHandle, + const sibr::Texture2DArrayLum32F::Ptr & inputDepths, + bool passthroughDepth + ); + + + protected: + /// Shader names. + std::string fragString, vertexString; + + sibr::GLShader _ulrShader; + sibr::GLShader _depthShader; + + sibr::RenderTargetRGBA32F::Ptr _depthRT; + GLuniform _nCamProj; + GLuniform _nCamPos; + + GLuniform + _occTest = true, + _useMasks = false, + _discardBlackPixels = true, + _areMasksBinary = true, + _invertMasks = false, + _flipRGBs = false, + _showWeights = false, + _winnerTakesAll = false, + _gammaCorrection = false; + + size_t _maxNumCams = 0; + GLuniform _camsCount = 0; + + GLuniform _epsilonOcclusion = 0.01f; + bool _backFaceCulling = true; + bool _clearDst = true; + + /** Camera infos data structure shared between the CPU and GPU. + We have to be careful about alignment if we want to send those struct directly into the UBO. */ + struct CameraUBOInfos { + Matrix4f vp; ///< Matrix viewproj. + Vector3f pos; ///< Camera position. + int selected = 0; ///< Is the camera selected (0/1). + Vector3f dir; ///< Camera direction. + float dummy = 0.0f; ///< Padding to a multiple of 16 bytes for alignment on the GPU. + }; + + std::vector _cameraInfos; + GLuint _uboIndex; + + bool _profiling = false; + sibr::Timer _depthPassTimer; + sibr::Timer _blendPassTimer; + int _numFramesProfiling = 100; + std::string _profileStr = ""; + std::vector _depthCost, _blendCost; + + }; + + +} /*namespace sibr*/ + diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRV3View.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRV3View.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ab67e46a17edc9acbef7468573b15f6eda0c4fa2 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRV3View.cpp @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#include +#include + +sibr::ULRV3View::ULRV3View(const sibr::BasicIBRScene::Ptr & ibrScene, uint render_w, uint render_h) : + _scene(ibrScene), + sibr::ViewBase(render_w, render_h) +{ + const uint w = render_w; + const uint h = render_h; + + // Renderers. + _ulrRenderer.reset(new ULRV3Renderer(ibrScene->cameras()->inputCameras(), w, h)); + _poissonRenderer.reset(new PoissonRenderer(w, h)); + _poissonRenderer->enableFix() = true; + + // Rendertargets. + _poissonRT.reset(new RenderTargetRGBA(w, h, SIBR_CLAMP_UVS)); + _blendRT.reset(new RenderTargetRGBA(w, h, SIBR_CLAMP_UVS)); + + // Tell the scene we are a priori using all active cameras. + std::vector imgs_ulr; + const auto & cams = ibrScene->cameras()->inputCameras(); + for(size_t cid = 0; cid < cams.size(); ++cid) { + if(cams[cid]->isActive()) { + imgs_ulr.push_back(uint(cid)); + } + } + _scene->cameras()->debugFlagCameraAsUsed(imgs_ulr); +} + +void sibr::ULRV3View::setScene(const sibr::BasicIBRScene::Ptr & newScene) { + _scene = newScene; + const uint w = getResolution().x(); + const uint h = getResolution().y(); + + std::string shaderName = "ulr_v3"; + if (_weightsMode == VARIANCE_BASED_W) { + shaderName = "ulr_v3_alt"; + } + else if (_weightsMode == ULR_FAST) { + shaderName = "ulr_v3_fast"; + } + + _ulrRenderer.reset(new ULRV3Renderer(newScene->cameras()->inputCameras(), w, h, shaderName)); + + // Tell the scene we are a priori using all active cameras. + std::vector imgs_ulr; + const auto & cams = newScene->cameras()->inputCameras(); + for (size_t cid = 0; cid < cams.size(); ++cid) { + if (cams[cid]->isActive()) { + imgs_ulr.push_back(uint(cid)); + } + } + _scene->cameras()->debugFlagCameraAsUsed(imgs_ulr); +} + +void sibr::ULRV3View::setMode(const WeightsMode mode) { + _weightsMode = mode; + if (_weightsMode == VARIANCE_BASED_W) { + _ulrRenderer->setupShaders("ulr/ulr_v3_alt"); + } + else if (_weightsMode == ULR_FAST) { + _ulrRenderer->setupShaders("ulr/ulr_v3_fast"); + } + else { + _ulrRenderer->setupShaders(); + } +} + +void sibr::ULRV3View::onRenderIBR(sibr::IRenderTarget & dst, const sibr::Camera & eye) +{ + // Perform ULR rendering, either directly to the destination RT, or to the intermediate RT when poisson blending is enabled. + _ulrRenderer->process( + _scene->proxies()->proxy(), + eye, + _poissonBlend ? *_blendRT : dst, + _scene->renderTargets()->getInputRGBTextureArrayPtr(), + _scene->renderTargets()->getInputDepthMapArrayPtr() + ); + + // Perform Poisson blending if enabled and copy to the destination RT. + if (_poissonBlend) { + _poissonRenderer->process(_blendRT, _poissonRT); + blit(*_poissonRT, dst); + } + +} + +void sibr::ULRV3View::onUpdate(Input & input) +{ +} + +void sibr::ULRV3View::onGUI() +{ + const std::string guiName = "ULRV3 Settings (" + name() + ")"; + if (ImGui::Begin(guiName.c_str())) { + + // Poisson settings. + ImGui::Checkbox("Poisson ", &_poissonBlend); ImGui::SameLine(); + ImGui::Checkbox("Poisson fix", &_poissonRenderer->enableFix()); + + // Other settings. + ImGui::Checkbox("Flip RGB ", &getULRrenderer()->flipRGBs()); + ImGui::PushScaledItemWidth(150); + ImGui::InputFloat("Epsilon occlusion", &_ulrRenderer->epsilonOcclusion(), 0.001f, 0.01f); + + ImGui::Separator(); + // Rendering mode selection. + if(ImGui::Combo("Rendering mode", (int*)(&_renderMode), "Standard\0One image\0Leave one out\0Every N\0\0")) { + updateCameras(true); + } + + // Get the desired index, make sure it falls in the cameras range. + if (_renderMode == ONE_CAM || _renderMode == LEAVE_ONE_OUT) { + const bool changedIndex = ImGui::InputInt("Selected image", &_singleCamId, 1, 10); + _singleCamId = sibr::clamp(_singleCamId, 0, (int)_scene->cameras()->inputCameras().size() - 1); + if (changedIndex) { + // If we are in "leave one out" or "one camera only" mode, we have to update the list of enabled cameras. + updateCameras(false); + } + } + + if (_renderMode == EVERY_N_CAM) { + if (ImGui::InputInt("Selection step", &_everyNCamStep, 1, 10)) { + _everyNCamStep = std::max(1, _everyNCamStep); + updateCameras(false); + } + } + ImGui::Separator(); + // Switch the shaders for ULR rendering. + if (ImGui::Combo("Weights mode", (int*)(&_weightsMode), "Standard ULR\0Variance based\0Fast ULR\0\0")) { + setMode(_weightsMode); + } + + ImGui::Checkbox("Occlusion Testing", &_ulrRenderer->occTest()); + ImGui::Checkbox("Debug weights", &_ulrRenderer->showWeights()); + ImGui::Checkbox("Gamma correction", &_ulrRenderer->gammaCorrection()); + ImGui::PopItemWidth(); + } + ImGui::End(); +} + +void sibr::ULRV3View::updateCameras(bool allowResetToDefault) { + // If we are here, the rendering mode or the selected index have changed, we need to update the enabled cameras. + std::vector imgs_ulr; + const auto & cams = _scene->cameras()->inputCameras(); + + // Compute the cameras indices based on the new mode. + if (_renderMode == RenderMode::ONE_CAM) { + // We only use the given camera (if it is active). + if (cams[_singleCamId]->isActive()) { + imgs_ulr = { (uint)_singleCamId }; + } else { + std::cerr << "The camera is not active, using all cameras." << std::endl; + } + } else if (_renderMode == RenderMode::LEAVE_ONE_OUT) { + // We use all active cameras apart from the one given. + for (size_t cid = 0; cid < cams.size(); ++cid) { + if (cid != (size_t)_singleCamId && cams[cid]->isActive()) { + imgs_ulr.push_back(uint(cid)); + } + } + } + else if (_renderMode == RenderMode::EVERY_N_CAM) { + // We pick one camera every N + for (size_t cid = 0; cid < cams.size(); ++cid) { + if ((cid % _everyNCamStep == 0) && cams[cid]->isActive()) { + imgs_ulr.push_back(uint(cid)); + } + } + } else if(allowResetToDefault){ + // We use all active cameras. + for (size_t cid = 0; cid < cams.size(); ++cid) { + if (cams[cid]->isActive()) { + imgs_ulr.push_back(uint(cid)); + } + } + } + // Only update if there is at least one camera enabled. + if(!imgs_ulr.empty()) { + // Update the shader informations in the renderer. + _ulrRenderer->updateCameras(imgs_ulr); + // Tell the scene which cameras we are using for debug visualization. + _scene->cameras()->debugFlagCameraAsUsed(imgs_ulr); + } + +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRV3View.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRV3View.hpp new file mode 100644 index 0000000000000000000000000000000000000000..53d9722e2bc9feb2e6ac0249b7ac2a72703e4bf6 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRV3View.hpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include "Config.hpp" +# include +# include +# include +# include +# include +# include + +namespace sibr { + + /** + * \class ULRV3View + * \brief Wrap a ULR renderer with additional parameters and information. + */ + class SIBR_EXP_ULR_EXPORT ULRV3View : public sibr::ViewBase + { + SIBR_CLASS_PTR(ULRV3View); + + /// Rendering mode: default, use only one camera, use all cameras but one. + enum RenderMode { ALL_CAMS, ONE_CAM, LEAVE_ONE_OUT, EVERY_N_CAM }; + + /// Blending mode: keep the four best values per pixel, or aggregate them all. + enum WeightsMode { ULR_W , VARIANCE_BASED_W, ULR_FAST}; + + public: + + /** + * Constructor + * \param ibrScene The scene to use for rendering. + * \param render_w rendering width + * \param render_h rendering height + */ + ULRV3View(const sibr::BasicIBRScene::Ptr& ibrScene, uint render_w, uint render_h); + + /** Replace the current scene. + *\param newScene the new scene to render */ + void setScene(const sibr::BasicIBRScene::Ptr & newScene); + + /** + * Perform rendering. Called by the view manager or rendering mode. + * \param dst The destination rendertarget. + * \param eye The novel viewpoint. + */ + void onRenderIBR(sibr::IRenderTarget& dst, const sibr::Camera& eye) override; + + /** + * Update inputs (do nothing). + * \param input The inputs state. + */ + void onUpdate(Input& input) override; + + /** + * Update the GUI. + */ + void onGUI() override; + + /** \return a reference to the renderer. */ + const ULRV3Renderer::Ptr & getULRrenderer() const { return _ulrRenderer; } + + /** Set the renderer blending weights mode. + *\param mode the new mode to use + *\sa WeightsMode + **/ + void setMode(const WeightsMode mode); + + /** \return a reference to the scene */ + const std::shared_ptr & getScene() const { return _scene; } + + protected: + + /** + * Update the camera informations in the ULR renderer based on the current rendering mode and selected index. + * \param allowResetToDefault If true, when the rendering mode is ALL_CAMS, the cameras information will be updated. + */ + void updateCameras(bool allowResetToDefault); + + std::shared_ptr _scene; ///< The current scene. + ULRV3Renderer::Ptr _ulrRenderer; ///< The ULR renderer. + PoissonRenderer::Ptr _poissonRenderer; ///< The poisson filling renderer. + + RenderTargetRGBA::Ptr _blendRT; ///< ULR destination RT. + RenderTargetRGBA::Ptr _poissonRT; ///< Poisson filling destination RT. + + bool _poissonBlend = false; ///< Should Poisson filling be applied. + + RenderMode _renderMode = ALL_CAMS; ///< Current rendering mode. + WeightsMode _weightsMode = ULR_W; ///< Current blend weights mode. + int _singleCamId = 0; ///< Selected camera for the single view mode. + int _everyNCamStep = 1; ///< Camera step size for the every other N mode. + }; + +} /*namespace sibr*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRView.cpp b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRView.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7d24f35868803181f127afac8508b810864f7903 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRView.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +/// \todo TODO: make shorter +#include "Config.hpp" +#include +#include +#include +#include +#include +#include + +namespace sibr { + +ULRView::~ULRView( ) +{ + _altMesh.reset(); +} + +ULRView::ULRView( const sibr::BasicIBRScene::Ptr& ibrScene, uint render_w, uint render_h ) : + _scene(ibrScene), + sibr::ViewBase(render_w, render_h) +{ + _altMesh.reset(); + _altMesh = nullptr; + _numDistUlr = 10, _numAnglUlr = 14; + std::cerr << "\n[ULRenderer] setting number of images to blend "<< _numDistUlr << " " << _numAnglUlr << std::endl; + + _ulr.reset(new ULRRenderer(render_w, render_h)); + + _inputRTs = ibrScene->renderTargets()->inputImagesRT(); +} + +void ULRView::onRenderIBR( sibr::IRenderTarget& dst, const sibr::Camera& eye ) { + // Select subset of input images for ULR + std::vector imgs_ulr = chosen_cameras(eye); + _scene->cameras()->debugFlagCameraAsUsed(imgs_ulr); + _ulr->process( + /* input -- images chosen */ imgs_ulr, + /* input -- camera position */ eye, + /* input -- scene */ _scene, + /* input -- alt mesh if available */ _altMesh, + /* input -- input RTs -- can be RGB or alpha */ _inputRTs, + /* output */ dst); +} + +// ----------------------------------------------------------------------- +/// \todo Select a subset from imput images speed up URL +/// \todo TODO: This function needs serious cleanup +// +std::vector ULRView::chosen_cameras(const sibr::Camera& eye) { + std::vector imgs_id; + std::multimap distMap; // distance wise closest input cameras + std::multimap dang; // angular distance from inputs to novel camera + for (uint i=0; i<_scene->cameras()->inputCameras().size(); i++ ) { + const sibr::InputCamera& inputCam = *_scene->cameras()->inputCameras()[i]; + if (inputCam.isActive()) { + // Convert following to Eigen versions + float dist = sibr::distance(inputCam.position(), eye.position()); + float angle = sibr::dot(inputCam.dir(),eye.dir()); + // if (angle > 0.707) { // cameras with 45 degrees + distMap.insert(std::make_pair(dist,i)); // sort distances in increasing order + dang.insert(std::make_pair( acos(angle),i)); // sort angles in increasing order +// } + } + } + + // HACK GD -- should really look at camera angles as well and sort them +//// bool not_enough = false; + // if you have < 2 cameras, choose the (NUM_DIST+NUM_ANGL)/2 closest ones +//// if( dang.size() + distMap.size() < 2 ) +//// not_enough = true; + for (uint i=0; i< _scene->cameras()->inputCameras().size(); i++) { + const sibr::InputCamera& inputCam = *_scene->cameras()->inputCameras()[i]; + if (inputCam.isActive() && distMap.size() <= (_numDistUlr+_numAnglUlr)/2 ) { + float dist = sibr::distance(inputCam.position(),eye.position()); + distMap.insert(std::make_pair(dist,i)); // sort distances in increasing order + } + } + + std::multimap::const_iterator d_it(distMap.begin()); // select the _numDistUlr closest cameras + for (int i=0; d_it!=distMap.end() && i<_numDistUlr; d_it++,i++) { + imgs_id.push_back(d_it->second); + } + + std::multimap::const_iterator a_it(dang.begin()); // select the NUM_ANG_ULR closest cameras + for (int i=0; a_it!=dang.end() && i<_numAnglUlr; a_it++,i++) { + imgs_id.push_back(a_it->second); + } + + std::sort( imgs_id.begin(), imgs_id.end() ); // Avoid repetitions + imgs_id.erase( std::unique( imgs_id.begin(), imgs_id.end() ), imgs_id.end() ); + + SIBR_ASSERT(imgs_id.size() <= _numDistUlr + _numAnglUlr); + return imgs_id; +} + +void ULRView::setMasks( const std::vector& masks ) { + _ulr->setMasks(masks); +} + +} /*namespace sibr*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRView.hpp b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRView.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ced556dbeeb64c5b8e9c90850530033c1e35a0cb --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/ULRView.hpp @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#pragma once + +# include "Config.hpp" +# include +# include +# include +# include +# include +# include + +namespace sibr { + + /** View associated to ULRRenderer v1, providing interface and options. */ + class SIBR_EXP_ULR_EXPORT ULRView : public sibr::ViewBase + { + SIBR_CLASS_PTR( ULRView ); + + public: + + /** Constructor. + *\param ibrScene the scene + *\param render_w rendering width + *\param render_h rendering height + **/ + ULRView( const sibr::BasicIBRScene::Ptr& ibrScene, uint render_w, uint render_h ); + + /** Destructor. */ + ~ULRView(); + + /** Render using the ULR algorithm. + *\param dst destination target + *\param eye novel viewpoint + **/ + virtual void onRenderIBR( sibr::IRenderTarget& dst, const sibr::Camera& eye ); + + /** Select input cameras to use for rendering. + *\param eye the current viewpoint + *\return a list of camera indices. + **/ + virtual std::vector chosen_cameras(const sibr::Camera& eye) ; + + /** Set the altMesh and use instead of scene proxy. + *\param m mesh to use + **/ + void altMesh(std::shared_ptr m) { _altMesh = m; } + + /** Toggle occlusion testing. + *\param val should occlusion testing be performed + */ + void doOccl(bool val) { _ulr->doOccl(val); } + + /** \return a pointer to the alt mesh if it exists */ + std::shared_ptr altMesh() { return _altMesh; } + + /** Set the number of cmaeras to select for blending. + *\param dist number of cameras for the distance criterion + *\param angle number of cameras for the angle criterion + **/ + void setNumBlend(short int dist, short int angle) { _numDistUlr = dist, _numAnglUlr = angle; } + + /** Set the input RGBD textures. + *\param iRTs the new textures to use. + */ + void inputRTs(const std::vector >& iRTs) { _inputRTs = iRTs;} + + /** Set the masks for ignoring some regions of the input images. + *\param masks the new masks + **/ + void setMasks( const std::vector& masks); + + protected: + + ULRRenderer::Ptr _ulr; ///< Renderer. + std::shared_ptr _scene; ///< Scene. + std::shared_ptr _altMesh; ///< For the cases when using a different mesh than the scene + short int _numDistUlr, _numAnglUlr; ///< max number of selected cameras for each criterion. + std::vector > _inputRTs; ///< input RTs -- usually RGB but can be alpha or other + + }; + +} /*namespace sibr*/ diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/shaders/ulr.vert b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/shaders/ulr.vert new file mode 100644 index 0000000000000000000000000000000000000000..4623dec2c7ac2df7eb69af0dcae6450cbeac42d2 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/shaders/ulr.vert @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +layout(location = 0) in vec3 in_vertex; +layout(location = 2) in vec3 in_normal; + +out vec3 vertex_coord; + +void main(void) { + gl_Position = vec4(in_vertex,1.0); + vertex_coord = in_vertex; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/shaders/ulr1.frag b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/shaders/ulr1.frag new file mode 100644 index 0000000000000000000000000000000000000000..ad009b572950e60fc6036197d1f6c0ebbfab0072 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/shaders/ulr1.frag @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +layout(location=0) out vec4 out_color0; +layout(location=1) out vec4 out_color1; +layout(location=2) out vec4 out_color2; +layout(location=3) out vec4 out_color3; + +layout(binding=0) uniform sampler2D image; // input image with camera-proxy distance in alpha +layout(binding=1) uniform sampler2D proxy; // intersection point with proxy with depth in alpha +layout(binding=2) uniform sampler2D texture0; // best candidate for each pixel +layout(binding=3) uniform sampler2D texture1; // second best candidate for each pixel +layout(binding=4) uniform sampler2D texture2; // third best candidate for each pixel +layout(binding=5) uniform sampler2D texture3; // fourth best candidate for each pixel +layout(binding=6) uniform sampler2D mask; // masking texture. + +uniform mat4 iCamProj; // input camera projection +uniform vec3 iCamPos; // input camera position +uniform vec3 iCamDir; // novel camera projection +uniform vec3 nCamPos; // novel camera position +uniform bool occlTest; // do occlusion test +uniform bool doMasking; // do masking + +// vertex coordinates of the 2D screen size quad, +// used for computing texture coordinates +in vec3 vertex_coord; + +#define EPSILON 1e-2 +#define BETA 1e-1 /* Relative importance of resolution penalty */ + +vec3 project(vec3 point, mat4 proj) { + vec4 p1 = proj * vec4(point, 1.0); + vec3 p2 = (p1.xyz/p1.w); + return (p2.xyz*vec3(0.5) + vec3(0.5)); +} + +bool frustumTest(vec3 p, vec2 uv) { + vec3 d1 = iCamDir; + vec3 d2 = p - iCamPos; + bool r = dot(d1,d2)>0.0 && uv.x<1.0 && uv.x>0.0 && uv.y<1.0 && uv.y>0.0; + return r; +} + +void main(void) { + + float penalty_res = 0; /* Resolution penalty */ + float penalty_ang = 0; /* Angular penalty */ + + vec2 texcoord = (vertex_coord.xy + vec2(1.0)) / 2.0; + + vec4 point = texture(proxy, texcoord); + vec4 color0 = texture(texture0, texcoord); + vec4 color1 = texture(texture1, texcoord); + vec4 color2 = texture(texture2, texcoord); + vec4 color3 = texture(texture3, texcoord); + + vec3 uvd = project(point.xyz, iCamProj); + vec2 uv = uvd.xy; + + vec4 color = texture(image, uv); + + out_color0 = color0; + out_color1 = color1; + out_color2 = color2; + out_color3 = color3; + + if(doMasking){ + float masked = texture(mask, uv).r; + if(masked < 0.5){ + return; + } + } + + if (frustumTest(point.xyz, uv)) + { + float dist_i2p = distance(point.xyz, iCamPos); + float dist_n2p = distance(point.xyz, nCamPos); + penalty_res = max(0.0001, (dist_i2p - dist_n2p)/dist_i2p ); + + //if (abs(dist-color.w) < EPSILON) { + + vec3 v1 = normalize(point.xyz - iCamPos); + vec3 v2 = normalize(point.xyz - nCamPos); + if (occlTest && abs(uvd.z-color.w) < EPSILON) { /* occlusion test */ + //color.w = max(0.0001, acos(dot(v1,v2))); + penalty_ang = max(0.0001, acos(dot(v1,v2))); + } else if( occlTest ) { + return;; + //color.w = 5.0 + max(0.001, acos(dot(v1,v2))); /* increase the penalty */ + } + if (all(equal(color.xyz, vec3(0,0,0)))){ + return; + } + + color.w = penalty_ang + BETA*penalty_res; + + // compare with best four candiates and insert at the + // appropriate rank + bool done = false; + if (!done && color.w0.0; +} + + + + +void main(void){ + + vec4 point = texture(proxy, vertex_coord); + // discard if there was no intersection with the proxy + if ( point.w >= 1.0) { + discard; + } + + vec4 color0 = vec4(0.0,0.0,0.0,INFTY_W); + vec4 color1 = vec4(0.0,0.0,0.0,INFTY_W); + vec4 color2 = vec4(0.0,0.0,0.0,INFTY_W); + vec4 color3 = vec4(0.0,0.0,0.0,INFTY_W); + + // We need to keep the uvs of the selected colors for the fov blending. + vec4 uvs01 = vec4(0.0,0.0,0.0,0.0); + vec4 uvs23 = vec4(0.0,0.0,0.0,0.0); + + for(int cam_id = 0; cam_id < NUM_CAMS; cam_id++){ + if(cam_id >= camsCount){ + break; + } + vec3 uvd = project(point.xyz, icam_proj[cam_id]); + vec2 ndc = abs(2.0*uvd.xy-1.0); + + if (frustumTest(point.xyz, ndc, cam_id)) + { + vec4 color = texture(input_rgb[cam_id], uvd.xy); + + + if(doMasking){ + + float masked = texture(masks[cam_id], uvd.xy).r; + + if( invert_mask ){ + masked = 1.0 - masked; + } + + if( is_binary_mask ){ + if( masked < 0.5) { + continue; + } + } else { + color.xyz = masked*color.xyz; + } + + } + + + /// \todo Separate uniform and per-pixel branching. TODO SR: test impact. + + if (discard_black_pixels){ + if(all(equal(color.xyz, vec3(0.0)))){ + continue; + } + } + + if (occ_test){ + if(abs(uvd.z-color.w) >= epsilonOcclusion) { + continue; + } + } + + vec3 v1 = (point.xyz - icam_pos[cam_id]); + vec3 v2 = (point.xyz - ncam_pos); + float dist_i2p = length(v1); + float dist_n2p = length(v2); + + float penalty_ang = float(occ_test) * max(0.0001, acos(dot(v1,v2)/(dist_i2p*dist_n2p))); + + float penalty_res = max(0.0001, (dist_i2p - dist_n2p)/dist_i2p ); + + color.w = penalty_ang + BETA*penalty_res; + + if(useSoftVisibility){ + + //vec4 dist_from_edge = vec4(2.0,2.0,2.0,2.0); // texture(soft_visibility_maps, vec3(uvd.xy, cam_true_id)); + vec4 dist_from_edge = texture(soft_visibility_maps, vec3(uvd.xy, selected_cams[cam_id])); + float weight_visibility = min(dist_from_edge.x/softVisibilityThreshold,1.0); + color.w /= weight_visibility; + + } + + + // compare with best four candiates and insert at the + // appropriate rank + if (color.w0.0; +} + +void main(void){ + + vec4 point = texture(proxy, vertex_coord); + // discard if there was no intersection with the proxy + if ( point.w >= 1.0) { + discard; + } + + vec4 color_sum = vec4(0.0,0.0,0.0,0.0); + //vec3 color_sum_simple = vec3(0.0,0.0,0.0); + //vec3 color_sum_square = vec3(0.0,0.0,0.0); + //vec3 color_sum_square_w = vec3(0.0,0.0,0.0); + //float num = 0.0; + + vec3 v2 = (point.xyz - ncam_pos); + float dist_n2p = length(v2); + + for(int cam_id = 0; cam_id < NUM_CAMS; cam_id++){ + + if(cam_id >= camsCount){ + break; + } + vec3 uvd = project(point.xyz, icam_proj[cam_id]); + vec2 ndc = abs(2.0*uvd.xy-1.0); + + if (!frustumTest(point.xyz, ndc, cam_id)) { + continue; + } + + vec4 color = texture(input_rgb[cam_id], uvd.xy); + + if(doMasking){ + float masked = texture(masks[cam_id], uvd.xy).r; + + if( invert_mask ){ + masked = 1.0 - masked; + } + + if( is_binary_mask ){ + if( masked < 0.5) { + continue; + } + } else { + color.xyz = masked*color.xyz; + } + } + + if (discard_black_pixels){ + if(all(equal(color.xyz, vec3(0.0)))){ + continue; + } + } + + if (occ_test){ + if(abs(uvd.z-color.w) >= EPSILON) { + continue; + } + } + + vec3 v1 = (point.xyz - icam_pos[cam_id]); + float dist_i2p = length(v1); + + float penalty_ang = float(occ_test) * max(0.0001, acos(dot(v1,v2)/(dist_i2p*dist_n2p))); + + float penalty_res = max(0.0001, (dist_i2p - dist_n2p)/dist_i2p ); + + color.w = penalty_ang + BETA*penalty_res; + + if(useSoftVisibility){ + vec4 dist_from_edge = texture(soft_visibility_maps, vec3(uvd.xy, selected_cams[cam_id])); + float weight_visibility = min(dist_from_edge.x/softVisibilityThreshold,1.0); + color.w /= (weight_visibility*weight_visibility); + } + + color.w = 1.0 / color.w; + + color_sum.xyz += color.w * color.xyz; + color_sum.w += color.w; + + //color_sum_simple += color.xyz; + //color_sum_square += color.xyz*color.xyz; + //color_sum_square_w += color.w * color.xyz*color.xyz; + //num++; + } + + //vec3 mean = color_sum_simple / num; + //vec3 variance = color_sum_square / num - mean*mean; + //vec3 deviation = sqrt(variance); + + //vec3 mean = color_sum.xyz / color_sum.w; + //vec3 variance = color_sum_square_w / color_sum.w - mean*mean; + //vec3 deviation = 3.0*sqrt(variance); + + color_sum.xyz /= color_sum.w; + + // blending + out_color.w = 1.0; + out_color.xyz = color_sum.xyz; + //out_color.xyz = deviation; + + gl_FragDepth = point.w; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/shaders/ulr_v3.frag b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/shaders/ulr_v3.frag new file mode 100644 index 0000000000000000000000000000000000000000..2f4a5650f68c83c130ea13a59d37d91d09a72775 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/shaders/ulr_v3.frag @@ -0,0 +1,345 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +#define NUM_CAMS (12) +#define ULR_STREAMING (0) + +in vec2 vertex_coord; +layout(location = 0) out vec4 out_color; + +// 2D proxy texture. +layout(binding=0) uniform sampler2D proxy; + +// Input cameras. +struct CameraInfos +{ + mat4 vp; + vec3 pos; + int selected; + vec3 dir; +}; +// They are stored in a contiguous buffer (UBO), lifting most limitations on the number of uniforms. +layout(std140, binding=4) uniform InputCameras +{ + CameraInfos cameras[NUM_CAMS]; +}; + +// Uniforms. +uniform int camsCount; +uniform vec3 ncam_pos; +uniform bool occ_test = true; +uniform bool invert_mask = false; +uniform bool is_binary_mask = true; +uniform bool discard_black_pixels = true; +uniform bool doMasking = false; +uniform bool flipRGBs = false; +uniform bool showWeights = false; +uniform float epsilonOcclusion = 1e-2; +uniform bool winner_takes_all = false; + +// for uv derivatives blending +uniform bool useUVDerivatives = false; +uniform float uvDerivativesAlphaBlending = 0.5f; +uniform float uvDerivativesScaleFactor = 1.0f; +uniform vec2 rtResolution = vec2(1.0); + +#define INFTY_W 100000.0 +#define BETA 1e-1 /* Relative importance of resolution penalty */ + +// Textures. +// To support both the regular version (using texture arrays) and the streaming version (using 2D RTs), +// we wrap the texture accesses in two helpers that hide the difference. + +#if ULR_STREAMING + +uniform sampler2D input_rgbds[NUM_CAMS]; +uniform sampler2D input_masks[NUM_CAMS]; + +vec4 getRGBD(vec3 xy_camid){ + if(flipRGBs){ + xy_camid.y = 1.0 - xy_camid.y; + } + vec4 rgbd = texture(input_rgbds[int(xy_camid.z)], xy_camid.xy); + if(flipRGBs){ + xy_camid.y = 1.0 - xy_camid.y; + } + return rgbd; +} + +float getMask(vec3 xy_camid){ + return texture(input_masks[int(xy_camid.z)], xy_camid.xy).r; +} + +#else + +layout(binding=1) uniform sampler2DArray input_rgbs; +layout(binding=2) uniform sampler2DArray input_depths; +layout(binding=3) uniform sampler2DArray input_masks; + +vec4 getRGBD(vec3 xy_camid){ + if(flipRGBs){ + xy_camid.y = 1.0 - xy_camid.y; + } + vec3 rgb = texture(input_rgbs, xy_camid).rgb; + if(flipRGBs){ + xy_camid.y = 1.0 - xy_camid.y; + } + float depth = texture(input_depths, xy_camid).r; + return vec4(rgb,depth); +} + +float getMask(vec3 xy_camid){ + return texture(input_masks, xy_camid).r; +} + +#endif + +// Helpers. + +vec3 project(vec3 point, mat4 proj) { + vec4 p1 = proj * vec4(point, 1.0); + vec3 p2 = (p1.xyz/p1.w); + return (p2.xyz*0.5 + 0.5); +} + +bool frustumTest(vec3 p, vec2 ndc, int i) { + vec3 d1 = cameras[i].dir; + vec3 d2 = p - cameras[i].pos; + return !any(greaterThan(ndc, vec2(1.0))) && dot(d1,d2)>0.0; +} + +vec3 getRandomColor(int x); + +void main(void){ + + vec4 point = texture(proxy, vertex_coord); + // discard if there was no intersection with the proxy + if ( point.w >= 1.0) { + discard; + } + + vec4 color0 = vec4(0.0,0.0,0.0,INFTY_W); + vec4 color1 = vec4(0.0,0.0,0.0,INFTY_W); + vec4 color2 = vec4(0.0,0.0,0.0,INFTY_W); + vec4 color3 = vec4(0.0,0.0,0.0,INFTY_W); + + bool atLeastOneValid = false; + + for(int i = 0; i < NUM_CAMS; i++){ + if(i>=camsCount){ + continue; + } + if(cameras[i].selected == 0){ + continue; + } + + vec3 uvd = project(point.xyz, cameras[i].vp); + vec2 ndc = abs(2.0*uvd.xy-1.0); + + vec2 uv_ddx = dFdx(uvd.xy * rtResolution); + vec2 uv_ddy = dFdy(uvd.xy * rtResolution); + + + if (frustumTest(point.xyz, ndc, i)){ + vec3 xy_camid = vec3(uvd.xy,i); + + + vec4 color = getRGBD(xy_camid); + + + + if(doMasking){ + float masked = getMask(xy_camid); + + if( invert_mask ){ + masked = 1.0 - masked; + } + + if( is_binary_mask ){ + if( masked < 0.5) { + continue; + } + } else { + color.xyz = masked*color.xyz; + } + + } + + if (discard_black_pixels){ + if(all(equal(color.xyz, vec3(0.0)))){ + continue; + } + } + + if (occ_test){ + if(abs(uvd.z-color.w) >= epsilonOcclusion) { + continue; + } + } + + // Support output weights as random colors for debug. + if(showWeights){ + color.xyz = getRandomColor(i); + } + + float penaltyValue = 0; + + if (!useUVDerivatives) { + // classic ulr + vec3 v1 = (point.xyz - cameras[i].pos); + vec3 v2 = (point.xyz - ncam_pos); + float dist_i2p = length(v1); + float dist_n2p = length(v2); + + float penalty_ang = float(occ_test) * max(0.0001, acos(dot(v1,v2)/(dist_i2p*dist_n2p))); + + float penalty_res = max(0.0001, (dist_i2p - dist_n2p)/dist_i2p ); + + penaltyValue = penalty_ang + BETA*penalty_res; + } else { + /// use uv derivatives + /// \todo TODO: check if uv needs to be scale by screen size as needed in unity hlsl + + vec3 crossProduct = cross(vec3(uv_ddx, 0), vec3(uv_ddy, 0)); + float transformScale = length (crossProduct); + float weight = 1.0f / transformScale; + penaltyValue = weight; + } + + atLeastOneValid = true; + color.w = penaltyValue; + + // compare with best four candiates and insert at the + // appropriate rank + if (color.w> 1U)^(p)); + uint h32 = 1103515245U*((p)^(p>>3U)); + return h32^(h32 >> 16); +} + +/** Generate a random vec3 from an index seed (see http://random.mat.sbg.ac.at/results/karl/server/node4.html). + \param x the seed + \return a random vec3 +*/ +vec3 getRandomColor(int x) { + // Color 0 is black, so we shift everything. + x = x+1; + uint n = baseHash(uint(x)); + uvec3 rz = uvec3(n, n*16807U, n*48271U); + return vec3(rz & uvec3(0x7fffffffU))/float(0x7fffffff); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/shaders/ulr_v3.vert b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/shaders/ulr_v3.vert new file mode 100644 index 0000000000000000000000000000000000000000..4182bac4e85e001d6e9bad94c8b282a964246be8 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/shaders/ulr_v3.vert @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + + +layout(location = 0) in vec3 in_vertex; + +out vec2 vertex_coord; + +void main(void) { + gl_Position = vec4(in_vertex,1.0); + vertex_coord = in_vertex.xy * 0.5 + 0.5; +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/shaders/ulr_v3_alt.frag b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/shaders/ulr_v3_alt.frag new file mode 100644 index 0000000000000000000000000000000000000000..7f9bed7c1a547875c15af652679d60cff9a40dc6 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/shaders/ulr_v3_alt.frag @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +#define NUM_CAMS (12) +#define ULR_STREAMING (0) + +in vec2 vertex_coord; +layout(location = 0) out vec4 out_color; + +// 2D proxy texture. +layout(binding=0) uniform sampler2D proxy; + +// Input cameras. +struct CameraInfos +{ + mat4 vp; + vec3 pos; + int selected; + vec3 dir; +}; +// They are stored in a contiguous buffer (UBO), lifting most limitations on the number of uniforms. +layout(std140, binding=4) uniform InputCameras +{ + CameraInfos cameras[NUM_CAMS]; +}; + +// Uniforms. +uniform int camsCount; +uniform vec3 ncam_pos; +uniform bool occ_test = true; +uniform bool invert_mask = false; +uniform bool is_binary_mask = true; +uniform bool discard_black_pixels = true; +uniform bool doMasking = false; +uniform bool flipRGBs = false; +uniform bool showWeights = false; +uniform float epsilonOcclusion = 1e-2; +#define INFTY_W 100000.0 +#define BETA 1e-1 /* Relative importance of resolution penalty */ + +// Textures. +// To support both the regular version (using texture arrays) and the streaming version (using 2D RTs), +// we wrap the texture accesses in two helpers that hide the difference. + +#if ULR_STREAMING + +uniform sampler2D input_rgbds[NUM_CAMS]; +uniform sampler2D input_masks[NUM_CAMS]; + +vec4 getRGBD(vec3 xy_camid){ + if(flipRGBs){ + xy_camid.y = 1.0 - xy_camid.y; + } + vec4 rgbd = texture(input_rgbds[int(xy_camid.z)], xy_camid.xy); + if(flipRGBs){ + xy_camid.y = 1.0 - xy_camid.y; + } + return rgbd; +} + +float getMask(vec3 xy_camid){ + return texture(input_masks[int(xy_camid.z)], xy_camid.xy).r; +} + +#else + +layout(binding=1) uniform sampler2DArray input_rgbs; +layout(binding=2) uniform sampler2DArray input_depths; +layout(binding=3) uniform sampler2DArray input_masks; + +vec4 getRGBD(vec3 xy_camid){ + if(flipRGBs){ + xy_camid.y = 1.0 - xy_camid.y; + } + vec3 rgb = texture(input_rgbs, xy_camid).rgb; + if(flipRGBs){ + xy_camid.y = 1.0 - xy_camid.y; + } + float depth = texture(input_depths, xy_camid).r; + return vec4(rgb,depth); +} + +float getMask(vec3 xy_camid){ + return texture(input_masks, xy_camid).r; +} + +#endif + +// Helpers. + +vec3 project(vec3 point, mat4 proj) { + vec4 p1 = proj * vec4(point, 1.0); + vec3 p2 = (p1.xyz/p1.w); + return (p2.xyz*0.5 + 0.5); +} + +bool frustumTest(vec3 p, vec2 ndc, int i) { + vec3 d1 = cameras[i].dir; + vec3 d2 = p - cameras[i].pos; + return !any(greaterThan(ndc, vec2(1.0))) && dot(d1,d2)>0.0; +} + +vec3 getRandomColor(int x); + +void main(void){ + + vec4 point = texture(proxy, vertex_coord); + // discard if there was no intersection with the proxy + if ( point.w >= 1.0) { + discard; + } + + vec4 color_sum = vec4(0.0,0.0,0.0,0.0); + //vec3 color_sum_simple = vec3(0.0,0.0,0.0); + //vec3 color_sum_square = vec3(0.0,0.0,0.0); + //vec3 color_sum_square_w = vec3(0.0,0.0,0.0); + //float num = 0.0; + + vec3 v2 = (point.xyz - ncam_pos); + float dist_n2p = length(v2); + + for(int i = 0; i < NUM_CAMS; i++){ + if(i>=camsCount){ + continue; + } + if(cameras[i].selected == 0){ + break; + } + + vec3 uvd = project(point.xyz, cameras[i].vp); + vec2 ndc = abs(2.0*uvd.xy-1.0); + + if (!frustumTest(point.xyz, ndc, i)) { + continue; + } + + vec3 xy_camid = vec3(uvd.xy,i); + vec4 color = getRGBD(xy_camid); + + // Support output weights as random colors for debug. + if(showWeights){ + color.xyz = getRandomColor(i); + } + + if(doMasking){ + float masked = getMask(xy_camid); + + if( invert_mask ){ + masked = 1.0 - masked; + } + + if( is_binary_mask ){ + if( masked < 0.5) { + continue; + } + } else { + color.xyz = masked*color.xyz; + } + } + + if (discard_black_pixels){ + if(all(equal(color.xyz, vec3(0.0)))){ + continue; + } + } + + if (occ_test){ + if(abs(uvd.z-color.w) >= epsilonOcclusion) { + continue; + } + } + + vec3 v1 = (point.xyz - cameras[i].pos); + float dist_i2p = length(v1); + + float penalty_ang = float(occ_test) * max(0.0001, acos(dot(v1,v2)/(dist_i2p*dist_n2p))); + + float penalty_res = max(0.0001, (dist_i2p - dist_n2p)/dist_i2p ); + + color.w = penalty_ang + BETA*penalty_res; + + color.w = 1.0 / color.w; + + color_sum.xyz += color.w * color.xyz; + color_sum.w += color.w; + + //color_sum_simple += color.xyz; + //color_sum_square += color.xyz*color.xyz; + //color_sum_square_w += color.w * color.xyz*color.xyz; + //num++; + } + + //vec3 mean = color_sum_simple / num; + //vec3 variance = color_sum_square / num - mean*mean; + //vec3 deviation = sqrt(variance); + + //vec3 mean = color_sum.xyz / color_sum.w; + //vec3 variance = color_sum_square_w / color_sum.w - mean*mean; + //vec3 deviation = 3.0*sqrt(variance); + + color_sum.xyz /= color_sum.w; + + // blending + out_color.w = 1.0; + out_color.xyz = color_sum.xyz; + //out_color.xyz = deviation; + + gl_FragDepth = point.w; +} + + +// Random number generation: +// "Quality hashes collection" (https://www.shadertoy.com/view/Xt3cDn) +// by nimitz 2018 (twitter: @stormoid) +// The MIT License +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +/** Compute the based hash for a given index. + \param p the index + \return the hash +*/ +uint baseHash(uint p) { + p = 1103515245U*((p >> 1U)^(p)); + uint h32 = 1103515245U*((p)^(p>>3U)); + return h32^(h32 >> 16); +} + +/** Generate a random vec3 from an index seed (see http://random.mat.sbg.ac.at/results/karl/server/node4.html). + \param x the seed + \return a random vec3 +*/ +vec3 getRandomColor(int x) { + uint n = baseHash(uint(x)); + uvec3 rz = uvec3(n, n*16807U, n*48271U); + return vec3(rz & uvec3(0x7fffffffU))/float(0x7fffffff); +} diff --git a/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/shaders/ulr_v3_fast.frag b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/shaders/ulr_v3_fast.frag new file mode 100644 index 0000000000000000000000000000000000000000..16e402640ff8432a27e28764dadbc7baf10950a3 --- /dev/null +++ b/submodules/gaussian-splatting/SIBR_viewers/src/projects/ulr/renderer/shaders/ulr_v3_fast.frag @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2020, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr + */ + + +#version 420 + +#define NUM_CAMS (12) +#define ULR_STREAMING (0) + +in vec2 vertex_coord; +layout(location = 0) out vec4 out_color; + +// 2D proxy texture. +layout(binding=0) uniform sampler2D proxy; + +// Input cameras. +struct CameraInfos +{ + mat4 vp; + vec3 pos; + int selected; + vec3 dir; +}; +// They are stored in a contiguous buffer (UBO), lifting most limitations on the number of uniforms. +layout(std140, binding=4) uniform InputCameras +{ + CameraInfos cameras[NUM_CAMS]; +}; + +// Uniforms. +uniform int camsCount; +uniform vec3 ncam_pos; +uniform bool occ_test = true; +uniform bool invert_mask = false; +uniform bool is_binary_mask = true; +uniform bool discard_black_pixels = true; +uniform bool doMasking = false; +uniform bool flipRGBs = false; +uniform bool showWeights = false; +uniform bool gammaCorrection = false; +uniform float epsilonOcclusion = 1e-2; + + +#define INFTY_W 100000.0 +/* Relative importance of resolution penalty */ +#define BETA 1e-1 +/* Relative importance of edges penalty */ +#define BETA_UV 0.0 + +// Textures. +// To support both the regular version (using texture arrays) and the streaming version (using 2D RTs), +// we wrap the texture accesses in two helpers that hide the difference. + +layout(binding=1) uniform sampler2DArray input_rgbs; +layout(binding=2) uniform sampler2DArray input_depths; +layout(binding=3) uniform sampler2DArray input_masks; + + +float getMask(vec3 xy_camid){ + return texture(input_masks, xy_camid).r; +} + + +// Helpers. + +vec3 project(vec3 point, mat4 proj) { + vec4 p1 = proj * vec4(point, 1.0); + vec3 p2 = (p1.xyz/p1.w); + return (p2.xyz*0.5 + 0.5); +} + +bool frustumTest(vec3 p, vec2 ndc, int i) { + vec3 d1 = cameras[i].dir; + vec3 d2 = p - cameras[i].pos; + return !any(greaterThan(ndc, vec2(1.0))) && dot(d1,d2)>0.0; +} + +vec3 getRandomColor(int x); + +void main(void){ + + vec4 point = texture(proxy, vertex_coord); + // discard if there was no intersection with the proxy + if ( point.w >= 1.0) { + discard; + } + + vec4 color0 = vec4(0.0,0.0,0.0,INFTY_W); + vec4 color1 = vec4(0.0,0.0,0.0,INFTY_W); + vec4 color2 = vec4(0.0,0.0,0.0,INFTY_W); + vec4 color3 = vec4(0.0,0.0,0.0,INFTY_W); + vec4 masks = vec4(1.0); + for(int i = 0; i < NUM_CAMS; i++){ + if(i>=camsCount){ + continue; + } + if(cameras[i].selected == 0){ + continue; + } + + vec3 uvd = project(point.xyz, cameras[i].vp); + vec2 ndc = abs(2.0*uvd.xy-1.0); + + if (frustumTest(point.xyz, ndc, i)){ + vec3 xy_camid = vec3(uvd.xy,i); + + float inputDepth = texture(input_depths, xy_camid).r; + + if (occ_test){ + if(abs(uvd.z-inputDepth) >= epsilonOcclusion) { + continue; + } + } + + + + float masked = 1.0; + if(doMasking){ + masked = getMask(xy_camid); + + if( invert_mask ){ + masked = 1.0 - masked; + } + + if( is_binary_mask ){ + if( masked < 0.5) { + continue; + } + } + } + + float penaltyValue = 0; + + + // classic ulr + vec3 v1 = (point.xyz - cameras[i].pos); + vec3 v2 = (point.xyz - ncam_pos); + float dist_i2p = length(v1); + float dist_n2p = length(v2); + + float penalty_ang = float(occ_test) * max(0.0001, acos(dot(v1,v2)/(dist_i2p*dist_n2p))); + + float penalty_res = max(0.0001, (dist_i2p - dist_n2p)/dist_i2p ); + + vec2 fc = vec2(1.0) - smoothstep(vec2(0.7), vec2(1.0), abs(2.0*uvd.xy-1.0)); + float penalty_uv = 1.0 - fc.x * fc.y; + + penaltyValue = penalty_ang + BETA*penalty_res + BETA_UV*penalty_uv; + + + + vec4 color = vec4(xy_camid, penaltyValue); + if(flipRGBs){ + color.y = 1.0 - color.y; + } + + // compare with best four candiates and insert at the + // appropriate rank + if (color.w> 1U)^(p)); + uint h32 = 1103515245U*((p)^(p>>3U)); + return h32^(h32 >> 16); +} + +/** Generate a random vec3 from an index seed (see http://random.mat.sbg.ac.at/results/karl/server/node4.html). + \param x the seed + \return a random vec3 +*/ +vec3 getRandomColor(int x) { + // Color 0 is black, so we shift everything. + x = x+1; + uint n = baseHash(uint(x)); + uvec3 rz = uvec3(n, n*16807U, n*48271U); + return vec3(rz & uvec3(0x7fffffffU))/float(0x7fffffff); +} diff --git a/submodules/gaussian-splatting/arguments/__init__.py b/submodules/gaussian-splatting/arguments/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..0b2f448d8fd3a563918485147e95f7e16352b162 --- /dev/null +++ b/submodules/gaussian-splatting/arguments/__init__.py @@ -0,0 +1,122 @@ +# +# Copyright (C) 2023, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact george.drettakis@inria.fr +# + +from argparse import ArgumentParser, Namespace +import sys +import os + +class GroupParams: + pass + +class ParamGroup: + def __init__(self, parser: ArgumentParser, name : str, fill_none = False): + group = parser.add_argument_group(name) + for key, value in vars(self).items(): + shorthand = False + if key.startswith("_"): + shorthand = True + key = key[1:] + t = type(value) + value = value if not fill_none else None + if shorthand: + if t == bool: + group.add_argument("--" + key, ("-" + key[0:1]), default=value, action="store_true") + else: + group.add_argument("--" + key, ("-" + key[0:1]), default=value, type=t) + else: + if t == bool: + group.add_argument("--" + key, default=value, action="store_true") + else: + group.add_argument("--" + key, default=value, type=t) + + def extract(self, args): + group = GroupParams() + for arg in vars(args).items(): + if arg[0] in vars(self) or ("_" + arg[0]) in vars(self): + setattr(group, arg[0], arg[1]) + return group + +class ModelParams(ParamGroup): + def __init__(self, parser, sentinel=False): + self.sh_degree = 3 + self._source_path = "" + self._model_path = "" + self._images = "images" + self._depths = "" + self._resolution = -1 + self._white_background = False + self.train_test_exp = False + self.data_device = "cuda" + self.eval = False + super().__init__(parser, "Loading Parameters", sentinel) + + def extract(self, args): + g = super().extract(args) + g.source_path = os.path.abspath(g.source_path) + return g + +class PipelineParams(ParamGroup): + def __init__(self, parser): + self.convert_SHs_python = False + self.compute_cov3D_python = False + self.debug = False + self.antialiasing = False + super().__init__(parser, "Pipeline Parameters") + +class OptimizationParams(ParamGroup): + def __init__(self, parser): + self.iterations = 30_000 + self.position_lr_init = 0.00016 + self.position_lr_final = 0.0000016 + self.position_lr_delay_mult = 0.01 + self.position_lr_max_steps = 30_000 + self.feature_lr = 0.0025 + self.opacity_lr = 0.025 + self.scaling_lr = 0.005 + self.rotation_lr = 0.001 + self.exposure_lr_init = 0.01 + self.exposure_lr_final = 0.001 + self.exposure_lr_delay_steps = 0 + self.exposure_lr_delay_mult = 0.0 + self.percent_dense = 0.01 + self.lambda_dssim = 0.2 + self.densification_interval = 100 + self.opacity_reset_interval = 3000 + self.densify_from_iter = 500 + self.densify_until_iter = 15_000 + self.densify_grad_threshold = 0.0002 + self.depth_l1_weight_init = 1.0 + self.depth_l1_weight_final = 0.01 + self.random_background = False + self.optimizer_type = "default" + super().__init__(parser, "Optimization Parameters") + +def get_combined_args(parser : ArgumentParser): + cmdlne_string = sys.argv[1:] + cfgfile_string = "Namespace()" + args_cmdline = parser.parse_args(cmdlne_string) + + try: + cfgfilepath = os.path.join(args_cmdline.model_path, "cfg_args") + print("Looking for config file in", cfgfilepath) + with open(cfgfilepath) as cfg_file: + print("Config file found: {}".format(cfgfilepath)) + cfgfile_string = cfg_file.read() + except TypeError: + print("Config file not found at") + pass + args_cfgfile = eval(cfgfile_string) + + merged_dict = vars(args_cfgfile).copy() + for k,v in vars(args_cmdline).items(): + if v != None: + merged_dict[k] = v + return Namespace(**merged_dict) diff --git a/submodules/gaussian-splatting/convert.py b/submodules/gaussian-splatting/convert.py new file mode 100644 index 0000000000000000000000000000000000000000..78948848f4849a88d686542790cd04f34f34beb0 --- /dev/null +++ b/submodules/gaussian-splatting/convert.py @@ -0,0 +1,124 @@ +# +# Copyright (C) 2023, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact george.drettakis@inria.fr +# + +import os +import logging +from argparse import ArgumentParser +import shutil + +# This Python script is based on the shell converter script provided in the MipNerF 360 repository. +parser = ArgumentParser("Colmap converter") +parser.add_argument("--no_gpu", action='store_true') +parser.add_argument("--skip_matching", action='store_true') +parser.add_argument("--source_path", "-s", required=True, type=str) +parser.add_argument("--camera", default="OPENCV", type=str) +parser.add_argument("--colmap_executable", default="", type=str) +parser.add_argument("--resize", action="store_true") +parser.add_argument("--magick_executable", default="", type=str) +args = parser.parse_args() +colmap_command = '"{}"'.format(args.colmap_executable) if len(args.colmap_executable) > 0 else "colmap" +magick_command = '"{}"'.format(args.magick_executable) if len(args.magick_executable) > 0 else "magick" +use_gpu = 1 if not args.no_gpu else 0 + +if not args.skip_matching: + os.makedirs(args.source_path + "/distorted/sparse", exist_ok=True) + + ## Feature extraction + feat_extracton_cmd = colmap_command + " feature_extractor "\ + "--database_path " + args.source_path + "/distorted/database.db \ + --image_path " + args.source_path + "/input \ + --ImageReader.single_camera 1 \ + --ImageReader.camera_model " + args.camera + " \ + --SiftExtraction.use_gpu " + str(use_gpu) + exit_code = os.system(feat_extracton_cmd) + if exit_code != 0: + logging.error(f"Feature extraction failed with code {exit_code}. Exiting.") + exit(exit_code) + + ## Feature matching + feat_matching_cmd = colmap_command + " exhaustive_matcher \ + --database_path " + args.source_path + "/distorted/database.db \ + --SiftMatching.use_gpu " + str(use_gpu) + exit_code = os.system(feat_matching_cmd) + if exit_code != 0: + logging.error(f"Feature matching failed with code {exit_code}. Exiting.") + exit(exit_code) + + ### Bundle adjustment + # The default Mapper tolerance is unnecessarily large, + # decreasing it speeds up bundle adjustment steps. + mapper_cmd = (colmap_command + " mapper \ + --database_path " + args.source_path + "/distorted/database.db \ + --image_path " + args.source_path + "/input \ + --output_path " + args.source_path + "/distorted/sparse \ + --Mapper.ba_global_function_tolerance=0.000001") + exit_code = os.system(mapper_cmd) + if exit_code != 0: + logging.error(f"Mapper failed with code {exit_code}. Exiting.") + exit(exit_code) + +### Image undistortion +## We need to undistort our images into ideal pinhole intrinsics. +img_undist_cmd = (colmap_command + " image_undistorter \ + --image_path " + args.source_path + "/input \ + --input_path " + args.source_path + "/distorted/sparse/0 \ + --output_path " + args.source_path + "\ + --output_type COLMAP") +exit_code = os.system(img_undist_cmd) +if exit_code != 0: + logging.error(f"Mapper failed with code {exit_code}. Exiting.") + exit(exit_code) + +files = os.listdir(args.source_path + "/sparse") +os.makedirs(args.source_path + "/sparse/0", exist_ok=True) +# Copy each file from the source directory to the destination directory +for file in files: + if file == '0': + continue + source_file = os.path.join(args.source_path, "sparse", file) + destination_file = os.path.join(args.source_path, "sparse", "0", file) + shutil.move(source_file, destination_file) + +if(args.resize): + print("Copying and resizing...") + + # Resize images. + os.makedirs(args.source_path + "/images_2", exist_ok=True) + os.makedirs(args.source_path + "/images_4", exist_ok=True) + os.makedirs(args.source_path + "/images_8", exist_ok=True) + # Get the list of files in the source directory + files = os.listdir(args.source_path + "/images") + # Copy each file from the source directory to the destination directory + for file in files: + source_file = os.path.join(args.source_path, "images", file) + + destination_file = os.path.join(args.source_path, "images_2", file) + shutil.copy2(source_file, destination_file) + exit_code = os.system(magick_command + " mogrify -resize 50% " + destination_file) + if exit_code != 0: + logging.error(f"50% resize failed with code {exit_code}. Exiting.") + exit(exit_code) + + destination_file = os.path.join(args.source_path, "images_4", file) + shutil.copy2(source_file, destination_file) + exit_code = os.system(magick_command + " mogrify -resize 25% " + destination_file) + if exit_code != 0: + logging.error(f"25% resize failed with code {exit_code}. Exiting.") + exit(exit_code) + + destination_file = os.path.join(args.source_path, "images_8", file) + shutil.copy2(source_file, destination_file) + exit_code = os.system(magick_command + " mogrify -resize 12.5% " + destination_file) + if exit_code != 0: + logging.error(f"12.5% resize failed with code {exit_code}. Exiting.") + exit(exit_code) + +print("Done.") diff --git a/submodules/gaussian-splatting/environment.yml b/submodules/gaussian-splatting/environment.yml new file mode 100644 index 0000000000000000000000000000000000000000..d91d37ffc1213f120427bb782e0d8d4a5e30ff19 --- /dev/null +++ b/submodules/gaussian-splatting/environment.yml @@ -0,0 +1,20 @@ +name: gaussian_splatting +channels: + - pytorch + - conda-forge + - defaults +dependencies: + - cudatoolkit=11.6 + - plyfile + - python=3.7.13 + - pip=22.3.1 + - pytorch=1.12.1 + - torchaudio=0.12.1 + - torchvision=0.13.1 + - tqdm + - pip: + - submodules/diff-gaussian-rasterization + - submodules/simple-knn + - submodules/fused-ssim + - opencv-python + - joblib diff --git a/submodules/gaussian-splatting/full_eval.py b/submodules/gaussian-splatting/full_eval.py new file mode 100644 index 0000000000000000000000000000000000000000..e0eb2d0e4fef893c061b919d8372f037b09865c2 --- /dev/null +++ b/submodules/gaussian-splatting/full_eval.py @@ -0,0 +1,112 @@ +# +# Copyright (C) 2023, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact george.drettakis@inria.fr +# + +import os +from argparse import ArgumentParser +import time + +mipnerf360_outdoor_scenes = ["bicycle", "flowers", "garden", "stump", "treehill"] +mipnerf360_indoor_scenes = ["room", "counter", "kitchen", "bonsai"] +tanks_and_temples_scenes = ["truck", "train"] +deep_blending_scenes = ["drjohnson", "playroom"] + +parser = ArgumentParser(description="Full evaluation script parameters") +parser.add_argument("--skip_training", action="store_true") +parser.add_argument("--skip_rendering", action="store_true") +parser.add_argument("--skip_metrics", action="store_true") +parser.add_argument("--output_path", default="./eval") +parser.add_argument("--use_depth", action="store_true") +parser.add_argument("--use_expcomp", action="store_true") +parser.add_argument("--fast", action="store_true") +parser.add_argument("--aa", action="store_true") + + + + +args, _ = parser.parse_known_args() + +all_scenes = [] +all_scenes.extend(mipnerf360_outdoor_scenes) +all_scenes.extend(mipnerf360_indoor_scenes) +all_scenes.extend(tanks_and_temples_scenes) +all_scenes.extend(deep_blending_scenes) + +if not args.skip_training or not args.skip_rendering: + parser.add_argument('--mipnerf360', "-m360", required=True, type=str) + parser.add_argument("--tanksandtemples", "-tat", required=True, type=str) + parser.add_argument("--deepblending", "-db", required=True, type=str) + args = parser.parse_args() +if not args.skip_training: + common_args = " --disable_viewer --quiet --eval --test_iterations -1 " + + if args.aa: + common_args += " --antialiasing " + if args.use_depth: + common_args += " -d depths2/ " + + if args.use_expcomp: + common_args += " --exposure_lr_init 0.001 --exposure_lr_final 0.0001 --exposure_lr_delay_steps 5000 --exposure_lr_delay_mult 0.001 --train_test_exp " + + if args.fast: + common_args += " --optimizer_type sparse_adam " + + start_time = time.time() + for scene in mipnerf360_outdoor_scenes: + source = args.mipnerf360 + "/" + scene + os.system("python train.py -s " + source + " -i images_4 -m " + args.output_path + "/" + scene + common_args) + for scene in mipnerf360_indoor_scenes: + source = args.mipnerf360 + "/" + scene + os.system("python train.py -s " + source + " -i images_2 -m " + args.output_path + "/" + scene + common_args) + m360_timing = (time.time() - start_time)/60.0 + + start_time = time.time() + for scene in tanks_and_temples_scenes: + source = args.tanksandtemples + "/" + scene + os.system("python train.py -s " + source + " -m " + args.output_path + "/" + scene + common_args) + tandt_timing = (time.time() - start_time)/60.0 + + start_time = time.time() + for scene in deep_blending_scenes: + source = args.deepblending + "/" + scene + os.system("python train.py -s " + source + " -m " + args.output_path + "/" + scene + common_args) + db_timing = (time.time() - start_time)/60.0 + +with open(os.path.join(args.output_path,"timing.txt"), 'w') as file: + file.write(f"m360: {m360_timing} minutes \n tandt: {tandt_timing} minutes \n db: {db_timing} minutes\n") + +if not args.skip_rendering: + all_sources = [] + for scene in mipnerf360_outdoor_scenes: + all_sources.append(args.mipnerf360 + "/" + scene) + for scene in mipnerf360_indoor_scenes: + all_sources.append(args.mipnerf360 + "/" + scene) + for scene in tanks_and_temples_scenes: + all_sources.append(args.tanksandtemples + "/" + scene) + for scene in deep_blending_scenes: + all_sources.append(args.deepblending + "/" + scene) + + common_args = " --quiet --eval --skip_train" + + if args.aa: + common_args += " --antialiasing " + if args.use_expcomp: + common_args += " --train_test_exp " + + for scene, source in zip(all_scenes, all_sources): + os.system("python render.py --iteration 7000 -s " + source + " -m " + args.output_path + "/" + scene + common_args) + os.system("python render.py --iteration 30000 -s " + source + " -m " + args.output_path + "/" + scene + common_args) + +if not args.skip_metrics: + scenes_string = "" + for scene in all_scenes: + scenes_string += "\"" + args.output_path + "/" + scene + "\" " + + os.system("python metrics.py -m " + scenes_string) diff --git a/submodules/gaussian-splatting/gaussian_renderer/__init__.py b/submodules/gaussian-splatting/gaussian_renderer/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e18460ed2691d5136bfef468badd408fd87baeb2 --- /dev/null +++ b/submodules/gaussian-splatting/gaussian_renderer/__init__.py @@ -0,0 +1,127 @@ +# +# Copyright (C) 2023, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact george.drettakis@inria.fr +# + +import torch +import math +from diff_gaussian_rasterization import GaussianRasterizationSettings, GaussianRasterizer +from scene.gaussian_model import GaussianModel +from utils.sh_utils import eval_sh + +def render(viewpoint_camera, pc : GaussianModel, pipe, bg_color : torch.Tensor, scaling_modifier = 1.0, separate_sh = False, override_color = None, use_trained_exp=False): + """ + Render the scene. + + Background tensor (bg_color) must be on GPU! + """ + + # Create zero tensor. We will use it to make pytorch return gradients of the 2D (screen-space) means + screenspace_points = torch.zeros_like(pc.get_xyz, dtype=pc.get_xyz.dtype, requires_grad=True, device="cuda") + 0 + try: + screenspace_points.retain_grad() + except: + pass + + # Set up rasterization configuration + tanfovx = math.tan(viewpoint_camera.FoVx * 0.5) + tanfovy = math.tan(viewpoint_camera.FoVy * 0.5) + + raster_settings = GaussianRasterizationSettings( + image_height=int(viewpoint_camera.image_height), + image_width=int(viewpoint_camera.image_width), + tanfovx=tanfovx, + tanfovy=tanfovy, + bg=bg_color, + scale_modifier=scaling_modifier, + viewmatrix=viewpoint_camera.world_view_transform, + projmatrix=viewpoint_camera.full_proj_transform, + sh_degree=pc.active_sh_degree, + campos=viewpoint_camera.camera_center, + prefiltered=False, + debug=pipe.debug + ) + + rasterizer = GaussianRasterizer(raster_settings=raster_settings) + + means3D = pc.get_xyz + means2D = screenspace_points + opacity = pc.get_opacity + + # If precomputed 3d covariance is provided, use it. If not, then it will be computed from + # scaling / rotation by the rasterizer. + scales = None + rotations = None + cov3D_precomp = None + + if pipe.compute_cov3D_python: + cov3D_precomp = pc.get_covariance(scaling_modifier) + else: + scales = pc.get_scaling + rotations = pc.get_rotation + + # If precomputed colors are provided, use them. Otherwise, if it is desired to precompute colors + # from SHs in Python, do it. If not, then SH -> RGB conversion will be done by rasterizer. + shs = None + colors_precomp = None + if override_color is None: + if pipe.convert_SHs_python: + shs_view = pc.get_features.transpose(1, 2).view(-1, 3, (pc.max_sh_degree+1)**2) + dir_pp = (pc.get_xyz - viewpoint_camera.camera_center.repeat(pc.get_features.shape[0], 1)) + dir_pp_normalized = dir_pp/dir_pp.norm(dim=1, keepdim=True) + sh2rgb = eval_sh(pc.active_sh_degree, shs_view, dir_pp_normalized) + colors_precomp = torch.clamp_min(sh2rgb + 0.5, 0.0) + else: + if separate_sh: + dc, shs = pc.get_features_dc, pc.get_features_rest + else: + shs = pc.get_features + else: + colors_precomp = override_color + + # Rasterize visible Gaussians to image, obtain their radii (on screen). + if separate_sh: + rendered_image, radii = rasterizer( + means3D = means3D, + means2D = means2D, + dc = dc, + shs = shs, + colors_precomp = colors_precomp, + opacities = opacity, + scales = scales, + rotations = rotations, + cov3D_precomp = cov3D_precomp) + else: + rendered_image, radii = rasterizer( + means3D = means3D, + means2D = means2D, + shs = shs, + colors_precomp = colors_precomp, + opacities = opacity, + scales = scales, + rotations = rotations, + cov3D_precomp = cov3D_precomp) + + # Apply exposure to rendered image (training only) + if use_trained_exp: + exposure = pc.get_exposure_from_name(viewpoint_camera.image_name) + rendered_image = torch.matmul(rendered_image.permute(1, 2, 0), exposure[:3, :3]).permute(2, 0, 1) + exposure[:3, 3, None, None] + + # Those Gaussians that were frustum culled or had a radius of 0 were not visible. + # They will be excluded from value updates used in the splitting criteria. + rendered_image = rendered_image.clamp(0, 1) + out = { + "render": rendered_image, + "viewspace_points": screenspace_points, + "visibility_filter" : (radii > 0).nonzero(), + "radii": radii, + "depth" : None + } + + return out diff --git a/submodules/gaussian-splatting/gaussian_renderer/network_gui.py b/submodules/gaussian-splatting/gaussian_renderer/network_gui.py new file mode 100644 index 0000000000000000000000000000000000000000..df2f9dae782b24527ae5b09f91ca4009361de53f --- /dev/null +++ b/submodules/gaussian-splatting/gaussian_renderer/network_gui.py @@ -0,0 +1,86 @@ +# +# Copyright (C) 2023, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact george.drettakis@inria.fr +# + +import torch +import traceback +import socket +import json +from scene.cameras import MiniCam + +host = "127.0.0.1" +port = 6009 + +conn = None +addr = None + +listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + +def init(wish_host, wish_port): + global host, port, listener + host = wish_host + port = wish_port + listener.bind((host, port)) + listener.listen() + listener.settimeout(0) + +def try_connect(): + global conn, addr, listener + try: + conn, addr = listener.accept() + print(f"\nConnected by {addr}") + conn.settimeout(None) + except Exception as inst: + pass + +def read(): + global conn + messageLength = conn.recv(4) + messageLength = int.from_bytes(messageLength, 'little') + message = conn.recv(messageLength) + return json.loads(message.decode("utf-8")) + +def send(message_bytes, verify): + global conn + if message_bytes != None: + conn.sendall(message_bytes) + conn.sendall(len(verify).to_bytes(4, 'little')) + conn.sendall(bytes(verify, 'ascii')) + +def receive(): + message = read() + + width = message["resolution_x"] + height = message["resolution_y"] + + if width != 0 and height != 0: + try: + do_training = bool(message["train"]) + fovy = message["fov_y"] + fovx = message["fov_x"] + znear = message["z_near"] + zfar = message["z_far"] + do_shs_python = bool(message["shs_python"]) + do_rot_scale_python = bool(message["rot_scale_python"]) + keep_alive = bool(message["keep_alive"]) + scaling_modifier = message["scaling_modifier"] + world_view_transform = torch.reshape(torch.tensor(message["view_matrix"]), (4, 4)).cuda() + world_view_transform[:,1] = -world_view_transform[:,1] + world_view_transform[:,2] = -world_view_transform[:,2] + full_proj_transform = torch.reshape(torch.tensor(message["view_projection_matrix"]), (4, 4)).cuda() + full_proj_transform[:,1] = -full_proj_transform[:,1] + custom_cam = MiniCam(width, height, fovy, fovx, znear, zfar, world_view_transform, full_proj_transform) + except Exception as e: + print("") + traceback.print_exc() + raise e + return custom_cam, do_training, do_shs_python, do_rot_scale_python, keep_alive, scaling_modifier + else: + return None, None, None, None, None, None \ No newline at end of file diff --git a/submodules/gaussian-splatting/lpipsPyTorch/__init__.py b/submodules/gaussian-splatting/lpipsPyTorch/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..2a6297daa457d1d041c9491dfdf6a75994ffe06e --- /dev/null +++ b/submodules/gaussian-splatting/lpipsPyTorch/__init__.py @@ -0,0 +1,21 @@ +import torch + +from .modules.lpips import LPIPS + + +def lpips(x: torch.Tensor, + y: torch.Tensor, + net_type: str = 'alex', + version: str = '0.1'): + r"""Function that measures + Learned Perceptual Image Patch Similarity (LPIPS). + + Arguments: + x, y (torch.Tensor): the input tensors to compare. + net_type (str): the network type to compare the features: + 'alex' | 'squeeze' | 'vgg'. Default: 'alex'. + version (str): the version of LPIPS. Default: 0.1. + """ + device = x.device + criterion = LPIPS(net_type, version).to(device) + return criterion(x, y) diff --git a/submodules/gaussian-splatting/lpipsPyTorch/modules/lpips.py b/submodules/gaussian-splatting/lpipsPyTorch/modules/lpips.py new file mode 100644 index 0000000000000000000000000000000000000000..9cd001d1e1036c7f8f5db62e81446e2ff2db80ab --- /dev/null +++ b/submodules/gaussian-splatting/lpipsPyTorch/modules/lpips.py @@ -0,0 +1,36 @@ +import torch +import torch.nn as nn + +from .networks import get_network, LinLayers +from .utils import get_state_dict + + +class LPIPS(nn.Module): + r"""Creates a criterion that measures + Learned Perceptual Image Patch Similarity (LPIPS). + + Arguments: + net_type (str): the network type to compare the features: + 'alex' | 'squeeze' | 'vgg'. Default: 'alex'. + version (str): the version of LPIPS. Default: 0.1. + """ + def __init__(self, net_type: str = 'alex', version: str = '0.1'): + + assert version in ['0.1'], 'v0.1 is only supported now' + + super(LPIPS, self).__init__() + + # pretrained network + self.net = get_network(net_type) + + # linear layers + self.lin = LinLayers(self.net.n_channels_list) + self.lin.load_state_dict(get_state_dict(net_type, version)) + + def forward(self, x: torch.Tensor, y: torch.Tensor): + feat_x, feat_y = self.net(x), self.net(y) + + diff = [(fx - fy) ** 2 for fx, fy in zip(feat_x, feat_y)] + res = [l(d).mean((2, 3), True) for d, l in zip(diff, self.lin)] + + return torch.sum(torch.cat(res, 0), 0, True) diff --git a/submodules/gaussian-splatting/lpipsPyTorch/modules/networks.py b/submodules/gaussian-splatting/lpipsPyTorch/modules/networks.py new file mode 100644 index 0000000000000000000000000000000000000000..d36c6a56163004d49c321da5e26404af9baa4c2a --- /dev/null +++ b/submodules/gaussian-splatting/lpipsPyTorch/modules/networks.py @@ -0,0 +1,96 @@ +from typing import Sequence + +from itertools import chain + +import torch +import torch.nn as nn +from torchvision import models + +from .utils import normalize_activation + + +def get_network(net_type: str): + if net_type == 'alex': + return AlexNet() + elif net_type == 'squeeze': + return SqueezeNet() + elif net_type == 'vgg': + return VGG16() + else: + raise NotImplementedError('choose net_type from [alex, squeeze, vgg].') + + +class LinLayers(nn.ModuleList): + def __init__(self, n_channels_list: Sequence[int]): + super(LinLayers, self).__init__([ + nn.Sequential( + nn.Identity(), + nn.Conv2d(nc, 1, 1, 1, 0, bias=False) + ) for nc in n_channels_list + ]) + + for param in self.parameters(): + param.requires_grad = False + + +class BaseNet(nn.Module): + def __init__(self): + super(BaseNet, self).__init__() + + # register buffer + self.register_buffer( + 'mean', torch.Tensor([-.030, -.088, -.188])[None, :, None, None]) + self.register_buffer( + 'std', torch.Tensor([.458, .448, .450])[None, :, None, None]) + + def set_requires_grad(self, state: bool): + for param in chain(self.parameters(), self.buffers()): + param.requires_grad = state + + def z_score(self, x: torch.Tensor): + return (x - self.mean) / self.std + + def forward(self, x: torch.Tensor): + x = self.z_score(x) + + output = [] + for i, (_, layer) in enumerate(self.layers._modules.items(), 1): + x = layer(x) + if i in self.target_layers: + output.append(normalize_activation(x)) + if len(output) == len(self.target_layers): + break + return output + + +class SqueezeNet(BaseNet): + def __init__(self): + super(SqueezeNet, self).__init__() + + self.layers = models.squeezenet1_1(True).features + self.target_layers = [2, 5, 8, 10, 11, 12, 13] + self.n_channels_list = [64, 128, 256, 384, 384, 512, 512] + + self.set_requires_grad(False) + + +class AlexNet(BaseNet): + def __init__(self): + super(AlexNet, self).__init__() + + self.layers = models.alexnet(True).features + self.target_layers = [2, 5, 8, 10, 12] + self.n_channels_list = [64, 192, 384, 256, 256] + + self.set_requires_grad(False) + + +class VGG16(BaseNet): + def __init__(self): + super(VGG16, self).__init__() + + self.layers = models.vgg16(weights=models.VGG16_Weights.IMAGENET1K_V1).features + self.target_layers = [4, 9, 16, 23, 30] + self.n_channels_list = [64, 128, 256, 512, 512] + + self.set_requires_grad(False) diff --git a/submodules/gaussian-splatting/lpipsPyTorch/modules/utils.py b/submodules/gaussian-splatting/lpipsPyTorch/modules/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..3d15a0983775810ef6239c561c67939b2b9ee3b5 --- /dev/null +++ b/submodules/gaussian-splatting/lpipsPyTorch/modules/utils.py @@ -0,0 +1,30 @@ +from collections import OrderedDict + +import torch + + +def normalize_activation(x, eps=1e-10): + norm_factor = torch.sqrt(torch.sum(x ** 2, dim=1, keepdim=True)) + return x / (norm_factor + eps) + + +def get_state_dict(net_type: str = 'alex', version: str = '0.1'): + # build url + url = 'https://raw.githubusercontent.com/richzhang/PerceptualSimilarity/' \ + + f'master/lpips/weights/v{version}/{net_type}.pth' + + # download + old_state_dict = torch.hub.load_state_dict_from_url( + url, progress=True, + map_location=None if torch.cuda.is_available() else torch.device('cpu') + ) + + # rename keys + new_state_dict = OrderedDict() + for key, val in old_state_dict.items(): + new_key = key + new_key = new_key.replace('lin', '') + new_key = new_key.replace('model.', '') + new_state_dict[new_key] = val + + return new_state_dict diff --git a/submodules/gaussian-splatting/metrics.py b/submodules/gaussian-splatting/metrics.py new file mode 100644 index 0000000000000000000000000000000000000000..f7393a4c9b6978bb34c7121a66628335690b3279 --- /dev/null +++ b/submodules/gaussian-splatting/metrics.py @@ -0,0 +1,103 @@ +# +# Copyright (C) 2023, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact george.drettakis@inria.fr +# + +from pathlib import Path +import os +from PIL import Image +import torch +import torchvision.transforms.functional as tf +from utils.loss_utils import ssim +from lpipsPyTorch import lpips +import json +from tqdm import tqdm +from utils.image_utils import psnr +from argparse import ArgumentParser + +def readImages(renders_dir, gt_dir): + renders = [] + gts = [] + image_names = [] + for fname in os.listdir(renders_dir): + render = Image.open(renders_dir / fname) + gt = Image.open(gt_dir / fname) + renders.append(tf.to_tensor(render).unsqueeze(0)[:, :3, :, :].cuda()) + gts.append(tf.to_tensor(gt).unsqueeze(0)[:, :3, :, :].cuda()) + image_names.append(fname) + return renders, gts, image_names + +def evaluate(model_paths): + + full_dict = {} + per_view_dict = {} + full_dict_polytopeonly = {} + per_view_dict_polytopeonly = {} + print("") + + for scene_dir in model_paths: + try: + print("Scene:", scene_dir) + full_dict[scene_dir] = {} + per_view_dict[scene_dir] = {} + full_dict_polytopeonly[scene_dir] = {} + per_view_dict_polytopeonly[scene_dir] = {} + + test_dir = Path(scene_dir) / "test" + + for method in os.listdir(test_dir): + print("Method:", method) + + full_dict[scene_dir][method] = {} + per_view_dict[scene_dir][method] = {} + full_dict_polytopeonly[scene_dir][method] = {} + per_view_dict_polytopeonly[scene_dir][method] = {} + + method_dir = test_dir / method + gt_dir = method_dir/ "gt" + renders_dir = method_dir / "renders" + renders, gts, image_names = readImages(renders_dir, gt_dir) + + ssims = [] + psnrs = [] + lpipss = [] + + for idx in tqdm(range(len(renders)), desc="Metric evaluation progress"): + ssims.append(ssim(renders[idx], gts[idx])) + psnrs.append(psnr(renders[idx], gts[idx])) + lpipss.append(lpips(renders[idx], gts[idx], net_type='vgg')) + + print(" SSIM : {:>12.7f}".format(torch.tensor(ssims).mean(), ".5")) + print(" PSNR : {:>12.7f}".format(torch.tensor(psnrs).mean(), ".5")) + print(" LPIPS: {:>12.7f}".format(torch.tensor(lpipss).mean(), ".5")) + print("") + + full_dict[scene_dir][method].update({"SSIM": torch.tensor(ssims).mean().item(), + "PSNR": torch.tensor(psnrs).mean().item(), + "LPIPS": torch.tensor(lpipss).mean().item()}) + per_view_dict[scene_dir][method].update({"SSIM": {name: ssim for ssim, name in zip(torch.tensor(ssims).tolist(), image_names)}, + "PSNR": {name: psnr for psnr, name in zip(torch.tensor(psnrs).tolist(), image_names)}, + "LPIPS": {name: lp for lp, name in zip(torch.tensor(lpipss).tolist(), image_names)}}) + + with open(scene_dir + "/results.json", 'w') as fp: + json.dump(full_dict[scene_dir], fp, indent=True) + with open(scene_dir + "/per_view.json", 'w') as fp: + json.dump(per_view_dict[scene_dir], fp, indent=True) + except: + print("Unable to compute metrics for model", scene_dir) + +if __name__ == "__main__": + device = torch.device("cuda:0") + torch.cuda.set_device(device) + + # Set up command line argument parser + parser = ArgumentParser(description="Training script parameters") + parser.add_argument('--model_paths', '-m', required=True, nargs="+", type=str, default=[]) + args = parser.parse_args() + evaluate(args.model_paths) diff --git a/submodules/gaussian-splatting/render.py b/submodules/gaussian-splatting/render.py new file mode 100644 index 0000000000000000000000000000000000000000..244cb75312c40aa5ab5f1d136b90d182eaf670a5 --- /dev/null +++ b/submodules/gaussian-splatting/render.py @@ -0,0 +1,77 @@ +# +# Copyright (C) 2023, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact george.drettakis@inria.fr +# + +import torch +from scene import Scene +import os +from tqdm import tqdm +from os import makedirs +from gaussian_renderer import render +import torchvision +from utils.general_utils import safe_state +from argparse import ArgumentParser +from arguments import ModelParams, PipelineParams, get_combined_args +from gaussian_renderer import GaussianModel +try: + from diff_gaussian_rasterization import SparseGaussianAdam + SPARSE_ADAM_AVAILABLE = True +except: + SPARSE_ADAM_AVAILABLE = False + + +def render_set(model_path, name, iteration, views, gaussians, pipeline, background, train_test_exp, separate_sh): + render_path = os.path.join(model_path, name, "ours_{}".format(iteration), "renders") + gts_path = os.path.join(model_path, name, "ours_{}".format(iteration), "gt") + + makedirs(render_path, exist_ok=True) + makedirs(gts_path, exist_ok=True) + + for idx, view in enumerate(tqdm(views, desc="Rendering progress")): + rendering = render(view, gaussians, pipeline, background, use_trained_exp=train_test_exp, separate_sh=separate_sh)["render"] + gt = view.original_image[0:3, :, :] + + if args.train_test_exp: + rendering = rendering[..., rendering.shape[-1] // 2:] + gt = gt[..., gt.shape[-1] // 2:] + + torchvision.utils.save_image(rendering, os.path.join(render_path, '{0:05d}'.format(idx) + ".png")) + torchvision.utils.save_image(gt, os.path.join(gts_path, '{0:05d}'.format(idx) + ".png")) + +def render_sets(dataset : ModelParams, iteration : int, pipeline : PipelineParams, skip_train : bool, skip_test : bool, separate_sh: bool): + with torch.no_grad(): + gaussians = GaussianModel(dataset.sh_degree) + scene = Scene(dataset, gaussians, load_iteration=iteration, shuffle=False) + + bg_color = [1,1,1] if dataset.white_background else [0, 0, 0] + background = torch.tensor(bg_color, dtype=torch.float32, device="cuda") + + if not skip_train: + render_set(dataset.model_path, "train", scene.loaded_iter, scene.getTrainCameras(), gaussians, pipeline, background, dataset.train_test_exp, separate_sh) + + if not skip_test: + render_set(dataset.model_path, "test", scene.loaded_iter, scene.getTestCameras(), gaussians, pipeline, background, dataset.train_test_exp, separate_sh) + +if __name__ == "__main__": + # Set up command line argument parser + parser = ArgumentParser(description="Testing script parameters") + model = ModelParams(parser, sentinel=True) + pipeline = PipelineParams(parser) + parser.add_argument("--iteration", default=-1, type=int) + parser.add_argument("--skip_train", action="store_true") + parser.add_argument("--skip_test", action="store_true") + parser.add_argument("--quiet", action="store_true") + args = get_combined_args(parser) + print("Rendering " + args.model_path) + + # Initialize system state (RNG) + safe_state(args.quiet) + + render_sets(model.extract(args), args.iteration, pipeline.extract(args), args.skip_train, args.skip_test, SPARSE_ADAM_AVAILABLE) \ No newline at end of file diff --git a/submodules/gaussian-splatting/results.md b/submodules/gaussian-splatting/results.md new file mode 100644 index 0000000000000000000000000000000000000000..571cde3687bf857f0d7645f3fe70193b22283519 --- /dev/null +++ b/submodules/gaussian-splatting/results.md @@ -0,0 +1,90 @@ +# Evaluations +We evaluated the impact of the features we added on MipNeRF360, Tanks&Temples and Deep Blending datasets. [Exposure Compensation](#exposure-compensation) is evaluated separately. Note that [Default rasterizer](#default-rasterizer) refers to the original [3dgs rasterizer](https://github.com/graphdeco-inria/diff-gaussian-rasterization/tree/9c5c2028f6fbee2be239bc4c9421ff894fe4fbe0) and [Accelerated rasterizer](#accelerated-rasterizer) refers to the [taming-3dgs rasterizer](https://github.com/graphdeco-inria/diff-gaussian-rasterization/tree/3dgs_accel). + +## Default rasterizer + +### PSNR + +![all results PSNR](assets/charts/base_PSNR.png) + +***DR**:depth regularization, **AA**:antialiasing* + +
+ +![nodepth/depth](assets/depth_comparison.png) + +### SSIM +![all results SSIM](assets/charts/base_SSIM.png) + +***DR**:depth regularization, **AA**:antialiasing* + +### LPIPS +![all results LPIPS](assets/charts/base_LPIPS.png) + +*lower is better, **DR**:depth regularization, **AA**:antialiasing* + +## Accelerated rasterizer + +### Default optimizer + +These numbers were obtained using the accelerated rasterizer and `--optimizer_type default` when training. + +#### PSNR +![all results PSNR](assets/charts/accel_default_PSNR.png) + +***DR**:depth regularization, **AA**:antialiasing* + +#### SSIM +![all results SSIM](assets/charts/accel_default_SSIM.png) + +***DR**:depth regularization, **AA**:antialiasing* + +#### LPIPS +![all results LPIPS](assets/charts/accel_default_LPIPS.png) + +*lower is better, **DR**:depth regularization, **AA**:antialiasing* + +### Sparse Adam optimizer + +These numbers were obtained using the accelerated rasterizer and `--optimizer_type sparse_adam` when training. + +#### PSNR +![all results PSNR](assets/charts/accel_sparse_adam_PSNR.png) + +***DR**:depth regularization, **AA**:antialiasing* + +#### SSIM +![all results SSIM](assets/charts/accel_sparse_adam_SSIM.png) + +***DR**:depth regularization, **AA**:antialiasing* + +#### LPIPS +![all results LPIPS](assets/charts/accel_sparse_adam_LPIPS.png) + +*lower is better, **DR**:depth regularization, **AA**:antialiasing* + +## Exposure compensation + +We account for exposure variations between images by optimizing a 3x4 affine transform for each image. During training, this transform is applied to the colour of the rendered images. +The exposure compensation is designed to improve the inputs' coherence during training and is not applied during real-time navigation. +Enabling the `--train_test_exp` option includes the left half of the test images in the training set, using only their right halves for testing, following the same testing methodology as NeRF-W and Mega-NeRF. This allows us to optimize the exposure affine transform for test views. However, since this setting alters the train/test splits, the resulting metrics are not comparable to those from models trained without it. Here we provide results with `--train_test_exp`, with and without exposure compensation. + +### PSNR + +![exposures_psnr](/assets/charts/exposure_PSNR.png) + +### SSIM + +![exposures_ssim](/assets/charts/exposure_SSIM.png) + +### LPIPS + +*Lower is better.* +![exposures_lpips](/assets/charts/exposure_LPIPS.png) + +![noexposure/exposure](assets/Exposure_comparison.png) + +## Training times comparisons + +We report the training times with all features enabled using the original 3dgs rasterizer *(baseline)* and the accelerated rasterizer with default optimizer then sparse adam. +![Training-times](assets/charts/timings.png) diff --git a/submodules/gaussian-splatting/scene/__init__.py b/submodules/gaussian-splatting/scene/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..8091614091a80cbb1bb448d0104454b2deb88231 --- /dev/null +++ b/submodules/gaussian-splatting/scene/__init__.py @@ -0,0 +1,100 @@ +# +# Copyright (C) 2023, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact george.drettakis@inria.fr +# + +import os +import random +import json +from utils.system_utils import searchForMaxIteration +from scene.dataset_readers import sceneLoadTypeCallbacks +from scene.gaussian_model import GaussianModel +from arguments import ModelParams +from utils.camera_utils import cameraList_from_camInfos, camera_to_JSON + +class Scene: + + gaussians : GaussianModel + + def __init__(self, args : ModelParams, gaussians : GaussianModel, load_iteration=None, shuffle=True, resolution_scales=[1.0]): + """b + :param path: Path to colmap scene main folder. + """ + self.model_path = args.model_path + self.loaded_iter = None + self.gaussians = gaussians + + if load_iteration: + if load_iteration == -1: + self.loaded_iter = searchForMaxIteration(os.path.join(self.model_path, "point_cloud")) + else: + self.loaded_iter = load_iteration + print("Loading trained model at iteration {}".format(self.loaded_iter)) + + self.train_cameras = {} + self.test_cameras = {} + + if os.path.exists(os.path.join(args.source_path, "sparse")): + scene_info = sceneLoadTypeCallbacks["Colmap"](args.source_path, args.images, args.depths, args.eval, args.train_test_exp) + elif os.path.exists(os.path.join(args.source_path, "transforms_train.json")): + print("Found transforms_train.json file, assuming Blender data set!") + scene_info = sceneLoadTypeCallbacks["Blender"](args.source_path, args.white_background, args.depths, args.eval) + else: + assert False, "Could not recognize scene type!" + + if not self.loaded_iter: + with open(scene_info.ply_path, 'rb') as src_file, open(os.path.join(self.model_path, "input.ply") , 'wb') as dest_file: + dest_file.write(src_file.read()) + json_cams = [] + camlist = [] + if scene_info.test_cameras: + camlist.extend(scene_info.test_cameras) + if scene_info.train_cameras: + camlist.extend(scene_info.train_cameras) + for id, cam in enumerate(camlist): + json_cams.append(camera_to_JSON(id, cam)) + with open(os.path.join(self.model_path, "cameras.json"), 'w') as file: + json.dump(json_cams, file) + + if shuffle: + random.shuffle(scene_info.train_cameras) # Multi-res consistent random shuffling + random.shuffle(scene_info.test_cameras) # Multi-res consistent random shuffling + + self.cameras_extent = scene_info.nerf_normalization["radius"] + + for resolution_scale in resolution_scales: + print("Loading Training Cameras") + self.train_cameras[resolution_scale] = cameraList_from_camInfos(scene_info.train_cameras, resolution_scale, args, scene_info.is_nerf_synthetic, False) + print("Loading Test Cameras") + self.test_cameras[resolution_scale] = cameraList_from_camInfos(scene_info.test_cameras, resolution_scale, args, scene_info.is_nerf_synthetic, True) + + if self.loaded_iter: + self.gaussians.load_ply(os.path.join(self.model_path, + "point_cloud", + "iteration_" + str(self.loaded_iter), + "point_cloud.ply"), args.train_test_exp) + else: + self.gaussians.create_from_pcd(scene_info.point_cloud, scene_info.train_cameras, self.cameras_extent) + + def save(self, iteration): + point_cloud_path = os.path.join(self.model_path, "point_cloud/iteration_{}".format(iteration)) + self.gaussians.save_ply(os.path.join(point_cloud_path, "point_cloud.ply")) + exposure_dict = { + image_name: self.gaussians.get_exposure_from_name(image_name).detach().cpu().numpy().tolist() + for image_name in self.gaussians.exposure_mapping + } + + with open(os.path.join(self.model_path, "exposure.json"), "w") as f: + json.dump(exposure_dict, f, indent=2) + + def getTrainCameras(self, scale=1.0): + return self.train_cameras[scale] + + def getTestCameras(self, scale=1.0): + return self.test_cameras[scale] diff --git a/submodules/gaussian-splatting/scene/cameras.py b/submodules/gaussian-splatting/scene/cameras.py new file mode 100644 index 0000000000000000000000000000000000000000..63161b90c195527bd12a3a97bb0eb4c7573da380 --- /dev/null +++ b/submodules/gaussian-splatting/scene/cameras.py @@ -0,0 +1,103 @@ +# +# Copyright (C) 2023, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact george.drettakis@inria.fr +# + +import torch +from torch import nn +import numpy as np +from utils.graphics_utils import getWorld2View2, getProjectionMatrix +from utils.general_utils import PILtoTorch +import cv2 + +class Camera(nn.Module): + def __init__(self, resolution, colmap_id, R, T, FoVx, FoVy, depth_params, image, invdepthmap, + image_name, uid, + trans=np.array([0.0, 0.0, 0.0]), scale=1.0, data_device = "cuda", + train_test_exp = False, is_test_dataset = False, is_test_view = False + ): + super(Camera, self).__init__() + + self.uid = uid + self.colmap_id = colmap_id + self.R = R + self.T = T + self.FoVx = FoVx + self.FoVy = FoVy + self.image_name = image_name + + try: + self.data_device = torch.device(data_device) + except Exception as e: + print(e) + print(f"[Warning] Custom device {data_device} failed, fallback to default cuda device" ) + self.data_device = torch.device("cuda") + + resized_image_rgb = PILtoTorch(image, resolution) + gt_image = resized_image_rgb[:3, ...] + self.alpha_mask = None + if resized_image_rgb.shape[0] == 4: + self.alpha_mask = resized_image_rgb[3:4, ...].to(self.data_device) + else: + self.alpha_mask = torch.ones_like(resized_image_rgb[0:1, ...].to(self.data_device)) + + if train_test_exp and is_test_view: + if is_test_dataset: + self.alpha_mask[..., :self.alpha_mask.shape[-1] // 2] = 0 + else: + self.alpha_mask[..., self.alpha_mask.shape[-1] // 2:] = 0 + + self.original_image = gt_image.clamp(0.0, 1.0).to(self.data_device) + self.image_width = self.original_image.shape[2] + self.image_height = self.original_image.shape[1] + + self.invdepthmap = None + self.depth_reliable = False + if invdepthmap is not None: + self.depth_mask = torch.ones_like(self.alpha_mask) + self.invdepthmap = cv2.resize(invdepthmap, resolution) + self.invdepthmap[self.invdepthmap < 0] = 0 + self.depth_reliable = True + + if depth_params is not None: + if depth_params["scale"] < 0.2 * depth_params["med_scale"] or depth_params["scale"] > 5 * depth_params["med_scale"]: + self.depth_reliable = False + self.depth_mask *= 0 + + if depth_params["scale"] > 0: + self.invdepthmap = self.invdepthmap * depth_params["scale"] + depth_params["offset"] + + if self.invdepthmap.ndim != 2: + self.invdepthmap = self.invdepthmap[..., 0] + self.invdepthmap = torch.from_numpy(self.invdepthmap[None]).to(self.data_device) + + self.zfar = 100.0 + self.znear = 0.01 + + self.trans = trans + self.scale = scale + + self.world_view_transform = torch.tensor(getWorld2View2(R, T, trans, scale)).transpose(0, 1).cuda() + self.projection_matrix = getProjectionMatrix(znear=self.znear, zfar=self.zfar, fovX=self.FoVx, fovY=self.FoVy).transpose(0,1).cuda() + self.full_proj_transform = (self.world_view_transform.unsqueeze(0).bmm(self.projection_matrix.unsqueeze(0))).squeeze(0) + self.camera_center = self.world_view_transform.inverse()[3, :3] + +class MiniCam: + def __init__(self, width, height, fovy, fovx, znear, zfar, world_view_transform, full_proj_transform): + self.image_width = width + self.image_height = height + self.FoVy = fovy + self.FoVx = fovx + self.znear = znear + self.zfar = zfar + self.world_view_transform = world_view_transform + self.full_proj_transform = full_proj_transform + view_inv = torch.inverse(self.world_view_transform) + self.camera_center = view_inv[3][:3] + diff --git a/submodules/gaussian-splatting/scene/colmap_loader.py b/submodules/gaussian-splatting/scene/colmap_loader.py new file mode 100644 index 0000000000000000000000000000000000000000..8f6fba6a9c961f52c88780ecb44d7821b4cb73ee --- /dev/null +++ b/submodules/gaussian-splatting/scene/colmap_loader.py @@ -0,0 +1,294 @@ +# +# Copyright (C) 2023, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact george.drettakis@inria.fr +# + +import numpy as np +import collections +import struct + +CameraModel = collections.namedtuple( + "CameraModel", ["model_id", "model_name", "num_params"]) +Camera = collections.namedtuple( + "Camera", ["id", "model", "width", "height", "params"]) +BaseImage = collections.namedtuple( + "Image", ["id", "qvec", "tvec", "camera_id", "name", "xys", "point3D_ids"]) +Point3D = collections.namedtuple( + "Point3D", ["id", "xyz", "rgb", "error", "image_ids", "point2D_idxs"]) +CAMERA_MODELS = { + CameraModel(model_id=0, model_name="SIMPLE_PINHOLE", num_params=3), + CameraModel(model_id=1, model_name="PINHOLE", num_params=4), + CameraModel(model_id=2, model_name="SIMPLE_RADIAL", num_params=4), + CameraModel(model_id=3, model_name="RADIAL", num_params=5), + CameraModel(model_id=4, model_name="OPENCV", num_params=8), + CameraModel(model_id=5, model_name="OPENCV_FISHEYE", num_params=8), + CameraModel(model_id=6, model_name="FULL_OPENCV", num_params=12), + CameraModel(model_id=7, model_name="FOV", num_params=5), + CameraModel(model_id=8, model_name="SIMPLE_RADIAL_FISHEYE", num_params=4), + CameraModel(model_id=9, model_name="RADIAL_FISHEYE", num_params=5), + CameraModel(model_id=10, model_name="THIN_PRISM_FISHEYE", num_params=12) +} +CAMERA_MODEL_IDS = dict([(camera_model.model_id, camera_model) + for camera_model in CAMERA_MODELS]) +CAMERA_MODEL_NAMES = dict([(camera_model.model_name, camera_model) + for camera_model in CAMERA_MODELS]) + + +def qvec2rotmat(qvec): + return np.array([ + [1 - 2 * qvec[2]**2 - 2 * qvec[3]**2, + 2 * qvec[1] * qvec[2] - 2 * qvec[0] * qvec[3], + 2 * qvec[3] * qvec[1] + 2 * qvec[0] * qvec[2]], + [2 * qvec[1] * qvec[2] + 2 * qvec[0] * qvec[3], + 1 - 2 * qvec[1]**2 - 2 * qvec[3]**2, + 2 * qvec[2] * qvec[3] - 2 * qvec[0] * qvec[1]], + [2 * qvec[3] * qvec[1] - 2 * qvec[0] * qvec[2], + 2 * qvec[2] * qvec[3] + 2 * qvec[0] * qvec[1], + 1 - 2 * qvec[1]**2 - 2 * qvec[2]**2]]) + +def rotmat2qvec(R): + Rxx, Ryx, Rzx, Rxy, Ryy, Rzy, Rxz, Ryz, Rzz = R.flat + K = np.array([ + [Rxx - Ryy - Rzz, 0, 0, 0], + [Ryx + Rxy, Ryy - Rxx - Rzz, 0, 0], + [Rzx + Rxz, Rzy + Ryz, Rzz - Rxx - Ryy, 0], + [Ryz - Rzy, Rzx - Rxz, Rxy - Ryx, Rxx + Ryy + Rzz]]) / 3.0 + eigvals, eigvecs = np.linalg.eigh(K) + qvec = eigvecs[[3, 0, 1, 2], np.argmax(eigvals)] + if qvec[0] < 0: + qvec *= -1 + return qvec + +class Image(BaseImage): + def qvec2rotmat(self): + return qvec2rotmat(self.qvec) + +def read_next_bytes(fid, num_bytes, format_char_sequence, endian_character="<"): + """Read and unpack the next bytes from a binary file. + :param fid: + :param num_bytes: Sum of combination of {2, 4, 8}, e.g. 2, 6, 16, 30, etc. + :param format_char_sequence: List of {c, e, f, d, h, H, i, I, l, L, q, Q}. + :param endian_character: Any of {@, =, <, >, !} + :return: Tuple of read and unpacked values. + """ + data = fid.read(num_bytes) + return struct.unpack(endian_character + format_char_sequence, data) + +def read_points3D_text(path): + """ + see: src/base/reconstruction.cc + void Reconstruction::ReadPoints3DText(const std::string& path) + void Reconstruction::WritePoints3DText(const std::string& path) + """ + xyzs = None + rgbs = None + errors = None + num_points = 0 + with open(path, "r") as fid: + while True: + line = fid.readline() + if not line: + break + line = line.strip() + if len(line) > 0 and line[0] != "#": + num_points += 1 + + + xyzs = np.empty((num_points, 3)) + rgbs = np.empty((num_points, 3)) + errors = np.empty((num_points, 1)) + count = 0 + with open(path, "r") as fid: + while True: + line = fid.readline() + if not line: + break + line = line.strip() + if len(line) > 0 and line[0] != "#": + elems = line.split() + xyz = np.array(tuple(map(float, elems[1:4]))) + rgb = np.array(tuple(map(int, elems[4:7]))) + error = np.array(float(elems[7])) + xyzs[count] = xyz + rgbs[count] = rgb + errors[count] = error + count += 1 + + return xyzs, rgbs, errors + +def read_points3D_binary(path_to_model_file): + """ + see: src/base/reconstruction.cc + void Reconstruction::ReadPoints3DBinary(const std::string& path) + void Reconstruction::WritePoints3DBinary(const std::string& path) + """ + + + with open(path_to_model_file, "rb") as fid: + num_points = read_next_bytes(fid, 8, "Q")[0] + + xyzs = np.empty((num_points, 3)) + rgbs = np.empty((num_points, 3)) + errors = np.empty((num_points, 1)) + + for p_id in range(num_points): + binary_point_line_properties = read_next_bytes( + fid, num_bytes=43, format_char_sequence="QdddBBBd") + xyz = np.array(binary_point_line_properties[1:4]) + rgb = np.array(binary_point_line_properties[4:7]) + error = np.array(binary_point_line_properties[7]) + track_length = read_next_bytes( + fid, num_bytes=8, format_char_sequence="Q")[0] + track_elems = read_next_bytes( + fid, num_bytes=8*track_length, + format_char_sequence="ii"*track_length) + xyzs[p_id] = xyz + rgbs[p_id] = rgb + errors[p_id] = error + return xyzs, rgbs, errors + +def read_intrinsics_text(path): + """ + Taken from https://github.com/colmap/colmap/blob/dev/scripts/python/read_write_model.py + """ + cameras = {} + with open(path, "r") as fid: + while True: + line = fid.readline() + if not line: + break + line = line.strip() + if len(line) > 0 and line[0] != "#": + elems = line.split() + camera_id = int(elems[0]) + model = elems[1] + assert model == "PINHOLE", "While the loader support other types, the rest of the code assumes PINHOLE" + width = int(elems[2]) + height = int(elems[3]) + params = np.array(tuple(map(float, elems[4:]))) + cameras[camera_id] = Camera(id=camera_id, model=model, + width=width, height=height, + params=params) + return cameras + +def read_extrinsics_binary(path_to_model_file): + """ + see: src/base/reconstruction.cc + void Reconstruction::ReadImagesBinary(const std::string& path) + void Reconstruction::WriteImagesBinary(const std::string& path) + """ + images = {} + with open(path_to_model_file, "rb") as fid: + num_reg_images = read_next_bytes(fid, 8, "Q")[0] + for _ in range(num_reg_images): + binary_image_properties = read_next_bytes( + fid, num_bytes=64, format_char_sequence="idddddddi") + image_id = binary_image_properties[0] + qvec = np.array(binary_image_properties[1:5]) + tvec = np.array(binary_image_properties[5:8]) + camera_id = binary_image_properties[8] + image_name = "" + current_char = read_next_bytes(fid, 1, "c")[0] + while current_char != b"\x00": # look for the ASCII 0 entry + image_name += current_char.decode("utf-8") + current_char = read_next_bytes(fid, 1, "c")[0] + num_points2D = read_next_bytes(fid, num_bytes=8, + format_char_sequence="Q")[0] + x_y_id_s = read_next_bytes(fid, num_bytes=24*num_points2D, + format_char_sequence="ddq"*num_points2D) + xys = np.column_stack([tuple(map(float, x_y_id_s[0::3])), + tuple(map(float, x_y_id_s[1::3]))]) + point3D_ids = np.array(tuple(map(int, x_y_id_s[2::3]))) + images[image_id] = Image( + id=image_id, qvec=qvec, tvec=tvec, + camera_id=camera_id, name=image_name, + xys=xys, point3D_ids=point3D_ids) + return images + + +def read_intrinsics_binary(path_to_model_file): + """ + see: src/base/reconstruction.cc + void Reconstruction::WriteCamerasBinary(const std::string& path) + void Reconstruction::ReadCamerasBinary(const std::string& path) + """ + cameras = {} + with open(path_to_model_file, "rb") as fid: + num_cameras = read_next_bytes(fid, 8, "Q")[0] + for _ in range(num_cameras): + camera_properties = read_next_bytes( + fid, num_bytes=24, format_char_sequence="iiQQ") + camera_id = camera_properties[0] + model_id = camera_properties[1] + model_name = CAMERA_MODEL_IDS[camera_properties[1]].model_name + width = camera_properties[2] + height = camera_properties[3] + num_params = CAMERA_MODEL_IDS[model_id].num_params + params = read_next_bytes(fid, num_bytes=8*num_params, + format_char_sequence="d"*num_params) + cameras[camera_id] = Camera(id=camera_id, + model=model_name, + width=width, + height=height, + params=np.array(params)) + assert len(cameras) == num_cameras + return cameras + + +def read_extrinsics_text(path): + """ + Taken from https://github.com/colmap/colmap/blob/dev/scripts/python/read_write_model.py + """ + images = {} + with open(path, "r") as fid: + while True: + line = fid.readline() + if not line: + break + line = line.strip() + if len(line) > 0 and line[0] != "#": + elems = line.split() + image_id = int(elems[0]) + qvec = np.array(tuple(map(float, elems[1:5]))) + tvec = np.array(tuple(map(float, elems[5:8]))) + camera_id = int(elems[8]) + image_name = elems[9] + elems = fid.readline().split() + xys = np.column_stack([tuple(map(float, elems[0::3])), + tuple(map(float, elems[1::3]))]) + point3D_ids = np.array(tuple(map(int, elems[2::3]))) + images[image_id] = Image( + id=image_id, qvec=qvec, tvec=tvec, + camera_id=camera_id, name=image_name, + xys=xys, point3D_ids=point3D_ids) + return images + + +def read_colmap_bin_array(path): + """ + Taken from https://github.com/colmap/colmap/blob/dev/scripts/python/read_dense.py + + :param path: path to the colmap binary file. + :return: nd array with the floating point values in the value + """ + with open(path, "rb") as fid: + width, height, channels = np.genfromtxt(fid, delimiter="&", max_rows=1, + usecols=(0, 1, 2), dtype=int) + fid.seek(0) + num_delimiter = 0 + byte = fid.read(1) + while True: + if byte == b"&": + num_delimiter += 1 + if num_delimiter >= 3: + break + byte = fid.read(1) + array = np.fromfile(fid, np.float32) + array = array.reshape((width, height, channels), order="F") + return np.transpose(array, (1, 0, 2)).squeeze() diff --git a/submodules/gaussian-splatting/scene/dataset_readers.py b/submodules/gaussian-splatting/scene/dataset_readers.py new file mode 100644 index 0000000000000000000000000000000000000000..493d98dc8eb43a4a315abe93b77218d007463c5d --- /dev/null +++ b/submodules/gaussian-splatting/scene/dataset_readers.py @@ -0,0 +1,315 @@ +# +# Copyright (C) 2023, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact george.drettakis@inria.fr +# + +import os +import sys +from PIL import Image +from typing import NamedTuple +from scene.colmap_loader import read_extrinsics_text, read_intrinsics_text, qvec2rotmat, \ + read_extrinsics_binary, read_intrinsics_binary, read_points3D_binary, read_points3D_text +from utils.graphics_utils import getWorld2View2, focal2fov, fov2focal +import numpy as np +import json +from pathlib import Path +from plyfile import PlyData, PlyElement +from utils.sh_utils import SH2RGB +from scene.gaussian_model import BasicPointCloud + +class CameraInfo(NamedTuple): + uid: int + R: np.array + T: np.array + FovY: np.array + FovX: np.array + depth_params: dict + image_path: str + image_name: str + depth_path: str + width: int + height: int + is_test: bool + +class SceneInfo(NamedTuple): + point_cloud: BasicPointCloud + train_cameras: list + test_cameras: list + nerf_normalization: dict + ply_path: str + is_nerf_synthetic: bool + +def getNerfppNorm(cam_info): + def get_center_and_diag(cam_centers): + cam_centers = np.hstack(cam_centers) + avg_cam_center = np.mean(cam_centers, axis=1, keepdims=True) + center = avg_cam_center + dist = np.linalg.norm(cam_centers - center, axis=0, keepdims=True) + diagonal = np.max(dist) + return center.flatten(), diagonal + + cam_centers = [] + + for cam in cam_info: + W2C = getWorld2View2(cam.R, cam.T) + C2W = np.linalg.inv(W2C) + cam_centers.append(C2W[:3, 3:4]) + + center, diagonal = get_center_and_diag(cam_centers) + radius = diagonal * 1.1 + + translate = -center + + return {"translate": translate, "radius": radius} + +def readColmapCameras(cam_extrinsics, cam_intrinsics, depths_params, images_folder, depths_folder, test_cam_names_list): + cam_infos = [] + for idx, key in enumerate(cam_extrinsics): + sys.stdout.write('\r') + # the exact output you're looking for: + sys.stdout.write("Reading camera {}/{}".format(idx+1, len(cam_extrinsics))) + sys.stdout.flush() + + extr = cam_extrinsics[key] + intr = cam_intrinsics[extr.camera_id] + height = intr.height + width = intr.width + + uid = intr.id + R = np.transpose(qvec2rotmat(extr.qvec)) + T = np.array(extr.tvec) + + if intr.model=="SIMPLE_PINHOLE": + focal_length_x = intr.params[0] + FovY = focal2fov(focal_length_x, height) + FovX = focal2fov(focal_length_x, width) + elif intr.model=="PINHOLE": + focal_length_x = intr.params[0] + focal_length_y = intr.params[1] + FovY = focal2fov(focal_length_y, height) + FovX = focal2fov(focal_length_x, width) + else: + assert False, "Colmap camera model not handled: only undistorted datasets (PINHOLE or SIMPLE_PINHOLE cameras) supported!" + + n_remove = len(extr.name.split('.')[-1]) + 1 + depth_params = None + if depths_params is not None: + try: + depth_params = depths_params[extr.name[:-n_remove]] + except: + print("\n", key, "not found in depths_params") + + image_path = os.path.join(images_folder, extr.name) + image_name = extr.name + depth_path = os.path.join(depths_folder, f"{extr.name[:-n_remove]}.png") if depths_folder != "" else "" + + cam_info = CameraInfo(uid=uid, R=R, T=T, FovY=FovY, FovX=FovX, depth_params=depth_params, + image_path=image_path, image_name=image_name, depth_path=depth_path, + width=width, height=height, is_test=image_name in test_cam_names_list) + cam_infos.append(cam_info) + + sys.stdout.write('\n') + return cam_infos + +def fetchPly(path): + plydata = PlyData.read(path) + vertices = plydata['vertex'] + positions = np.vstack([vertices['x'], vertices['y'], vertices['z']]).T + colors = np.vstack([vertices['red'], vertices['green'], vertices['blue']]).T / 255.0 + normals = np.vstack([vertices['nx'], vertices['ny'], vertices['nz']]).T + return BasicPointCloud(points=positions, colors=colors, normals=normals) + +def storePly(path, xyz, rgb): + # Define the dtype for the structured array + dtype = [('x', 'f4'), ('y', 'f4'), ('z', 'f4'), + ('nx', 'f4'), ('ny', 'f4'), ('nz', 'f4'), + ('red', 'u1'), ('green', 'u1'), ('blue', 'u1')] + + normals = np.zeros_like(xyz) + + elements = np.empty(xyz.shape[0], dtype=dtype) + attributes = np.concatenate((xyz, normals, rgb), axis=1) + elements[:] = list(map(tuple, attributes)) + + # Create the PlyData object and write to file + vertex_element = PlyElement.describe(elements, 'vertex') + ply_data = PlyData([vertex_element]) + ply_data.write(path) + +def readColmapSceneInfo(path, images, depths, eval, train_test_exp, llffhold=8): + try: + cameras_extrinsic_file = os.path.join(path, "sparse/0", "images.bin") + cameras_intrinsic_file = os.path.join(path, "sparse/0", "cameras.bin") + cam_extrinsics = read_extrinsics_binary(cameras_extrinsic_file) + cam_intrinsics = read_intrinsics_binary(cameras_intrinsic_file) + except: + cameras_extrinsic_file = os.path.join(path, "sparse/0", "images.txt") + cameras_intrinsic_file = os.path.join(path, "sparse/0", "cameras.txt") + cam_extrinsics = read_extrinsics_text(cameras_extrinsic_file) + cam_intrinsics = read_intrinsics_text(cameras_intrinsic_file) + + depth_params_file = os.path.join(path, "sparse/0", "depth_params.json") + ## if depth_params_file isnt there AND depths file is here -> throw error + depths_params = None + if depths != "": + try: + with open(depth_params_file, "r") as f: + depths_params = json.load(f) + all_scales = np.array([depths_params[key]["scale"] for key in depths_params]) + if (all_scales > 0).sum(): + med_scale = np.median(all_scales[all_scales > 0]) + else: + med_scale = 0 + for key in depths_params: + depths_params[key]["med_scale"] = med_scale + + except FileNotFoundError: + print(f"Error: depth_params.json file not found at path '{depth_params_file}'.") + sys.exit(1) + except Exception as e: + print(f"An unexpected error occurred when trying to open depth_params.json file: {e}") + sys.exit(1) + + if eval: + if "360" in path: + llffhold = 8 + if llffhold: + print("------------LLFF HOLD-------------") + cam_names = [cam_extrinsics[cam_id].name for cam_id in cam_extrinsics] + cam_names = sorted(cam_names) + test_cam_names_list = [name for idx, name in enumerate(cam_names) if idx % llffhold == 0] + else: + with open(os.path.join(path, "sparse/0", "test.txt"), 'r') as file: + test_cam_names_list = [line.strip() for line in file] + else: + test_cam_names_list = [] + + reading_dir = "images" if images == None else images + cam_infos_unsorted = readColmapCameras( + cam_extrinsics=cam_extrinsics, cam_intrinsics=cam_intrinsics, depths_params=depths_params, + images_folder=os.path.join(path, reading_dir), + depths_folder=os.path.join(path, depths) if depths != "" else "", test_cam_names_list=test_cam_names_list) + cam_infos = sorted(cam_infos_unsorted.copy(), key = lambda x : x.image_name) + + train_cam_infos = [c for c in cam_infos if train_test_exp or not c.is_test] + test_cam_infos = [c for c in cam_infos if c.is_test] + + nerf_normalization = getNerfppNorm(train_cam_infos) + + ply_path = os.path.join(path, "sparse/0/points3D.ply") + bin_path = os.path.join(path, "sparse/0/points3D.bin") + txt_path = os.path.join(path, "sparse/0/points3D.txt") + if not os.path.exists(ply_path): + print("Converting point3d.bin to .ply, will happen only the first time you open the scene.") + try: + xyz, rgb, _ = read_points3D_binary(bin_path) + except: + xyz, rgb, _ = read_points3D_text(txt_path) + storePly(ply_path, xyz, rgb) + try: + pcd = fetchPly(ply_path) + except: + pcd = None + + scene_info = SceneInfo(point_cloud=pcd, + train_cameras=train_cam_infos, + test_cameras=test_cam_infos, + nerf_normalization=nerf_normalization, + ply_path=ply_path, + is_nerf_synthetic=False) + return scene_info + +def readCamerasFromTransforms(path, transformsfile, depths_folder, white_background, is_test, extension=".png"): + cam_infos = [] + + with open(os.path.join(path, transformsfile)) as json_file: + contents = json.load(json_file) + fovx = contents["camera_angle_x"] + + frames = contents["frames"] + for idx, frame in enumerate(frames): + cam_name = os.path.join(path, frame["file_path"] + extension) + + # NeRF 'transform_matrix' is a camera-to-world transform + c2w = np.array(frame["transform_matrix"]) + # change from OpenGL/Blender camera axes (Y up, Z back) to COLMAP (Y down, Z forward) + c2w[:3, 1:3] *= -1 + + # get the world-to-camera transform and set R, T + w2c = np.linalg.inv(c2w) + R = np.transpose(w2c[:3,:3]) # R is stored transposed due to 'glm' in CUDA code + T = w2c[:3, 3] + + image_path = os.path.join(path, cam_name) + image_name = Path(cam_name).stem + image = Image.open(image_path) + + im_data = np.array(image.convert("RGBA")) + + bg = np.array([1,1,1]) if white_background else np.array([0, 0, 0]) + + norm_data = im_data / 255.0 + arr = norm_data[:,:,:3] * norm_data[:, :, 3:4] + bg * (1 - norm_data[:, :, 3:4]) + image = Image.fromarray(np.array(arr*255.0, dtype=np.byte), "RGB") + + fovy = focal2fov(fov2focal(fovx, image.size[0]), image.size[1]) + FovY = fovy + FovX = fovx + + depth_path = os.path.join(depths_folder, f"{image_name}.png") if depths_folder != "" else "" + + cam_infos.append(CameraInfo(uid=idx, R=R, T=T, FovY=FovY, FovX=FovX, + image_path=image_path, image_name=image_name, + width=image.size[0], height=image.size[1], depth_path=depth_path, depth_params=None, is_test=is_test)) + + return cam_infos + +def readNerfSyntheticInfo(path, white_background, depths, eval, extension=".png"): + + depths_folder=os.path.join(path, depths) if depths != "" else "" + print("Reading Training Transforms") + train_cam_infos = readCamerasFromTransforms(path, "transforms_train.json", depths_folder, white_background, False, extension) + print("Reading Test Transforms") + test_cam_infos = readCamerasFromTransforms(path, "transforms_test.json", depths_folder, white_background, True, extension) + + if not eval: + train_cam_infos.extend(test_cam_infos) + test_cam_infos = [] + + nerf_normalization = getNerfppNorm(train_cam_infos) + + ply_path = os.path.join(path, "points3d.ply") + if not os.path.exists(ply_path): + # Since this data set has no colmap data, we start with random points + num_pts = 100_000 + print(f"Generating random point cloud ({num_pts})...") + + # We create random points inside the bounds of the synthetic Blender scenes + xyz = np.random.random((num_pts, 3)) * 2.6 - 1.3 + shs = np.random.random((num_pts, 3)) / 255.0 + pcd = BasicPointCloud(points=xyz, colors=SH2RGB(shs), normals=np.zeros((num_pts, 3))) + + storePly(ply_path, xyz, SH2RGB(shs) * 255) + try: + pcd = fetchPly(ply_path) + except: + pcd = None + + scene_info = SceneInfo(point_cloud=pcd, + train_cameras=train_cam_infos, + test_cameras=test_cam_infos, + nerf_normalization=nerf_normalization, + ply_path=ply_path, + is_nerf_synthetic=True) + return scene_info + +sceneLoadTypeCallbacks = { + "Colmap": readColmapSceneInfo, + "Blender" : readNerfSyntheticInfo +} \ No newline at end of file diff --git a/submodules/gaussian-splatting/scene/gaussian_model.py b/submodules/gaussian-splatting/scene/gaussian_model.py new file mode 100644 index 0000000000000000000000000000000000000000..12e0773cbe3a03909316bd99711071371134885c --- /dev/null +++ b/submodules/gaussian-splatting/scene/gaussian_model.py @@ -0,0 +1,480 @@ +# +# Copyright (C) 2023, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact george.drettakis@inria.fr +# + +import torch +import numpy as np +from utils.general_utils import inverse_sigmoid, get_expon_lr_func, build_rotation +from torch import nn +import os +import json +from utils.system_utils import mkdir_p +from plyfile import PlyData, PlyElement +from utils.sh_utils import RGB2SH +from utils.graphics_utils import BasicPointCloud +from utils.general_utils import strip_symmetric, build_scaling_rotation +from scipy.spatial import KDTree +import torch + +def distCUDA2(points): + points_np = points.detach().cpu().float().numpy() + dists, inds = KDTree(points_np).query(points_np, k=4) + meanDists = (dists[:, 1:] ** 2).mean(1) + + return torch.tensor(meanDists, dtype=points.dtype, device=points.device) + +try: + from diff_gaussian_rasterization import SparseGaussianAdam +except: + pass + +class GaussianModel: + + def setup_functions(self): + def build_covariance_from_scaling_rotation(scaling, scaling_modifier, rotation): + L = build_scaling_rotation(scaling_modifier * scaling, rotation) + actual_covariance = L @ L.transpose(1, 2) + symm = strip_symmetric(actual_covariance) + return symm + + self.scaling_activation = torch.exp + self.scaling_inverse_activation = torch.log + + self.covariance_activation = build_covariance_from_scaling_rotation + + self.opacity_activation = torch.sigmoid + self.inverse_opacity_activation = inverse_sigmoid + + self.rotation_activation = torch.nn.functional.normalize + + + def __init__(self, sh_degree, optimizer_type="default"): + self.active_sh_degree = 0 + self.optimizer_type = optimizer_type + self.max_sh_degree = sh_degree + self._xyz = torch.empty(0) + self._features_dc = torch.empty(0) + self._features_rest = torch.empty(0) + self._scaling = torch.empty(0) + self._rotation = torch.empty(0) + self._opacity = torch.empty(0) + self.max_radii2D = torch.empty(0) + self.xyz_gradient_accum = torch.empty(0) + self.denom = torch.empty(0) + self.optimizer = None + self.percent_dense = 0 + self.spatial_lr_scale = 0 + self.setup_functions() + + def capture(self): + return ( + self.active_sh_degree, + self._xyz, + self._features_dc, + self._features_rest, + self._scaling, + self._rotation, + self._opacity, + self.max_radii2D, + self.xyz_gradient_accum, + self.denom, + self.optimizer.state_dict(), + self.spatial_lr_scale, + ) + + def restore(self, model_args, training_args): + (self.active_sh_degree, + self._xyz, + self._features_dc, + self._features_rest, + self._scaling, + self._rotation, + self._opacity, + self.max_radii2D, + xyz_gradient_accum, + denom, + opt_dict, + self.spatial_lr_scale) = model_args + self.training_setup(training_args) + self.xyz_gradient_accum = xyz_gradient_accum + self.denom = denom + self.optimizer.load_state_dict(opt_dict) + + @property + def get_scaling(self): + return self.scaling_activation(self._scaling) + + @property + def get_rotation(self): + return self.rotation_activation(self._rotation) + + @property + def get_xyz(self): + return self._xyz + + @property + def get_features(self): + features_dc = self._features_dc + features_rest = self._features_rest + return torch.cat((features_dc, features_rest), dim=1) + + @property + def get_features_dc(self): + return self._features_dc + + @property + def get_features_rest(self): + return self._features_rest + + @property + def get_opacity(self): + return self.opacity_activation(self._opacity) + + @property + def get_exposure(self): + return self._exposure + + def get_exposure_from_name(self, image_name): + if self.pretrained_exposures is None: + return self._exposure[self.exposure_mapping[image_name]] + else: + return self.pretrained_exposures[image_name] + + def get_covariance(self, scaling_modifier = 1): + return self.covariance_activation(self.get_scaling, scaling_modifier, self._rotation) + + def oneupSHdegree(self): + if self.active_sh_degree < self.max_sh_degree: + self.active_sh_degree += 1 + + def create_from_pcd(self, pcd : BasicPointCloud, cam_infos : int, spatial_lr_scale : float): + self.spatial_lr_scale = spatial_lr_scale + fused_point_cloud = torch.tensor(np.asarray(pcd.points)).float().to("cuda") + fused_color = RGB2SH(torch.tensor(np.asarray(pcd.colors)).float().to("cuda")) + features = torch.zeros((fused_color.shape[0], 3, (self.max_sh_degree + 1) ** 2)).float().cuda() + features[:, :3, 0 ] = fused_color + features[:, 3:, 1:] = 0.0 + + print("Number of points at initialisation : ", fused_point_cloud.shape[0]) + dist2 = torch.clamp_min(distCUDA2(torch.from_numpy(np.asarray(pcd.points)).float().to("cuda")), 0.0000001) + scales = torch.log(torch.sqrt(dist2))[...,None].repeat(1, 3) + rots = torch.zeros((fused_point_cloud.shape[0], 4), device="cuda") + rots[:, 0] = 1 + + opacities = self.inverse_opacity_activation(0.1 * torch.ones((fused_point_cloud.shape[0], 1), dtype=torch.float, device="cuda")) + + self._xyz = nn.Parameter(fused_point_cloud.requires_grad_(True)) + self._features_dc = nn.Parameter(features[:,:,0:1].transpose(1, 2).contiguous().requires_grad_(True)) + self._features_rest = nn.Parameter(features[:,:,1:].transpose(1, 2).contiguous().requires_grad_(True)) + self._scaling = nn.Parameter(scales.requires_grad_(True)) + self._rotation = nn.Parameter(rots.requires_grad_(True)) + self._opacity = nn.Parameter(opacities.requires_grad_(True)) + self.max_radii2D = torch.zeros((self.get_xyz.shape[0]), device="cuda") + self.exposure_mapping = {cam_info.image_name: idx for idx, cam_info in enumerate(cam_infos)} + self.pretrained_exposures = None + exposure = torch.eye(3, 4, device="cuda")[None].repeat(len(cam_infos), 1, 1) + self._exposure = nn.Parameter(exposure.requires_grad_(True)) + + def training_setup(self, training_args): + self.percent_dense = training_args.percent_dense + self.xyz_gradient_accum = torch.zeros((self.get_xyz.shape[0], 1), device="cuda") + self.denom = torch.zeros((self.get_xyz.shape[0], 1), device="cuda") + + l = [ + {'params': [self._xyz], 'lr': training_args.position_lr_init * self.spatial_lr_scale, "name": "xyz"}, + {'params': [self._features_dc], 'lr': training_args.feature_lr, "name": "f_dc"}, + {'params': [self._features_rest], 'lr': training_args.feature_lr / 20.0, "name": "f_rest"}, + {'params': [self._opacity], 'lr': training_args.opacity_lr, "name": "opacity"}, + {'params': [self._scaling], 'lr': training_args.scaling_lr, "name": "scaling"}, + {'params': [self._rotation], 'lr': training_args.rotation_lr, "name": "rotation"} + ] + + if self.optimizer_type == "default": + self.optimizer = torch.optim.Adam(l, lr=0.0, eps=1e-15) + elif self.optimizer_type == "sparse_adam": + try: + self.optimizer = SparseGaussianAdam(l, lr=0.0, eps=1e-15) + except: + # A special version of the rasterizer is required to enable sparse adam + self.optimizer = torch.optim.Adam(l, lr=0.0, eps=1e-15) + + self.exposure_optimizer = torch.optim.Adam([self._exposure]) + + self.xyz_scheduler_args = get_expon_lr_func(lr_init=training_args.position_lr_init*self.spatial_lr_scale, + lr_final=training_args.position_lr_final*self.spatial_lr_scale, + lr_delay_mult=training_args.position_lr_delay_mult, + max_steps=training_args.position_lr_max_steps) + + self.exposure_scheduler_args = get_expon_lr_func(training_args.exposure_lr_init, training_args.exposure_lr_final, + lr_delay_steps=training_args.exposure_lr_delay_steps, + lr_delay_mult=training_args.exposure_lr_delay_mult, + max_steps=training_args.iterations) + + def update_learning_rate(self, iteration): + ''' Learning rate scheduling per step ''' + if self.pretrained_exposures is None: + for param_group in self.exposure_optimizer.param_groups: + param_group['lr'] = self.exposure_scheduler_args(iteration) + + for param_group in self.optimizer.param_groups: + if param_group["name"] == "xyz": + lr = self.xyz_scheduler_args(iteration) + param_group['lr'] = lr + return lr + + def construct_list_of_attributes(self): + l = ['x', 'y', 'z', 'nx', 'ny', 'nz'] + # All channels except the 3 DC + for i in range(self._features_dc.shape[1]*self._features_dc.shape[2]): + l.append('f_dc_{}'.format(i)) + for i in range(self._features_rest.shape[1]*self._features_rest.shape[2]): + l.append('f_rest_{}'.format(i)) + l.append('opacity') + for i in range(self._scaling.shape[1]): + l.append('scale_{}'.format(i)) + for i in range(self._rotation.shape[1]): + l.append('rot_{}'.format(i)) + return l + + def save_ply(self, path): + mkdir_p(os.path.dirname(path)) + + xyz = self._xyz.detach().cpu().numpy() + normals = np.zeros_like(xyz) + f_dc = self._features_dc.detach().transpose(1, 2).flatten(start_dim=1).contiguous().cpu().numpy() + f_rest = self._features_rest.detach().transpose(1, 2).flatten(start_dim=1).contiguous().cpu().numpy() + opacities = self._opacity.detach().cpu().numpy() + scale = self._scaling.detach().cpu().numpy() + rotation = self._rotation.detach().cpu().numpy() + + dtype_full = [(attribute, 'f4') for attribute in self.construct_list_of_attributes()] + + elements = np.empty(xyz.shape[0], dtype=dtype_full) + attributes = np.concatenate((xyz, normals, f_dc, f_rest, opacities, scale, rotation), axis=1) + elements[:] = list(map(tuple, attributes)) + el = PlyElement.describe(elements, 'vertex') + PlyData([el]).write(path) + + def reset_opacity(self): + opacities_new = self.inverse_opacity_activation(torch.min(self.get_opacity, torch.ones_like(self.get_opacity)*0.01)) + optimizable_tensors = self.replace_tensor_to_optimizer(opacities_new, "opacity") + self._opacity = optimizable_tensors["opacity"] + + def load_ply(self, path, use_train_test_exp = False): + plydata = PlyData.read(path) + if use_train_test_exp: + exposure_file = os.path.join(os.path.dirname(path), os.pardir, os.pardir, "exposure.json") + if os.path.exists(exposure_file): + with open(exposure_file, "r") as f: + exposures = json.load(f) + self.pretrained_exposures = {image_name: torch.FloatTensor(exposures[image_name]).requires_grad_(False).cuda() for image_name in exposures} + print(f"Pretrained exposures loaded.") + else: + print(f"No exposure to be loaded at {exposure_file}") + self.pretrained_exposures = None + + xyz = np.stack((np.asarray(plydata.elements[0]["x"]), + np.asarray(plydata.elements[0]["y"]), + np.asarray(plydata.elements[0]["z"])), axis=1) + opacities = np.asarray(plydata.elements[0]["opacity"])[..., np.newaxis] + + features_dc = np.zeros((xyz.shape[0], 3, 1)) + features_dc[:, 0, 0] = np.asarray(plydata.elements[0]["f_dc_0"]) + features_dc[:, 1, 0] = np.asarray(plydata.elements[0]["f_dc_1"]) + features_dc[:, 2, 0] = np.asarray(plydata.elements[0]["f_dc_2"]) + + extra_f_names = [p.name for p in plydata.elements[0].properties if p.name.startswith("f_rest_")] + extra_f_names = sorted(extra_f_names, key = lambda x: int(x.split('_')[-1])) + assert len(extra_f_names)==3*(self.max_sh_degree + 1) ** 2 - 3 + features_extra = np.zeros((xyz.shape[0], len(extra_f_names))) + for idx, attr_name in enumerate(extra_f_names): + features_extra[:, idx] = np.asarray(plydata.elements[0][attr_name]) + # Reshape (P,F*SH_coeffs) to (P, F, SH_coeffs except DC) + features_extra = features_extra.reshape((features_extra.shape[0], 3, (self.max_sh_degree + 1) ** 2 - 1)) + + scale_names = [p.name for p in plydata.elements[0].properties if p.name.startswith("scale_")] + scale_names = sorted(scale_names, key = lambda x: int(x.split('_')[-1])) + scales = np.zeros((xyz.shape[0], len(scale_names))) + for idx, attr_name in enumerate(scale_names): + scales[:, idx] = np.asarray(plydata.elements[0][attr_name]) + + rot_names = [p.name for p in plydata.elements[0].properties if p.name.startswith("rot")] + rot_names = sorted(rot_names, key = lambda x: int(x.split('_')[-1])) + rots = np.zeros((xyz.shape[0], len(rot_names))) + for idx, attr_name in enumerate(rot_names): + rots[:, idx] = np.asarray(plydata.elements[0][attr_name]) + + self._xyz = nn.Parameter(torch.tensor(xyz, dtype=torch.float, device="cuda").requires_grad_(True)) + self._features_dc = nn.Parameter(torch.tensor(features_dc, dtype=torch.float, device="cuda").transpose(1, 2).contiguous().requires_grad_(True)) + self._features_rest = nn.Parameter(torch.tensor(features_extra, dtype=torch.float, device="cuda").transpose(1, 2).contiguous().requires_grad_(True)) + self._opacity = nn.Parameter(torch.tensor(opacities, dtype=torch.float, device="cuda").requires_grad_(True)) + self._scaling = nn.Parameter(torch.tensor(scales, dtype=torch.float, device="cuda").requires_grad_(True)) + self._rotation = nn.Parameter(torch.tensor(rots, dtype=torch.float, device="cuda").requires_grad_(True)) + + self.active_sh_degree = self.max_sh_degree + + def replace_tensor_to_optimizer(self, tensor, name): + optimizable_tensors = {} + for group in self.optimizer.param_groups: + if group["name"] == name: + stored_state = self.optimizer.state.get(group['params'][0], None) + stored_state["exp_avg"] = torch.zeros_like(tensor) + stored_state["exp_avg_sq"] = torch.zeros_like(tensor) + + del self.optimizer.state[group['params'][0]] + group["params"][0] = nn.Parameter(tensor.requires_grad_(True)) + self.optimizer.state[group['params'][0]] = stored_state + + optimizable_tensors[group["name"]] = group["params"][0] + return optimizable_tensors + + def _prune_optimizer(self, mask): + optimizable_tensors = {} + for group in self.optimizer.param_groups: + stored_state = self.optimizer.state.get(group['params'][0], None) + if stored_state is not None: + stored_state["exp_avg"] = stored_state["exp_avg"][mask] + stored_state["exp_avg_sq"] = stored_state["exp_avg_sq"][mask] + + del self.optimizer.state[group['params'][0]] + group["params"][0] = nn.Parameter((group["params"][0][mask].requires_grad_(True))) + self.optimizer.state[group['params'][0]] = stored_state + + optimizable_tensors[group["name"]] = group["params"][0] + else: + group["params"][0] = nn.Parameter(group["params"][0][mask].requires_grad_(True)) + optimizable_tensors[group["name"]] = group["params"][0] + return optimizable_tensors + + def prune_points(self, mask): + valid_points_mask = ~mask + optimizable_tensors = self._prune_optimizer(valid_points_mask) + + self._xyz = optimizable_tensors["xyz"] + self._features_dc = optimizable_tensors["f_dc"] + self._features_rest = optimizable_tensors["f_rest"] + self._opacity = optimizable_tensors["opacity"] + self._scaling = optimizable_tensors["scaling"] + self._rotation = optimizable_tensors["rotation"] + + self.xyz_gradient_accum = self.xyz_gradient_accum[valid_points_mask] + + self.denom = self.denom[valid_points_mask] + self.max_radii2D = self.max_radii2D[valid_points_mask] + self.tmp_radii = self.tmp_radii[valid_points_mask] + + def cat_tensors_to_optimizer(self, tensors_dict): + optimizable_tensors = {} + for group in self.optimizer.param_groups: + assert len(group["params"]) == 1 + extension_tensor = tensors_dict[group["name"]] + stored_state = self.optimizer.state.get(group['params'][0], None) + if stored_state is not None: + + stored_state["exp_avg"] = torch.cat((stored_state["exp_avg"], torch.zeros_like(extension_tensor)), dim=0) + stored_state["exp_avg_sq"] = torch.cat((stored_state["exp_avg_sq"], torch.zeros_like(extension_tensor)), dim=0) + + del self.optimizer.state[group['params'][0]] + group["params"][0] = nn.Parameter(torch.cat((group["params"][0], extension_tensor), dim=0).requires_grad_(True)) + self.optimizer.state[group['params'][0]] = stored_state + + optimizable_tensors[group["name"]] = group["params"][0] + else: + group["params"][0] = nn.Parameter(torch.cat((group["params"][0], extension_tensor), dim=0).requires_grad_(True)) + optimizable_tensors[group["name"]] = group["params"][0] + + return optimizable_tensors + + def densification_postfix(self, new_xyz, new_features_dc, new_features_rest, new_opacities, new_scaling, new_rotation, new_tmp_radii): + d = {"xyz": new_xyz, + "f_dc": new_features_dc, + "f_rest": new_features_rest, + "opacity": new_opacities, + "scaling" : new_scaling, + "rotation" : new_rotation} + + optimizable_tensors = self.cat_tensors_to_optimizer(d) + self._xyz = optimizable_tensors["xyz"] + self._features_dc = optimizable_tensors["f_dc"] + self._features_rest = optimizable_tensors["f_rest"] + self._opacity = optimizable_tensors["opacity"] + self._scaling = optimizable_tensors["scaling"] + self._rotation = optimizable_tensors["rotation"] + + self.tmp_radii = torch.cat((self.tmp_radii, new_tmp_radii)) + self.xyz_gradient_accum = torch.zeros((self.get_xyz.shape[0], 1), device="cuda") + self.denom = torch.zeros((self.get_xyz.shape[0], 1), device="cuda") + self.max_radii2D = torch.zeros((self.get_xyz.shape[0]), device="cuda") + + def densify_and_split(self, grads, grad_threshold, scene_extent, N=2): + n_init_points = self.get_xyz.shape[0] + # Extract points that satisfy the gradient condition + padded_grad = torch.zeros((n_init_points), device="cuda") + padded_grad[:grads.shape[0]] = grads.squeeze() + selected_pts_mask = torch.where(padded_grad >= grad_threshold, True, False) + selected_pts_mask = torch.logical_and(selected_pts_mask, + torch.max(self.get_scaling, dim=1).values > self.percent_dense*scene_extent) + + stds = self.get_scaling[selected_pts_mask].repeat(N,1) + means =torch.zeros((stds.size(0), 3),device="cuda") + samples = torch.normal(mean=means, std=stds) + rots = build_rotation(self._rotation[selected_pts_mask]).repeat(N,1,1) + new_xyz = torch.bmm(rots, samples.unsqueeze(-1)).squeeze(-1) + self.get_xyz[selected_pts_mask].repeat(N, 1) + new_scaling = self.scaling_inverse_activation(self.get_scaling[selected_pts_mask].repeat(N,1) / (0.8*N)) + new_rotation = self._rotation[selected_pts_mask].repeat(N,1) + new_features_dc = self._features_dc[selected_pts_mask].repeat(N,1,1) + new_features_rest = self._features_rest[selected_pts_mask].repeat(N,1,1) + new_opacity = self._opacity[selected_pts_mask].repeat(N,1) + new_tmp_radii = self.tmp_radii[selected_pts_mask].repeat(N) + + self.densification_postfix(new_xyz, new_features_dc, new_features_rest, new_opacity, new_scaling, new_rotation, new_tmp_radii) + + prune_filter = torch.cat((selected_pts_mask, torch.zeros(N * selected_pts_mask.sum(), device="cuda", dtype=bool))) + self.prune_points(prune_filter) + + def densify_and_clone(self, grads, grad_threshold, scene_extent): + # Extract points that satisfy the gradient condition + selected_pts_mask = torch.where(torch.norm(grads, dim=-1) >= grad_threshold, True, False) + selected_pts_mask = torch.logical_and(selected_pts_mask, + torch.max(self.get_scaling, dim=1).values <= self.percent_dense*scene_extent) + + new_xyz = self._xyz[selected_pts_mask] + new_features_dc = self._features_dc[selected_pts_mask] + new_features_rest = self._features_rest[selected_pts_mask] + new_opacities = self._opacity[selected_pts_mask] + new_scaling = self._scaling[selected_pts_mask] + new_rotation = self._rotation[selected_pts_mask] + + new_tmp_radii = self.tmp_radii[selected_pts_mask] + + self.densification_postfix(new_xyz, new_features_dc, new_features_rest, new_opacities, new_scaling, new_rotation, new_tmp_radii) + + def densify_and_prune(self, max_grad, min_opacity, extent, max_screen_size, radii): + grads = self.xyz_gradient_accum / self.denom + grads[grads.isnan()] = 0.0 + + self.tmp_radii = radii + self.densify_and_clone(grads, max_grad, extent) + self.densify_and_split(grads, max_grad, extent) + + prune_mask = (self.get_opacity < min_opacity).squeeze() + if max_screen_size: + big_points_vs = self.max_radii2D > max_screen_size + big_points_ws = self.get_scaling.max(dim=1).values > 0.1 * extent + prune_mask = torch.logical_or(torch.logical_or(prune_mask, big_points_vs), big_points_ws) + self.prune_points(prune_mask) + tmp_radii = self.tmp_radii + self.tmp_radii = None + + torch.cuda.empty_cache() + + def add_densification_stats(self, viewspace_point_tensor, update_filter): + self.xyz_gradient_accum[update_filter] += torch.norm(viewspace_point_tensor.grad[update_filter,:2], dim=-1, keepdim=True) + self.denom[update_filter] += 1 diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/.gitignore b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..1e1c4ca8a718b5cc403d16441996c98214bb30cb --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/.gitignore @@ -0,0 +1,3 @@ +build/ +diff_gaussian_rasterization.egg-info/ +dist/ diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/.gitmodules b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/.gitmodules new file mode 100644 index 0000000000000000000000000000000000000000..4553c29f4224a9a8723482bc9aca759a97693a64 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/.gitmodules @@ -0,0 +1,3 @@ +[submodule "third_party/glm"] + path = third_party/glm + url = https://github.com/g-truc/glm.git diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/CMakeLists.txt b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..f8cf822e83c5f8d15288d497f5c3bb138cfd8c48 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/CMakeLists.txt @@ -0,0 +1,36 @@ +# +# Copyright (C) 2023, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact george.drettakis@inria.fr +# + +cmake_minimum_required(VERSION 3.20) + +project(DiffRast LANGUAGES CUDA CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_CUDA_STANDARD 17) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +add_library(CudaRasterizer + cuda_rasterizer/backward.h + cuda_rasterizer/backward.cu + cuda_rasterizer/forward.h + cuda_rasterizer/forward.cu + cuda_rasterizer/auxiliary.h + cuda_rasterizer/rasterizer_impl.cu + cuda_rasterizer/rasterizer_impl.h + cuda_rasterizer/rasterizer.h +) + +set_target_properties(CudaRasterizer PROPERTIES CUDA_ARCHITECTURES "70;75;86") + +target_include_directories(CudaRasterizer PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/cuda_rasterizer) +target_include_directories(CudaRasterizer PRIVATE third_party/glm ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES}) diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/LICENSE.md b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/LICENSE.md new file mode 100644 index 0000000000000000000000000000000000000000..c869e695fa63bfde6f887d63a24a2a71f03480ac --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/LICENSE.md @@ -0,0 +1,83 @@ +Gaussian-Splatting License +=========================== + +**Inria** and **the Max Planck Institut for Informatik (MPII)** hold all the ownership rights on the *Software* named **gaussian-splatting**. +The *Software* is in the process of being registered with the Agence pour la Protection des +Programmes (APP). + +The *Software* is still being developed by the *Licensor*. + +*Licensor*'s goal is to allow the research community to use, test and evaluate +the *Software*. + +## 1. Definitions + +*Licensee* means any person or entity that uses the *Software* and distributes +its *Work*. + +*Licensor* means the owners of the *Software*, i.e Inria and MPII + +*Software* means the original work of authorship made available under this +License ie gaussian-splatting. + +*Work* means the *Software* and any additions to or derivative works of the +*Software* that are made available under this License. + + +## 2. Purpose +This license is intended to define the rights granted to the *Licensee* by +Licensors under the *Software*. + +## 3. Rights granted + +For the above reasons Licensors have decided to distribute the *Software*. +Licensors grant non-exclusive rights to use the *Software* for research purposes +to research users (both academic and industrial), free of charge, without right +to sublicense.. The *Software* may be used "non-commercially", i.e., for research +and/or evaluation purposes only. + +Subject to the terms and conditions of this License, you are granted a +non-exclusive, royalty-free, license to reproduce, prepare derivative works of, +publicly display, publicly perform and distribute its *Work* and any resulting +derivative works in any form. + +## 4. Limitations + +**4.1 Redistribution.** You may reproduce or distribute the *Work* only if (a) you do +so under this License, (b) you include a complete copy of this License with +your distribution, and (c) you retain without modification any copyright, +patent, trademark, or attribution notices that are present in the *Work*. + +**4.2 Derivative Works.** You may specify that additional or different terms apply +to the use, reproduction, and distribution of your derivative works of the *Work* +("Your Terms") only if (a) Your Terms provide that the use limitation in +Section 2 applies to your derivative works, and (b) you identify the specific +derivative works that are subject to Your Terms. Notwithstanding Your Terms, +this License (including the redistribution requirements in Section 3.1) will +continue to apply to the *Work* itself. + +**4.3** Any other use without of prior consent of Licensors is prohibited. Research +users explicitly acknowledge having received from Licensors all information +allowing to appreciate the adequacy between of the *Software* and their needs and +to undertake all necessary precautions for its execution and use. + +**4.4** The *Software* is provided both as a compiled library file and as source +code. In case of using the *Software* for a publication or other results obtained +through the use of the *Software*, users are strongly encouraged to cite the +corresponding publications as explained in the documentation of the *Software*. + +## 5. Disclaimer + +THE USER CANNOT USE, EXPLOIT OR DISTRIBUTE THE *SOFTWARE* FOR COMMERCIAL PURPOSES +WITHOUT PRIOR AND EXPLICIT CONSENT OF LICENSORS. YOU MUST CONTACT INRIA FOR ANY +UNAUTHORIZED USE: stip-sophia.transfert@inria.fr . ANY SUCH ACTION WILL +CONSTITUTE A FORGERY. THIS *SOFTWARE* IS PROVIDED "AS IS" WITHOUT ANY WARRANTIES +OF ANY NATURE AND ANY EXPRESS OR IMPLIED WARRANTIES, WITH REGARDS TO COMMERCIAL +USE, PROFESSIONNAL USE, LEGAL OR NOT, OR OTHER, OR COMMERCIALISATION OR +ADAPTATION. UNLESS EXPLICITLY PROVIDED BY LAW, IN NO EVENT, SHALL INRIA OR THE +AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES, LOSS OF USE, DATA, OR PROFITS OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING FROM, OUT OF OR +IN CONNECTION WITH THE *SOFTWARE* OR THE USE OR OTHER DEALINGS IN THE *SOFTWARE*. diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/README.md b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/README.md new file mode 100644 index 0000000000000000000000000000000000000000..6e165b0bb683a987485e2730216d5fa2919288ef --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/README.md @@ -0,0 +1,19 @@ +# Differential Gaussian Rasterization + +Used as the rasterization engine for the paper "3D Gaussian Splatting for Real-Time Rendering of Radiance Fields". If you can make use of it in your own research, please be so kind to cite us. + +
+
+

BibTeX

+
@Article{kerbl3Dgaussians,
+      author       = {Kerbl, Bernhard and Kopanas, Georgios and Leimk{\"u}hler, Thomas and Drettakis, George},
+      title        = {3D Gaussian Splatting for Real-Time Radiance Field Rendering},
+      journal      = {ACM Transactions on Graphics},
+      number       = {4},
+      volume       = {42},
+      month        = {July},
+      year         = {2023},
+      url          = {https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/}
+}
+
+
\ No newline at end of file diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/cuda_rasterizer/auxiliary.h b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/cuda_rasterizer/auxiliary.h new file mode 100644 index 0000000000000000000000000000000000000000..aaf219155b0277946b82548665c6a4886136ef0b --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/cuda_rasterizer/auxiliary.h @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2023, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact george.drettakis@inria.fr + */ + +#ifndef CUDA_RASTERIZER_AUXILIARY_H_INCLUDED +#define CUDA_RASTERIZER_AUXILIARY_H_INCLUDED + +#include "config.h" +#include "stdio.h" + +#define BLOCK_SIZE (BLOCK_X * BLOCK_Y) +#define NUM_WARPS (BLOCK_SIZE/32) +// Spherical harmonics coefficients +__device__ const float SH_C0 = 0.28209479177387814f; +__device__ const float SH_C1 = 0.4886025119029199f; +__device__ const float SH_C2[] = { + 1.0925484305920792f, + -1.0925484305920792f, + 0.31539156525252005f, + -1.0925484305920792f, + 0.5462742152960396f +}; +__device__ const float SH_C3[] = { + -0.5900435899266435f, + 2.890611442640554f, + -0.4570457994644658f, + 0.3731763325901154f, + -0.4570457994644658f, + 1.445305721320277f, + -0.5900435899266435f +}; + +__forceinline__ __device__ float ndc2Pix(float v, int S) +{ + return ((v + 1.0) * S - 1.0) * 0.5; +} + +__forceinline__ __device__ void getRect(const float2 p, int max_radius, uint2& rect_min, uint2& rect_max, dim3 grid) +{ + rect_min = { + min(grid.x, max((int)0, (int)((p.x - max_radius) / BLOCK_X))), + min(grid.y, max((int)0, (int)((p.y - max_radius) / BLOCK_Y))) + }; + rect_max = { + min(grid.x, max((int)0, (int)((p.x + max_radius + BLOCK_X - 1) / BLOCK_X))), + min(grid.y, max((int)0, (int)((p.y + max_radius + BLOCK_Y - 1) / BLOCK_Y))) + }; +} + +__forceinline__ __device__ void getRect(const float2 p, int2 ext_rect, uint2& rect_min, uint2& rect_max, dim3 grid) +{ + rect_min = { + min(grid.x, max((int)0, (int)((p.x - ext_rect.x) / BLOCK_X))), + min(grid.y, max((int)0, (int)((p.y - ext_rect.y) / BLOCK_Y))) + }; + rect_max = { + min(grid.x, max((int)0, (int)((p.x + ext_rect.x + BLOCK_X - 1) / BLOCK_X))), + min(grid.y, max((int)0, (int)((p.y + ext_rect.y + BLOCK_Y - 1) / BLOCK_Y))) + }; +} + + +__forceinline__ __device__ float3 transformPoint4x3(const float3& p, const float* matrix) +{ + float3 transformed = { + matrix[0] * p.x + matrix[4] * p.y + matrix[8] * p.z + matrix[12], + matrix[1] * p.x + matrix[5] * p.y + matrix[9] * p.z + matrix[13], + matrix[2] * p.x + matrix[6] * p.y + matrix[10] * p.z + matrix[14], + }; + return transformed; +} + +__forceinline__ __device__ float4 transformPoint4x4(const float3& p, const float* matrix) +{ + float4 transformed = { + matrix[0] * p.x + matrix[4] * p.y + matrix[8] * p.z + matrix[12], + matrix[1] * p.x + matrix[5] * p.y + matrix[9] * p.z + matrix[13], + matrix[2] * p.x + matrix[6] * p.y + matrix[10] * p.z + matrix[14], + matrix[3] * p.x + matrix[7] * p.y + matrix[11] * p.z + matrix[15] + }; + return transformed; +} + +__forceinline__ __device__ float3 transformVec4x3(const float3& p, const float* matrix) +{ + float3 transformed = { + matrix[0] * p.x + matrix[4] * p.y + matrix[8] * p.z, + matrix[1] * p.x + matrix[5] * p.y + matrix[9] * p.z, + matrix[2] * p.x + matrix[6] * p.y + matrix[10] * p.z, + }; + return transformed; +} + +__forceinline__ __device__ float3 transformVec4x3Transpose(const float3& p, const float* matrix) +{ + float3 transformed = { + matrix[0] * p.x + matrix[1] * p.y + matrix[2] * p.z, + matrix[4] * p.x + matrix[5] * p.y + matrix[6] * p.z, + matrix[8] * p.x + matrix[9] * p.y + matrix[10] * p.z, + }; + return transformed; +} + +__forceinline__ __device__ float dnormvdz(float3 v, float3 dv) +{ + float sum2 = v.x * v.x + v.y * v.y + v.z * v.z; + float invsum32 = 1.0f / sqrt(sum2 * sum2 * sum2); + float dnormvdz = (-v.x * v.z * dv.x - v.y * v.z * dv.y + (sum2 - v.z * v.z) * dv.z) * invsum32; + return dnormvdz; +} + +__forceinline__ __device__ float3 dnormvdv(float3 v, float3 dv) +{ + float sum2 = v.x * v.x + v.y * v.y + v.z * v.z; + float invsum32 = 1.0f / sqrt(sum2 * sum2 * sum2); + + float3 dnormvdv; + dnormvdv.x = ((+sum2 - v.x * v.x) * dv.x - v.y * v.x * dv.y - v.z * v.x * dv.z) * invsum32; + dnormvdv.y = (-v.x * v.y * dv.x + (sum2 - v.y * v.y) * dv.y - v.z * v.y * dv.z) * invsum32; + dnormvdv.z = (-v.x * v.z * dv.x - v.y * v.z * dv.y + (sum2 - v.z * v.z) * dv.z) * invsum32; + return dnormvdv; +} + +__forceinline__ __device__ float4 dnormvdv(float4 v, float4 dv) +{ + float sum2 = v.x * v.x + v.y * v.y + v.z * v.z + v.w * v.w; + float invsum32 = 1.0f / sqrt(sum2 * sum2 * sum2); + + float4 vdv = { v.x * dv.x, v.y * dv.y, v.z * dv.z, v.w * dv.w }; + float vdv_sum = vdv.x + vdv.y + vdv.z + vdv.w; + float4 dnormvdv; + dnormvdv.x = ((sum2 - v.x * v.x) * dv.x - v.x * (vdv_sum - vdv.x)) * invsum32; + dnormvdv.y = ((sum2 - v.y * v.y) * dv.y - v.y * (vdv_sum - vdv.y)) * invsum32; + dnormvdv.z = ((sum2 - v.z * v.z) * dv.z - v.z * (vdv_sum - vdv.z)) * invsum32; + dnormvdv.w = ((sum2 - v.w * v.w) * dv.w - v.w * (vdv_sum - vdv.w)) * invsum32; + return dnormvdv; +} + +__forceinline__ __device__ float sigmoid(float x) +{ + return 1.0f / (1.0f + expf(-x)); +} + +__forceinline__ __device__ bool in_frustum(int idx, + const float* orig_points, + const float* viewmatrix, + const float* projmatrix, + bool prefiltered, + float3& p_view) +{ + float3 p_orig = { orig_points[3 * idx], orig_points[3 * idx + 1], orig_points[3 * idx + 2] }; + + // Bring points to screen space + float4 p_hom = transformPoint4x4(p_orig, projmatrix); + float p_w = 1.0f / (p_hom.w + 0.0000001f); + float3 p_proj = { p_hom.x * p_w, p_hom.y * p_w, p_hom.z * p_w }; + p_view = transformPoint4x3(p_orig, viewmatrix); + + if (p_view.z <= 0.2f)// || ((p_proj.x < -1.3 || p_proj.x > 1.3 || p_proj.y < -1.3 || p_proj.y > 1.3))) + { + if (prefiltered) + { + printf("Point is filtered although prefiltered is set. This shouldn't happen!"); + __trap(); + } + return false; + } + return true; +} + +#define CHECK_CUDA(A, debug) \ +A; if(debug) { \ +auto ret = cudaDeviceSynchronize(); \ +if (ret != cudaSuccess) { \ +std::cerr << "\n[CUDA ERROR] in " << __FILE__ << "\nLine " << __LINE__ << ": " << cudaGetErrorString(ret); \ +throw std::runtime_error(cudaGetErrorString(ret)); \ +} \ +} + +#endif diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/cuda_rasterizer/backward.cu b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/cuda_rasterizer/backward.cu new file mode 100644 index 0000000000000000000000000000000000000000..006b1ef77d08eb21d6b083f567e44dc1c2f8e802 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/cuda_rasterizer/backward.cu @@ -0,0 +1,753 @@ +/* + * Copyright (C) 2023, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact george.drettakis@inria.fr + */ + +#include "backward.h" +#include "auxiliary.h" +#include +#include +namespace cg = cooperative_groups; + +__device__ __forceinline__ float sq(float x) { return x * x; } + + +// Backward pass for conversion of spherical harmonics to RGB for +// each Gaussian. +__device__ void computeColorFromSH(int idx, int deg, int max_coeffs, const glm::vec3* means, glm::vec3 campos, const float* shs, const bool* clamped, const glm::vec3* dL_dcolor, glm::vec3* dL_dmeans, glm::vec3* dL_dshs) +{ + // Compute intermediate values, as it is done during forward + glm::vec3 pos = means[idx]; + glm::vec3 dir_orig = pos - campos; + glm::vec3 dir = dir_orig / glm::length(dir_orig); + + glm::vec3* sh = ((glm::vec3*)shs) + idx * max_coeffs; + + // Use PyTorch rule for clamping: if clamping was applied, + // gradient becomes 0. + glm::vec3 dL_dRGB = dL_dcolor[idx]; + dL_dRGB.x *= clamped[3 * idx + 0] ? 0 : 1; + dL_dRGB.y *= clamped[3 * idx + 1] ? 0 : 1; + dL_dRGB.z *= clamped[3 * idx + 2] ? 0 : 1; + + glm::vec3 dRGBdx(0, 0, 0); + glm::vec3 dRGBdy(0, 0, 0); + glm::vec3 dRGBdz(0, 0, 0); + float x = dir.x; + float y = dir.y; + float z = dir.z; + + // Target location for this Gaussian to write SH gradients to + glm::vec3* dL_dsh = dL_dshs + idx * max_coeffs; + + // No tricks here, just high school-level calculus. + float dRGBdsh0 = SH_C0; + dL_dsh[0] = dRGBdsh0 * dL_dRGB; + if (deg > 0) + { + float dRGBdsh1 = -SH_C1 * y; + float dRGBdsh2 = SH_C1 * z; + float dRGBdsh3 = -SH_C1 * x; + dL_dsh[1] = dRGBdsh1 * dL_dRGB; + dL_dsh[2] = dRGBdsh2 * dL_dRGB; + dL_dsh[3] = dRGBdsh3 * dL_dRGB; + + dRGBdx = -SH_C1 * sh[3]; + dRGBdy = -SH_C1 * sh[1]; + dRGBdz = SH_C1 * sh[2]; + + if (deg > 1) + { + float xx = x * x, yy = y * y, zz = z * z; + float xy = x * y, yz = y * z, xz = x * z; + + float dRGBdsh4 = SH_C2[0] * xy; + float dRGBdsh5 = SH_C2[1] * yz; + float dRGBdsh6 = SH_C2[2] * (2.f * zz - xx - yy); + float dRGBdsh7 = SH_C2[3] * xz; + float dRGBdsh8 = SH_C2[4] * (xx - yy); + dL_dsh[4] = dRGBdsh4 * dL_dRGB; + dL_dsh[5] = dRGBdsh5 * dL_dRGB; + dL_dsh[6] = dRGBdsh6 * dL_dRGB; + dL_dsh[7] = dRGBdsh7 * dL_dRGB; + dL_dsh[8] = dRGBdsh8 * dL_dRGB; + + dRGBdx += SH_C2[0] * y * sh[4] + SH_C2[2] * 2.f * -x * sh[6] + SH_C2[3] * z * sh[7] + SH_C2[4] * 2.f * x * sh[8]; + dRGBdy += SH_C2[0] * x * sh[4] + SH_C2[1] * z * sh[5] + SH_C2[2] * 2.f * -y * sh[6] + SH_C2[4] * 2.f * -y * sh[8]; + dRGBdz += SH_C2[1] * y * sh[5] + SH_C2[2] * 2.f * 2.f * z * sh[6] + SH_C2[3] * x * sh[7]; + + if (deg > 2) + { + float dRGBdsh9 = SH_C3[0] * y * (3.f * xx - yy); + float dRGBdsh10 = SH_C3[1] * xy * z; + float dRGBdsh11 = SH_C3[2] * y * (4.f * zz - xx - yy); + float dRGBdsh12 = SH_C3[3] * z * (2.f * zz - 3.f * xx - 3.f * yy); + float dRGBdsh13 = SH_C3[4] * x * (4.f * zz - xx - yy); + float dRGBdsh14 = SH_C3[5] * z * (xx - yy); + float dRGBdsh15 = SH_C3[6] * x * (xx - 3.f * yy); + dL_dsh[9] = dRGBdsh9 * dL_dRGB; + dL_dsh[10] = dRGBdsh10 * dL_dRGB; + dL_dsh[11] = dRGBdsh11 * dL_dRGB; + dL_dsh[12] = dRGBdsh12 * dL_dRGB; + dL_dsh[13] = dRGBdsh13 * dL_dRGB; + dL_dsh[14] = dRGBdsh14 * dL_dRGB; + dL_dsh[15] = dRGBdsh15 * dL_dRGB; + + dRGBdx += ( + SH_C3[0] * sh[9] * 3.f * 2.f * xy + + SH_C3[1] * sh[10] * yz + + SH_C3[2] * sh[11] * -2.f * xy + + SH_C3[3] * sh[12] * -3.f * 2.f * xz + + SH_C3[4] * sh[13] * (-3.f * xx + 4.f * zz - yy) + + SH_C3[5] * sh[14] * 2.f * xz + + SH_C3[6] * sh[15] * 3.f * (xx - yy)); + + dRGBdy += ( + SH_C3[0] * sh[9] * 3.f * (xx - yy) + + SH_C3[1] * sh[10] * xz + + SH_C3[2] * sh[11] * (-3.f * yy + 4.f * zz - xx) + + SH_C3[3] * sh[12] * -3.f * 2.f * yz + + SH_C3[4] * sh[13] * -2.f * xy + + SH_C3[5] * sh[14] * -2.f * yz + + SH_C3[6] * sh[15] * -3.f * 2.f * xy); + + dRGBdz += ( + SH_C3[1] * sh[10] * xy + + SH_C3[2] * sh[11] * 4.f * 2.f * yz + + SH_C3[3] * sh[12] * 3.f * (2.f * zz - xx - yy) + + SH_C3[4] * sh[13] * 4.f * 2.f * xz + + SH_C3[5] * sh[14] * (xx - yy)); + } + } + } + + // The view direction is an input to the computation. View direction + // is influenced by the Gaussian's mean, so SHs gradients + // must propagate back into 3D position. + glm::vec3 dL_ddir(glm::dot(dRGBdx, dL_dRGB), glm::dot(dRGBdy, dL_dRGB), glm::dot(dRGBdz, dL_dRGB)); + + // Account for normalization of direction + float3 dL_dmean = dnormvdv(float3{ dir_orig.x, dir_orig.y, dir_orig.z }, float3{ dL_ddir.x, dL_ddir.y, dL_ddir.z }); + + // Gradients of loss w.r.t. Gaussian means, but only the portion + // that is caused because the mean affects the view-dependent color. + // Additional mean gradient is accumulated in below methods. + dL_dmeans[idx] += glm::vec3(dL_dmean.x, dL_dmean.y, dL_dmean.z); +} + +// Backward version of INVERSE 2D covariance matrix computation +// (due to length launched as separate kernel before other +// backward steps contained in preprocess) +__global__ void computeCov2DCUDA(int P, + const float3* means, + const int* radii, + const float* cov3Ds, + const float h_x, float h_y, + const float tan_fovx, float tan_fovy, + const float* view_matrix, + const float* opacities, + const float* dL_dconics, + float* dL_dopacity, + const float* dL_dinvdepth, + float3* dL_dmeans, + float* dL_dcov, + bool antialiasing) +{ + auto idx = cg::this_grid().thread_rank(); + if (idx >= P || !(radii[idx] > 0)) + return; + + // Reading location of 3D covariance for this Gaussian + const float* cov3D = cov3Ds + 6 * idx; + + // Fetch gradients, recompute 2D covariance and relevant + // intermediate forward results needed in the backward. + float3 mean = means[idx]; + float3 dL_dconic = { dL_dconics[4 * idx], dL_dconics[4 * idx + 1], dL_dconics[4 * idx + 3] }; + float3 t = transformPoint4x3(mean, view_matrix); + + const float limx = 1.3f * tan_fovx; + const float limy = 1.3f * tan_fovy; + const float txtz = t.x / t.z; + const float tytz = t.y / t.z; + t.x = min(limx, max(-limx, txtz)) * t.z; + t.y = min(limy, max(-limy, tytz)) * t.z; + + const float x_grad_mul = txtz < -limx || txtz > limx ? 0 : 1; + const float y_grad_mul = tytz < -limy || tytz > limy ? 0 : 1; + + glm::mat3 J = glm::mat3(h_x / t.z, 0.0f, -(h_x * t.x) / (t.z * t.z), + 0.0f, h_y / t.z, -(h_y * t.y) / (t.z * t.z), + 0, 0, 0); + + glm::mat3 W = glm::mat3( + view_matrix[0], view_matrix[4], view_matrix[8], + view_matrix[1], view_matrix[5], view_matrix[9], + view_matrix[2], view_matrix[6], view_matrix[10]); + + glm::mat3 Vrk = glm::mat3( + cov3D[0], cov3D[1], cov3D[2], + cov3D[1], cov3D[3], cov3D[4], + cov3D[2], cov3D[4], cov3D[5]); + + glm::mat3 T = W * J; + + glm::mat3 cov2D = glm::transpose(T) * glm::transpose(Vrk) * T; + + // Use helper variables for 2D covariance entries. More compact. + float c_xx = cov2D[0][0]; + float c_xy = cov2D[0][1]; + float c_yy = cov2D[1][1]; + + constexpr float h_var = 0.3f; + float d_inside_root = 0.f; + if(antialiasing) + { + const float det_cov = c_xx * c_yy - c_xy * c_xy; + c_xx += h_var; + c_yy += h_var; + const float det_cov_plus_h_cov = c_xx * c_yy - c_xy * c_xy; + const float h_convolution_scaling = sqrt(max(0.000025f, det_cov / det_cov_plus_h_cov)); // max for numerical stability + const float dL_dopacity_v = dL_dopacity[idx]; + const float d_h_convolution_scaling = dL_dopacity_v * opacities[idx]; + dL_dopacity[idx] = dL_dopacity_v * h_convolution_scaling; + d_inside_root = (det_cov / det_cov_plus_h_cov) <= 0.000025f ? 0.f : d_h_convolution_scaling / (2 * h_convolution_scaling); + } + else + { + c_xx += h_var; + c_yy += h_var; + } + + float dL_dc_xx = 0; + float dL_dc_xy = 0; + float dL_dc_yy = 0; + if(antialiasing) + { + // https://www.wolframalpha.com/input?i=d+%28%28x*y+-+z%5E2%29%2F%28%28x%2Bw%29*%28y%2Bw%29+-+z%5E2%29%29+%2Fdx + // https://www.wolframalpha.com/input?i=d+%28%28x*y+-+z%5E2%29%2F%28%28x%2Bw%29*%28y%2Bw%29+-+z%5E2%29%29+%2Fdz + const float x = c_xx; + const float y = c_yy; + const float z = c_xy; + const float w = h_var; + const float denom_f = d_inside_root / sq(w * w + w * (x + y) + x * y - z * z); + const float dL_dx = w * (w * y + y * y + z * z) * denom_f; + const float dL_dy = w * (w * x + x * x + z * z) * denom_f; + const float dL_dz = -2.f * w * z * (w + x + y) * denom_f; + dL_dc_xx = dL_dx; + dL_dc_yy = dL_dy; + dL_dc_xy = dL_dz; + } + + float denom = c_xx * c_yy - c_xy * c_xy; + + float denom2inv = 1.0f / ((denom * denom) + 0.0000001f); + + if (denom2inv != 0) + { + // Gradients of loss w.r.t. entries of 2D covariance matrix, + // given gradients of loss w.r.t. conic matrix (inverse covariance matrix). + // e.g., dL / da = dL / d_conic_a * d_conic_a / d_a + + dL_dc_xx += denom2inv * (-c_yy * c_yy * dL_dconic.x + 2 * c_xy * c_yy * dL_dconic.y + (denom - c_xx * c_yy) * dL_dconic.z); + dL_dc_yy += denom2inv * (-c_xx * c_xx * dL_dconic.z + 2 * c_xx * c_xy * dL_dconic.y + (denom - c_xx * c_yy) * dL_dconic.x); + dL_dc_xy += denom2inv * 2 * (c_xy * c_yy * dL_dconic.x - (denom + 2 * c_xy * c_xy) * dL_dconic.y + c_xx * c_xy * dL_dconic.z); + + // Gradients of loss L w.r.t. each 3D covariance matrix (Vrk) entry, + // given gradients w.r.t. 2D covariance matrix (diagonal). + // cov2D = transpose(T) * transpose(Vrk) * T; + dL_dcov[6 * idx + 0] = (T[0][0] * T[0][0] * dL_dc_xx + T[0][0] * T[1][0] * dL_dc_xy + T[1][0] * T[1][0] * dL_dc_yy); + dL_dcov[6 * idx + 3] = (T[0][1] * T[0][1] * dL_dc_xx + T[0][1] * T[1][1] * dL_dc_xy + T[1][1] * T[1][1] * dL_dc_yy); + dL_dcov[6 * idx + 5] = (T[0][2] * T[0][2] * dL_dc_xx + T[0][2] * T[1][2] * dL_dc_xy + T[1][2] * T[1][2] * dL_dc_yy); + + // Gradients of loss L w.r.t. each 3D covariance matrix (Vrk) entry, + // given gradients w.r.t. 2D covariance matrix (off-diagonal). + // Off-diagonal elements appear twice --> double the gradient. + // cov2D = transpose(T) * transpose(Vrk) * T; + dL_dcov[6 * idx + 1] = 2 * T[0][0] * T[0][1] * dL_dc_xx + (T[0][0] * T[1][1] + T[0][1] * T[1][0]) * dL_dc_xy + 2 * T[1][0] * T[1][1] * dL_dc_yy; + dL_dcov[6 * idx + 2] = 2 * T[0][0] * T[0][2] * dL_dc_xx + (T[0][0] * T[1][2] + T[0][2] * T[1][0]) * dL_dc_xy + 2 * T[1][0] * T[1][2] * dL_dc_yy; + dL_dcov[6 * idx + 4] = 2 * T[0][2] * T[0][1] * dL_dc_xx + (T[0][1] * T[1][2] + T[0][2] * T[1][1]) * dL_dc_xy + 2 * T[1][1] * T[1][2] * dL_dc_yy; + } + else + { + for (int i = 0; i < 6; i++) + dL_dcov[6 * idx + i] = 0; + } + + // Gradients of loss w.r.t. upper 2x3 portion of intermediate matrix T + // cov2D = transpose(T) * transpose(Vrk) * T; + float dL_dT00 = 2 * (T[0][0] * Vrk[0][0] + T[0][1] * Vrk[0][1] + T[0][2] * Vrk[0][2]) * dL_dc_xx + + (T[1][0] * Vrk[0][0] + T[1][1] * Vrk[0][1] + T[1][2] * Vrk[0][2]) * dL_dc_xy; + float dL_dT01 = 2 * (T[0][0] * Vrk[1][0] + T[0][1] * Vrk[1][1] + T[0][2] * Vrk[1][2]) * dL_dc_xx + + (T[1][0] * Vrk[1][0] + T[1][1] * Vrk[1][1] + T[1][2] * Vrk[1][2]) * dL_dc_xy; + float dL_dT02 = 2 * (T[0][0] * Vrk[2][0] + T[0][1] * Vrk[2][1] + T[0][2] * Vrk[2][2]) * dL_dc_xx + + (T[1][0] * Vrk[2][0] + T[1][1] * Vrk[2][1] + T[1][2] * Vrk[2][2]) * dL_dc_xy; + float dL_dT10 = 2 * (T[1][0] * Vrk[0][0] + T[1][1] * Vrk[0][1] + T[1][2] * Vrk[0][2]) * dL_dc_yy + + (T[0][0] * Vrk[0][0] + T[0][1] * Vrk[0][1] + T[0][2] * Vrk[0][2]) * dL_dc_xy; + float dL_dT11 = 2 * (T[1][0] * Vrk[1][0] + T[1][1] * Vrk[1][1] + T[1][2] * Vrk[1][2]) * dL_dc_yy + + (T[0][0] * Vrk[1][0] + T[0][1] * Vrk[1][1] + T[0][2] * Vrk[1][2]) * dL_dc_xy; + float dL_dT12 = 2 * (T[1][0] * Vrk[2][0] + T[1][1] * Vrk[2][1] + T[1][2] * Vrk[2][2]) * dL_dc_yy + + (T[0][0] * Vrk[2][0] + T[0][1] * Vrk[2][1] + T[0][2] * Vrk[2][2]) * dL_dc_xy; + + // Gradients of loss w.r.t. upper 3x2 non-zero entries of Jacobian matrix + // T = W * J + float dL_dJ00 = W[0][0] * dL_dT00 + W[0][1] * dL_dT01 + W[0][2] * dL_dT02; + float dL_dJ02 = W[2][0] * dL_dT00 + W[2][1] * dL_dT01 + W[2][2] * dL_dT02; + float dL_dJ11 = W[1][0] * dL_dT10 + W[1][1] * dL_dT11 + W[1][2] * dL_dT12; + float dL_dJ12 = W[2][0] * dL_dT10 + W[2][1] * dL_dT11 + W[2][2] * dL_dT12; + + float tz = 1.f / t.z; + float tz2 = tz * tz; + float tz3 = tz2 * tz; + + // Gradients of loss w.r.t. transformed Gaussian mean t + float dL_dtx = x_grad_mul * -h_x * tz2 * dL_dJ02; + float dL_dty = y_grad_mul * -h_y * tz2 * dL_dJ12; + float dL_dtz = -h_x * tz2 * dL_dJ00 - h_y * tz2 * dL_dJ11 + (2 * h_x * t.x) * tz3 * dL_dJ02 + (2 * h_y * t.y) * tz3 * dL_dJ12; + // Account for inverse depth gradients + if (dL_dinvdepth) + dL_dtz -= dL_dinvdepth[idx] / (t.z * t.z); + + + // Account for transformation of mean to t + // t = transformPoint4x3(mean, view_matrix); + float3 dL_dmean = transformVec4x3Transpose({ dL_dtx, dL_dty, dL_dtz }, view_matrix); + + // Gradients of loss w.r.t. Gaussian means, but only the portion + // that is caused because the mean affects the covariance matrix. + // Additional mean gradient is accumulated in BACKWARD::preprocess. + dL_dmeans[idx] = dL_dmean; +} + +// Backward pass for the conversion of scale and rotation to a +// 3D covariance matrix for each Gaussian. +__device__ void computeCov3D(int idx, const glm::vec3 scale, float mod, const glm::vec4 rot, const float* dL_dcov3Ds, glm::vec3* dL_dscales, glm::vec4* dL_drots) +{ + // Recompute (intermediate) results for the 3D covariance computation. + glm::vec4 q = rot;// / glm::length(rot); + float r = q.x; + float x = q.y; + float y = q.z; + float z = q.w; + + glm::mat3 R = glm::mat3( + 1.f - 2.f * (y * y + z * z), 2.f * (x * y - r * z), 2.f * (x * z + r * y), + 2.f * (x * y + r * z), 1.f - 2.f * (x * x + z * z), 2.f * (y * z - r * x), + 2.f * (x * z - r * y), 2.f * (y * z + r * x), 1.f - 2.f * (x * x + y * y) + ); + + glm::mat3 S = glm::mat3(1.0f); + + glm::vec3 s = mod * scale; + S[0][0] = s.x; + S[1][1] = s.y; + S[2][2] = s.z; + + glm::mat3 M = S * R; + + const float* dL_dcov3D = dL_dcov3Ds + 6 * idx; + + glm::vec3 dunc(dL_dcov3D[0], dL_dcov3D[3], dL_dcov3D[5]); + glm::vec3 ounc = 0.5f * glm::vec3(dL_dcov3D[1], dL_dcov3D[2], dL_dcov3D[4]); + + // Convert per-element covariance loss gradients to matrix form + glm::mat3 dL_dSigma = glm::mat3( + dL_dcov3D[0], 0.5f * dL_dcov3D[1], 0.5f * dL_dcov3D[2], + 0.5f * dL_dcov3D[1], dL_dcov3D[3], 0.5f * dL_dcov3D[4], + 0.5f * dL_dcov3D[2], 0.5f * dL_dcov3D[4], dL_dcov3D[5] + ); + + // Compute loss gradient w.r.t. matrix M + // dSigma_dM = 2 * M + glm::mat3 dL_dM = 2.0f * M * dL_dSigma; + + glm::mat3 Rt = glm::transpose(R); + glm::mat3 dL_dMt = glm::transpose(dL_dM); + + // Gradients of loss w.r.t. scale + glm::vec3* dL_dscale = dL_dscales + idx; + dL_dscale->x = glm::dot(Rt[0], dL_dMt[0]); + dL_dscale->y = glm::dot(Rt[1], dL_dMt[1]); + dL_dscale->z = glm::dot(Rt[2], dL_dMt[2]); + + dL_dMt[0] *= s.x; + dL_dMt[1] *= s.y; + dL_dMt[2] *= s.z; + + // Gradients of loss w.r.t. normalized quaternion + glm::vec4 dL_dq; + dL_dq.x = 2 * z * (dL_dMt[0][1] - dL_dMt[1][0]) + 2 * y * (dL_dMt[2][0] - dL_dMt[0][2]) + 2 * x * (dL_dMt[1][2] - dL_dMt[2][1]); + dL_dq.y = 2 * y * (dL_dMt[1][0] + dL_dMt[0][1]) + 2 * z * (dL_dMt[2][0] + dL_dMt[0][2]) + 2 * r * (dL_dMt[1][2] - dL_dMt[2][1]) - 4 * x * (dL_dMt[2][2] + dL_dMt[1][1]); + dL_dq.z = 2 * x * (dL_dMt[1][0] + dL_dMt[0][1]) + 2 * r * (dL_dMt[2][0] - dL_dMt[0][2]) + 2 * z * (dL_dMt[1][2] + dL_dMt[2][1]) - 4 * y * (dL_dMt[2][2] + dL_dMt[0][0]); + dL_dq.w = 2 * r * (dL_dMt[0][1] - dL_dMt[1][0]) + 2 * x * (dL_dMt[2][0] + dL_dMt[0][2]) + 2 * y * (dL_dMt[1][2] + dL_dMt[2][1]) - 4 * z * (dL_dMt[1][1] + dL_dMt[0][0]); + + // Gradients of loss w.r.t. unnormalized quaternion + float4* dL_drot = (float4*)(dL_drots + idx); + *dL_drot = float4{ dL_dq.x, dL_dq.y, dL_dq.z, dL_dq.w };//dnormvdv(float4{ rot.x, rot.y, rot.z, rot.w }, float4{ dL_dq.x, dL_dq.y, dL_dq.z, dL_dq.w }); +} + +// Backward pass of the preprocessing steps, except +// for the covariance computation and inversion +// (those are handled by a previous kernel call) +template +__global__ void preprocessCUDA( + int P, int D, int M, + const float3* means, + const int* radii, + const float* shs, + const bool* clamped, + const glm::vec3* scales, + const glm::vec4* rotations, + const float scale_modifier, + const float* proj, + const glm::vec3* campos, + const float3* dL_dmean2D, + glm::vec3* dL_dmeans, + float* dL_dcolor, + float* dL_dcov3D, + float* dL_dsh, + glm::vec3* dL_dscale, + glm::vec4* dL_drot, + float* dL_dopacity) +{ + auto idx = cg::this_grid().thread_rank(); + if (idx >= P || !(radii[idx] > 0)) + return; + + float3 m = means[idx]; + + // Taking care of gradients from the screenspace points + float4 m_hom = transformPoint4x4(m, proj); + float m_w = 1.0f / (m_hom.w + 0.0000001f); + + // Compute loss gradient w.r.t. 3D means due to gradients of 2D means + // from rendering procedure + glm::vec3 dL_dmean; + float mul1 = (proj[0] * m.x + proj[4] * m.y + proj[8] * m.z + proj[12]) * m_w * m_w; + float mul2 = (proj[1] * m.x + proj[5] * m.y + proj[9] * m.z + proj[13]) * m_w * m_w; + dL_dmean.x = (proj[0] * m_w - proj[3] * mul1) * dL_dmean2D[idx].x + (proj[1] * m_w - proj[3] * mul2) * dL_dmean2D[idx].y; + dL_dmean.y = (proj[4] * m_w - proj[7] * mul1) * dL_dmean2D[idx].x + (proj[5] * m_w - proj[7] * mul2) * dL_dmean2D[idx].y; + dL_dmean.z = (proj[8] * m_w - proj[11] * mul1) * dL_dmean2D[idx].x + (proj[9] * m_w - proj[11] * mul2) * dL_dmean2D[idx].y; + + // That's the second part of the mean gradient. Previous computation + // of cov2D and following SH conversion also affects it. + dL_dmeans[idx] += dL_dmean; + + // Compute gradient updates due to computing colors from SHs + if (shs) + computeColorFromSH(idx, D, M, (glm::vec3*)means, *campos, shs, clamped, (glm::vec3*)dL_dcolor, (glm::vec3*)dL_dmeans, (glm::vec3*)dL_dsh); + + // Compute gradient updates due to computing covariance from scale/rotation + if (scales) + computeCov3D(idx, scales[idx], scale_modifier, rotations[idx], dL_dcov3D, dL_dscale, dL_drot); +} + +// Backward version of the rendering procedure. +template +__global__ void __launch_bounds__(BLOCK_X * BLOCK_Y) +renderCUDA( + const uint2* __restrict__ ranges, + const uint32_t* __restrict__ point_list, + int W, int H, + const float* __restrict__ bg_color, + const float2* __restrict__ points_xy_image, + const float4* __restrict__ conic_opacity, + const float* __restrict__ colors, + const float* __restrict__ depths, + const float* __restrict__ final_Ts, + const uint32_t* __restrict__ n_contrib, + const float* __restrict__ dL_dpixels, + const float* __restrict__ dL_invdepths, + float3* __restrict__ dL_dmean2D, + float4* __restrict__ dL_dconic2D, + float* __restrict__ dL_dopacity, + float* __restrict__ dL_dcolors, + float* __restrict__ dL_dinvdepths +) +{ + // We rasterize again. Compute necessary block info. + auto block = cg::this_thread_block(); + const uint32_t horizontal_blocks = (W + BLOCK_X - 1) / BLOCK_X; + const uint2 pix_min = { block.group_index().x * BLOCK_X, block.group_index().y * BLOCK_Y }; + const uint2 pix_max = { min(pix_min.x + BLOCK_X, W), min(pix_min.y + BLOCK_Y , H) }; + const uint2 pix = { pix_min.x + block.thread_index().x, pix_min.y + block.thread_index().y }; + const uint32_t pix_id = W * pix.y + pix.x; + const float2 pixf = { (float)pix.x, (float)pix.y }; + + const bool inside = pix.x < W&& pix.y < H; + const uint2 range = ranges[block.group_index().y * horizontal_blocks + block.group_index().x]; + + const int rounds = ((range.y - range.x + BLOCK_SIZE - 1) / BLOCK_SIZE); + + bool done = !inside; + int toDo = range.y - range.x; + + __shared__ int collected_id[BLOCK_SIZE]; + __shared__ float2 collected_xy[BLOCK_SIZE]; + __shared__ float4 collected_conic_opacity[BLOCK_SIZE]; + __shared__ float collected_colors[C * BLOCK_SIZE]; + __shared__ float collected_depths[BLOCK_SIZE]; + + + // In the forward, we stored the final value for T, the + // product of all (1 - alpha) factors. + const float T_final = inside ? final_Ts[pix_id] : 0; + float T = T_final; + + // We start from the back. The ID of the last contributing + // Gaussian is known from each pixel from the forward. + uint32_t contributor = toDo; + const int last_contributor = inside ? n_contrib[pix_id] : 0; + + float accum_rec[C] = { 0 }; + float dL_dpixel[C]; + float dL_invdepth; + float accum_invdepth_rec = 0; + if (inside) + { + for (int i = 0; i < C; i++) + dL_dpixel[i] = dL_dpixels[i * H * W + pix_id]; + if(dL_invdepths) + dL_invdepth = dL_invdepths[pix_id]; + } + + float last_alpha = 0; + float last_color[C] = { 0 }; + float last_invdepth = 0; + + + // Gradient of pixel coordinate w.r.t. normalized + // screen-space viewport corrdinates (-1 to 1) + const float ddelx_dx = 0.5 * W; + const float ddely_dy = 0.5 * H; + + // Traverse all Gaussians + for (int i = 0; i < rounds; i++, toDo -= BLOCK_SIZE) + { + // Load auxiliary data into shared memory, start in the BACK + // and load them in revers order. + block.sync(); + const int progress = i * BLOCK_SIZE + block.thread_rank(); + if (range.x + progress < range.y) + { + const int coll_id = point_list[range.y - progress - 1]; + collected_id[block.thread_rank()] = coll_id; + collected_xy[block.thread_rank()] = points_xy_image[coll_id]; + collected_conic_opacity[block.thread_rank()] = conic_opacity[coll_id]; + for (int i = 0; i < C; i++) + collected_colors[i * BLOCK_SIZE + block.thread_rank()] = colors[coll_id * C + i]; + + if(dL_invdepths) + collected_depths[block.thread_rank()] = depths[coll_id]; + } + block.sync(); + + // Iterate over Gaussians + for (int j = 0; !done && j < min(BLOCK_SIZE, toDo); j++) + { + // Keep track of current Gaussian ID. Skip, if this one + // is behind the last contributor for this pixel. + contributor--; + if (contributor >= last_contributor) + continue; + + // Compute blending values, as before. + const float2 xy = collected_xy[j]; + const float2 d = { xy.x - pixf.x, xy.y - pixf.y }; + const float4 con_o = collected_conic_opacity[j]; + const float power = -0.5f * (con_o.x * d.x * d.x + con_o.z * d.y * d.y) - con_o.y * d.x * d.y; + if (power > 0.0f) + continue; + + const float G = exp(power); + const float alpha = min(0.99f, con_o.w * G); + if (alpha < 1.0f / 255.0f) + continue; + + T = T / (1.f - alpha); + const float dchannel_dcolor = alpha * T; + + // Propagate gradients to per-Gaussian colors and keep + // gradients w.r.t. alpha (blending factor for a Gaussian/pixel + // pair). + float dL_dalpha = 0.0f; + const int global_id = collected_id[j]; + for (int ch = 0; ch < C; ch++) + { + const float c = collected_colors[ch * BLOCK_SIZE + j]; + // Update last color (to be used in the next iteration) + accum_rec[ch] = last_alpha * last_color[ch] + (1.f - last_alpha) * accum_rec[ch]; + last_color[ch] = c; + + const float dL_dchannel = dL_dpixel[ch]; + dL_dalpha += (c - accum_rec[ch]) * dL_dchannel; + // Update the gradients w.r.t. color of the Gaussian. + // Atomic, since this pixel is just one of potentially + // many that were affected by this Gaussian. + atomicAdd(&(dL_dcolors[global_id * C + ch]), dchannel_dcolor * dL_dchannel); + } + // Propagate gradients from inverse depth to alphaas and + // per Gaussian inverse depths + if (dL_dinvdepths) + { + const float invd = 1.f / collected_depths[j]; + accum_invdepth_rec = last_alpha * last_invdepth + (1.f - last_alpha) * accum_invdepth_rec; + last_invdepth = invd; + dL_dalpha += (invd - accum_invdepth_rec) * dL_invdepth; + atomicAdd(&(dL_dinvdepths[global_id]), dchannel_dcolor * dL_invdepth); + } + + dL_dalpha *= T; + // Update last alpha (to be used in the next iteration) + last_alpha = alpha; + + // Account for fact that alpha also influences how much of + // the background color is added if nothing left to blend + float bg_dot_dpixel = 0; + for (int i = 0; i < C; i++) + bg_dot_dpixel += bg_color[i] * dL_dpixel[i]; + dL_dalpha += (-T_final / (1.f - alpha)) * bg_dot_dpixel; + + + // Helpful reusable temporary variables + const float dL_dG = con_o.w * dL_dalpha; + const float gdx = G * d.x; + const float gdy = G * d.y; + const float dG_ddelx = -gdx * con_o.x - gdy * con_o.y; + const float dG_ddely = -gdy * con_o.z - gdx * con_o.y; + + // Update gradients w.r.t. 2D mean position of the Gaussian + atomicAdd(&dL_dmean2D[global_id].x, dL_dG * dG_ddelx * ddelx_dx); + atomicAdd(&dL_dmean2D[global_id].y, dL_dG * dG_ddely * ddely_dy); + + // Update gradients w.r.t. 2D covariance (2x2 matrix, symmetric) + atomicAdd(&dL_dconic2D[global_id].x, -0.5f * gdx * d.x * dL_dG); + atomicAdd(&dL_dconic2D[global_id].y, -0.5f * gdx * d.y * dL_dG); + atomicAdd(&dL_dconic2D[global_id].w, -0.5f * gdy * d.y * dL_dG); + + // Update gradients w.r.t. opacity of the Gaussian + atomicAdd(&(dL_dopacity[global_id]), G * dL_dalpha); + } + } +} + +void BACKWARD::preprocess( + int P, int D, int M, + const float3* means3D, + const int* radii, + const float* shs, + const bool* clamped, + const float* opacities, + const glm::vec3* scales, + const glm::vec4* rotations, + const float scale_modifier, + const float* cov3Ds, + const float* viewmatrix, + const float* projmatrix, + const float focal_x, float focal_y, + const float tan_fovx, float tan_fovy, + const glm::vec3* campos, + const float3* dL_dmean2D, + const float* dL_dconic, + const float* dL_dinvdepth, + float* dL_dopacity, + glm::vec3* dL_dmean3D, + float* dL_dcolor, + float* dL_dcov3D, + float* dL_dsh, + glm::vec3* dL_dscale, + glm::vec4* dL_drot, + bool antialiasing) +{ + // Propagate gradients for the path of 2D conic matrix computation. + // Somewhat long, thus it is its own kernel rather than being part of + // "preprocess". When done, loss gradient w.r.t. 3D means has been + // modified and gradient w.r.t. 3D covariance matrix has been computed. + computeCov2DCUDA << <(P + 255) / 256, 256 >> > ( + P, + means3D, + radii, + cov3Ds, + focal_x, + focal_y, + tan_fovx, + tan_fovy, + viewmatrix, + opacities, + dL_dconic, + dL_dopacity, + dL_dinvdepth, + (float3*)dL_dmean3D, + dL_dcov3D, + antialiasing); + + // Propagate gradients for remaining steps: finish 3D mean gradients, + // propagate color gradients to SH (if desireD), propagate 3D covariance + // matrix gradients to scale and rotation. + preprocessCUDA << < (P + 255) / 256, 256 >> > ( + P, D, M, + (float3*)means3D, + radii, + shs, + clamped, + (glm::vec3*)scales, + (glm::vec4*)rotations, + scale_modifier, + projmatrix, + campos, + (float3*)dL_dmean2D, + (glm::vec3*)dL_dmean3D, + dL_dcolor, + dL_dcov3D, + dL_dsh, + dL_dscale, + dL_drot, + dL_dopacity); +} + +void BACKWARD::render( + const dim3 grid, const dim3 block, + const uint2* ranges, + const uint32_t* point_list, + int W, int H, + const float* bg_color, + const float2* means2D, + const float4* conic_opacity, + const float* colors, + const float* depths, + const float* final_Ts, + const uint32_t* n_contrib, + const float* dL_dpixels, + const float* dL_invdepths, + float3* dL_dmean2D, + float4* dL_dconic2D, + float* dL_dopacity, + float* dL_dcolors, + float* dL_dinvdepths) +{ + renderCUDA << > >( + ranges, + point_list, + W, H, + bg_color, + means2D, + conic_opacity, + colors, + depths, + final_Ts, + n_contrib, + dL_dpixels, + dL_invdepths, + dL_dmean2D, + dL_dconic2D, + dL_dopacity, + dL_dcolors, + dL_dinvdepths + ); +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/cuda_rasterizer/backward.h b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/cuda_rasterizer/backward.h new file mode 100644 index 0000000000000000000000000000000000000000..4d02560f9cd6d8f66bd5801a8cd9f5c6fbc0243e --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/cuda_rasterizer/backward.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2023, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact george.drettakis@inria.fr + */ + +#ifndef CUDA_RASTERIZER_BACKWARD_H_INCLUDED +#define CUDA_RASTERIZER_BACKWARD_H_INCLUDED + +#include +#include "cuda_runtime.h" +#include "device_launch_parameters.h" +#define GLM_FORCE_CUDA +#include + +namespace BACKWARD +{ + void render( + const dim3 grid, dim3 block, + const uint2* ranges, + const uint32_t* point_list, + int W, int H, + const float* bg_color, + const float2* means2D, + const float4* conic_opacity, + const float* colors, + const float* depths, + const float* final_Ts, + const uint32_t* n_contrib, + const float* dL_dpixels, + const float* dL_invdepths, + float3* dL_dmean2D, + float4* dL_dconic2D, + float* dL_dopacity, + float* dL_dcolors, + float* dL_dinvdepths); + + void preprocess( + int P, int D, int M, + const float3* means, + const int* radii, + const float* shs, + const bool* clamped, + const float* opacities, + const glm::vec3* scales, + const glm::vec4* rotations, + const float scale_modifier, + const float* cov3Ds, + const float* view, + const float* proj, + const float focal_x, float focal_y, + const float tan_fovx, float tan_fovy, + const glm::vec3* campos, + const float3* dL_dmean2D, + const float* dL_dconics, + const float* dL_dinvdepth, + float* dL_dopacity, + glm::vec3* dL_dmeans, + float* dL_dcolor, + float* dL_dcov3D, + float* dL_dsh, + glm::vec3* dL_dscale, + glm::vec4* dL_drot, + bool antialiasing); +} + +#endif diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/cuda_rasterizer/config.h b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/cuda_rasterizer/config.h new file mode 100644 index 0000000000000000000000000000000000000000..2a912fb34824349caadffe435fc1ab4b31e5aa4f --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/cuda_rasterizer/config.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2023, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact george.drettakis@inria.fr + */ + +#ifndef CUDA_RASTERIZER_CONFIG_H_INCLUDED +#define CUDA_RASTERIZER_CONFIG_H_INCLUDED + +#define NUM_CHANNELS 3 // Default 3, RGB +#define BLOCK_X 16 +#define BLOCK_Y 16 + +#endif \ No newline at end of file diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/cuda_rasterizer/forward.cu b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/cuda_rasterizer/forward.cu new file mode 100644 index 0000000000000000000000000000000000000000..c5e01ddc475c88f41c4368894330851aa3acc67e --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/cuda_rasterizer/forward.cu @@ -0,0 +1,484 @@ +/* + * Copyright (C) 2023, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact george.drettakis@inria.fr + */ + +#include "forward.h" +#include "auxiliary.h" +#include +#include +namespace cg = cooperative_groups; + +// Forward method for converting the input spherical harmonics +// coefficients of each Gaussian to a simple RGB color. +__device__ glm::vec3 computeColorFromSH(int idx, int deg, int max_coeffs, const glm::vec3* means, glm::vec3 campos, const float* shs, bool* clamped) +{ + // The implementation is loosely based on code for + // "Differentiable Point-Based Radiance Fields for + // Efficient View Synthesis" by Zhang et al. (2022) + glm::vec3 pos = means[idx]; + glm::vec3 dir = pos - campos; + dir = dir / glm::length(dir); + + glm::vec3* sh = ((glm::vec3*)shs) + idx * max_coeffs; + glm::vec3 result = SH_C0 * sh[0]; + + if (deg > 0) + { + float x = dir.x; + float y = dir.y; + float z = dir.z; + result = result - SH_C1 * y * sh[1] + SH_C1 * z * sh[2] - SH_C1 * x * sh[3]; + + if (deg > 1) + { + float xx = x * x, yy = y * y, zz = z * z; + float xy = x * y, yz = y * z, xz = x * z; + result = result + + SH_C2[0] * xy * sh[4] + + SH_C2[1] * yz * sh[5] + + SH_C2[2] * (2.0f * zz - xx - yy) * sh[6] + + SH_C2[3] * xz * sh[7] + + SH_C2[4] * (xx - yy) * sh[8]; + + if (deg > 2) + { + result = result + + SH_C3[0] * y * (3.0f * xx - yy) * sh[9] + + SH_C3[1] * xy * z * sh[10] + + SH_C3[2] * y * (4.0f * zz - xx - yy) * sh[11] + + SH_C3[3] * z * (2.0f * zz - 3.0f * xx - 3.0f * yy) * sh[12] + + SH_C3[4] * x * (4.0f * zz - xx - yy) * sh[13] + + SH_C3[5] * z * (xx - yy) * sh[14] + + SH_C3[6] * x * (xx - 3.0f * yy) * sh[15]; + } + } + } + result += 0.5f; + + // RGB colors are clamped to positive values. If values are + // clamped, we need to keep track of this for the backward pass. + clamped[3 * idx + 0] = (result.x < 0); + clamped[3 * idx + 1] = (result.y < 0); + clamped[3 * idx + 2] = (result.z < 0); + return glm::max(result, 0.0f); +} + +// Forward version of 2D covariance matrix computation +__device__ float3 computeCov2D(const float3& mean, float focal_x, float focal_y, float tan_fovx, float tan_fovy, const float* cov3D, const float* viewmatrix) +{ + // The following models the steps outlined by equations 29 + // and 31 in "EWA Splatting" (Zwicker et al., 2002). + // Additionally considers aspect / scaling of viewport. + // Transposes used to account for row-/column-major conventions. + float3 t = transformPoint4x3(mean, viewmatrix); + + const float limx = 1.3f * tan_fovx; + const float limy = 1.3f * tan_fovy; + const float txtz = t.x / t.z; + const float tytz = t.y / t.z; + t.x = min(limx, max(-limx, txtz)) * t.z; + t.y = min(limy, max(-limy, tytz)) * t.z; + + glm::mat3 J = glm::mat3( + focal_x / t.z, 0.0f, -(focal_x * t.x) / (t.z * t.z), + 0.0f, focal_y / t.z, -(focal_y * t.y) / (t.z * t.z), + 0, 0, 0); + + glm::mat3 W = glm::mat3( + viewmatrix[0], viewmatrix[4], viewmatrix[8], + viewmatrix[1], viewmatrix[5], viewmatrix[9], + viewmatrix[2], viewmatrix[6], viewmatrix[10]); + + glm::mat3 T = W * J; + + glm::mat3 Vrk = glm::mat3( + cov3D[0], cov3D[1], cov3D[2], + cov3D[1], cov3D[3], cov3D[4], + cov3D[2], cov3D[4], cov3D[5]); + + glm::mat3 cov = glm::transpose(T) * glm::transpose(Vrk) * T; + + return { float(cov[0][0]), float(cov[0][1]), float(cov[1][1]) }; +} + +// Forward method for converting scale and rotation properties of each +// Gaussian to a 3D covariance matrix in world space. Also takes care +// of quaternion normalization. +__device__ void computeCov3D(const glm::vec3 scale, float mod, const glm::vec4 rot, float* cov3D) +{ + // Create scaling matrix + glm::mat3 S = glm::mat3(1.0f); + S[0][0] = mod * scale.x; + S[1][1] = mod * scale.y; + S[2][2] = mod * scale.z; + + // Normalize quaternion to get valid rotation + glm::vec4 q = rot;// / glm::length(rot); + float r = q.x; + float x = q.y; + float y = q.z; + float z = q.w; + + // Compute rotation matrix from quaternion + glm::mat3 R = glm::mat3( + 1.f - 2.f * (y * y + z * z), 2.f * (x * y - r * z), 2.f * (x * z + r * y), + 2.f * (x * y + r * z), 1.f - 2.f * (x * x + z * z), 2.f * (y * z - r * x), + 2.f * (x * z - r * y), 2.f * (y * z + r * x), 1.f - 2.f * (x * x + y * y) + ); + + glm::mat3 M = S * R; + + // Compute 3D world covariance matrix Sigma + glm::mat3 Sigma = glm::transpose(M) * M; + + // Covariance is symmetric, only store upper right + cov3D[0] = Sigma[0][0]; + cov3D[1] = Sigma[0][1]; + cov3D[2] = Sigma[0][2]; + cov3D[3] = Sigma[1][1]; + cov3D[4] = Sigma[1][2]; + cov3D[5] = Sigma[2][2]; +} + +// Perform initial steps for each Gaussian prior to rasterization. +template +__global__ void preprocessCUDA(int P, int D, int M, + const float* orig_points, + const glm::vec3* scales, + const float scale_modifier, + const glm::vec4* rotations, + const float* opacities, + const float* shs, + bool* clamped, + const float* cov3D_precomp, + const float* colors_precomp, + const float* viewmatrix, + const float* projmatrix, + const glm::vec3* cam_pos, + const int W, int H, + const float tan_fovx, float tan_fovy, + const float focal_x, float focal_y, + int* radii, + float2* points_xy_image, + float* depths, + float* cov3Ds, + float* rgb, + float4* conic_opacity, + const dim3 grid, + uint32_t* tiles_touched, + bool prefiltered, + bool antialiasing) +{ + auto idx = cg::this_grid().thread_rank(); + if (idx >= P) + return; + + // Initialize radius and touched tiles to 0. If this isn't changed, + // this Gaussian will not be processed further. + radii[idx] = 0; + tiles_touched[idx] = 0; + + // Perform near culling, quit if outside. + float3 p_view; + if (!in_frustum(idx, orig_points, viewmatrix, projmatrix, prefiltered, p_view)) + return; + + // Transform point by projecting + float3 p_orig = { orig_points[3 * idx], orig_points[3 * idx + 1], orig_points[3 * idx + 2] }; + float4 p_hom = transformPoint4x4(p_orig, projmatrix); + float p_w = 1.0f / (p_hom.w + 0.0000001f); + float3 p_proj = { p_hom.x * p_w, p_hom.y * p_w, p_hom.z * p_w }; + + // If 3D covariance matrix is precomputed, use it, otherwise compute + // from scaling and rotation parameters. + const float* cov3D; + if (cov3D_precomp != nullptr) + { + cov3D = cov3D_precomp + idx * 6; + } + else + { + computeCov3D(scales[idx], scale_modifier, rotations[idx], cov3Ds + idx * 6); + cov3D = cov3Ds + idx * 6; + } + + // Compute 2D screen-space covariance matrix + float3 cov = computeCov2D(p_orig, focal_x, focal_y, tan_fovx, tan_fovy, cov3D, viewmatrix); + + constexpr float h_var = 0.3f; + const float det_cov = cov.x * cov.z - cov.y * cov.y; + cov.x += h_var; + cov.z += h_var; + const float det_cov_plus_h_cov = cov.x * cov.z - cov.y * cov.y; + float h_convolution_scaling = 1.0f; + + if(antialiasing) + h_convolution_scaling = sqrt(max(0.000025f, det_cov / det_cov_plus_h_cov)); // max for numerical stability + + // Invert covariance (EWA algorithm) + const float det = det_cov_plus_h_cov; + + if (det == 0.0f) + return; + float det_inv = 1.f / det; + float3 conic = { cov.z * det_inv, -cov.y * det_inv, cov.x * det_inv }; + + // Compute extent in screen space (by finding eigenvalues of + // 2D covariance matrix). Use extent to compute a bounding rectangle + // of screen-space tiles that this Gaussian overlaps with. Quit if + // rectangle covers 0 tiles. + float mid = 0.5f * (cov.x + cov.z); + float lambda1 = mid + sqrt(max(0.1f, mid * mid - det)); + float lambda2 = mid - sqrt(max(0.1f, mid * mid - det)); + float my_radius = ceil(3.f * sqrt(max(lambda1, lambda2))); + float2 point_image = { ndc2Pix(p_proj.x, W), ndc2Pix(p_proj.y, H) }; + uint2 rect_min, rect_max; + getRect(point_image, my_radius, rect_min, rect_max, grid); + if ((rect_max.x - rect_min.x) * (rect_max.y - rect_min.y) == 0) + return; + + // If colors have been precomputed, use them, otherwise convert + // spherical harmonics coefficients to RGB color. + if (colors_precomp == nullptr) + { + glm::vec3 result = computeColorFromSH(idx, D, M, (glm::vec3*)orig_points, *cam_pos, shs, clamped); + rgb[idx * C + 0] = result.x; + rgb[idx * C + 1] = result.y; + rgb[idx * C + 2] = result.z; + } + + // Store some useful helper data for the next steps. + depths[idx] = p_view.z; + radii[idx] = my_radius; + points_xy_image[idx] = point_image; + // Inverse 2D covariance and opacity neatly pack into one float4 + float opacity = opacities[idx]; + + + conic_opacity[idx] = { conic.x, conic.y, conic.z, opacity * h_convolution_scaling }; + + + tiles_touched[idx] = (rect_max.y - rect_min.y) * (rect_max.x - rect_min.x); +} + +// Main rasterization method. Collaboratively works on one tile per +// block, each thread treats one pixel. Alternates between fetching +// and rasterizing data. +template +__global__ void __launch_bounds__(BLOCK_X * BLOCK_Y) +renderCUDA( + const uint2* __restrict__ ranges, + const uint32_t* __restrict__ point_list, + int W, int H, + const float2* __restrict__ points_xy_image, + const float* __restrict__ features, + const float4* __restrict__ conic_opacity, + float* __restrict__ final_T, + uint32_t* __restrict__ n_contrib, + const float* __restrict__ bg_color, + float* __restrict__ out_color, + const float* __restrict__ depths, + float* __restrict__ invdepth) +{ + // Identify current tile and associated min/max pixel range. + auto block = cg::this_thread_block(); + uint32_t horizontal_blocks = (W + BLOCK_X - 1) / BLOCK_X; + uint2 pix_min = { block.group_index().x * BLOCK_X, block.group_index().y * BLOCK_Y }; + uint2 pix_max = { min(pix_min.x + BLOCK_X, W), min(pix_min.y + BLOCK_Y , H) }; + uint2 pix = { pix_min.x + block.thread_index().x, pix_min.y + block.thread_index().y }; + uint32_t pix_id = W * pix.y + pix.x; + float2 pixf = { (float)pix.x, (float)pix.y }; + + // Check if this thread is associated with a valid pixel or outside. + bool inside = pix.x < W&& pix.y < H; + // Done threads can help with fetching, but don't rasterize + bool done = !inside; + + // Load start/end range of IDs to process in bit sorted list. + uint2 range = ranges[block.group_index().y * horizontal_blocks + block.group_index().x]; + const int rounds = ((range.y - range.x + BLOCK_SIZE - 1) / BLOCK_SIZE); + int toDo = range.y - range.x; + + // Allocate storage for batches of collectively fetched data. + __shared__ int collected_id[BLOCK_SIZE]; + __shared__ float2 collected_xy[BLOCK_SIZE]; + __shared__ float4 collected_conic_opacity[BLOCK_SIZE]; + + // Initialize helper variables + float T = 1.0f; + uint32_t contributor = 0; + uint32_t last_contributor = 0; + float C[CHANNELS] = { 0 }; + + float expected_invdepth = 0.0f; + + // Iterate over batches until all done or range is complete + for (int i = 0; i < rounds; i++, toDo -= BLOCK_SIZE) + { + // End if entire block votes that it is done rasterizing + int num_done = __syncthreads_count(done); + if (num_done == BLOCK_SIZE) + break; + + // Collectively fetch per-Gaussian data from global to shared + int progress = i * BLOCK_SIZE + block.thread_rank(); + if (range.x + progress < range.y) + { + int coll_id = point_list[range.x + progress]; + collected_id[block.thread_rank()] = coll_id; + collected_xy[block.thread_rank()] = points_xy_image[coll_id]; + collected_conic_opacity[block.thread_rank()] = conic_opacity[coll_id]; + } + block.sync(); + + // Iterate over current batch + for (int j = 0; !done && j < min(BLOCK_SIZE, toDo); j++) + { + // Keep track of current position in range + contributor++; + + // Resample using conic matrix (cf. "Surface + // Splatting" by Zwicker et al., 2001) + float2 xy = collected_xy[j]; + float2 d = { xy.x - pixf.x, xy.y - pixf.y }; + float4 con_o = collected_conic_opacity[j]; + float power = -0.5f * (con_o.x * d.x * d.x + con_o.z * d.y * d.y) - con_o.y * d.x * d.y; + if (power > 0.0f) + continue; + + // Eq. (2) from 3D Gaussian splatting paper. + // Obtain alpha by multiplying with Gaussian opacity + // and its exponential falloff from mean. + // Avoid numerical instabilities (see paper appendix). + float alpha = min(0.99f, con_o.w * exp(power)); + if (alpha < 1.0f / 255.0f) + continue; + float test_T = T * (1 - alpha); + if (test_T < 0.0001f) + { + done = true; + continue; + } + + // Eq. (3) from 3D Gaussian splatting paper. + for (int ch = 0; ch < CHANNELS; ch++) + C[ch] += features[collected_id[j] * CHANNELS + ch] * alpha * T; + + if(invdepth) + expected_invdepth += (1 / depths[collected_id[j]]) * alpha * T; + + T = test_T; + + // Keep track of last range entry to update this + // pixel. + last_contributor = contributor; + } + } + + // All threads that treat valid pixel write out their final + // rendering data to the frame and auxiliary buffers. + if (inside) + { + final_T[pix_id] = T; + n_contrib[pix_id] = last_contributor; + for (int ch = 0; ch < CHANNELS; ch++) + out_color[ch * H * W + pix_id] = C[ch] + T * bg_color[ch]; + + if (invdepth) + invdepth[pix_id] = expected_invdepth;// 1. / (expected_depth + T * 1e3); + } +} + +void FORWARD::render( + const dim3 grid, dim3 block, + const uint2* ranges, + const uint32_t* point_list, + int W, int H, + const float2* means2D, + const float* colors, + const float4* conic_opacity, + float* final_T, + uint32_t* n_contrib, + const float* bg_color, + float* out_color, + float* depths, + float* depth) +{ + renderCUDA << > > ( + ranges, + point_list, + W, H, + means2D, + colors, + conic_opacity, + final_T, + n_contrib, + bg_color, + out_color, + depths, + depth); +} + +void FORWARD::preprocess(int P, int D, int M, + const float* means3D, + const glm::vec3* scales, + const float scale_modifier, + const glm::vec4* rotations, + const float* opacities, + const float* shs, + bool* clamped, + const float* cov3D_precomp, + const float* colors_precomp, + const float* viewmatrix, + const float* projmatrix, + const glm::vec3* cam_pos, + const int W, int H, + const float focal_x, float focal_y, + const float tan_fovx, float tan_fovy, + int* radii, + float2* means2D, + float* depths, + float* cov3Ds, + float* rgb, + float4* conic_opacity, + const dim3 grid, + uint32_t* tiles_touched, + bool prefiltered, + bool antialiasing) +{ + preprocessCUDA << <(P + 255) / 256, 256 >> > ( + P, D, M, + means3D, + scales, + scale_modifier, + rotations, + opacities, + shs, + clamped, + cov3D_precomp, + colors_precomp, + viewmatrix, + projmatrix, + cam_pos, + W, H, + tan_fovx, tan_fovy, + focal_x, focal_y, + radii, + means2D, + depths, + cov3Ds, + rgb, + conic_opacity, + grid, + tiles_touched, + prefiltered, + antialiasing + ); +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/cuda_rasterizer/forward.h b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/cuda_rasterizer/forward.h new file mode 100644 index 0000000000000000000000000000000000000000..5b18005f73e0c78d4444fac676a93da3ba21753a --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/cuda_rasterizer/forward.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2023, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact george.drettakis@inria.fr + */ + +#ifndef CUDA_RASTERIZER_FORWARD_H_INCLUDED +#define CUDA_RASTERIZER_FORWARD_H_INCLUDED + +#include +#include "cuda_runtime.h" +#include "device_launch_parameters.h" +#define GLM_FORCE_CUDA +#include + +namespace FORWARD +{ + // Perform initial steps for each Gaussian prior to rasterization. + void preprocess(int P, int D, int M, + const float* orig_points, + const glm::vec3* scales, + const float scale_modifier, + const glm::vec4* rotations, + const float* opacities, + const float* shs, + bool* clamped, + const float* cov3D_precomp, + const float* colors_precomp, + const float* viewmatrix, + const float* projmatrix, + const glm::vec3* cam_pos, + const int W, int H, + const float focal_x, float focal_y, + const float tan_fovx, float tan_fovy, + int* radii, + float2* points_xy_image, + float* depths, + float* cov3Ds, + float* colors, + float4* conic_opacity, + const dim3 grid, + uint32_t* tiles_touched, + bool prefiltered, + bool antialiasing); + + // Main rasterization method. + void render( + const dim3 grid, dim3 block, + const uint2* ranges, + const uint32_t* point_list, + int W, int H, + const float2* points_xy_image, + const float* features, + const float4* conic_opacity, + float* final_T, + uint32_t* n_contrib, + const float* bg_color, + float* out_color, + float* depths, + float* depth); +} + + +#endif diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/cuda_rasterizer/rasterizer.h b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/cuda_rasterizer/rasterizer.h new file mode 100644 index 0000000000000000000000000000000000000000..64afdee905d2f6c45d71d3f9f168b25d1844a581 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/cuda_rasterizer/rasterizer.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2023, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact george.drettakis@inria.fr + */ + +#ifndef CUDA_RASTERIZER_H_INCLUDED +#define CUDA_RASTERIZER_H_INCLUDED + +#include +#include + +namespace CudaRasterizer +{ + class Rasterizer + { + public: + + static void markVisible( + int P, + float* means3D, + float* viewmatrix, + float* projmatrix, + bool* present); + + static int forward( + std::function geometryBuffer, + std::function binningBuffer, + std::function imageBuffer, + const int P, int D, int M, + const float* background, + const int width, int height, + const float* means3D, + const float* shs, + const float* colors_precomp, + const float* opacities, + const float* scales, + const float scale_modifier, + const float* rotations, + const float* cov3D_precomp, + const float* viewmatrix, + const float* projmatrix, + const float* cam_pos, + const float tan_fovx, float tan_fovy, + const bool prefiltered, + float* out_color, + float* depth, + bool antialiasing, + int* radii = nullptr, + bool debug = false); + + static void backward( + const int P, int D, int M, int R, + const float* background, + const int width, int height, + const float* means3D, + const float* shs, + const float* colors_precomp, + const float* opacities, + const float* scales, + const float scale_modifier, + const float* rotations, + const float* cov3D_precomp, + const float* viewmatrix, + const float* projmatrix, + const float* campos, + const float tan_fovx, float tan_fovy, + const int* radii, + char* geom_buffer, + char* binning_buffer, + char* image_buffer, + const float* dL_dpix, + const float* dL_invdepths, + float* dL_dmean2D, + float* dL_dconic, + float* dL_dopacity, + float* dL_dcolor, + float* dL_dinvdepth, + float* dL_dmean3D, + float* dL_dcov3D, + float* dL_dsh, + float* dL_dscale, + float* dL_drot, + bool antialiasing, + bool debug); + }; +}; + +#endif diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/cuda_rasterizer/rasterizer_impl.cu b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/cuda_rasterizer/rasterizer_impl.cu new file mode 100644 index 0000000000000000000000000000000000000000..41c4ed3a433d260770732b8e0e7a43f2d995aa61 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/cuda_rasterizer/rasterizer_impl.cu @@ -0,0 +1,450 @@ +/* + * Copyright (C) 2023, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact george.drettakis@inria.fr + */ + +#include "rasterizer_impl.h" +#include +#include +#include +#include +#include +#include "cuda_runtime.h" +#include "device_launch_parameters.h" +#include +#include +#define GLM_FORCE_CUDA +#include + +#include +#include +namespace cg = cooperative_groups; + +#include "auxiliary.h" +#include "forward.h" +#include "backward.h" + +// Helper function to find the next-highest bit of the MSB +// on the CPU. +uint32_t getHigherMsb(uint32_t n) +{ + uint32_t msb = sizeof(n) * 4; + uint32_t step = msb; + while (step > 1) + { + step /= 2; + if (n >> msb) + msb += step; + else + msb -= step; + } + if (n >> msb) + msb++; + return msb; +} + +// Wrapper method to call auxiliary coarse frustum containment test. +// Mark all Gaussians that pass it. +__global__ void checkFrustum(int P, + const float* orig_points, + const float* viewmatrix, + const float* projmatrix, + bool* present) +{ + auto idx = cg::this_grid().thread_rank(); + if (idx >= P) + return; + + float3 p_view; + present[idx] = in_frustum(idx, orig_points, viewmatrix, projmatrix, false, p_view); +} + +// Generates one key/value pair for all Gaussian / tile overlaps. +// Run once per Gaussian (1:N mapping). +__global__ void duplicateWithKeys( + int P, + const float2* points_xy, + const float* depths, + const uint32_t* offsets, + uint64_t* gaussian_keys_unsorted, + uint32_t* gaussian_values_unsorted, + int* radii, + dim3 grid) +{ + auto idx = cg::this_grid().thread_rank(); + if (idx >= P) + return; + + // Generate no key/value pair for invisible Gaussians + if (radii[idx] > 0) + { + // Find this Gaussian's offset in buffer for writing keys/values. + uint32_t off = (idx == 0) ? 0 : offsets[idx - 1]; + uint2 rect_min, rect_max; + + getRect(points_xy[idx], radii[idx], rect_min, rect_max, grid); + + // For each tile that the bounding rect overlaps, emit a + // key/value pair. The key is | tile ID | depth |, + // and the value is the ID of the Gaussian. Sorting the values + // with this key yields Gaussian IDs in a list, such that they + // are first sorted by tile and then by depth. + for (int y = rect_min.y; y < rect_max.y; y++) + { + for (int x = rect_min.x; x < rect_max.x; x++) + { + uint64_t key = y * grid.x + x; + key <<= 32; + key |= *((uint32_t*)&depths[idx]); + gaussian_keys_unsorted[off] = key; + gaussian_values_unsorted[off] = idx; + off++; + } + } + } +} + +// Check keys to see if it is at the start/end of one tile's range in +// the full sorted list. If yes, write start/end of this tile. +// Run once per instanced (duplicated) Gaussian ID. +__global__ void identifyTileRanges(int L, uint64_t* point_list_keys, uint2* ranges) +{ + auto idx = cg::this_grid().thread_rank(); + if (idx >= L) + return; + + // Read tile ID from key. Update start/end of tile range if at limit. + uint64_t key = point_list_keys[idx]; + uint32_t currtile = key >> 32; + if (idx == 0) + ranges[currtile].x = 0; + else + { + uint32_t prevtile = point_list_keys[idx - 1] >> 32; + if (currtile != prevtile) + { + ranges[prevtile].y = idx; + ranges[currtile].x = idx; + } + } + if (idx == L - 1) + ranges[currtile].y = L; +} + +// Mark Gaussians as visible/invisible, based on view frustum testing +void CudaRasterizer::Rasterizer::markVisible( + int P, + float* means3D, + float* viewmatrix, + float* projmatrix, + bool* present) +{ + checkFrustum << <(P + 255) / 256, 256 >> > ( + P, + means3D, + viewmatrix, projmatrix, + present); +} + +CudaRasterizer::GeometryState CudaRasterizer::GeometryState::fromChunk(char*& chunk, size_t P) +{ + GeometryState geom; + obtain(chunk, geom.depths, P, 128); + obtain(chunk, geom.clamped, P * 3, 128); + obtain(chunk, geom.internal_radii, P, 128); + obtain(chunk, geom.means2D, P, 128); + obtain(chunk, geom.cov3D, P * 6, 128); + obtain(chunk, geom.conic_opacity, P, 128); + obtain(chunk, geom.rgb, P * 3, 128); + obtain(chunk, geom.tiles_touched, P, 128); + cub::DeviceScan::InclusiveSum(nullptr, geom.scan_size, geom.tiles_touched, geom.tiles_touched, P); + obtain(chunk, geom.scanning_space, geom.scan_size, 128); + obtain(chunk, geom.point_offsets, P, 128); + return geom; +} + +CudaRasterizer::ImageState CudaRasterizer::ImageState::fromChunk(char*& chunk, size_t N) +{ + ImageState img; + obtain(chunk, img.accum_alpha, N, 128); + obtain(chunk, img.n_contrib, N, 128); + obtain(chunk, img.ranges, N, 128); + return img; +} + +CudaRasterizer::BinningState CudaRasterizer::BinningState::fromChunk(char*& chunk, size_t P) +{ + BinningState binning; + obtain(chunk, binning.point_list, P, 128); + obtain(chunk, binning.point_list_unsorted, P, 128); + obtain(chunk, binning.point_list_keys, P, 128); + obtain(chunk, binning.point_list_keys_unsorted, P, 128); + cub::DeviceRadixSort::SortPairs( + nullptr, binning.sorting_size, + binning.point_list_keys_unsorted, binning.point_list_keys, + binning.point_list_unsorted, binning.point_list, P); + obtain(chunk, binning.list_sorting_space, binning.sorting_size, 128); + return binning; +} + +// Forward rendering procedure for differentiable rasterization +// of Gaussians. +int CudaRasterizer::Rasterizer::forward( + std::function geometryBuffer, + std::function binningBuffer, + std::function imageBuffer, + const int P, int D, int M, + const float* background, + const int width, int height, + const float* means3D, + const float* shs, + const float* colors_precomp, + const float* opacities, + const float* scales, + const float scale_modifier, + const float* rotations, + const float* cov3D_precomp, + const float* viewmatrix, + const float* projmatrix, + const float* cam_pos, + const float tan_fovx, float tan_fovy, + const bool prefiltered, + float* out_color, + float* depth, + bool antialiasing, + int* radii, + bool debug) +{ + const float focal_y = height / (2.0f * tan_fovy); + const float focal_x = width / (2.0f * tan_fovx); + + size_t chunk_size = required(P); + char* chunkptr = geometryBuffer(chunk_size); + GeometryState geomState = GeometryState::fromChunk(chunkptr, P); + + if (radii == nullptr) + { + radii = geomState.internal_radii; + } + + dim3 tile_grid((width + BLOCK_X - 1) / BLOCK_X, (height + BLOCK_Y - 1) / BLOCK_Y, 1); + dim3 block(BLOCK_X, BLOCK_Y, 1); + + // Dynamically resize image-based auxiliary buffers during training + size_t img_chunk_size = required(width * height); + char* img_chunkptr = imageBuffer(img_chunk_size); + ImageState imgState = ImageState::fromChunk(img_chunkptr, width * height); + + if (NUM_CHANNELS != 3 && colors_precomp == nullptr) + { + throw std::runtime_error("For non-RGB, provide precomputed Gaussian colors!"); + } + + // Run preprocessing per-Gaussian (transformation, bounding, conversion of SHs to RGB) + CHECK_CUDA(FORWARD::preprocess( + P, D, M, + means3D, + (glm::vec3*)scales, + scale_modifier, + (glm::vec4*)rotations, + opacities, + shs, + geomState.clamped, + cov3D_precomp, + colors_precomp, + viewmatrix, projmatrix, + (glm::vec3*)cam_pos, + width, height, + focal_x, focal_y, + tan_fovx, tan_fovy, + radii, + geomState.means2D, + geomState.depths, + geomState.cov3D, + geomState.rgb, + geomState.conic_opacity, + tile_grid, + geomState.tiles_touched, + prefiltered, + antialiasing + ), debug) + + // Compute prefix sum over full list of touched tile counts by Gaussians + // E.g., [2, 3, 0, 2, 1] -> [2, 5, 5, 7, 8] + CHECK_CUDA(cub::DeviceScan::InclusiveSum(geomState.scanning_space, geomState.scan_size, geomState.tiles_touched, geomState.point_offsets, P), debug) + + // Retrieve total number of Gaussian instances to launch and resize aux buffers + int num_rendered; + CHECK_CUDA(cudaMemcpy(&num_rendered, geomState.point_offsets + P - 1, sizeof(int), cudaMemcpyDeviceToHost), debug); + + size_t binning_chunk_size = required(num_rendered); + char* binning_chunkptr = binningBuffer(binning_chunk_size); + BinningState binningState = BinningState::fromChunk(binning_chunkptr, num_rendered); + + // For each instance to be rendered, produce adequate [ tile | depth ] key + // and corresponding dublicated Gaussian indices to be sorted + duplicateWithKeys << <(P + 255) / 256, 256 >> > ( + P, + geomState.means2D, + geomState.depths, + geomState.point_offsets, + binningState.point_list_keys_unsorted, + binningState.point_list_unsorted, + radii, + tile_grid) + CHECK_CUDA(, debug) + + int bit = getHigherMsb(tile_grid.x * tile_grid.y); + + // Sort complete list of (duplicated) Gaussian indices by keys + CHECK_CUDA(cub::DeviceRadixSort::SortPairs( + binningState.list_sorting_space, + binningState.sorting_size, + binningState.point_list_keys_unsorted, binningState.point_list_keys, + binningState.point_list_unsorted, binningState.point_list, + num_rendered, 0, 32 + bit), debug) + + CHECK_CUDA(cudaMemset(imgState.ranges, 0, tile_grid.x * tile_grid.y * sizeof(uint2)), debug); + + // Identify start and end of per-tile workloads in sorted list + if (num_rendered > 0) + identifyTileRanges << <(num_rendered + 255) / 256, 256 >> > ( + num_rendered, + binningState.point_list_keys, + imgState.ranges); + CHECK_CUDA(, debug) + + // Let each tile blend its range of Gaussians independently in parallel + const float* feature_ptr = colors_precomp != nullptr ? colors_precomp : geomState.rgb; + CHECK_CUDA(FORWARD::render( + tile_grid, block, + imgState.ranges, + binningState.point_list, + width, height, + geomState.means2D, + feature_ptr, + geomState.conic_opacity, + imgState.accum_alpha, + imgState.n_contrib, + background, + out_color, + geomState.depths, + depth), debug) + + return num_rendered; +} + +// Produce necessary gradients for optimization, corresponding +// to forward render pass +void CudaRasterizer::Rasterizer::backward( + const int P, int D, int M, int R, + const float* background, + const int width, int height, + const float* means3D, + const float* shs, + const float* colors_precomp, + const float* opacities, + const float* scales, + const float scale_modifier, + const float* rotations, + const float* cov3D_precomp, + const float* viewmatrix, + const float* projmatrix, + const float* campos, + const float tan_fovx, float tan_fovy, + const int* radii, + char* geom_buffer, + char* binning_buffer, + char* img_buffer, + const float* dL_dpix, + const float* dL_invdepths, + float* dL_dmean2D, + float* dL_dconic, + float* dL_dopacity, + float* dL_dcolor, + float* dL_dinvdepth, + float* dL_dmean3D, + float* dL_dcov3D, + float* dL_dsh, + float* dL_dscale, + float* dL_drot, + bool antialiasing, + bool debug) +{ + GeometryState geomState = GeometryState::fromChunk(geom_buffer, P); + BinningState binningState = BinningState::fromChunk(binning_buffer, R); + ImageState imgState = ImageState::fromChunk(img_buffer, width * height); + + if (radii == nullptr) + { + radii = geomState.internal_radii; + } + + const float focal_y = height / (2.0f * tan_fovy); + const float focal_x = width / (2.0f * tan_fovx); + + const dim3 tile_grid((width + BLOCK_X - 1) / BLOCK_X, (height + BLOCK_Y - 1) / BLOCK_Y, 1); + const dim3 block(BLOCK_X, BLOCK_Y, 1); + + // Compute loss gradients w.r.t. 2D mean position, conic matrix, + // opacity and RGB of Gaussians from per-pixel loss gradients. + // If we were given precomputed colors and not SHs, use them. + const float* color_ptr = (colors_precomp != nullptr) ? colors_precomp : geomState.rgb; + CHECK_CUDA(BACKWARD::render( + tile_grid, + block, + imgState.ranges, + binningState.point_list, + width, height, + background, + geomState.means2D, + geomState.conic_opacity, + color_ptr, + geomState.depths, + imgState.accum_alpha, + imgState.n_contrib, + dL_dpix, + dL_invdepths, + (float3*)dL_dmean2D, + (float4*)dL_dconic, + dL_dopacity, + dL_dcolor, + dL_dinvdepth), debug); + + // Take care of the rest of preprocessing. Was the precomputed covariance + // given to us or a scales/rot pair? If precomputed, pass that. If not, + // use the one we computed ourselves. + const float* cov3D_ptr = (cov3D_precomp != nullptr) ? cov3D_precomp : geomState.cov3D; + CHECK_CUDA(BACKWARD::preprocess(P, D, M, + (float3*)means3D, + radii, + shs, + geomState.clamped, + opacities, + (glm::vec3*)scales, + (glm::vec4*)rotations, + scale_modifier, + cov3D_ptr, + viewmatrix, + projmatrix, + focal_x, focal_y, + tan_fovx, tan_fovy, + (glm::vec3*)campos, + (float3*)dL_dmean2D, + dL_dconic, + dL_dinvdepth, + dL_dopacity, + (glm::vec3*)dL_dmean3D, + dL_dcolor, + dL_dcov3D, + dL_dsh, + (glm::vec3*)dL_dscale, + (glm::vec4*)dL_drot, + antialiasing), debug); +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/cuda_rasterizer/rasterizer_impl.h b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/cuda_rasterizer/rasterizer_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..bc3f0ece7f3eed613be1f95c212b07ac1220b58c --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/cuda_rasterizer/rasterizer_impl.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2023, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact george.drettakis@inria.fr + */ + +#pragma once + +#include +#include +#include "rasterizer.h" +#include + +namespace CudaRasterizer +{ + template + static void obtain(char*& chunk, T*& ptr, std::size_t count, std::size_t alignment) + { + std::size_t offset = (reinterpret_cast(chunk) + alignment - 1) & ~(alignment - 1); + ptr = reinterpret_cast(offset); + chunk = reinterpret_cast(ptr + count); + } + + struct GeometryState + { + size_t scan_size; + float* depths; + char* scanning_space; + bool* clamped; + int* internal_radii; + float2* means2D; + float* cov3D; + float4* conic_opacity; + float* rgb; + uint32_t* point_offsets; + uint32_t* tiles_touched; + + static GeometryState fromChunk(char*& chunk, size_t P); + }; + + struct ImageState + { + uint2* ranges; + uint32_t* n_contrib; + float* accum_alpha; + + static ImageState fromChunk(char*& chunk, size_t N); + }; + + struct BinningState + { + size_t sorting_size; + uint64_t* point_list_keys_unsorted; + uint64_t* point_list_keys; + uint32_t* point_list_unsorted; + uint32_t* point_list; + char* list_sorting_space; + + static BinningState fromChunk(char*& chunk, size_t P); + }; + + template + size_t required(size_t P) + { + char* size = nullptr; + T::fromChunk(size, P); + return ((size_t)size) + 128; + } +}; \ No newline at end of file diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/diff_gaussian_rasterization/__init__.py b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/diff_gaussian_rasterization/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..7f228cec5e753f9d20d958172938a799eb588a18 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/diff_gaussian_rasterization/__init__.py @@ -0,0 +1,208 @@ +# +# Copyright (C) 2023, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact george.drettakis@inria.fr +# + +from typing import NamedTuple +import torch.nn as nn +import torch +from . import _C + +def cpu_deep_copy_tuple(input_tuple): + copied_tensors = [item.cpu().clone() if isinstance(item, torch.Tensor) else item for item in input_tuple] + return tuple(copied_tensors) + +def rasterize_gaussians( + means3D, + means2D, + sh, + colors_precomp, + opacities, + scales, + rotations, + cov3Ds_precomp, + raster_settings, +): + return _RasterizeGaussians.apply( + means3D, + means2D, + sh, + colors_precomp, + opacities, + scales, + rotations, + cov3Ds_precomp, + raster_settings, + ) + +class _RasterizeGaussians(torch.autograd.Function): + @staticmethod + def forward( + ctx, + means3D, + means2D, + sh, + colors_precomp, + opacities, + scales, + rotations, + cov3Ds_precomp, + raster_settings, + ): + + # Restructure arguments the way that the C++ lib expects them + args = ( + raster_settings.bg, + means3D, + colors_precomp, + opacities, + scales, + rotations, + raster_settings.scale_modifier, + cov3Ds_precomp, + raster_settings.viewmatrix, + raster_settings.projmatrix, + raster_settings.tanfovx, + raster_settings.tanfovy, + raster_settings.image_height, + raster_settings.image_width, + sh, + raster_settings.sh_degree, + raster_settings.campos, + raster_settings.prefiltered, + raster_settings.antialiasing, + raster_settings.debug + ) + + # Invoke C++/CUDA rasterizer + num_rendered, color, radii, geomBuffer, binningBuffer, imgBuffer, invdepths = _C.rasterize_gaussians(*args) + + # Keep relevant tensors for backward + ctx.raster_settings = raster_settings + ctx.num_rendered = num_rendered + ctx.save_for_backward(colors_precomp, means3D, scales, rotations, cov3Ds_precomp, radii, sh, opacities, geomBuffer, binningBuffer, imgBuffer) + return color, radii, invdepths + + @staticmethod + def backward(ctx, grad_out_color, _, grad_out_depth): + + # Restore necessary values from context + num_rendered = ctx.num_rendered + raster_settings = ctx.raster_settings + colors_precomp, means3D, scales, rotations, cov3Ds_precomp, radii, sh, opacities, geomBuffer, binningBuffer, imgBuffer = ctx.saved_tensors + + # Restructure args as C++ method expects them + args = (raster_settings.bg, + means3D, + radii, + colors_precomp, + opacities, + scales, + rotations, + raster_settings.scale_modifier, + cov3Ds_precomp, + raster_settings.viewmatrix, + raster_settings.projmatrix, + raster_settings.tanfovx, + raster_settings.tanfovy, + grad_out_color, + grad_out_depth, + sh, + raster_settings.sh_degree, + raster_settings.campos, + geomBuffer, + num_rendered, + binningBuffer, + imgBuffer, + raster_settings.antialiasing, + raster_settings.debug) + + # Compute gradients for relevant tensors by invoking backward method + grad_means2D, grad_colors_precomp, grad_opacities, grad_means3D, grad_cov3Ds_precomp, grad_sh, grad_scales, grad_rotations = _C.rasterize_gaussians_backward(*args) + + grads = ( + grad_means3D, + grad_means2D, + grad_sh, + grad_colors_precomp, + grad_opacities, + grad_scales, + grad_rotations, + grad_cov3Ds_precomp, + None, + ) + + return grads + +class GaussianRasterizationSettings(NamedTuple): + image_height: int + image_width: int + tanfovx : float + tanfovy : float + bg : torch.Tensor + scale_modifier : float + viewmatrix : torch.Tensor + projmatrix : torch.Tensor + sh_degree : int + campos : torch.Tensor + prefiltered : bool + debug : bool + antialiasing : bool + +class GaussianRasterizer(nn.Module): + def __init__(self, raster_settings): + super().__init__() + self.raster_settings = raster_settings + + def markVisible(self, positions): + # Mark visible points (based on frustum culling for camera) with a boolean + with torch.no_grad(): + raster_settings = self.raster_settings + visible = _C.mark_visible( + positions, + raster_settings.viewmatrix, + raster_settings.projmatrix) + + return visible + + def forward(self, means3D, means2D, opacities, shs = None, colors_precomp = None, scales = None, rotations = None, cov3D_precomp = None): + + raster_settings = self.raster_settings + + if (shs is None and colors_precomp is None) or (shs is not None and colors_precomp is not None): + raise Exception('Please provide excatly one of either SHs or precomputed colors!') + + if ((scales is None or rotations is None) and cov3D_precomp is None) or ((scales is not None or rotations is not None) and cov3D_precomp is not None): + raise Exception('Please provide exactly one of either scale/rotation pair or precomputed 3D covariance!') + + if shs is None: + shs = torch.Tensor([]) + if colors_precomp is None: + colors_precomp = torch.Tensor([]) + + if scales is None: + scales = torch.Tensor([]) + if rotations is None: + rotations = torch.Tensor([]) + if cov3D_precomp is None: + cov3D_precomp = torch.Tensor([]) + + # Invoke C++/CUDA rasterization routine + return rasterize_gaussians( + means3D, + means2D, + shs, + colors_precomp, + opacities, + scales, + rotations, + cov3D_precomp, + raster_settings, + ) + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/ext.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/ext.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d768779579761238347972a973fbd1603d44235e --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/ext.cpp @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2023, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact george.drettakis@inria.fr + */ + +#include +#include "rasterize_points.h" + +PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { + m.def("rasterize_gaussians", &RasterizeGaussiansCUDA); + m.def("rasterize_gaussians_backward", &RasterizeGaussiansBackwardCUDA); + m.def("mark_visible", &markVisible); +} \ No newline at end of file diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/rasterize_points.cu b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/rasterize_points.cu new file mode 100644 index 0000000000000000000000000000000000000000..e625c19e465b62deeeb7505b9d95b5543137c497 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/rasterize_points.cu @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2023, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact george.drettakis@inria.fr + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cuda_rasterizer/config.h" +#include "cuda_rasterizer/rasterizer.h" +#include +#include +#include + +std::function resizeFunctional(torch::Tensor& t) { + auto lambda = [&t](size_t N) { + t.resize_({(long long)N}); + return reinterpret_cast(t.contiguous().data_ptr()); + }; + return lambda; +} + +std::tuple +RasterizeGaussiansCUDA( + const torch::Tensor& background, + const torch::Tensor& means3D, + const torch::Tensor& colors, + const torch::Tensor& opacity, + const torch::Tensor& scales, + const torch::Tensor& rotations, + const float scale_modifier, + const torch::Tensor& cov3D_precomp, + const torch::Tensor& viewmatrix, + const torch::Tensor& projmatrix, + const float tan_fovx, + const float tan_fovy, + const int image_height, + const int image_width, + const torch::Tensor& sh, + const int degree, + const torch::Tensor& campos, + const bool prefiltered, + const bool antialiasing, + const bool debug) +{ + if (means3D.ndimension() != 2 || means3D.size(1) != 3) { + AT_ERROR("means3D must have dimensions (num_points, 3)"); + } + + const int P = means3D.size(0); + const int H = image_height; + const int W = image_width; + + auto int_opts = means3D.options().dtype(torch::kInt32); + auto float_opts = means3D.options().dtype(torch::kFloat32); + + torch::Tensor out_color = torch::full({NUM_CHANNELS, H, W}, 0.0, float_opts); + torch::Tensor out_invdepth = torch::full({0, H, W}, 0.0, float_opts); + float* out_invdepthptr = nullptr; + + out_invdepth = torch::full({1, H, W}, 0.0, float_opts).contiguous(); + out_invdepthptr = out_invdepth.data(); + + torch::Tensor radii = torch::full({P}, 0, means3D.options().dtype(torch::kInt32)); + + torch::Device device(torch::kCUDA); + torch::TensorOptions options(torch::kByte); + torch::Tensor geomBuffer = torch::empty({0}, options.device(device)); + torch::Tensor binningBuffer = torch::empty({0}, options.device(device)); + torch::Tensor imgBuffer = torch::empty({0}, options.device(device)); + std::function geomFunc = resizeFunctional(geomBuffer); + std::function binningFunc = resizeFunctional(binningBuffer); + std::function imgFunc = resizeFunctional(imgBuffer); + + int rendered = 0; + if(P != 0) + { + int M = 0; + if(sh.size(0) != 0) + { + M = sh.size(1); + } + + rendered = CudaRasterizer::Rasterizer::forward( + geomFunc, + binningFunc, + imgFunc, + P, degree, M, + background.contiguous().data(), + W, H, + means3D.contiguous().data(), + sh.contiguous().data_ptr(), + colors.contiguous().data(), + opacity.contiguous().data(), + scales.contiguous().data_ptr(), + scale_modifier, + rotations.contiguous().data_ptr(), + cov3D_precomp.contiguous().data(), + viewmatrix.contiguous().data(), + projmatrix.contiguous().data(), + campos.contiguous().data(), + tan_fovx, + tan_fovy, + prefiltered, + out_color.contiguous().data(), + out_invdepthptr, + antialiasing, + radii.contiguous().data(), + debug); + } + return std::make_tuple(rendered, out_color, radii, geomBuffer, binningBuffer, imgBuffer, out_invdepth); +} + +std::tuple + RasterizeGaussiansBackwardCUDA( + const torch::Tensor& background, + const torch::Tensor& means3D, + const torch::Tensor& radii, + const torch::Tensor& colors, + const torch::Tensor& opacities, + const torch::Tensor& scales, + const torch::Tensor& rotations, + const float scale_modifier, + const torch::Tensor& cov3D_precomp, + const torch::Tensor& viewmatrix, + const torch::Tensor& projmatrix, + const float tan_fovx, + const float tan_fovy, + const torch::Tensor& dL_dout_color, + const torch::Tensor& dL_dout_invdepth, + const torch::Tensor& sh, + const int degree, + const torch::Tensor& campos, + const torch::Tensor& geomBuffer, + const int R, + const torch::Tensor& binningBuffer, + const torch::Tensor& imageBuffer, + const bool antialiasing, + const bool debug) +{ + const int P = means3D.size(0); + const int H = dL_dout_color.size(1); + const int W = dL_dout_color.size(2); + + int M = 0; + if(sh.size(0) != 0) + { + M = sh.size(1); + } + + torch::Tensor dL_dmeans3D = torch::zeros({P, 3}, means3D.options()); + torch::Tensor dL_dmeans2D = torch::zeros({P, 3}, means3D.options()); + torch::Tensor dL_dcolors = torch::zeros({P, NUM_CHANNELS}, means3D.options()); + torch::Tensor dL_dconic = torch::zeros({P, 2, 2}, means3D.options()); + torch::Tensor dL_dopacity = torch::zeros({P, 1}, means3D.options()); + torch::Tensor dL_dcov3D = torch::zeros({P, 6}, means3D.options()); + torch::Tensor dL_dsh = torch::zeros({P, M, 3}, means3D.options()); + torch::Tensor dL_dscales = torch::zeros({P, 3}, means3D.options()); + torch::Tensor dL_drotations = torch::zeros({P, 4}, means3D.options()); + torch::Tensor dL_dinvdepths = torch::zeros({0, 1}, means3D.options()); + + float* dL_dinvdepthsptr = nullptr; + float* dL_dout_invdepthptr = nullptr; + if(dL_dout_invdepth.size(0) != 0) + { + dL_dinvdepths = torch::zeros({P, 1}, means3D.options()); + dL_dinvdepths = dL_dinvdepths.contiguous(); + dL_dinvdepthsptr = dL_dinvdepths.data(); + dL_dout_invdepthptr = dL_dout_invdepth.data(); + } + + if(P != 0) + { + CudaRasterizer::Rasterizer::backward(P, degree, M, R, + background.contiguous().data(), + W, H, + means3D.contiguous().data(), + sh.contiguous().data(), + colors.contiguous().data(), + opacities.contiguous().data(), + scales.data_ptr(), + scale_modifier, + rotations.data_ptr(), + cov3D_precomp.contiguous().data(), + viewmatrix.contiguous().data(), + projmatrix.contiguous().data(), + campos.contiguous().data(), + tan_fovx, + tan_fovy, + radii.contiguous().data(), + reinterpret_cast(geomBuffer.contiguous().data_ptr()), + reinterpret_cast(binningBuffer.contiguous().data_ptr()), + reinterpret_cast(imageBuffer.contiguous().data_ptr()), + dL_dout_color.contiguous().data(), + dL_dout_invdepthptr, + dL_dmeans2D.contiguous().data(), + dL_dconic.contiguous().data(), + dL_dopacity.contiguous().data(), + dL_dcolors.contiguous().data(), + dL_dinvdepthsptr, + dL_dmeans3D.contiguous().data(), + dL_dcov3D.contiguous().data(), + dL_dsh.contiguous().data(), + dL_dscales.contiguous().data(), + dL_drotations.contiguous().data(), + antialiasing, + debug); + } + + return std::make_tuple(dL_dmeans2D, dL_dcolors, dL_dopacity, dL_dmeans3D, dL_dcov3D, dL_dsh, dL_dscales, dL_drotations); +} + +torch::Tensor markVisible( + torch::Tensor& means3D, + torch::Tensor& viewmatrix, + torch::Tensor& projmatrix) +{ + const int P = means3D.size(0); + + torch::Tensor present = torch::full({P}, false, means3D.options().dtype(at::kBool)); + + if(P != 0) + { + CudaRasterizer::Rasterizer::markVisible(P, + means3D.contiguous().data(), + viewmatrix.contiguous().data(), + projmatrix.contiguous().data(), + present.contiguous().data()); + } + + return present; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/rasterize_points.h b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/rasterize_points.h new file mode 100644 index 0000000000000000000000000000000000000000..82cbd4f2cbbcd97af3164482f5fa455c9b9581a5 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/rasterize_points.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2023, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact george.drettakis@inria.fr + */ + +#pragma once +#include +#include +#include +#include + +std::tuple +RasterizeGaussiansCUDA( + const torch::Tensor& background, + const torch::Tensor& means3D, + const torch::Tensor& colors, + const torch::Tensor& opacity, + const torch::Tensor& scales, + const torch::Tensor& rotations, + const float scale_modifier, + const torch::Tensor& cov3D_precomp, + const torch::Tensor& viewmatrix, + const torch::Tensor& projmatrix, + const float tan_fovx, + const float tan_fovy, + const int image_height, + const int image_width, + const torch::Tensor& sh, + const int degree, + const torch::Tensor& campos, + const bool prefiltered, + const bool antialiasing, + const bool debug); + +std::tuple + RasterizeGaussiansBackwardCUDA( + const torch::Tensor& background, + const torch::Tensor& means3D, + const torch::Tensor& radii, + const torch::Tensor& colors, + const torch::Tensor& scales, + const torch::Tensor& opacities, + const torch::Tensor& rotations, + const float scale_modifier, + const torch::Tensor& cov3D_precomp, + const torch::Tensor& viewmatrix, + const torch::Tensor& projmatrix, + const float tan_fovx, + const float tan_fovy, + const torch::Tensor& dL_dout_color, + const torch::Tensor& dL_dout_invdepth, + const torch::Tensor& sh, + const int degree, + const torch::Tensor& campos, + const torch::Tensor& geomBuffer, + const int R, + const torch::Tensor& binningBuffer, + const torch::Tensor& imageBuffer, + const bool antialiasing, + const bool debug); + +torch::Tensor markVisible( + torch::Tensor& means3D, + torch::Tensor& viewmatrix, + torch::Tensor& projmatrix); diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/setup.py b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/setup.py new file mode 100644 index 0000000000000000000000000000000000000000..bb7220d2934d006ea756e35ecb0f391403b43d64 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/setup.py @@ -0,0 +1,34 @@ +# +# Copyright (C) 2023, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact george.drettakis@inria.fr +# + +from setuptools import setup +from torch.utils.cpp_extension import CUDAExtension, BuildExtension +import os +os.path.dirname(os.path.abspath(__file__)) + +setup( + name="diff_gaussian_rasterization", + packages=['diff_gaussian_rasterization'], + ext_modules=[ + CUDAExtension( + name="diff_gaussian_rasterization._C", + sources=[ + "cuda_rasterizer/rasterizer_impl.cu", + "cuda_rasterizer/forward.cu", + "cuda_rasterizer/backward.cu", + "rasterize_points.cu", + "ext.cpp"], + extra_compile_args={"nvcc": ["-I" + os.path.join(os.path.dirname(os.path.abspath(__file__)), "third_party/glm/")]}) + ], + cmdclass={ + 'build_ext': BuildExtension + } +) diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/.appveyor.yml b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/.appveyor.yml new file mode 100644 index 0000000000000000000000000000000000000000..5ce6028184b763af011bd0e325abf45a3370e182 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/.appveyor.yml @@ -0,0 +1,92 @@ +shallow_clone: true + +platform: + - x86 + - x64 + +configuration: + - Debug + - Release + +image: + - Visual Studio 2013 + - Visual Studio 2015 + - Visual Studio 2017 + - Visual Studio 2019 + +environment: + matrix: + - GLM_ARGUMENTS: -DGLM_TEST_FORCE_PURE=ON + - GLM_ARGUMENTS: -DGLM_TEST_ENABLE_SIMD_SSE2=ON -DGLM_TEST_ENABLE_LANG_EXTENSIONS=ON + - GLM_ARGUMENTS: -DGLM_TEST_ENABLE_SIMD_AVX=ON -DGLM_TEST_ENABLE_LANG_EXTENSIONS=ON + - GLM_ARGUMENTS: -DGLM_TEST_ENABLE_SIMD_AVX=ON -DGLM_TEST_ENABLE_LANG_EXTENSIONS=ON -DGLM_TEST_ENABLE_CXX_14=ON + - GLM_ARGUMENTS: -DGLM_TEST_ENABLE_SIMD_AVX=ON -DGLM_TEST_ENABLE_LANG_EXTENSIONS=ON -DGLM_TEST_ENABLE_CXX_17=ON + +matrix: + exclude: + - image: Visual Studio 2013 + GLM_ARGUMENTS: -DGLM_TEST_ENABLE_SIMD_AVX=ON -DGLM_TEST_ENABLE_LANG_EXTENSIONS=ON + - image: Visual Studio 2013 + GLM_ARGUMENTS: -DGLM_TEST_ENABLE_SIMD_AVX=ON -DGLM_TEST_ENABLE_LANG_EXTENSIONS=ON -DGLM_TEST_ENABLE_CXX_14=ON + - image: Visual Studio 2013 + GLM_ARGUMENTS: -DGLM_TEST_ENABLE_SIMD_AVX=ON -DGLM_TEST_ENABLE_LANG_EXTENSIONS=ON -DGLM_TEST_ENABLE_CXX_17=ON + - image: Visual Studio 2013 + configuration: Debug + - image: Visual Studio 2015 + GLM_ARGUMENTS: -DGLM_TEST_ENABLE_SIMD_SSE2=ON -DGLM_TEST_ENABLE_LANG_EXTENSIONS=ON + - image: Visual Studio 2015 + GLM_ARGUMENTS: -DGLM_TEST_ENABLE_SIMD_AVX=ON -DGLM_TEST_ENABLE_LANG_EXTENSIONS=ON -DGLM_TEST_ENABLE_CXX_14=ON + - image: Visual Studio 2015 + GLM_ARGUMENTS: -DGLM_TEST_ENABLE_SIMD_AVX=ON -DGLM_TEST_ENABLE_LANG_EXTENSIONS=ON -DGLM_TEST_ENABLE_CXX_17=ON + - image: Visual Studio 2015 + platform: x86 + - image: Visual Studio 2015 + configuration: Debug + - image: Visual Studio 2017 + platform: x86 + - image: Visual Studio 2017 + configuration: Debug + - image: Visual Studio 2019 + platform: x64 + +branches: + only: + - master + +before_build: + - ps: | + mkdir build + cd build + + if ("$env:APPVEYOR_JOB_NAME" -match "Image: Visual Studio 2013") { + $env:generator="Visual Studio 12 2013" + } + if ("$env:APPVEYOR_JOB_NAME" -match "Image: Visual Studio 2015") { + $env:generator="Visual Studio 14 2015" + } + if ("$env:APPVEYOR_JOB_NAME" -match "Image: Visual Studio 2017") { + $env:generator="Visual Studio 15 2017" + } + if ("$env:APPVEYOR_JOB_NAME" -match "Image: Visual Studio 2019") { + $env:generator="Visual Studio 16 2019" + } + if ($env:PLATFORM -eq "x64") { + $env:generator="$env:generator Win64" + } + echo generator="$env:generator" + cmake .. -G "$env:generator" -DCMAKE_INSTALL_PREFIX="$env:APPVEYOR_BUILD_FOLDER/install" -DGLM_QUIET=ON -DGLM_TEST_ENABLE=ON "$env:GLM_ARGUMENTS" + +build_script: + - cmake --build . --parallel --config %CONFIGURATION% -- /m /v:minimal + - cmake --build . --target install --parallel --config %CONFIGURATION% -- /m /v:minimal + +test_script: + - ctest --parallel 4 --verbose -C %CONFIGURATION% + - cd .. + - ps: | + mkdir build_test_cmake + cd build_test_cmake + cmake ..\test\cmake\ -G "$env:generator" -DCMAKE_PREFIX_PATH="$env:APPVEYOR_BUILD_FOLDER/install" + - cmake --build . --parallel --config %CONFIGURATION% -- /m /v:minimal + +deploy: off diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/.gitignore b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..9dbd6d8c0b89bdc20124cfec9766821a252fbd67 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/.gitignore @@ -0,0 +1,61 @@ +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +# CMake +CMakeCache.txt +CMakeFiles +cmake_install.cmake +install_manifest.txt +*.cmake +!glmConfig.cmake +!glmConfig-version.cmake +# ^ May need to add future .cmake files as exceptions + +# Test logs +Testing/* + +# Test input +test/gtc/*.dds + +# Project Files +Makefile +*.cbp +*.user + +# Misc. +*.log + +# local build(s) +build* + +/.vs +/.vscode +/CMakeSettings.json +.DS_Store +*.swp diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/.travis.yml b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/.travis.yml new file mode 100644 index 0000000000000000000000000000000000000000..1660ec0c59d213b94ff7925503b2caff73567aeb --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/.travis.yml @@ -0,0 +1,388 @@ +language: cpp + +branches: + only: + - master + - stable + +jobs: + include: + - name: "Xcode 7.3 C++98 pure release" + os: osx + osx_image: xcode7.3 + env: + - MATRIX_EVAL="" + - CMAKE_BUILD_ENV="-DCMAKE_BUILD_TYPE=Release -DGLM_TEST_ENABLE=ON -DGLM_TEST_ENABLE_CXX_98=ON -DGLM_TEST_FORCE_PURE=ON" + + - name: "Xcode 7.3 C++98 sse2 release" + os: osx + osx_image: xcode7.3 + env: + - MATRIX_EVAL="" + - CMAKE_BUILD_ENV="-DCMAKE_BUILD_TYPE=Release -DGLM_TEST_ENABLE=ON -DGLM_TEST_ENABLE_CXX_98=ON -DGLM_TEST_ENABLE_LANG_EXTENSIONS=ON -DGLM_TEST_ENABLE_SIMD_SSE2=ON" + + - name: "Xcode 7.3 C++98 ms release" + os: osx + osx_image: xcode7.3 + env: + - MATRIX_EVAL="" + - CMAKE_BUILD_ENV="-DCMAKE_BUILD_TYPE=Release -DGLM_TEST_ENABLE=ON -DGLM_TEST_ENABLE_CXX_98=ON -DGLM_TEST_ENABLE_LANG_EXTENSIONS=ON" + + - name: "XCode 7.3 C++11 pure release" + os: osx + osx_image: xcode7.3 + env: + - MATRIX_EVAL="" + - CMAKE_BUILD_ENV="-DCMAKE_BUILD_TYPE=Release -DGLM_TEST_ENABLE=ON -DGLM_TEST_ENABLE_CXX_11=ON -DGLM_TEST_FORCE_PURE=ON" + + - name: "XCode 7.3 C++11 sse2 release" + os: osx + osx_image: xcode7.3 + env: + - MATRIX_EVAL="" + - CMAKE_BUILD_ENV="-DCMAKE_BUILD_TYPE=Release -DGLM_TEST_ENABLE=ON -DGLM_TEST_ENABLE_CXX_11=ON -DGLM_TEST_ENABLE_LANG_EXTENSIONS=ON -DGLM_TEST_ENABLE_SIMD_SSE3=ON" + + - name: "XCode 10.3 C++11 sse2 release" + os: osx + osx_image: xcode10.3 + env: + - MATRIX_EVAL="" + - CMAKE_BUILD_ENV="-DCMAKE_BUILD_TYPE=Release -DGLM_TEST_ENABLE=ON -DGLM_TEST_ENABLE_CXX_11=ON -DGLM_TEST_ENABLE_LANG_EXTENSIONS=ON -DGLM_TEST_ENABLE_SIMD_SSE3=ON" + + - name: "XCode 12.2 C++11 sse2 release" + os: osx + osx_image: xcode12.2 + env: + - MATRIX_EVAL="" + - CMAKE_BUILD_ENV="-DCMAKE_BUILD_TYPE=Release -DGLM_TEST_ENABLE=ON -DGLM_TEST_ENABLE_CXX_11=ON -DGLM_TEST_ENABLE_LANG_EXTENSIONS=ON -DGLM_TEST_ENABLE_SIMD_SSE3=ON" + - CTEST_ENV="--parallel 4 --output-on-failure" + - CMAKE_ENV="--parallel" + + - name: "XCode 12.2 C++11 sse2 debug" + os: osx + osx_image: xcode12.2 + env: + - MATRIX_EVAL="" + - CMAKE_BUILD_ENV="-DCMAKE_BUILD_TYPE=Debug -DGLM_TEST_ENABLE=ON -DGLM_TEST_ENABLE_CXX_11=ON -DGLM_TEST_ENABLE_LANG_EXTENSIONS=ON -DGLM_TEST_ENABLE_SIMD_SSE3=ON" + - CTEST_ENV="--parallel 4 --output-on-failure" + - CMAKE_ENV="--parallel" + + - name: "XCode 12.2 C++11 avx debug" + os: osx + osx_image: xcode12.2 + env: + - MATRIX_EVAL="" + - CMAKE_BUILD_ENV="-DCMAKE_BUILD_TYPE=Debug -DGLM_TEST_ENABLE=ON -DGLM_TEST_ENABLE_CXX_11=ON -DGLM_TEST_ENABLE_LANG_EXTENSIONS=ON -DGLM_TEST_ENABLE_SIMD_AVX=ON" + - CTEST_ENV="--parallel 4 --output-on-failure" + - CMAKE_ENV="--parallel" + + - name: "XCode 12.2 C++14 avx debug" + os: osx + osx_image: xcode12.2 + env: + - MATRIX_EVAL="" + - CMAKE_BUILD_ENV="-DCMAKE_BUILD_TYPE=Debug -DGLM_TEST_ENABLE=ON -DGLM_TEST_ENABLE_CXX_14=ON -DGLM_TEST_ENABLE_LANG_EXTENSIONS=ON -DGLM_TEST_ENABLE_SIMD_AVX=ON" + - CTEST_ENV="--parallel 4 --output-on-failure" + - CMAKE_ENV="--parallel" + + - name: "XCode 12.2 C++14 pure debug" + os: osx + osx_image: xcode12.2 + env: + - MATRIX_EVAL="" + - CMAKE_BUILD_ENV="-DCMAKE_BUILD_TYPE=Debug -DGLM_TEST_ENABLE=ON -DGLM_TEST_ENABLE_CXX_14=ON -DGLM_TEST_ENABLE_LANG_EXTENSIONS=ON -DGLM_TEST_FORCE_PURE=ON" + - CTEST_ENV="--parallel 4 --output-on-failure" + - CMAKE_ENV="--parallel" + + - name: "XCode 12.2 C++17 pure debug" + os: osx + osx_image: xcode12.2 + env: + - MATRIX_EVAL="" + - CMAKE_BUILD_ENV="-DCMAKE_BUILD_TYPE=Debug -DGLM_TEST_ENABLE=ON -DGLM_TEST_ENABLE_CXX_17=ON -DGLM_TEST_ENABLE_LANG_EXTENSIONS=ON -DGLM_TEST_FORCE_PURE=ON" + - CTEST_ENV="--parallel 4 --output-on-failure" + - CMAKE_ENV="--parallel" + + - name: "XCode 12.2 C++17 sse2 debug" + os: osx + osx_image: xcode12.2 + env: + - MATRIX_EVAL="" + - CMAKE_BUILD_ENV="-DCMAKE_BUILD_TYPE=Debug -DGLM_TEST_ENABLE=ON -DGLM_TEST_ENABLE_CXX_17=ON -DGLM_TEST_ENABLE_LANG_EXTENSIONS=ON -DGLM_TEST_ENABLE_SIMD_SSE2=ON" + - CTEST_ENV="--parallel 4 --output-on-failure" + - CMAKE_ENV="--parallel" + + - name: "XCode 12.2 C++17 sse2 release" + os: osx + osx_image: xcode12.2 + env: + - MATRIX_EVAL="" + - CMAKE_BUILD_ENV="-DCMAKE_BUILD_TYPE=Release -DGLM_TEST_ENABLE=ON -DGLM_TEST_ENABLE_CXX_17=ON -DGLM_TEST_ENABLE_LANG_EXTENSIONS=ON -DGLM_TEST_ENABLE_SIMD_SSE2=ON" + - CTEST_ENV="--parallel 4 --output-on-failure" + - CMAKE_ENV="--parallel" + + - name: "XCode 12.2 C++17 avx release" + os: osx + osx_image: xcode12.2 + env: + - MATRIX_EVAL="" + - CMAKE_BUILD_ENV="-DCMAKE_BUILD_TYPE=Release -DGLM_TEST_ENABLE=ON -DGLM_TEST_ENABLE_CXX_17=ON -DGLM_TEST_ENABLE_LANG_EXTENSIONS=ON -DGLM_TEST_ENABLE_SIMD_AVX=ON" + - CTEST_ENV="--parallel 4 --output-on-failure" + - CMAKE_ENV="--parallel" + + - name: "GCC 4.9 C++98 pure release" + os: linux + dist: Xenial + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-4.9 + env: + - MATRIX_EVAL="CC=gcc-4.9 && CXX=g++-4.9" + - CMAKE_BUILD_ENV="-DCMAKE_BUILD_TYPE=Release -DGLM_TEST_ENABLE=ON -DGLM_TEST_ENABLE_CXX_98=ON -DGLM_TEST_FORCE_PURE=ON" + - CTEST_ENV="--parallel 4 --output-on-failure" + - CMAKE_ENV="--parallel" + + - name: "GCC 4.9 C++98 pure debug" + os: linux + dist: Xenial + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-4.9 + env: + - MATRIX_EVAL="CC=gcc-4.9 && CXX=g++-4.9" + - CMAKE_BUILD_ENV="-DCMAKE_BUILD_TYPE=Debug -DGLM_TEST_ENABLE=ON -DGLM_TEST_ENABLE_CXX_98=ON -DGLM_TEST_FORCE_PURE=ON" + - CTEST_ENV="--parallel 4 --output-on-failure" + - CMAKE_ENV="--parallel" + + - name: "GCC 4.9 C++98 ms debug" + os: linux + dist: Xenial + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-4.9 + env: + - MATRIX_EVAL="CC=gcc-4.9 && CXX=g++-4.9" + - CMAKE_BUILD_ENV="-DCMAKE_BUILD_TYPE=Debug -DGLM_TEST_ENABLE=ON -DGLM_TEST_ENABLE_CXX_98=ON -DGLM_TEST_ENABLE_LANG_EXTENSIONS=ON" + - CTEST_ENV="--parallel 4 --output-on-failure" + - CMAKE_ENV="--parallel" + + - name: "GCC 4.9 C++11 ms debug" + os: linux + dist: Xenial + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-4.9 + env: + - MATRIX_EVAL="CC=gcc-4.9 && CXX=g++-4.9" + - CMAKE_BUILD_ENV="-DCMAKE_BUILD_TYPE=Debug -DGLM_TEST_ENABLE=ON -DGLM_TEST_ENABLE_CXX_11=ON -DGLM_TEST_ENABLE_LANG_EXTENSIONS=ON" + - CTEST_ENV="--parallel 4 --output-on-failure" + - CMAKE_ENV="--parallel" + + - name: "GCC 4.9 C++11 pure debug" + os: linux + dist: Xenial + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-4.9 + env: + - MATRIX_EVAL="CC=gcc-4.9 && CXX=g++-4.9" + - CMAKE_BUILD_ENV="-DCMAKE_BUILD_TYPE=Debug -DGLM_TEST_ENABLE=ON -DGLM_TEST_ENABLE_CXX_11=ON -DGLM_TEST_FORCE_PURE=ON" + - CTEST_ENV="--parallel 4 --output-on-failure" + - CMAKE_ENV="--parallel" + + - name: "GCC 6 C++14 pure debug" + os: linux + dist: bionic + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-6 + env: + - MATRIX_EVAL="CC=gcc-6 && CXX=g++-6" + - CMAKE_BUILD_ENV="-DCMAKE_BUILD_TYPE=Debug -DGLM_TEST_ENABLE=ON -DGLM_TEST_ENABLE_CXX_14=ON -DGLM_TEST_FORCE_PURE=ON" + - CTEST_ENV="--parallel 4 --output-on-failure" + - CMAKE_ENV="--parallel" + + - name: "GCC 6 C++14 ms debug" + os: linux + dist: bionic + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-6 + env: + - MATRIX_EVAL="CC=gcc-6 && CXX=g++-6" + - CMAKE_BUILD_ENV="-DCMAKE_BUILD_TYPE=Debug -DGLM_TEST_ENABLE=ON -DGLM_TEST_ENABLE_CXX_14=ON -DGLM_TEST_ENABLE_LANG_EXTENSIONS=ON" + - CTEST_ENV="--parallel 4 --output-on-failure" + - CMAKE_ENV="--parallel" + + - name: "GCC 7 C++17 ms debug" + os: linux + dist: bionic + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-7 + env: + - MATRIX_EVAL="CC=gcc-7 && CXX=g++-7" + - CMAKE_BUILD_ENV="-DCMAKE_BUILD_TYPE=Debug -DGLM_TEST_ENABLE=ON -DGLM_TEST_ENABLE_CXX_17=ON -DGLM_TEST_ENABLE_LANG_EXTENSIONS=ON" + - CTEST_ENV="--parallel 4 --output-on-failure" + - CMAKE_ENV="--parallel" + + - name: "GCC 7 C++17 pure debug" + os: linux + dist: bionic + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-7 + env: + - MATRIX_EVAL="CC=gcc-7 && CXX=g++-7" + - CMAKE_BUILD_ENV="-DCMAKE_BUILD_TYPE=Debug -DGLM_TEST_ENABLE=ON -DGLM_TEST_ENABLE_CXX_17=ON -DGLM_TEST_FORCE_PURE=ON" + - CTEST_ENV="--parallel 4 --output-on-failure" + - CMAKE_ENV="--parallel" + + - name: "GCC 10 C++17 pure debug" + os: linux + dist: bionic + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-10 + env: + - MATRIX_EVAL="CC=gcc-10 && CXX=g++-10" + - CMAKE_BUILD_ENV="-DCMAKE_BUILD_TYPE=Debug -DGLM_TEST_ENABLE=ON -DGLM_TEST_ENABLE_CXX_17=ON -DGLM_TEST_FORCE_PURE=ON" + - CTEST_ENV="--parallel 4 --output-on-failure" + - CMAKE_ENV="--parallel" + + - name: "GCC 10 C++17 pure release" + os: linux + dist: bionic + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-10 + env: + - MATRIX_EVAL="CC=gcc-10 && CXX=g++-10" + - CMAKE_BUILD_ENV="-DCMAKE_BUILD_TYPE=Release -DGLM_TEST_ENABLE=ON -DGLM_TEST_ENABLE_CXX_17=ON -DGLM_TEST_FORCE_PURE=ON" + - CTEST_ENV="--parallel 4 --output-on-failure" + - CMAKE_ENV="--parallel" + + - name: "Clang C++14 pure release" + os: linux + dist: Xenial + env: + - MATRIX_EVAL="CC=clang && CXX=clang++" + - CMAKE_BUILD_ENV="-DCMAKE_BUILD_TYPE=Release -DGLM_TEST_ENABLE=ON -DGLM_TEST_ENABLE_CXX_14=ON -DGLM_TEST_FORCE_PURE=ON" + - CTEST_ENV="--parallel 4 --output-on-failure" + - CMAKE_ENV="--parallel" + + - name: "Clang C++14 pure debug" + os: linux + dist: Xenial + env: + - MATRIX_EVAL="CC=clang && CXX=clang++" + - CMAKE_BUILD_ENV="-DCMAKE_BUILD_TYPE=Debug -DGLM_TEST_ENABLE=ON -DGLM_TEST_ENABLE_CXX_14=ON -DGLM_TEST_FORCE_PURE=ON" + - CTEST_ENV="--parallel 4 --output-on-failure" + - CMAKE_ENV="--parallel" + + - name: "Clang C++14 sse2 debug" + os: linux + dist: Xenial + env: + - MATRIX_EVAL="CC=clang && CXX=clang++" + - CMAKE_BUILD_ENV="-DCMAKE_BUILD_TYPE=Debug -DGLM_TEST_ENABLE=ON -DGLM_TEST_ENABLE_CXX_14=ON -DGLM_TEST_ENABLE_LANG_EXTENSIONS=ON -DGLM_TEST_ENABLE_SIMD_SSE2=ON" + - CTEST_ENV="--parallel 4 --output-on-failure" + - CMAKE_ENV="--parallel" + + - name: "Clang C++14 sse2 debug" + os: linux + dist: focal + env: + - MATRIX_EVAL="CC=clang && CXX=clang++" + - CMAKE_BUILD_ENV="-DCMAKE_BUILD_TYPE=Debug -DGLM_TEST_ENABLE=ON -DGLM_TEST_ENABLE_CXX_14=ON -DGLM_TEST_ENABLE_LANG_EXTENSIONS=ON -DGLM_TEST_ENABLE_SIMD_SSE2=ON" + - CTEST_ENV="--parallel 4 --output-on-failure" + - CMAKE_ENV="--parallel" + + - name: "Clang C++17 sse2 debug" + os: linux + dist: focal + env: + - MATRIX_EVAL="CC=clang && CXX=clang++" + - CMAKE_BUILD_ENV="-DCMAKE_BUILD_TYPE=Debug -DGLM_TEST_ENABLE=ON -DGLM_TEST_ENABLE_CXX_17=ON -DGLM_TEST_ENABLE_LANG_EXTENSIONS=ON -DGLM_TEST_ENABLE_SIMD_SSE2=ON" + - CTEST_ENV="--parallel 4 --output-on-failure" + - CMAKE_ENV="--parallel" + + - name: "Clang C++17 avx2 debug" + os: linux + dist: focal + env: + - MATRIX_EVAL="CC=clang && CXX=clang++" + - CMAKE_BUILD_ENV="-DCMAKE_BUILD_TYPE=Debug -DGLM_TEST_ENABLE=ON -DGLM_TEST_ENABLE_CXX_17=ON -DGLM_TEST_ENABLE_LANG_EXTENSIONS=ON -DGLM_TEST_ENABLE_SIMD_AVX2=ON" + - CTEST_ENV="--parallel 4 --output-on-failure" + - CMAKE_ENV="--parallel" + + - name: "Clang C++17 pure debug" + os: linux + dist: focal + env: + - MATRIX_EVAL="CC=clang && CXX=clang++" + - CMAKE_BUILD_ENV="-DCMAKE_BUILD_TYPE=Debug -DGLM_TEST_ENABLE=ON -DGLM_TEST_ENABLE_CXX_17=ON -DGLM_TEST_FORCE_PURE=ON" + - CTEST_ENV="--parallel 4 --output-on-failure" + - CMAKE_ENV="--parallel" + + - name: "Clang C++17 pure release" + os: linux + dist: focal + env: + - MATRIX_EVAL="CC=clang && CXX=clang++" + - CMAKE_BUILD_ENV="-DCMAKE_BUILD_TYPE=Release -DGLM_TEST_ENABLE=ON -DGLM_TEST_ENABLE_CXX_17=ON -DGLM_TEST_FORCE_PURE=ON" + - CTEST_ENV="--parallel 4 --output-on-failure" + - CMAKE_ENV="--parallel" + +before_script: + - cmake --version + - eval "${MATRIX_EVAL}" + +script: + - ${CC} --version + - mkdir ./build + - cd ./build + - cmake -DCMAKE_INSTALL_PREFIX=$TRAVIS_BUILD_DIR/install -DCMAKE_CXX_COMPILER=$COMPILER ${CMAKE_BUILD_ENV} .. + - cmake --build . ${CMAKE_ENV} + - ctest ${CTEST_ENV} + - cmake --build . --target install ${CMAKE_ENV} + - cd $TRAVIS_BUILD_DIR + - mkdir ./build_test_cmake + - cd ./build_test_cmake + - cmake -DCMAKE_CXX_COMPILER=$COMPILER $TRAVIS_BUILD_DIR/test/cmake/ -DCMAKE_PREFIX_PATH=$TRAVIS_BUILD_DIR/install + - cmake --build . + + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/CMakeLists.txt b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..b7641a28699119f1a87e563c8dc1b449dd6e6b8f --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/CMakeLists.txt @@ -0,0 +1,45 @@ +cmake_minimum_required(VERSION 3.2 FATAL_ERROR) +cmake_policy(VERSION 3.2) + + +file(READ "glm/detail/setup.hpp" GLM_SETUP_FILE) +string(REGEX MATCH "#define[ ]+GLM_VERSION_MAJOR[ ]+([0-9]+)" _ ${GLM_SETUP_FILE}) +set(GLM_VERSION_MAJOR "${CMAKE_MATCH_1}") +string(REGEX MATCH "#define[ ]+GLM_VERSION_MINOR[ ]+([0-9]+)" _ ${GLM_SETUP_FILE}) +set(GLM_VERSION_MINOR "${CMAKE_MATCH_1}") +string(REGEX MATCH "#define[ ]+GLM_VERSION_PATCH[ ]+([0-9]+)" _ ${GLM_SETUP_FILE}) +set(GLM_VERSION_PATCH "${CMAKE_MATCH_1}") +string(REGEX MATCH "#define[ ]+GLM_VERSION_REVISION[ ]+([0-9]+)" _ ${GLM_SETUP_FILE}) +set(GLM_VERSION_REVISION "${CMAKE_MATCH_1}") + +set(GLM_VERSION ${GLM_VERSION_MAJOR}.${GLM_VERSION_MINOR}.${GLM_VERSION_PATCH}.${GLM_VERSION_REVISION}) +project(glm VERSION ${GLM_VERSION} LANGUAGES CXX) +message(STATUS "GLM: Version " ${GLM_VERSION}) + +add_subdirectory(glm) +add_library(glm::glm ALIAS glm) + +if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) + + include(CPack) + install(DIRECTORY glm DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} PATTERN "CMakeLists.txt" EXCLUDE) + install(EXPORT glm FILE glmConfig.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/glm NAMESPACE glm::) + include(CMakePackageConfigHelpers) + write_basic_package_version_file("glmConfigVersion.cmake" COMPATIBILITY AnyNewerVersion) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/glmConfigVersion.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/glm) + + include(CTest) + if(BUILD_TESTING) + add_subdirectory(test) + endif() + +endif(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) + +if (NOT TARGET uninstall) +configure_file(cmake/cmake_uninstall.cmake.in + cmake_uninstall.cmake IMMEDIATE @ONLY) + +add_custom_target(uninstall + "${CMAKE_COMMAND}" -P + "${CMAKE_BINARY_DIR}/cmake_uninstall.cmake") +endif() diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/cmake/cmake_uninstall.cmake.in b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/cmake/cmake_uninstall.cmake.in new file mode 100644 index 0000000000000000000000000000000000000000..c2d34d4796d9e2abd8aa0e7aca99a558a1e0366b --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/cmake/cmake_uninstall.cmake.in @@ -0,0 +1,21 @@ +if(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt") + message(FATAL_ERROR "Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt") +endif() + +file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files) +string(REGEX REPLACE "\n" ";" files "${files}") +foreach(file ${files}) + message(STATUS "Uninstalling $ENV{DESTDIR}${file}") + if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") + exec_program( + "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" + OUTPUT_VARIABLE rm_out + RETURN_VALUE rm_retval + ) + if(NOT "${rm_retval}" STREQUAL 0) + message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") + endif() + else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") + message(STATUS "File $ENV{DESTDIR}${file} does not exist.") + endif() +endforeach() diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/copying.txt b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/copying.txt new file mode 100644 index 0000000000000000000000000000000000000000..779c32fb9afef1180798d46f08b4373e427ac693 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/copying.txt @@ -0,0 +1,54 @@ +================================================================================ +OpenGL Mathematics (GLM) +-------------------------------------------------------------------------------- +GLM is licensed under The Happy Bunny License or MIT License + +================================================================================ +The Happy Bunny License (Modified MIT License) +-------------------------------------------------------------------------------- +Copyright (c) 2005 - G-Truc Creation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +Restrictions: + By making use of the Software for military purposes, you choose to make a + Bunny unhappy. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +================================================================================ +The MIT License +-------------------------------------------------------------------------------- +Copyright (c) 2005 - G-Truc Creation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/CMakeLists.txt b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..2d5cff2f3465a86b121ed5c45f652a0c16ae6c77 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/CMakeLists.txt @@ -0,0 +1,78 @@ +file(GLOB ROOT_SOURCE *.cpp) +file(GLOB ROOT_INLINE *.inl) +file(GLOB ROOT_HEADER *.hpp) +file(GLOB ROOT_TEXT ../*.txt) +file(GLOB ROOT_MD ../*.md) +file(GLOB ROOT_NAT ../util/glm.natvis) + +file(GLOB_RECURSE CORE_SOURCE ./detail/*.cpp) +file(GLOB_RECURSE CORE_INLINE ./detail/*.inl) +file(GLOB_RECURSE CORE_HEADER ./detail/*.hpp) + +file(GLOB_RECURSE EXT_SOURCE ./ext/*.cpp) +file(GLOB_RECURSE EXT_INLINE ./ext/*.inl) +file(GLOB_RECURSE EXT_HEADER ./ext/*.hpp) + +file(GLOB_RECURSE GTC_SOURCE ./gtc/*.cpp) +file(GLOB_RECURSE GTC_INLINE ./gtc/*.inl) +file(GLOB_RECURSE GTC_HEADER ./gtc/*.hpp) + +file(GLOB_RECURSE GTX_SOURCE ./gtx/*.cpp) +file(GLOB_RECURSE GTX_INLINE ./gtx/*.inl) +file(GLOB_RECURSE GTX_HEADER ./gtx/*.hpp) + +file(GLOB_RECURSE SIMD_SOURCE ./simd/*.cpp) +file(GLOB_RECURSE SIMD_INLINE ./simd/*.inl) +file(GLOB_RECURSE SIMD_HEADER ./simd/*.h) + +source_group("Text Files" FILES ${ROOT_TEXT} ${ROOT_MD}) +source_group("Core Files" FILES ${CORE_SOURCE}) +source_group("Core Files" FILES ${CORE_INLINE}) +source_group("Core Files" FILES ${CORE_HEADER}) +source_group("EXT Files" FILES ${EXT_SOURCE}) +source_group("EXT Files" FILES ${EXT_INLINE}) +source_group("EXT Files" FILES ${EXT_HEADER}) +source_group("GTC Files" FILES ${GTC_SOURCE}) +source_group("GTC Files" FILES ${GTC_INLINE}) +source_group("GTC Files" FILES ${GTC_HEADER}) +source_group("GTX Files" FILES ${GTX_SOURCE}) +source_group("GTX Files" FILES ${GTX_INLINE}) +source_group("GTX Files" FILES ${GTX_HEADER}) +source_group("SIMD Files" FILES ${SIMD_SOURCE}) +source_group("SIMD Files" FILES ${SIMD_INLINE}) +source_group("SIMD Files" FILES ${SIMD_HEADER}) + +add_library(glm INTERFACE) + +include(GNUInstallDirs) + +target_include_directories(glm INTERFACE + $ + $ +) + +install(TARGETS glm EXPORT glm) + +if(BUILD_STATIC_LIBS) +add_library(glm_static STATIC ${ROOT_TEXT} ${ROOT_MD} ${ROOT_NAT} + ${ROOT_SOURCE} ${ROOT_INLINE} ${ROOT_HEADER} + ${CORE_SOURCE} ${CORE_INLINE} ${CORE_HEADER} + ${EXT_SOURCE} ${EXT_INLINE} ${EXT_HEADER} + ${GTC_SOURCE} ${GTC_INLINE} ${GTC_HEADER} + ${GTX_SOURCE} ${GTX_INLINE} ${GTX_HEADER} + ${SIMD_SOURCE} ${SIMD_INLINE} ${SIMD_HEADER}) + target_link_libraries(glm_static PUBLIC glm) + add_library(glm::glm_static ALIAS glm_static) +endif() + +if(BUILD_SHARED_LIBS) +add_library(glm_shared SHARED ${ROOT_TEXT} ${ROOT_MD} ${ROOT_NAT} + ${ROOT_SOURCE} ${ROOT_INLINE} ${ROOT_HEADER} + ${CORE_SOURCE} ${CORE_INLINE} ${CORE_HEADER} + ${EXT_SOURCE} ${EXT_INLINE} ${EXT_HEADER} + ${GTC_SOURCE} ${GTC_INLINE} ${GTC_HEADER} + ${GTX_SOURCE} ${GTX_INLINE} ${GTX_HEADER} + ${SIMD_SOURCE} ${SIMD_INLINE} ${SIMD_HEADER}) + target_link_libraries(glm_shared PUBLIC glm) + add_library(glm::glm_shared ALIAS glm_shared) +endif() diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/common.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/common.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0328dc91ee26fb5a760342b09879a3152840414c --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/common.hpp @@ -0,0 +1,539 @@ +/// @ref core +/// @file glm/common.hpp +/// +/// @see GLSL 4.20.8 specification, section 8.3 Common Functions +/// +/// @defgroup core_func_common Common functions +/// @ingroup core +/// +/// Provides GLSL common functions +/// +/// These all operate component-wise. The description is per component. +/// +/// Include to use these core features. + +#pragma once + +#include "detail/qualifier.hpp" +#include "detail/_fixes.hpp" + +namespace glm +{ + /// @addtogroup core_func_common + /// @{ + + /// Returns x if x >= 0; otherwise, it returns -x. + /// + /// @tparam genType floating-point or signed integer; scalar or vector types. + /// + /// @see GLSL abs man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR genType abs(genType x); + + /// Returns x if x >= 0; otherwise, it returns -x. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or signed integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL abs man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec abs(vec const& x); + + /// Returns 1.0 if x > 0, 0.0 if x == 0, or -1.0 if x < 0. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL sign man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec sign(vec const& x); + + /// Returns a value equal to the nearest integer that is less then or equal to x. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL floor man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec floor(vec const& x); + + /// Returns a value equal to the nearest integer to x + /// whose absolute value is not larger than the absolute value of x. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL trunc man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec trunc(vec const& x); + + /// Returns a value equal to the nearest integer to x. + /// The fraction 0.5 will round in a direction chosen by the + /// implementation, presumably the direction that is fastest. + /// This includes the possibility that round(x) returns the + /// same value as roundEven(x) for all values of x. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL round man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec round(vec const& x); + + /// Returns a value equal to the nearest integer to x. + /// A fractional part of 0.5 will round toward the nearest even + /// integer. (Both 3.5 and 4.5 for x will return 4.0.) + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL roundEven man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + /// @see New round to even technique + template + GLM_FUNC_DECL vec roundEven(vec const& x); + + /// Returns a value equal to the nearest integer + /// that is greater than or equal to x. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL ceil man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec ceil(vec const& x); + + /// Return x - floor(x). + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see GLSL fract man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL genType fract(genType x); + + /// Return x - floor(x). + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL fract man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec fract(vec const& x); + + template + GLM_FUNC_DECL genType mod(genType x, genType y); + + template + GLM_FUNC_DECL vec mod(vec const& x, T y); + + /// Modulus. Returns x - y * floor(x / y) + /// for each component in x using the floating point value y. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types, include glm/gtc/integer for integer scalar types support + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL mod man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec mod(vec const& x, vec const& y); + + /// Returns the fractional part of x and sets i to the integer + /// part (as a whole number floating point value). Both the + /// return value and the output parameter will have the same + /// sign as x. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see GLSL modf man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL genType modf(genType x, genType& i); + + /// Returns y if y < x; otherwise, it returns x. + /// + /// @tparam genType Floating-point or integer; scalar or vector types. + /// + /// @see GLSL min man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR genType min(genType x, genType y); + + /// Returns y if y < x; otherwise, it returns x. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL min man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec min(vec const& x, T y); + + /// Returns y if y < x; otherwise, it returns x. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL min man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec min(vec const& x, vec const& y); + + /// Returns y if x < y; otherwise, it returns x. + /// + /// @tparam genType Floating-point or integer; scalar or vector types. + /// + /// @see GLSL max man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR genType max(genType x, genType y); + + /// Returns y if x < y; otherwise, it returns x. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL max man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec max(vec const& x, T y); + + /// Returns y if x < y; otherwise, it returns x. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL max man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec max(vec const& x, vec const& y); + + /// Returns min(max(x, minVal), maxVal) for each component in x + /// using the floating-point values minVal and maxVal. + /// + /// @tparam genType Floating-point or integer; scalar or vector types. + /// + /// @see GLSL clamp man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR genType clamp(genType x, genType minVal, genType maxVal); + + /// Returns min(max(x, minVal), maxVal) for each component in x + /// using the floating-point values minVal and maxVal. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL clamp man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec clamp(vec const& x, T minVal, T maxVal); + + /// Returns min(max(x, minVal), maxVal) for each component in x + /// using the floating-point values minVal and maxVal. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL clamp man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec clamp(vec const& x, vec const& minVal, vec const& maxVal); + + /// If genTypeU is a floating scalar or vector: + /// Returns x * (1.0 - a) + y * a, i.e., the linear blend of + /// x and y using the floating-point value a. + /// The value for a is not restricted to the range [0, 1]. + /// + /// If genTypeU is a boolean scalar or vector: + /// Selects which vector each returned component comes + /// from. For a component of 'a' that is false, the + /// corresponding component of 'x' is returned. For a + /// component of 'a' that is true, the corresponding + /// component of 'y' is returned. Components of 'x' and 'y' that + /// are not selected are allowed to be invalid floating point + /// values and will have no effect on the results. Thus, this + /// provides different functionality than + /// genType mix(genType x, genType y, genType(a)) + /// where a is a Boolean vector. + /// + /// @see GLSL mix man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + /// + /// @param[in] x Value to interpolate. + /// @param[in] y Value to interpolate. + /// @param[in] a Interpolant. + /// + /// @tparam genTypeT Floating point scalar or vector. + /// @tparam genTypeU Floating point or boolean scalar or vector. It can't be a vector if it is the length of genTypeT. + /// + /// @code + /// #include + /// ... + /// float a; + /// bool b; + /// glm::dvec3 e; + /// glm::dvec3 f; + /// glm::vec4 g; + /// glm::vec4 h; + /// ... + /// glm::vec4 r = glm::mix(g, h, a); // Interpolate with a floating-point scalar two vectors. + /// glm::vec4 s = glm::mix(g, h, b); // Returns g or h; + /// glm::dvec3 t = glm::mix(e, f, a); // Types of the third parameter is not required to match with the first and the second. + /// glm::vec4 u = glm::mix(g, h, r); // Interpolations can be perform per component with a vector for the last parameter. + /// @endcode + template + GLM_FUNC_DECL genTypeT mix(genTypeT x, genTypeT y, genTypeU a); + + template + GLM_FUNC_DECL vec mix(vec const& x, vec const& y, vec const& a); + + template + GLM_FUNC_DECL vec mix(vec const& x, vec const& y, U a); + + /// Returns 0.0 if x < edge, otherwise it returns 1.0 for each component of a genType. + /// + /// @see GLSL step man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL genType step(genType edge, genType x); + + /// Returns 0.0 if x < edge, otherwise it returns 1.0. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL step man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec step(T edge, vec const& x); + + /// Returns 0.0 if x < edge, otherwise it returns 1.0. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL step man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec step(vec const& edge, vec const& x); + + /// Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and + /// performs smooth Hermite interpolation between 0 and 1 + /// when edge0 < x < edge1. This is useful in cases where + /// you would want a threshold function with a smooth + /// transition. This is equivalent to: + /// genType t; + /// t = clamp ((x - edge0) / (edge1 - edge0), 0, 1); + /// return t * t * (3 - 2 * t); + /// Results are undefined if edge0 >= edge1. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see GLSL smoothstep man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL genType smoothstep(genType edge0, genType edge1, genType x); + + template + GLM_FUNC_DECL vec smoothstep(T edge0, T edge1, vec const& x); + + template + GLM_FUNC_DECL vec smoothstep(vec const& edge0, vec const& edge1, vec const& x); + + /// Returns true if x holds a NaN (not a number) + /// representation in the underlying implementation's set of + /// floating point representations. Returns false otherwise, + /// including for implementations with no NaN + /// representations. + /// + /// /!\ When using compiler fast math, this function may fail. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL isnan man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec isnan(vec const& x); + + /// Returns true if x holds a positive infinity or negative + /// infinity representation in the underlying implementation's + /// set of floating point representations. Returns false + /// otherwise, including for implementations with no infinity + /// representations. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL isinf man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec isinf(vec const& x); + + /// Returns a signed integer value representing + /// the encoding of a floating-point value. The floating-point + /// value's bit-level representation is preserved. + /// + /// @see GLSL floatBitsToInt man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + GLM_FUNC_DECL int floatBitsToInt(float const& v); + + /// Returns a signed integer value representing + /// the encoding of a floating-point value. The floatingpoint + /// value's bit-level representation is preserved. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL floatBitsToInt man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec floatBitsToInt(vec const& v); + + /// Returns a unsigned integer value representing + /// the encoding of a floating-point value. The floatingpoint + /// value's bit-level representation is preserved. + /// + /// @see GLSL floatBitsToUint man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + GLM_FUNC_DECL uint floatBitsToUint(float const& v); + + /// Returns a unsigned integer value representing + /// the encoding of a floating-point value. The floatingpoint + /// value's bit-level representation is preserved. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL floatBitsToUint man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec floatBitsToUint(vec const& v); + + /// Returns a floating-point value corresponding to a signed + /// integer encoding of a floating-point value. + /// If an inf or NaN is passed in, it will not signal, and the + /// resulting floating point value is unspecified. Otherwise, + /// the bit-level representation is preserved. + /// + /// @see GLSL intBitsToFloat man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + GLM_FUNC_DECL float intBitsToFloat(int const& v); + + /// Returns a floating-point value corresponding to a signed + /// integer encoding of a floating-point value. + /// If an inf or NaN is passed in, it will not signal, and the + /// resulting floating point value is unspecified. Otherwise, + /// the bit-level representation is preserved. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL intBitsToFloat man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec intBitsToFloat(vec const& v); + + /// Returns a floating-point value corresponding to a + /// unsigned integer encoding of a floating-point value. + /// If an inf or NaN is passed in, it will not signal, and the + /// resulting floating point value is unspecified. Otherwise, + /// the bit-level representation is preserved. + /// + /// @see GLSL uintBitsToFloat man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + GLM_FUNC_DECL float uintBitsToFloat(uint const& v); + + /// Returns a floating-point value corresponding to a + /// unsigned integer encoding of a floating-point value. + /// If an inf or NaN is passed in, it will not signal, and the + /// resulting floating point value is unspecified. Otherwise, + /// the bit-level representation is preserved. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL uintBitsToFloat man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec uintBitsToFloat(vec const& v); + + /// Computes and returns a * b + c. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see GLSL fma man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL genType fma(genType const& a, genType const& b, genType const& c); + + /// Splits x into a floating-point significand in the range + /// [0.5, 1.0) and an integral exponent of two, such that: + /// x = significand * exp(2, exponent) + /// + /// The significand is returned by the function and the + /// exponent is returned in the parameter exp. For a + /// floating-point value of zero, the significant and exponent + /// are both zero. For a floating-point value that is an + /// infinity or is not a number, the results are undefined. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see GLSL frexp man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL genType frexp(genType x, int& exp); + + template + GLM_FUNC_DECL vec frexp(vec const& v, vec& exp); + + /// Builds a floating-point number from x and the + /// corresponding integral exponent of two in exp, returning: + /// significand * exp(2, exponent) + /// + /// If this product is too large to be represented in the + /// floating-point type, the result is undefined. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see GLSL ldexp man page; + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL genType ldexp(genType const& x, int const& exp); + + template + GLM_FUNC_DECL vec ldexp(vec const& v, vec const& exp); + + /// @} +}//namespace glm + +#include "detail/func_common.inl" + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/_features.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/_features.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b0cbe9ff02cf50fc8a2e298998efabe59a9b07ea --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/_features.hpp @@ -0,0 +1,394 @@ +#pragma once + +// #define GLM_CXX98_EXCEPTIONS +// #define GLM_CXX98_RTTI + +// #define GLM_CXX11_RVALUE_REFERENCES +// Rvalue references - GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2118.html + +// GLM_CXX11_TRAILING_RETURN +// Rvalue references for *this - GCC not supported +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2439.htm + +// GLM_CXX11_NONSTATIC_MEMBER_INIT +// Initialization of class objects by rvalues - GCC any +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1610.html + +// GLM_CXX11_NONSTATIC_MEMBER_INIT +// Non-static data member initializers - GCC 4.7 +// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2756.htm + +// #define GLM_CXX11_VARIADIC_TEMPLATE +// Variadic templates - GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2242.pdf + +// +// Extending variadic template template parameters - GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2555.pdf + +// #define GLM_CXX11_GENERALIZED_INITIALIZERS +// Initializer lists - GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2672.htm + +// #define GLM_CXX11_STATIC_ASSERT +// Static assertions - GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1720.html + +// #define GLM_CXX11_AUTO_TYPE +// auto-typed variables - GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1984.pdf + +// #define GLM_CXX11_AUTO_TYPE +// Multi-declarator auto - GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1737.pdf + +// #define GLM_CXX11_AUTO_TYPE +// Removal of auto as a storage-class specifier - GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2546.htm + +// #define GLM_CXX11_AUTO_TYPE +// New function declarator syntax - GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2541.htm + +// #define GLM_CXX11_LAMBDAS +// New wording for C++0x lambdas - GCC 4.5 +// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2927.pdf + +// #define GLM_CXX11_DECLTYPE +// Declared type of an expression - GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2343.pdf + +// +// Right angle brackets - GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1757.html + +// +// Default template arguments for function templates DR226 GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#226 + +// +// Solving the SFINAE problem for expressions DR339 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2634.html + +// #define GLM_CXX11_ALIAS_TEMPLATE +// Template aliases N2258 GCC 4.7 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2258.pdf + +// +// Extern templates N1987 Yes +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1987.htm + +// #define GLM_CXX11_NULLPTR +// Null pointer constant N2431 GCC 4.6 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2431.pdf + +// #define GLM_CXX11_STRONG_ENUMS +// Strongly-typed enums N2347 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2347.pdf + +// +// Forward declarations for enums N2764 GCC 4.6 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2764.pdf + +// +// Generalized attributes N2761 GCC 4.8 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2761.pdf + +// +// Generalized constant expressions N2235 GCC 4.6 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf + +// +// Alignment support N2341 GCC 4.8 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2341.pdf + +// #define GLM_CXX11_DELEGATING_CONSTRUCTORS +// Delegating constructors N1986 GCC 4.7 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1986.pdf + +// +// Inheriting constructors N2540 GCC 4.8 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2540.htm + +// #define GLM_CXX11_EXPLICIT_CONVERSIONS +// Explicit conversion operators N2437 GCC 4.5 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2437.pdf + +// +// New character types N2249 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2249.html + +// +// Unicode string literals N2442 GCC 4.5 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2442.htm + +// +// Raw string literals N2442 GCC 4.5 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2442.htm + +// +// Universal character name literals N2170 GCC 4.5 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2170.html + +// #define GLM_CXX11_USER_LITERALS +// User-defined literals N2765 GCC 4.7 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2765.pdf + +// +// Standard Layout Types N2342 GCC 4.5 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2342.htm + +// #define GLM_CXX11_DEFAULTED_FUNCTIONS +// #define GLM_CXX11_DELETED_FUNCTIONS +// Defaulted and deleted functions N2346 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm + +// +// Extended friend declarations N1791 GCC 4.7 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1791.pdf + +// +// Extending sizeof N2253 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2253.html + +// #define GLM_CXX11_INLINE_NAMESPACES +// Inline namespaces N2535 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2535.htm + +// #define GLM_CXX11_UNRESTRICTED_UNIONS +// Unrestricted unions N2544 GCC 4.6 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf + +// #define GLM_CXX11_LOCAL_TYPE_TEMPLATE_ARGS +// Local and unnamed types as template arguments N2657 GCC 4.5 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2657.htm + +// #define GLM_CXX11_RANGE_FOR +// Range-based for N2930 GCC 4.6 +// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2930.html + +// #define GLM_CXX11_OVERRIDE_CONTROL +// Explicit virtual overrides N2928 N3206 N3272 GCC 4.7 +// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2928.htm +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3206.htm +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3272.htm + +// +// Minimal support for garbage collection and reachability-based leak detection N2670 No +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2670.htm + +// #define GLM_CXX11_NOEXCEPT +// Allowing move constructors to throw [noexcept] N3050 GCC 4.6 (core language only) +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3050.html + +// +// Defining move special member functions N3053 GCC 4.6 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3053.html + +// +// Sequence points N2239 Yes +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2239.html + +// +// Atomic operations N2427 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2239.html + +// +// Strong Compare and Exchange N2748 GCC 4.5 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2427.html + +// +// Bidirectional Fences N2752 GCC 4.8 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2752.htm + +// +// Memory model N2429 GCC 4.8 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2429.htm + +// +// Data-dependency ordering: atomics and memory model N2664 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2664.htm + +// +// Propagating exceptions N2179 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2179.html + +// +// Abandoning a process and at_quick_exit N2440 GCC 4.8 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2440.htm + +// +// Allow atomics use in signal handlers N2547 Yes +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2547.htm + +// +// Thread-local storage N2659 GCC 4.8 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2659.htm + +// +// Dynamic initialization and destruction with concurrency N2660 GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2660.htm + +// +// __func__ predefined identifier N2340 GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2340.htm + +// +// C99 preprocessor N1653 GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1653.htm + +// +// long long N1811 GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1811.pdf + +// +// Extended integral types N1988 Yes +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1988.pdf + +#if(GLM_COMPILER & GLM_COMPILER_GCC) + +# define GLM_CXX11_STATIC_ASSERT + +#elif(GLM_COMPILER & GLM_COMPILER_CLANG) +# if(__has_feature(cxx_exceptions)) +# define GLM_CXX98_EXCEPTIONS +# endif + +# if(__has_feature(cxx_rtti)) +# define GLM_CXX98_RTTI +# endif + +# if(__has_feature(cxx_access_control_sfinae)) +# define GLM_CXX11_ACCESS_CONTROL_SFINAE +# endif + +# if(__has_feature(cxx_alias_templates)) +# define GLM_CXX11_ALIAS_TEMPLATE +# endif + +# if(__has_feature(cxx_alignas)) +# define GLM_CXX11_ALIGNAS +# endif + +# if(__has_feature(cxx_attributes)) +# define GLM_CXX11_ATTRIBUTES +# endif + +# if(__has_feature(cxx_constexpr)) +# define GLM_CXX11_CONSTEXPR +# endif + +# if(__has_feature(cxx_decltype)) +# define GLM_CXX11_DECLTYPE +# endif + +# if(__has_feature(cxx_default_function_template_args)) +# define GLM_CXX11_DEFAULT_FUNCTION_TEMPLATE_ARGS +# endif + +# if(__has_feature(cxx_defaulted_functions)) +# define GLM_CXX11_DEFAULTED_FUNCTIONS +# endif + +# if(__has_feature(cxx_delegating_constructors)) +# define GLM_CXX11_DELEGATING_CONSTRUCTORS +# endif + +# if(__has_feature(cxx_deleted_functions)) +# define GLM_CXX11_DELETED_FUNCTIONS +# endif + +# if(__has_feature(cxx_explicit_conversions)) +# define GLM_CXX11_EXPLICIT_CONVERSIONS +# endif + +# if(__has_feature(cxx_generalized_initializers)) +# define GLM_CXX11_GENERALIZED_INITIALIZERS +# endif + +# if(__has_feature(cxx_implicit_moves)) +# define GLM_CXX11_IMPLICIT_MOVES +# endif + +# if(__has_feature(cxx_inheriting_constructors)) +# define GLM_CXX11_INHERITING_CONSTRUCTORS +# endif + +# if(__has_feature(cxx_inline_namespaces)) +# define GLM_CXX11_INLINE_NAMESPACES +# endif + +# if(__has_feature(cxx_lambdas)) +# define GLM_CXX11_LAMBDAS +# endif + +# if(__has_feature(cxx_local_type_template_args)) +# define GLM_CXX11_LOCAL_TYPE_TEMPLATE_ARGS +# endif + +# if(__has_feature(cxx_noexcept)) +# define GLM_CXX11_NOEXCEPT +# endif + +# if(__has_feature(cxx_nonstatic_member_init)) +# define GLM_CXX11_NONSTATIC_MEMBER_INIT +# endif + +# if(__has_feature(cxx_nullptr)) +# define GLM_CXX11_NULLPTR +# endif + +# if(__has_feature(cxx_override_control)) +# define GLM_CXX11_OVERRIDE_CONTROL +# endif + +# if(__has_feature(cxx_reference_qualified_functions)) +# define GLM_CXX11_REFERENCE_QUALIFIED_FUNCTIONS +# endif + +# if(__has_feature(cxx_range_for)) +# define GLM_CXX11_RANGE_FOR +# endif + +# if(__has_feature(cxx_raw_string_literals)) +# define GLM_CXX11_RAW_STRING_LITERALS +# endif + +# if(__has_feature(cxx_rvalue_references)) +# define GLM_CXX11_RVALUE_REFERENCES +# endif + +# if(__has_feature(cxx_static_assert)) +# define GLM_CXX11_STATIC_ASSERT +# endif + +# if(__has_feature(cxx_auto_type)) +# define GLM_CXX11_AUTO_TYPE +# endif + +# if(__has_feature(cxx_strong_enums)) +# define GLM_CXX11_STRONG_ENUMS +# endif + +# if(__has_feature(cxx_trailing_return)) +# define GLM_CXX11_TRAILING_RETURN +# endif + +# if(__has_feature(cxx_unicode_literals)) +# define GLM_CXX11_UNICODE_LITERALS +# endif + +# if(__has_feature(cxx_unrestricted_unions)) +# define GLM_CXX11_UNRESTRICTED_UNIONS +# endif + +# if(__has_feature(cxx_user_literals)) +# define GLM_CXX11_USER_LITERALS +# endif + +# if(__has_feature(cxx_variadic_templates)) +# define GLM_CXX11_VARIADIC_TEMPLATES +# endif + +#endif//(GLM_COMPILER & GLM_COMPILER_CLANG) diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/_fixes.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/_fixes.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a503c7c0d041a9df14c88e391fee1b26b615f2c7 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/_fixes.hpp @@ -0,0 +1,27 @@ +#include + +//! Workaround for compatibility with other libraries +#ifdef max +#undef max +#endif + +//! Workaround for compatibility with other libraries +#ifdef min +#undef min +#endif + +//! Workaround for Android +#ifdef isnan +#undef isnan +#endif + +//! Workaround for Android +#ifdef isinf +#undef isinf +#endif + +//! Workaround for Chrone Native Client +#ifdef log2 +#undef log2 +#endif + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/_noise.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/_noise.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5a874a02221f1c5eaa0ed393d9f24aec3be898c5 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/_noise.hpp @@ -0,0 +1,81 @@ +#pragma once + +#include "../common.hpp" + +namespace glm{ +namespace detail +{ + template + GLM_FUNC_QUALIFIER T mod289(T const& x) + { + return x - floor(x * (static_cast(1.0) / static_cast(289.0))) * static_cast(289.0); + } + + template + GLM_FUNC_QUALIFIER T permute(T const& x) + { + return mod289(((x * static_cast(34)) + static_cast(1)) * x); + } + + template + GLM_FUNC_QUALIFIER vec<2, T, Q> permute(vec<2, T, Q> const& x) + { + return mod289(((x * static_cast(34)) + static_cast(1)) * x); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> permute(vec<3, T, Q> const& x) + { + return mod289(((x * static_cast(34)) + static_cast(1)) * x); + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> permute(vec<4, T, Q> const& x) + { + return mod289(((x * static_cast(34)) + static_cast(1)) * x); + } + + template + GLM_FUNC_QUALIFIER T taylorInvSqrt(T const& r) + { + return static_cast(1.79284291400159) - static_cast(0.85373472095314) * r; + } + + template + GLM_FUNC_QUALIFIER vec<2, T, Q> taylorInvSqrt(vec<2, T, Q> const& r) + { + return static_cast(1.79284291400159) - static_cast(0.85373472095314) * r; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> taylorInvSqrt(vec<3, T, Q> const& r) + { + return static_cast(1.79284291400159) - static_cast(0.85373472095314) * r; + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> taylorInvSqrt(vec<4, T, Q> const& r) + { + return static_cast(1.79284291400159) - static_cast(0.85373472095314) * r; + } + + template + GLM_FUNC_QUALIFIER vec<2, T, Q> fade(vec<2, T, Q> const& t) + { + return (t * t * t) * (t * (t * static_cast(6) - static_cast(15)) + static_cast(10)); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> fade(vec<3, T, Q> const& t) + { + return (t * t * t) * (t * (t * static_cast(6) - static_cast(15)) + static_cast(10)); + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> fade(vec<4, T, Q> const& t) + { + return (t * t * t) * (t * (t * static_cast(6) - static_cast(15)) + static_cast(10)); + } +}//namespace detail +}//namespace glm + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/_swizzle.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/_swizzle.hpp new file mode 100644 index 0000000000000000000000000000000000000000..87896ef4f6f25e5d336a74c98b8369adea378e80 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/_swizzle.hpp @@ -0,0 +1,804 @@ +#pragma once + +namespace glm{ +namespace detail +{ + // Internal class for implementing swizzle operators + template + struct _swizzle_base0 + { + protected: + GLM_FUNC_QUALIFIER T& elem(size_t i){ return (reinterpret_cast(_buffer))[i]; } + GLM_FUNC_QUALIFIER T const& elem(size_t i) const{ return (reinterpret_cast(_buffer))[i]; } + + // Use an opaque buffer to *ensure* the compiler doesn't call a constructor. + // The size 1 buffer is assumed to aligned to the actual members so that the + // elem() + char _buffer[1]; + }; + + template + struct _swizzle_base1 : public _swizzle_base0 + { + }; + + template + struct _swizzle_base1<2, T, Q, E0,E1,-1,-2, Aligned> : public _swizzle_base0 + { + GLM_FUNC_QUALIFIER vec<2, T, Q> operator ()() const { return vec<2, T, Q>(this->elem(E0), this->elem(E1)); } + }; + + template + struct _swizzle_base1<3, T, Q, E0,E1,E2,-1, Aligned> : public _swizzle_base0 + { + GLM_FUNC_QUALIFIER vec<3, T, Q> operator ()() const { return vec<3, T, Q>(this->elem(E0), this->elem(E1), this->elem(E2)); } + }; + + template + struct _swizzle_base1<4, T, Q, E0,E1,E2,E3, Aligned> : public _swizzle_base0 + { + GLM_FUNC_QUALIFIER vec<4, T, Q> operator ()() const { return vec<4, T, Q>(this->elem(E0), this->elem(E1), this->elem(E2), this->elem(E3)); } + }; + + // Internal class for implementing swizzle operators + /* + Template parameters: + + T = type of scalar values (e.g. float, double) + N = number of components in the vector (e.g. 3) + E0...3 = what index the n-th element of this swizzle refers to in the unswizzled vec + + DUPLICATE_ELEMENTS = 1 if there is a repeated element, 0 otherwise (used to specialize swizzles + containing duplicate elements so that they cannot be used as r-values). + */ + template + struct _swizzle_base2 : public _swizzle_base1::value> + { + struct op_equal + { + GLM_FUNC_QUALIFIER void operator() (T& e, T& t) const{ e = t; } + }; + + struct op_minus + { + GLM_FUNC_QUALIFIER void operator() (T& e, T& t) const{ e -= t; } + }; + + struct op_plus + { + GLM_FUNC_QUALIFIER void operator() (T& e, T& t) const{ e += t; } + }; + + struct op_mul + { + GLM_FUNC_QUALIFIER void operator() (T& e, T& t) const{ e *= t; } + }; + + struct op_div + { + GLM_FUNC_QUALIFIER void operator() (T& e, T& t) const{ e /= t; } + }; + + public: + GLM_FUNC_QUALIFIER _swizzle_base2& operator= (const T& t) + { + for (int i = 0; i < N; ++i) + (*this)[i] = t; + return *this; + } + + GLM_FUNC_QUALIFIER _swizzle_base2& operator= (vec const& that) + { + _apply_op(that, op_equal()); + return *this; + } + + GLM_FUNC_QUALIFIER void operator -= (vec const& that) + { + _apply_op(that, op_minus()); + } + + GLM_FUNC_QUALIFIER void operator += (vec const& that) + { + _apply_op(that, op_plus()); + } + + GLM_FUNC_QUALIFIER void operator *= (vec const& that) + { + _apply_op(that, op_mul()); + } + + GLM_FUNC_QUALIFIER void operator /= (vec const& that) + { + _apply_op(that, op_div()); + } + + GLM_FUNC_QUALIFIER T& operator[](size_t i) + { + const int offset_dst[4] = { E0, E1, E2, E3 }; + return this->elem(offset_dst[i]); + } + GLM_FUNC_QUALIFIER T operator[](size_t i) const + { + const int offset_dst[4] = { E0, E1, E2, E3 }; + return this->elem(offset_dst[i]); + } + + protected: + template + GLM_FUNC_QUALIFIER void _apply_op(vec const& that, const U& op) + { + // Make a copy of the data in this == &that. + // The copier should optimize out the copy in cases where the function is + // properly inlined and the copy is not necessary. + T t[N]; + for (int i = 0; i < N; ++i) + t[i] = that[i]; + for (int i = 0; i < N; ++i) + op( (*this)[i], t[i] ); + } + }; + + // Specialization for swizzles containing duplicate elements. These cannot be modified. + template + struct _swizzle_base2 : public _swizzle_base1::value> + { + struct Stub {}; + + GLM_FUNC_QUALIFIER _swizzle_base2& operator= (Stub const&) { return *this; } + + GLM_FUNC_QUALIFIER T operator[] (size_t i) const + { + const int offset_dst[4] = { E0, E1, E2, E3 }; + return this->elem(offset_dst[i]); + } + }; + + template + struct _swizzle : public _swizzle_base2 + { + typedef _swizzle_base2 base_type; + + using base_type::operator=; + + GLM_FUNC_QUALIFIER operator vec () const { return (*this)(); } + }; + +// +// To prevent the C++ syntax from getting entirely overwhelming, define some alias macros +// +#define GLM_SWIZZLE_TEMPLATE1 template +#define GLM_SWIZZLE_TEMPLATE2 template +#define GLM_SWIZZLE_TYPE1 _swizzle +#define GLM_SWIZZLE_TYPE2 _swizzle + +// +// Wrapper for a binary operator (e.g. u.yy + v.zy) +// +#define GLM_SWIZZLE_VECTOR_BINARY_OPERATOR_IMPLEMENTATION(OPERAND) \ + GLM_SWIZZLE_TEMPLATE2 \ + GLM_FUNC_QUALIFIER vec operator OPERAND ( const GLM_SWIZZLE_TYPE1& a, const GLM_SWIZZLE_TYPE2& b) \ + { \ + return a() OPERAND b(); \ + } \ + GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER vec operator OPERAND ( const GLM_SWIZZLE_TYPE1& a, const vec& b) \ + { \ + return a() OPERAND b; \ + } \ + GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER vec operator OPERAND ( const vec& a, const GLM_SWIZZLE_TYPE1& b) \ + { \ + return a OPERAND b(); \ + } + +// +// Wrapper for a operand between a swizzle and a binary (e.g. 1.0f - u.xyz) +// +#define GLM_SWIZZLE_SCALAR_BINARY_OPERATOR_IMPLEMENTATION(OPERAND) \ + GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER vec operator OPERAND ( const GLM_SWIZZLE_TYPE1& a, const T& b) \ + { \ + return a() OPERAND b; \ + } \ + GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER vec operator OPERAND ( const T& a, const GLM_SWIZZLE_TYPE1& b) \ + { \ + return a OPERAND b(); \ + } + +// +// Macro for wrapping a function taking one argument (e.g. abs()) +// +#define GLM_SWIZZLE_FUNCTION_1_ARGS(RETURN_TYPE,FUNCTION) \ + GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const GLM_SWIZZLE_TYPE1& a) \ + { \ + return FUNCTION(a()); \ + } + +// +// Macro for wrapping a function taking two vector arguments (e.g. dot()). +// +#define GLM_SWIZZLE_FUNCTION_2_ARGS(RETURN_TYPE,FUNCTION) \ + GLM_SWIZZLE_TEMPLATE2 \ + GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const GLM_SWIZZLE_TYPE1& a, const GLM_SWIZZLE_TYPE2& b) \ + { \ + return FUNCTION(a(), b()); \ + } \ + GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const GLM_SWIZZLE_TYPE1& a, const GLM_SWIZZLE_TYPE1& b) \ + { \ + return FUNCTION(a(), b()); \ + } \ + GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const GLM_SWIZZLE_TYPE1& a, const typename V& b) \ + { \ + return FUNCTION(a(), b); \ + } \ + GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const V& a, const GLM_SWIZZLE_TYPE1& b) \ + { \ + return FUNCTION(a, b()); \ + } + +// +// Macro for wrapping a function take 2 vec arguments followed by a scalar (e.g. mix()). +// +#define GLM_SWIZZLE_FUNCTION_2_ARGS_SCALAR(RETURN_TYPE,FUNCTION) \ + GLM_SWIZZLE_TEMPLATE2 \ + GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const GLM_SWIZZLE_TYPE1& a, const GLM_SWIZZLE_TYPE2& b, const T& c) \ + { \ + return FUNCTION(a(), b(), c); \ + } \ + GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const GLM_SWIZZLE_TYPE1& a, const GLM_SWIZZLE_TYPE1& b, const T& c) \ + { \ + return FUNCTION(a(), b(), c); \ + } \ + GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const GLM_SWIZZLE_TYPE1& a, const typename S0::vec_type& b, const T& c)\ + { \ + return FUNCTION(a(), b, c); \ + } \ + GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const typename V& a, const GLM_SWIZZLE_TYPE1& b, const T& c) \ + { \ + return FUNCTION(a, b(), c); \ + } + +}//namespace detail +}//namespace glm + +namespace glm +{ + namespace detail + { + GLM_SWIZZLE_SCALAR_BINARY_OPERATOR_IMPLEMENTATION(-) + GLM_SWIZZLE_SCALAR_BINARY_OPERATOR_IMPLEMENTATION(*) + GLM_SWIZZLE_VECTOR_BINARY_OPERATOR_IMPLEMENTATION(+) + GLM_SWIZZLE_VECTOR_BINARY_OPERATOR_IMPLEMENTATION(-) + GLM_SWIZZLE_VECTOR_BINARY_OPERATOR_IMPLEMENTATION(*) + GLM_SWIZZLE_VECTOR_BINARY_OPERATOR_IMPLEMENTATION(/) + } + + // + // Swizzles are distinct types from the unswizzled type. The below macros will + // provide template specializations for the swizzle types for the given functions + // so that the compiler does not have any ambiguity to choosing how to handle + // the function. + // + // The alternative is to use the operator()() when calling the function in order + // to explicitly convert the swizzled type to the unswizzled type. + // + + //GLM_SWIZZLE_FUNCTION_1_ARGS(vec_type, abs); + //GLM_SWIZZLE_FUNCTION_1_ARGS(vec_type, acos); + //GLM_SWIZZLE_FUNCTION_1_ARGS(vec_type, acosh); + //GLM_SWIZZLE_FUNCTION_1_ARGS(vec_type, all); + //GLM_SWIZZLE_FUNCTION_1_ARGS(vec_type, any); + + //GLM_SWIZZLE_FUNCTION_2_ARGS(value_type, dot); + //GLM_SWIZZLE_FUNCTION_2_ARGS(vec_type, cross); + //GLM_SWIZZLE_FUNCTION_2_ARGS(vec_type, step); + //GLM_SWIZZLE_FUNCTION_2_ARGS_SCALAR(vec_type, mix); +} + +#define GLM_SWIZZLE2_2_MEMBERS(T, Q, E0,E1) \ + struct { detail::_swizzle<2, T, Q, 0,0,-1,-2> E0 ## E0; }; \ + struct { detail::_swizzle<2, T, Q, 0,1,-1,-2> E0 ## E1; }; \ + struct { detail::_swizzle<2, T, Q, 1,0,-1,-2> E1 ## E0; }; \ + struct { detail::_swizzle<2, T, Q, 1,1,-1,-2> E1 ## E1; }; + +#define GLM_SWIZZLE2_3_MEMBERS(T, Q, E0,E1) \ + struct { detail::_swizzle<3,T, Q, 0,0,0,-1> E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<3,T, Q, 0,0,1,-1> E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<3,T, Q, 0,1,0,-1> E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<3,T, Q, 0,1,1,-1> E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<3,T, Q, 1,0,0,-1> E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<3,T, Q, 1,0,1,-1> E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<3,T, Q, 1,1,0,-1> E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<3,T, Q, 1,1,1,-1> E1 ## E1 ## E1; }; + +#define GLM_SWIZZLE2_4_MEMBERS(T, Q, E0,E1) \ + struct { detail::_swizzle<4,T, Q, 0,0,0,0> E0 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,0,0,1> E0 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,0,1,0> E0 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,0,1,1> E0 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,0,0> E0 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,0,1> E0 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,1,0> E0 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,1,1> E0 ## E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,0,0> E1 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,0,1> E1 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,1,0> E1 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,1,1> E1 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,0,0> E1 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,0,1> E1 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,1,0> E1 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,1,1> E1 ## E1 ## E1 ## E1; }; + +#define GLM_SWIZZLE3_2_MEMBERS(T, Q, E0,E1,E2) \ + struct { detail::_swizzle<2,T, Q, 0,0,-1,-2> E0 ## E0; }; \ + struct { detail::_swizzle<2,T, Q, 0,1,-1,-2> E0 ## E1; }; \ + struct { detail::_swizzle<2,T, Q, 0,2,-1,-2> E0 ## E2; }; \ + struct { detail::_swizzle<2,T, Q, 1,0,-1,-2> E1 ## E0; }; \ + struct { detail::_swizzle<2,T, Q, 1,1,-1,-2> E1 ## E1; }; \ + struct { detail::_swizzle<2,T, Q, 1,2,-1,-2> E1 ## E2; }; \ + struct { detail::_swizzle<2,T, Q, 2,0,-1,-2> E2 ## E0; }; \ + struct { detail::_swizzle<2,T, Q, 2,1,-1,-2> E2 ## E1; }; \ + struct { detail::_swizzle<2,T, Q, 2,2,-1,-2> E2 ## E2; }; + +#define GLM_SWIZZLE3_3_MEMBERS(T, Q ,E0,E1,E2) \ + struct { detail::_swizzle<3, T, Q, 0,0,0,-1> E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 0,0,1,-1> E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 0,0,2,-1> E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 0,1,0,-1> E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 0,1,1,-1> E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 0,1,2,-1> E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 0,2,0,-1> E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 0,2,1,-1> E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 0,2,2,-1> E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 1,0,0,-1> E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 1,0,1,-1> E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 1,0,2,-1> E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 1,1,0,-1> E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 1,1,1,-1> E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 1,1,2,-1> E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 1,2,0,-1> E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 1,2,1,-1> E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 1,2,2,-1> E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 2,0,0,-1> E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 2,0,1,-1> E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 2,0,2,-1> E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 2,1,0,-1> E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 2,1,1,-1> E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 2,1,2,-1> E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 2,2,0,-1> E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 2,2,1,-1> E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 2,2,2,-1> E2 ## E2 ## E2; }; + +#define GLM_SWIZZLE3_4_MEMBERS(T, Q, E0,E1,E2) \ + struct { detail::_swizzle<4,T, Q, 0,0,0,0> E0 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,0,0,1> E0 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,0,0,2> E0 ## E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 0,0,1,0> E0 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,0,1,1> E0 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,0,1,2> E0 ## E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 0,0,2,0> E0 ## E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,0,2,1> E0 ## E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,0,2,2> E0 ## E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,0,0> E0 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,0,1> E0 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,0,2> E0 ## E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,1,0> E0 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,1,1> E0 ## E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,1,2> E0 ## E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,2,0> E0 ## E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,2,1> E0 ## E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,2,2> E0 ## E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 0,2,0,0> E0 ## E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,2,0,1> E0 ## E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,2,0,2> E0 ## E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 0,2,1,0> E0 ## E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,2,1,1> E0 ## E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,2,1,2> E0 ## E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 0,2,2,0> E0 ## E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,2,2,1> E0 ## E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,2,2,2> E0 ## E2 ## E2 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,0,0> E1 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,0,1> E1 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,0,2> E1 ## E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,1,0> E1 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,1,1> E1 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,1,2> E1 ## E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,2,0> E1 ## E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,2,1> E1 ## E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,2,2> E1 ## E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,0,0> E1 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,0,1> E1 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,0,2> E1 ## E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,1,0> E1 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,1,1> E1 ## E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,1,2> E1 ## E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,2,0> E1 ## E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,2,1> E1 ## E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,2,2> E1 ## E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 1,2,0,0> E1 ## E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,2,0,1> E1 ## E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,2,0,2> E1 ## E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 1,2,1,0> E1 ## E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,2,1,1> E1 ## E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,2,1,2> E1 ## E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 1,2,2,0> E1 ## E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,2,2,1> E1 ## E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,2,2,2> E1 ## E2 ## E2 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 2,0,0,0> E2 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 2,0,0,1> E2 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 2,0,0,2> E2 ## E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 2,0,1,0> E2 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 2,0,1,1> E2 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 2,0,1,2> E2 ## E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 2,0,2,0> E2 ## E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 2,0,2,1> E2 ## E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 2,0,2,2> E2 ## E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 2,1,0,0> E2 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 2,1,0,1> E2 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 2,1,0,2> E2 ## E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 2,1,1,0> E2 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 2,1,1,1> E2 ## E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 2,1,1,2> E2 ## E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 2,1,2,0> E2 ## E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 2,1,2,1> E2 ## E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 2,1,2,2> E2 ## E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 2,2,0,0> E2 ## E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 2,2,0,1> E2 ## E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 2,2,0,2> E2 ## E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 2,2,1,0> E2 ## E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 2,2,1,1> E2 ## E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 2,2,1,2> E2 ## E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 2,2,2,0> E2 ## E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 2,2,2,1> E2 ## E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 2,2,2,2> E2 ## E2 ## E2 ## E2; }; + +#define GLM_SWIZZLE4_2_MEMBERS(T, Q, E0,E1,E2,E3) \ + struct { detail::_swizzle<2,T, Q, 0,0,-1,-2> E0 ## E0; }; \ + struct { detail::_swizzle<2,T, Q, 0,1,-1,-2> E0 ## E1; }; \ + struct { detail::_swizzle<2,T, Q, 0,2,-1,-2> E0 ## E2; }; \ + struct { detail::_swizzle<2,T, Q, 0,3,-1,-2> E0 ## E3; }; \ + struct { detail::_swizzle<2,T, Q, 1,0,-1,-2> E1 ## E0; }; \ + struct { detail::_swizzle<2,T, Q, 1,1,-1,-2> E1 ## E1; }; \ + struct { detail::_swizzle<2,T, Q, 1,2,-1,-2> E1 ## E2; }; \ + struct { detail::_swizzle<2,T, Q, 1,3,-1,-2> E1 ## E3; }; \ + struct { detail::_swizzle<2,T, Q, 2,0,-1,-2> E2 ## E0; }; \ + struct { detail::_swizzle<2,T, Q, 2,1,-1,-2> E2 ## E1; }; \ + struct { detail::_swizzle<2,T, Q, 2,2,-1,-2> E2 ## E2; }; \ + struct { detail::_swizzle<2,T, Q, 2,3,-1,-2> E2 ## E3; }; \ + struct { detail::_swizzle<2,T, Q, 3,0,-1,-2> E3 ## E0; }; \ + struct { detail::_swizzle<2,T, Q, 3,1,-1,-2> E3 ## E1; }; \ + struct { detail::_swizzle<2,T, Q, 3,2,-1,-2> E3 ## E2; }; \ + struct { detail::_swizzle<2,T, Q, 3,3,-1,-2> E3 ## E3; }; + +#define GLM_SWIZZLE4_3_MEMBERS(T, Q, E0,E1,E2,E3) \ + struct { detail::_swizzle<3, T, Q, 0,0,0,-1> E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 0,0,1,-1> E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 0,0,2,-1> E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 0,0,3,-1> E0 ## E0 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 0,1,0,-1> E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 0,1,1,-1> E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 0,1,2,-1> E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 0,1,3,-1> E0 ## E1 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 0,2,0,-1> E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 0,2,1,-1> E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 0,2,2,-1> E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 0,2,3,-1> E0 ## E2 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 0,3,0,-1> E0 ## E3 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 0,3,1,-1> E0 ## E3 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 0,3,2,-1> E0 ## E3 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 0,3,3,-1> E0 ## E3 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 1,0,0,-1> E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 1,0,1,-1> E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 1,0,2,-1> E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 1,0,3,-1> E1 ## E0 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 1,1,0,-1> E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 1,1,1,-1> E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 1,1,2,-1> E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 1,1,3,-1> E1 ## E1 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 1,2,0,-1> E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 1,2,1,-1> E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 1,2,2,-1> E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 1,2,3,-1> E1 ## E2 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 1,3,0,-1> E1 ## E3 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 1,3,1,-1> E1 ## E3 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 1,3,2,-1> E1 ## E3 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 1,3,3,-1> E1 ## E3 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 2,0,0,-1> E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 2,0,1,-1> E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 2,0,2,-1> E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 2,0,3,-1> E2 ## E0 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 2,1,0,-1> E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 2,1,1,-1> E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 2,1,2,-1> E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 2,1,3,-1> E2 ## E1 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 2,2,0,-1> E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 2,2,1,-1> E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 2,2,2,-1> E2 ## E2 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 2,2,3,-1> E2 ## E2 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 2,3,0,-1> E2 ## E3 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 2,3,1,-1> E2 ## E3 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 2,3,2,-1> E2 ## E3 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 2,3,3,-1> E2 ## E3 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 3,0,0,-1> E3 ## E0 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 3,0,1,-1> E3 ## E0 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 3,0,2,-1> E3 ## E0 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 3,0,3,-1> E3 ## E0 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 3,1,0,-1> E3 ## E1 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 3,1,1,-1> E3 ## E1 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 3,1,2,-1> E3 ## E1 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 3,1,3,-1> E3 ## E1 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 3,2,0,-1> E3 ## E2 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 3,2,1,-1> E3 ## E2 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 3,2,2,-1> E3 ## E2 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 3,2,3,-1> E3 ## E2 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 3,3,0,-1> E3 ## E3 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 3,3,1,-1> E3 ## E3 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 3,3,2,-1> E3 ## E3 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 3,3,3,-1> E3 ## E3 ## E3; }; + +#define GLM_SWIZZLE4_4_MEMBERS(T, Q, E0,E1,E2,E3) \ + struct { detail::_swizzle<4, T, Q, 0,0,0,0> E0 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,0,1> E0 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,0,2> E0 ## E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,0,3> E0 ## E0 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,1,0> E0 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,1,1> E0 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,1,2> E0 ## E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,1,3> E0 ## E0 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,2,0> E0 ## E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,2,1> E0 ## E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,2,2> E0 ## E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,2,3> E0 ## E0 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,3,0> E0 ## E0 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,3,1> E0 ## E0 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,3,2> E0 ## E0 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,3,3> E0 ## E0 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,0,0> E0 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,0,1> E0 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,0,2> E0 ## E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,0,3> E0 ## E1 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,1,0> E0 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,1,1> E0 ## E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,1,2> E0 ## E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,1,3> E0 ## E1 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,2,0> E0 ## E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,2,1> E0 ## E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,2,2> E0 ## E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,2,3> E0 ## E1 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,3,0> E0 ## E1 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,3,1> E0 ## E1 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,3,2> E0 ## E1 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,3,3> E0 ## E1 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,0,0> E0 ## E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,0,1> E0 ## E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,0,2> E0 ## E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,0,3> E0 ## E2 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,1,0> E0 ## E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,1,1> E0 ## E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,1,2> E0 ## E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,1,3> E0 ## E2 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,2,0> E0 ## E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,2,1> E0 ## E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,2,2> E0 ## E2 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,2,3> E0 ## E2 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,3,0> E0 ## E2 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,3,1> E0 ## E2 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,3,2> E0 ## E2 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,3,3> E0 ## E2 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,0,0> E0 ## E3 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,0,1> E0 ## E3 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,0,2> E0 ## E3 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,0,3> E0 ## E3 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,1,0> E0 ## E3 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,1,1> E0 ## E3 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,1,2> E0 ## E3 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,1,3> E0 ## E3 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,2,0> E0 ## E3 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,2,1> E0 ## E3 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,2,2> E0 ## E3 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,2,3> E0 ## E3 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,3,0> E0 ## E3 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,3,1> E0 ## E3 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,3,2> E0 ## E3 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,3,3> E0 ## E3 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,0,0> E1 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,0,1> E1 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,0,2> E1 ## E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,0,3> E1 ## E0 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,1,0> E1 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,1,1> E1 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,1,2> E1 ## E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,1,3> E1 ## E0 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,2,0> E1 ## E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,2,1> E1 ## E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,2,2> E1 ## E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,2,3> E1 ## E0 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,3,0> E1 ## E0 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,3,1> E1 ## E0 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,3,2> E1 ## E0 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,3,3> E1 ## E0 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,0,0> E1 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,0,1> E1 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,0,2> E1 ## E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,0,3> E1 ## E1 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,1,0> E1 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,1,1> E1 ## E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,1,2> E1 ## E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,1,3> E1 ## E1 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,2,0> E1 ## E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,2,1> E1 ## E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,2,2> E1 ## E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,2,3> E1 ## E1 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,3,0> E1 ## E1 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,3,1> E1 ## E1 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,3,2> E1 ## E1 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,3,3> E1 ## E1 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,0,0> E1 ## E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,0,1> E1 ## E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,0,2> E1 ## E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,0,3> E1 ## E2 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,1,0> E1 ## E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,1,1> E1 ## E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,1,2> E1 ## E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,1,3> E1 ## E2 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,2,0> E1 ## E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,2,1> E1 ## E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,2,2> E1 ## E2 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,2,3> E1 ## E2 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,3,0> E1 ## E2 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,3,1> E1 ## E2 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,3,2> E1 ## E2 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,3,3> E1 ## E2 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,0,0> E1 ## E3 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,0,1> E1 ## E3 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,0,2> E1 ## E3 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,0,3> E1 ## E3 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,1,0> E1 ## E3 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,1,1> E1 ## E3 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,1,2> E1 ## E3 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,1,3> E1 ## E3 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,2,0> E1 ## E3 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,2,1> E1 ## E3 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,2,2> E1 ## E3 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,2,3> E1 ## E3 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,3,0> E1 ## E3 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,3,1> E1 ## E3 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,3,2> E1 ## E3 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,3,3> E1 ## E3 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,0,0> E2 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,0,1> E2 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,0,2> E2 ## E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,0,3> E2 ## E0 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,1,0> E2 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,1,1> E2 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,1,2> E2 ## E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,1,3> E2 ## E0 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,2,0> E2 ## E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,2,1> E2 ## E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,2,2> E2 ## E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,2,3> E2 ## E0 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,3,0> E2 ## E0 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,3,1> E2 ## E0 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,3,2> E2 ## E0 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,3,3> E2 ## E0 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,0,0> E2 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,0,1> E2 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,0,2> E2 ## E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,0,3> E2 ## E1 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,1,0> E2 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,1,1> E2 ## E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,1,2> E2 ## E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,1,3> E2 ## E1 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,2,0> E2 ## E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,2,1> E2 ## E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,2,2> E2 ## E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,2,3> E2 ## E1 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,3,0> E2 ## E1 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,3,1> E2 ## E1 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,3,2> E2 ## E1 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,3,3> E2 ## E1 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,0,0> E2 ## E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,0,1> E2 ## E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,0,2> E2 ## E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,0,3> E2 ## E2 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,1,0> E2 ## E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,1,1> E2 ## E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,1,2> E2 ## E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,1,3> E2 ## E2 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,2,0> E2 ## E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,2,1> E2 ## E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,2,2> E2 ## E2 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,2,3> E2 ## E2 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,3,0> E2 ## E2 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,3,1> E2 ## E2 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,3,2> E2 ## E2 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,3,3> E2 ## E2 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,0,0> E2 ## E3 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,0,1> E2 ## E3 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,0,2> E2 ## E3 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,0,3> E2 ## E3 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,1,0> E2 ## E3 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,1,1> E2 ## E3 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,1,2> E2 ## E3 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,1,3> E2 ## E3 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,2,0> E2 ## E3 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,2,1> E2 ## E3 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,2,2> E2 ## E3 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,2,3> E2 ## E3 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,3,0> E2 ## E3 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,3,1> E2 ## E3 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,3,2> E2 ## E3 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,3,3> E2 ## E3 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,0,0> E3 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,0,1> E3 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,0,2> E3 ## E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,0,3> E3 ## E0 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,1,0> E3 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,1,1> E3 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,1,2> E3 ## E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,1,3> E3 ## E0 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,2,0> E3 ## E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,2,1> E3 ## E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,2,2> E3 ## E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,2,3> E3 ## E0 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,3,0> E3 ## E0 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,3,1> E3 ## E0 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,3,2> E3 ## E0 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,3,3> E3 ## E0 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,0,0> E3 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,0,1> E3 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,0,2> E3 ## E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,0,3> E3 ## E1 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,1,0> E3 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,1,1> E3 ## E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,1,2> E3 ## E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,1,3> E3 ## E1 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,2,0> E3 ## E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,2,1> E3 ## E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,2,2> E3 ## E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,2,3> E3 ## E1 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,3,0> E3 ## E1 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,3,1> E3 ## E1 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,3,2> E3 ## E1 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,3,3> E3 ## E1 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,0,0> E3 ## E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,0,1> E3 ## E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,0,2> E3 ## E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,0,3> E3 ## E2 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,1,0> E3 ## E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,1,1> E3 ## E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,1,2> E3 ## E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,1,3> E3 ## E2 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,2,0> E3 ## E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,2,1> E3 ## E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,2,2> E3 ## E2 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,2,3> E3 ## E2 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,3,0> E3 ## E2 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,3,1> E3 ## E2 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,3,2> E3 ## E2 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,3,3> E3 ## E2 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,0,0> E3 ## E3 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,0,1> E3 ## E3 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,0,2> E3 ## E3 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,0,3> E3 ## E3 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,1,0> E3 ## E3 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,1,1> E3 ## E3 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,1,2> E3 ## E3 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,1,3> E3 ## E3 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,2,0> E3 ## E3 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,2,1> E3 ## E3 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,2,2> E3 ## E3 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,2,3> E3 ## E3 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,3,0> E3 ## E3 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,3,1> E3 ## E3 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,3,2> E3 ## E3 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,3,3> E3 ## E3 ## E3 ## E3; }; diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/_swizzle_func.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/_swizzle_func.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d93c6afd5b79aeda66f5e96077503625519888fa --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/_swizzle_func.hpp @@ -0,0 +1,682 @@ +#pragma once + +#define GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, CONST, A, B) \ + vec<2, T, Q> A ## B() CONST \ + { \ + return vec<2, T, Q>(this->A, this->B); \ + } + +#define GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, CONST, A, B, C) \ + vec<3, T, Q> A ## B ## C() CONST \ + { \ + return vec<3, T, Q>(this->A, this->B, this->C); \ + } + +#define GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, CONST, A, B, C, D) \ + vec<4, T, Q> A ## B ## C ## D() CONST \ + { \ + return vec<4, T, Q>(this->A, this->B, this->C, this->D); \ + } + +#define GLM_SWIZZLE_GEN_VEC2_ENTRY_DEF(T, P, L, CONST, A, B) \ + template \ + vec vec::A ## B() CONST \ + { \ + return vec<2, T, Q>(this->A, this->B); \ + } + +#define GLM_SWIZZLE_GEN_VEC3_ENTRY_DEF(T, P, L, CONST, A, B, C) \ + template \ + vec<3, T, Q> vec::A ## B ## C() CONST \ + { \ + return vec<3, T, Q>(this->A, this->B, this->C); \ + } + +#define GLM_SWIZZLE_GEN_VEC4_ENTRY_DEF(T, P, L, CONST, A, B, C, D) \ + template \ + vec<4, T, Q> vec::A ## B ## C ## D() CONST \ + { \ + return vec<4, T, Q>(this->A, this->B, this->C, this->D); \ + } + +#define GLM_MUTABLE + +#define GLM_SWIZZLE_GEN_REF2_FROM_VEC2_SWIZZLE(T, P, A, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, 2, GLM_MUTABLE, A, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, 2, GLM_MUTABLE, B, A) + +#define GLM_SWIZZLE_GEN_REF_FROM_VEC2(T, P) \ + GLM_SWIZZLE_GEN_REF2_FROM_VEC2_SWIZZLE(T, P, x, y) \ + GLM_SWIZZLE_GEN_REF2_FROM_VEC2_SWIZZLE(T, P, r, g) \ + GLM_SWIZZLE_GEN_REF2_FROM_VEC2_SWIZZLE(T, P, s, t) + +#define GLM_SWIZZLE_GEN_REF2_FROM_VEC3_SWIZZLE(T, P, A, B, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, A, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, A, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, B, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, B, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, C, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, C, B) + +#define GLM_SWIZZLE_GEN_REF3_FROM_VEC3_SWIZZLE(T, P, A, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, GLM_MUTABLE, A, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, GLM_MUTABLE, A, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, GLM_MUTABLE, B, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, GLM_MUTABLE, B, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, GLM_MUTABLE, C, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, GLM_MUTABLE, C, B, A) + +#define GLM_SWIZZLE_GEN_REF_FROM_VEC3_COMP(T, P, A, B, C) \ + GLM_SWIZZLE_GEN_REF3_FROM_VEC3_SWIZZLE(T, P, A, B, C) \ + GLM_SWIZZLE_GEN_REF2_FROM_VEC3_SWIZZLE(T, P, A, B, C) + +#define GLM_SWIZZLE_GEN_REF_FROM_VEC3(T, P) \ + GLM_SWIZZLE_GEN_REF_FROM_VEC3_COMP(T, P, x, y, z) \ + GLM_SWIZZLE_GEN_REF_FROM_VEC3_COMP(T, P, r, g, b) \ + GLM_SWIZZLE_GEN_REF_FROM_VEC3_COMP(T, P, s, t, p) + +#define GLM_SWIZZLE_GEN_REF2_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, A, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, A, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, A, D) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, B, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, B, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, B, D) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, C, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, C, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, C, D) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, D, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, D, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, D, C) + +#define GLM_SWIZZLE_GEN_REF3_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , A, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , A, B, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , A, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , A, C, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , A, D, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , A, D, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , B, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , B, A, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , B, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , B, C, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , B, D, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , B, D, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , C, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , C, A, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , C, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , C, B, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , C, D, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , C, D, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , D, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , D, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , D, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , D, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , D, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , D, C, B) + +#define GLM_SWIZZLE_GEN_REF4_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , A, C, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , A, C, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , A, D, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , A, D, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , A, B, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , B, C, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , B, C, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , B, D, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , B, D, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , B, A, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , B, A, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , C, B, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , C, B, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , C, D, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , C, D, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , C, A, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , C, A, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , D, C, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , D, C, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , D, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , D, A, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , D, B, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , D, B, C, A) + +#define GLM_SWIZZLE_GEN_REF_FROM_VEC4_COMP(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_REF2_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_REF3_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_REF4_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) + +#define GLM_SWIZZLE_GEN_REF_FROM_VEC4(T, P) \ + GLM_SWIZZLE_GEN_REF_FROM_VEC4_COMP(T, P, x, y, z, w) \ + GLM_SWIZZLE_GEN_REF_FROM_VEC4_COMP(T, P, r, g, b, a) \ + GLM_SWIZZLE_GEN_REF_FROM_VEC4_COMP(T, P, s, t, p, q) + +#define GLM_SWIZZLE_GEN_VEC2_FROM_VEC2_SWIZZLE(T, P, A, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, B) + +#define GLM_SWIZZLE_GEN_VEC3_FROM_VEC2_SWIZZLE(T, P, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, B) + +#define GLM_SWIZZLE_GEN_VEC4_FROM_VEC2_SWIZZLE(T, P, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, B) + +#define GLM_SWIZZLE_GEN_VEC_FROM_VEC2_COMP(T, P, A, B) \ + GLM_SWIZZLE_GEN_VEC2_FROM_VEC2_SWIZZLE(T, P, A, B) \ + GLM_SWIZZLE_GEN_VEC3_FROM_VEC2_SWIZZLE(T, P, A, B) \ + GLM_SWIZZLE_GEN_VEC4_FROM_VEC2_SWIZZLE(T, P, A, B) + +#define GLM_SWIZZLE_GEN_VEC_FROM_VEC2(T, P) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC2_COMP(T, P, x, y) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC2_COMP(T, P, r, g) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC2_COMP(T, P, s, t) + +#define GLM_SWIZZLE_GEN_VEC2_FROM_VEC3_SWIZZLE(T, P, A, B, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, C, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, C, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, C, C) + +#define GLM_SWIZZLE_GEN_VEC3_FROM_VEC3_SWIZZLE(T, P, A, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, C, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, C, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, B, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, C, C) + +#define GLM_SWIZZLE_GEN_VEC4_FROM_VEC3_SWIZZLE(T, P, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, C, C) + +#define GLM_SWIZZLE_GEN_VEC_FROM_VEC3_COMP(T, P, A, B, C) \ + GLM_SWIZZLE_GEN_VEC2_FROM_VEC3_SWIZZLE(T, P, A, B, C) \ + GLM_SWIZZLE_GEN_VEC3_FROM_VEC3_SWIZZLE(T, P, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_FROM_VEC3_SWIZZLE(T, P, A, B, C) + +#define GLM_SWIZZLE_GEN_VEC_FROM_VEC3(T, P) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC3_COMP(T, P, x, y, z) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC3_COMP(T, P, r, g, b) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC3_COMP(T, P, s, t, p) + +#define GLM_SWIZZLE_GEN_VEC2_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, D) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, D) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, C, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, C, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, C, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, C, D) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, D, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, D, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, D, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, D, D) + +#define GLM_SWIZZLE_GEN_VEC3_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, C, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, C, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, D, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, D, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, D, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, D, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, C, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, C, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, D, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, D, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, D, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, D, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, A, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, B, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, B, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, C, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, C, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, D, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, D, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, D, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, D, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, A, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, B, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, B, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, C, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, C, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, D, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, D, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, D, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, D, D) + +#define GLM_SWIZZLE_GEN_VEC4_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, D, D) + +#define GLM_SWIZZLE_GEN_VEC_FROM_VEC4_COMP(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC2_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC3_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC4_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) + +#define GLM_SWIZZLE_GEN_VEC_FROM_VEC4(T, P) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC4_COMP(T, P, x, y, z, w) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC4_COMP(T, P, r, g, b, a) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC4_COMP(T, P, s, t, p, q) + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/_vectorize.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/_vectorize.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1fcaec3152846e6796a48a35b2cf8ad810415820 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/_vectorize.hpp @@ -0,0 +1,162 @@ +#pragma once + +namespace glm{ +namespace detail +{ + template class vec, length_t L, typename R, typename T, qualifier Q> + struct functor1{}; + + template class vec, typename R, typename T, qualifier Q> + struct functor1 + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<1, R, Q> call(R (*Func) (T x), vec<1, T, Q> const& v) + { + return vec<1, R, Q>(Func(v.x)); + } + }; + + template class vec, typename R, typename T, qualifier Q> + struct functor1 + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<2, R, Q> call(R (*Func) (T x), vec<2, T, Q> const& v) + { + return vec<2, R, Q>(Func(v.x), Func(v.y)); + } + }; + + template class vec, typename R, typename T, qualifier Q> + struct functor1 + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<3, R, Q> call(R (*Func) (T x), vec<3, T, Q> const& v) + { + return vec<3, R, Q>(Func(v.x), Func(v.y), Func(v.z)); + } + }; + + template class vec, typename R, typename T, qualifier Q> + struct functor1 + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, R, Q> call(R (*Func) (T x), vec<4, T, Q> const& v) + { + return vec<4, R, Q>(Func(v.x), Func(v.y), Func(v.z), Func(v.w)); + } + }; + + template class vec, length_t L, typename T, qualifier Q> + struct functor2{}; + + template class vec, typename T, qualifier Q> + struct functor2 + { + GLM_FUNC_QUALIFIER static vec<1, T, Q> call(T (*Func) (T x, T y), vec<1, T, Q> const& a, vec<1, T, Q> const& b) + { + return vec<1, T, Q>(Func(a.x, b.x)); + } + }; + + template class vec, typename T, qualifier Q> + struct functor2 + { + GLM_FUNC_QUALIFIER static vec<2, T, Q> call(T (*Func) (T x, T y), vec<2, T, Q> const& a, vec<2, T, Q> const& b) + { + return vec<2, T, Q>(Func(a.x, b.x), Func(a.y, b.y)); + } + }; + + template class vec, typename T, qualifier Q> + struct functor2 + { + GLM_FUNC_QUALIFIER static vec<3, T, Q> call(T (*Func) (T x, T y), vec<3, T, Q> const& a, vec<3, T, Q> const& b) + { + return vec<3, T, Q>(Func(a.x, b.x), Func(a.y, b.y), Func(a.z, b.z)); + } + }; + + template class vec, typename T, qualifier Q> + struct functor2 + { + GLM_FUNC_QUALIFIER static vec<4, T, Q> call(T (*Func) (T x, T y), vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + return vec<4, T, Q>(Func(a.x, b.x), Func(a.y, b.y), Func(a.z, b.z), Func(a.w, b.w)); + } + }; + + template class vec, length_t L, typename T, qualifier Q> + struct functor2_vec_sca{}; + + template class vec, typename T, qualifier Q> + struct functor2_vec_sca + { + GLM_FUNC_QUALIFIER static vec<1, T, Q> call(T (*Func) (T x, T y), vec<1, T, Q> const& a, T b) + { + return vec<1, T, Q>(Func(a.x, b)); + } + }; + + template class vec, typename T, qualifier Q> + struct functor2_vec_sca + { + GLM_FUNC_QUALIFIER static vec<2, T, Q> call(T (*Func) (T x, T y), vec<2, T, Q> const& a, T b) + { + return vec<2, T, Q>(Func(a.x, b), Func(a.y, b)); + } + }; + + template class vec, typename T, qualifier Q> + struct functor2_vec_sca + { + GLM_FUNC_QUALIFIER static vec<3, T, Q> call(T (*Func) (T x, T y), vec<3, T, Q> const& a, T b) + { + return vec<3, T, Q>(Func(a.x, b), Func(a.y, b), Func(a.z, b)); + } + }; + + template class vec, typename T, qualifier Q> + struct functor2_vec_sca + { + GLM_FUNC_QUALIFIER static vec<4, T, Q> call(T (*Func) (T x, T y), vec<4, T, Q> const& a, T b) + { + return vec<4, T, Q>(Func(a.x, b), Func(a.y, b), Func(a.z, b), Func(a.w, b)); + } + }; + + template + struct functor2_vec_int {}; + + template + struct functor2_vec_int<1, T, Q> + { + GLM_FUNC_QUALIFIER static vec<1, int, Q> call(int (*Func) (T x, int y), vec<1, T, Q> const& a, vec<1, int, Q> const& b) + { + return vec<1, int, Q>(Func(a.x, b.x)); + } + }; + + template + struct functor2_vec_int<2, T, Q> + { + GLM_FUNC_QUALIFIER static vec<2, int, Q> call(int (*Func) (T x, int y), vec<2, T, Q> const& a, vec<2, int, Q> const& b) + { + return vec<2, int, Q>(Func(a.x, b.x), Func(a.y, b.y)); + } + }; + + template + struct functor2_vec_int<3, T, Q> + { + GLM_FUNC_QUALIFIER static vec<3, int, Q> call(int (*Func) (T x, int y), vec<3, T, Q> const& a, vec<3, int, Q> const& b) + { + return vec<3, int, Q>(Func(a.x, b.x), Func(a.y, b.y), Func(a.z, b.z)); + } + }; + + template + struct functor2_vec_int<4, T, Q> + { + GLM_FUNC_QUALIFIER static vec<4, int, Q> call(int (*Func) (T x, int y), vec<4, T, Q> const& a, vec<4, int, Q> const& b) + { + return vec<4, int, Q>(Func(a.x, b.x), Func(a.y, b.y), Func(a.z, b.z), Func(a.w, b.w)); + } + }; +}//namespace detail +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/compute_common.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/compute_common.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7267a497c88b673605e3cae11e589e0659e5f996 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/compute_common.hpp @@ -0,0 +1,50 @@ +#pragma once + +#include "setup.hpp" +#include + +namespace glm{ +namespace detail +{ + template + struct compute_abs + {}; + + template + struct compute_abs + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static genFIType call(genFIType x) + { + GLM_STATIC_ASSERT( + std::numeric_limits::is_iec559 || std::numeric_limits::is_signed, + "'abs' only accept floating-point and integer scalar or vector inputs"); + + return x >= genFIType(0) ? x : -x; + // TODO, perf comp with: *(((int *) &x) + 1) &= 0x7fffffff; + } + }; + +#if (GLM_COMPILER & GLM_COMPILER_CUDA) || (GLM_COMPILER & GLM_COMPILER_HIP) + template<> + struct compute_abs + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static float call(float x) + { + return fabsf(x); + } + }; +#endif + + template + struct compute_abs + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static genFIType call(genFIType x) + { + GLM_STATIC_ASSERT( + (!std::numeric_limits::is_signed && std::numeric_limits::is_integer), + "'abs' only accept floating-point and integer scalar or vector inputs"); + return x; + } + }; +}//namespace detail +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/compute_vector_relational.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/compute_vector_relational.hpp new file mode 100644 index 0000000000000000000000000000000000000000..167b6345dd398e3822c772a113dab5864470f64e --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/compute_vector_relational.hpp @@ -0,0 +1,30 @@ +#pragma once + +//#include "compute_common.hpp" +#include "setup.hpp" +#include + +namespace glm{ +namespace detail +{ + template + struct compute_equal + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static bool call(T a, T b) + { + return a == b; + } + }; +/* + template + struct compute_equal + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static bool call(T a, T b) + { + return detail::compute_abs::is_signed>::call(b - a) <= static_cast(0); + //return std::memcmp(&a, &b, sizeof(T)) == 0; + } + }; +*/ +}//namespace detail +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_common.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_common.inl new file mode 100644 index 0000000000000000000000000000000000000000..86560be95601053e36972aacb44351332326b1aa --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_common.inl @@ -0,0 +1,792 @@ +/// @ref core +/// @file glm/detail/func_common.inl + +#include "../vector_relational.hpp" +#include "compute_common.hpp" +#include "type_vec1.hpp" +#include "type_vec2.hpp" +#include "type_vec3.hpp" +#include "type_vec4.hpp" +#include "_vectorize.hpp" +#include + +namespace glm +{ + // min + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType min(genType x, genType y) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer, "'min' only accept floating-point or integer inputs"); + return (y < x) ? y : x; + } + + // max + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType max(genType x, genType y) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer, "'max' only accept floating-point or integer inputs"); + + return (x < y) ? y : x; + } + + // abs + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR int abs(int x) + { + int const y = x >> (sizeof(int) * 8 - 1); + return (x ^ y) - y; + } + + // round +# if GLM_HAS_CXX11_STL + using ::std::round; +# else + template + GLM_FUNC_QUALIFIER genType round(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'round' only accept floating-point inputs"); + + return x < static_cast(0) ? static_cast(int(x - static_cast(0.5))) : static_cast(int(x + static_cast(0.5))); + } +# endif + + // trunc +# if GLM_HAS_CXX11_STL + using ::std::trunc; +# else + template + GLM_FUNC_QUALIFIER genType trunc(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'trunc' only accept floating-point inputs"); + + return x < static_cast(0) ? -std::floor(-x) : std::floor(x); + } +# endif + +}//namespace glm + +namespace glm{ +namespace detail +{ + template + struct compute_abs_vector + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec call(vec const& x) + { + return detail::functor1::call(abs, x); + } + }; + + template + struct compute_mix_vector + { + GLM_FUNC_QUALIFIER static vec call(vec const& x, vec const& y, vec const& a) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'mix' only accept floating-point inputs for the interpolator a"); + + return vec(vec(x) * (static_cast(1) - a) + vec(y) * a); + } + }; + + template + struct compute_mix_vector + { + GLM_FUNC_QUALIFIER static vec call(vec const& x, vec const& y, vec const& a) + { + vec Result; + for(length_t i = 0; i < x.length(); ++i) + Result[i] = a[i] ? y[i] : x[i]; + return Result; + } + }; + + template + struct compute_mix_scalar + { + GLM_FUNC_QUALIFIER static vec call(vec const& x, vec const& y, U const& a) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'mix' only accept floating-point inputs for the interpolator a"); + + return vec(vec(x) * (static_cast(1) - a) + vec(y) * a); + } + }; + + template + struct compute_mix_scalar + { + GLM_FUNC_QUALIFIER static vec call(vec const& x, vec const& y, bool const& a) + { + return a ? y : x; + } + }; + + template + struct compute_mix + { + GLM_FUNC_QUALIFIER static T call(T const& x, T const& y, U const& a) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'mix' only accept floating-point inputs for the interpolator a"); + + return static_cast(static_cast(x) * (static_cast(1) - a) + static_cast(y) * a); + } + }; + + template + struct compute_mix + { + GLM_FUNC_QUALIFIER static T call(T const& x, T const& y, bool const& a) + { + return a ? y : x; + } + }; + + template + struct compute_sign + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + return vec(glm::lessThan(vec(0), x)) - vec(glm::lessThan(x, vec(0))); + } + }; + +# if GLM_ARCH == GLM_ARCH_X86 + template + struct compute_sign + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + T const Shift(static_cast(sizeof(T) * 8 - 1)); + vec const y(vec::type, Q>(-x) >> typename detail::make_unsigned::type(Shift)); + + return (x >> Shift) | y; + } + }; +# endif + + template + struct compute_floor + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + return detail::functor1::call(std::floor, x); + } + }; + + template + struct compute_ceil + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + return detail::functor1::call(std::ceil, x); + } + }; + + template + struct compute_fract + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + return x - floor(x); + } + }; + + template + struct compute_trunc + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + return detail::functor1::call(trunc, x); + } + }; + + template + struct compute_round + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + return detail::functor1::call(round, x); + } + }; + + template + struct compute_mod + { + GLM_FUNC_QUALIFIER static vec call(vec const& a, vec const& b) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'mod' only accept floating-point inputs. Include for integer inputs."); + return a - b * floor(a / b); + } + }; + + template + struct compute_min_vector + { + GLM_FUNC_QUALIFIER static vec call(vec const& x, vec const& y) + { + return detail::functor2::call(min, x, y); + } + }; + + template + struct compute_max_vector + { + GLM_FUNC_QUALIFIER static vec call(vec const& x, vec const& y) + { + return detail::functor2::call(max, x, y); + } + }; + + template + struct compute_clamp_vector + { + GLM_FUNC_QUALIFIER static vec call(vec const& x, vec const& minVal, vec const& maxVal) + { + return min(max(x, minVal), maxVal); + } + }; + + template + struct compute_step_vector + { + GLM_FUNC_QUALIFIER static vec call(vec const& edge, vec const& x) + { + return mix(vec(1), vec(0), glm::lessThan(x, edge)); + } + }; + + template + struct compute_smoothstep_vector + { + GLM_FUNC_QUALIFIER static vec call(vec const& edge0, vec const& edge1, vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'smoothstep' only accept floating-point inputs"); + vec const tmp(clamp((x - edge0) / (edge1 - edge0), static_cast(0), static_cast(1))); + return tmp * tmp * (static_cast(3) - static_cast(2) * tmp); + } + }; +}//namespace detail + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genFIType abs(genFIType x) + { + return detail::compute_abs::is_signed>::call(x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec abs(vec const& x) + { + return detail::compute_abs_vector::value>::call(x); + } + + // sign + // fast and works for any type + template + GLM_FUNC_QUALIFIER genFIType sign(genFIType x) + { + GLM_STATIC_ASSERT( + std::numeric_limits::is_iec559 || (std::numeric_limits::is_signed && std::numeric_limits::is_integer), + "'sign' only accept signed inputs"); + + return detail::compute_sign<1, genFIType, defaultp, + std::numeric_limits::is_iec559, detail::is_aligned::value>::call(vec<1, genFIType>(x)).x; + } + + template + GLM_FUNC_QUALIFIER vec sign(vec const& x) + { + GLM_STATIC_ASSERT( + std::numeric_limits::is_iec559 || (std::numeric_limits::is_signed && std::numeric_limits::is_integer), + "'sign' only accept signed inputs"); + + return detail::compute_sign::is_iec559, detail::is_aligned::value>::call(x); + } + + // floor + using ::std::floor; + template + GLM_FUNC_QUALIFIER vec floor(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'floor' only accept floating-point inputs."); + return detail::compute_floor::value>::call(x); + } + + template + GLM_FUNC_QUALIFIER vec trunc(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'trunc' only accept floating-point inputs"); + return detail::compute_trunc::value>::call(x); + } + + template + GLM_FUNC_QUALIFIER vec round(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'round' only accept floating-point inputs"); + return detail::compute_round::value>::call(x); + } + +/* + // roundEven + template + GLM_FUNC_QUALIFIER genType roundEven(genType const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'roundEven' only accept floating-point inputs"); + + return genType(int(x + genType(int(x) % 2))); + } +*/ + + // roundEven + template + GLM_FUNC_QUALIFIER genType roundEven(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'roundEven' only accept floating-point inputs"); + + int Integer = static_cast(x); + genType IntegerPart = static_cast(Integer); + genType FractionalPart = fract(x); + + if(FractionalPart > static_cast(0.5) || FractionalPart < static_cast(0.5)) + { + return round(x); + } + else if((Integer % 2) == 0) + { + return IntegerPart; + } + else if(x <= static_cast(0)) // Work around... + { + return IntegerPart - static_cast(1); + } + else + { + return IntegerPart + static_cast(1); + } + //else // Bug on MinGW 4.5.2 + //{ + // return mix(IntegerPart + genType(-1), IntegerPart + genType(1), x <= genType(0)); + //} + } + + template + GLM_FUNC_QUALIFIER vec roundEven(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'roundEven' only accept floating-point inputs"); + return detail::functor1::call(roundEven, x); + } + + // ceil + using ::std::ceil; + template + GLM_FUNC_QUALIFIER vec ceil(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'ceil' only accept floating-point inputs"); + return detail::compute_ceil::value>::call(x); + } + + // fract + template + GLM_FUNC_QUALIFIER genType fract(genType x) + { + return fract(vec<1, genType>(x)).x; + } + + template + GLM_FUNC_QUALIFIER vec fract(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fract' only accept floating-point inputs"); + return detail::compute_fract::value>::call(x); + } + + // mod + template + GLM_FUNC_QUALIFIER genType mod(genType x, genType y) + { +# if (GLM_COMPILER & GLM_COMPILER_CUDA) || (GLM_COMPILER & GLM_COMPILER_HIP) + // Another Cuda compiler bug https://github.com/g-truc/glm/issues/530 + vec<1, genType, defaultp> Result(mod(vec<1, genType, defaultp>(x), y)); + return Result.x; +# else + return mod(vec<1, genType, defaultp>(x), y).x; +# endif + } + + template + GLM_FUNC_QUALIFIER vec mod(vec const& x, T y) + { + return detail::compute_mod::value>::call(x, vec(y)); + } + + template + GLM_FUNC_QUALIFIER vec mod(vec const& x, vec const& y) + { + return detail::compute_mod::value>::call(x, y); + } + + // modf + template + GLM_FUNC_QUALIFIER genType modf(genType x, genType & i) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'modf' only accept floating-point inputs"); + return std::modf(x, &i); + } + + template + GLM_FUNC_QUALIFIER vec<1, T, Q> modf(vec<1, T, Q> const& x, vec<1, T, Q> & i) + { + return vec<1, T, Q>( + modf(x.x, i.x)); + } + + template + GLM_FUNC_QUALIFIER vec<2, T, Q> modf(vec<2, T, Q> const& x, vec<2, T, Q> & i) + { + return vec<2, T, Q>( + modf(x.x, i.x), + modf(x.y, i.y)); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> modf(vec<3, T, Q> const& x, vec<3, T, Q> & i) + { + return vec<3, T, Q>( + modf(x.x, i.x), + modf(x.y, i.y), + modf(x.z, i.z)); + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> modf(vec<4, T, Q> const& x, vec<4, T, Q> & i) + { + return vec<4, T, Q>( + modf(x.x, i.x), + modf(x.y, i.y), + modf(x.z, i.z), + modf(x.w, i.w)); + } + + //// Only valid if (INT_MIN <= x-y <= INT_MAX) + //// min(x,y) + //r = y + ((x - y) & ((x - y) >> (sizeof(int) * + //CHAR_BIT - 1))); + //// max(x,y) + //r = x - ((x - y) & ((x - y) >> (sizeof(int) * + //CHAR_BIT - 1))); + + // min + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec min(vec const& a, T b) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer, "'min' only accept floating-point or integer inputs"); + return detail::compute_min_vector::value>::call(a, vec(b)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec min(vec const& a, vec const& b) + { + return detail::compute_min_vector::value>::call(a, b); + } + + // max + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec max(vec const& a, T b) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer, "'max' only accept floating-point or integer inputs"); + return detail::compute_max_vector::value>::call(a, vec(b)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec max(vec const& a, vec const& b) + { + return detail::compute_max_vector::value>::call(a, b); + } + + // clamp + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType clamp(genType x, genType minVal, genType maxVal) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer, "'clamp' only accept floating-point or integer inputs"); + return min(max(x, minVal), maxVal); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec clamp(vec const& x, T minVal, T maxVal) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer, "'clamp' only accept floating-point or integer inputs"); + return detail::compute_clamp_vector::value>::call(x, vec(minVal), vec(maxVal)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec clamp(vec const& x, vec const& minVal, vec const& maxVal) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer, "'clamp' only accept floating-point or integer inputs"); + return detail::compute_clamp_vector::value>::call(x, minVal, maxVal); + } + + template + GLM_FUNC_QUALIFIER genTypeT mix(genTypeT x, genTypeT y, genTypeU a) + { + return detail::compute_mix::call(x, y, a); + } + + template + GLM_FUNC_QUALIFIER vec mix(vec const& x, vec const& y, U a) + { + return detail::compute_mix_scalar::value>::call(x, y, a); + } + + template + GLM_FUNC_QUALIFIER vec mix(vec const& x, vec const& y, vec const& a) + { + return detail::compute_mix_vector::value>::call(x, y, a); + } + + // step + template + GLM_FUNC_QUALIFIER genType step(genType edge, genType x) + { + return mix(static_cast(1), static_cast(0), x < edge); + } + + template + GLM_FUNC_QUALIFIER vec step(T edge, vec const& x) + { + return detail::compute_step_vector::value>::call(vec(edge), x); + } + + template + GLM_FUNC_QUALIFIER vec step(vec const& edge, vec const& x) + { + return detail::compute_step_vector::value>::call(edge, x); + } + + // smoothstep + template + GLM_FUNC_QUALIFIER genType smoothstep(genType edge0, genType edge1, genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'smoothstep' only accept floating-point inputs"); + + genType const tmp(clamp((x - edge0) / (edge1 - edge0), genType(0), genType(1))); + return tmp * tmp * (genType(3) - genType(2) * tmp); + } + + template + GLM_FUNC_QUALIFIER vec smoothstep(T edge0, T edge1, vec const& x) + { + return detail::compute_smoothstep_vector::value>::call(vec(edge0), vec(edge1), x); + } + + template + GLM_FUNC_QUALIFIER vec smoothstep(vec const& edge0, vec const& edge1, vec const& x) + { + return detail::compute_smoothstep_vector::value>::call(edge0, edge1, x); + } + +# if GLM_HAS_CXX11_STL + using std::isnan; +# else + template + GLM_FUNC_QUALIFIER bool isnan(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isnan' only accept floating-point inputs"); + +# if GLM_HAS_CXX11_STL + return std::isnan(x); +# elif GLM_COMPILER & GLM_COMPILER_VC + return _isnan(x) != 0; +# elif GLM_COMPILER & GLM_COMPILER_INTEL +# if GLM_PLATFORM & GLM_PLATFORM_WINDOWS + return _isnan(x) != 0; +# else + return ::isnan(x) != 0; +# endif +# elif (GLM_COMPILER & (GLM_COMPILER_GCC | GLM_COMPILER_CLANG)) && (GLM_PLATFORM & GLM_PLATFORM_ANDROID) && __cplusplus < 201103L + return _isnan(x) != 0; +# elif (GLM_COMPILER & GLM_COMPILER_CUDA) || (GLM_COMPILER & GLM_COMPILER_HIP) + return ::isnan(x) != 0; +# else + return std::isnan(x); +# endif + } +# endif + + template + GLM_FUNC_QUALIFIER vec isnan(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isnan' only accept floating-point inputs"); + + vec Result; + for (length_t l = 0; l < v.length(); ++l) + Result[l] = glm::isnan(v[l]); + return Result; + } + +# if GLM_HAS_CXX11_STL + using std::isinf; +# else + template + GLM_FUNC_QUALIFIER bool isinf(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isinf' only accept floating-point inputs"); + +# if GLM_HAS_CXX11_STL + return std::isinf(x); +# elif GLM_COMPILER & (GLM_COMPILER_INTEL | GLM_COMPILER_VC) +# if(GLM_PLATFORM & GLM_PLATFORM_WINDOWS) + return _fpclass(x) == _FPCLASS_NINF || _fpclass(x) == _FPCLASS_PINF; +# else + return ::isinf(x); +# endif +# elif GLM_COMPILER & (GLM_COMPILER_GCC | GLM_COMPILER_CLANG) +# if(GLM_PLATFORM & GLM_PLATFORM_ANDROID && __cplusplus < 201103L) + return _isinf(x) != 0; +# else + return std::isinf(x); +# endif +# elif (GLM_COMPILER & GLM_COMPILER_CUDA) || (GLM_COMPILER & GLM_COMPILER_HIP) + // http://developer.download.nvidia.com/compute/cuda/4_2/rel/toolkit/docs/online/group__CUDA__MATH__DOUBLE_g13431dd2b40b51f9139cbb7f50c18fab.html#g13431dd2b40b51f9139cbb7f50c18fab + return ::isinf(double(x)) != 0; +# else + return std::isinf(x); +# endif + } +# endif + + template + GLM_FUNC_QUALIFIER vec isinf(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isinf' only accept floating-point inputs"); + + vec Result; + for (length_t l = 0; l < v.length(); ++l) + Result[l] = glm::isinf(v[l]); + return Result; + } + + GLM_FUNC_QUALIFIER int floatBitsToInt(float const& v) + { + union + { + float in; + int out; + } u; + + u.in = v; + + return u.out; + } + + template + GLM_FUNC_QUALIFIER vec floatBitsToInt(vec const& v) + { + return reinterpret_cast&>(const_cast&>(v)); + } + + GLM_FUNC_QUALIFIER uint floatBitsToUint(float const& v) + { + union + { + float in; + uint out; + } u; + + u.in = v; + + return u.out; + } + + template + GLM_FUNC_QUALIFIER vec floatBitsToUint(vec const& v) + { + return reinterpret_cast&>(const_cast&>(v)); + } + + GLM_FUNC_QUALIFIER float intBitsToFloat(int const& v) + { + union + { + int in; + float out; + } u; + + u.in = v; + + return u.out; + } + + template + GLM_FUNC_QUALIFIER vec intBitsToFloat(vec const& v) + { + return reinterpret_cast&>(const_cast&>(v)); + } + + GLM_FUNC_QUALIFIER float uintBitsToFloat(uint const& v) + { + union + { + uint in; + float out; + } u; + + u.in = v; + + return u.out; + } + + template + GLM_FUNC_QUALIFIER vec uintBitsToFloat(vec const& v) + { + return reinterpret_cast&>(const_cast&>(v)); + } + +# if GLM_HAS_CXX11_STL + using std::fma; +# else + template + GLM_FUNC_QUALIFIER genType fma(genType const& a, genType const& b, genType const& c) + { + return a * b + c; + } +# endif + + template + GLM_FUNC_QUALIFIER genType frexp(genType x, int& exp) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'frexp' only accept floating-point inputs"); + + return std::frexp(x, &exp); + } + + template + GLM_FUNC_QUALIFIER vec frexp(vec const& v, vec& exp) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'frexp' only accept floating-point inputs"); + + vec Result; + for (length_t l = 0; l < v.length(); ++l) + Result[l] = std::frexp(v[l], &exp[l]); + return Result; + } + + template + GLM_FUNC_QUALIFIER genType ldexp(genType const& x, int const& exp) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'ldexp' only accept floating-point inputs"); + + return std::ldexp(x, exp); + } + + template + GLM_FUNC_QUALIFIER vec ldexp(vec const& v, vec const& exp) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'ldexp' only accept floating-point inputs"); + + vec Result; + for (length_t l = 0; l < v.length(); ++l) + Result[l] = std::ldexp(v[l], exp[l]); + return Result; + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "func_common_simd.inl" +#endif diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_common_simd.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_common_simd.inl new file mode 100644 index 0000000000000000000000000000000000000000..ce0032d33fefbf095f9d5eb38ba56c88d11dc3a7 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_common_simd.inl @@ -0,0 +1,231 @@ +/// @ref core +/// @file glm/detail/func_common_simd.inl + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +#include "../simd/common.h" + +#include + +namespace glm{ +namespace detail +{ + template + struct compute_abs_vector<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v) + { + vec<4, float, Q> result; + result.data = glm_vec4_abs(v.data); + return result; + } + }; + + template + struct compute_abs_vector<4, int, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, int, Q> call(vec<4, int, Q> const& v) + { + vec<4, int, Q> result; + result.data = glm_ivec4_abs(v.data); + return result; + } + }; + + template + struct compute_floor<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v) + { + vec<4, float, Q> result; + result.data = glm_vec4_floor(v.data); + return result; + } + }; + + template + struct compute_ceil<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v) + { + vec<4, float, Q> result; + result.data = glm_vec4_ceil(v.data); + return result; + } + }; + + template + struct compute_fract<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v) + { + vec<4, float, Q> result; + result.data = glm_vec4_fract(v.data); + return result; + } + }; + + template + struct compute_round<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v) + { + vec<4, float, Q> result; + result.data = glm_vec4_round(v.data); + return result; + } + }; + + template + struct compute_mod<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& x, vec<4, float, Q> const& y) + { + vec<4, float, Q> result; + result.data = glm_vec4_mod(x.data, y.data); + return result; + } + }; + + template + struct compute_min_vector<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v1, vec<4, float, Q> const& v2) + { + vec<4, float, Q> result; + result.data = _mm_min_ps(v1.data, v2.data); + return result; + } + }; + + template + struct compute_min_vector<4, int, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, int, Q> call(vec<4, int, Q> const& v1, vec<4, int, Q> const& v2) + { + vec<4, int, Q> result; + result.data = _mm_min_epi32(v1.data, v2.data); + return result; + } + }; + + template + struct compute_min_vector<4, uint, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, uint, Q> call(vec<4, uint, Q> const& v1, vec<4, uint, Q> const& v2) + { + vec<4, uint, Q> result; + result.data = _mm_min_epu32(v1.data, v2.data); + return result; + } + }; + + template + struct compute_max_vector<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v1, vec<4, float, Q> const& v2) + { + vec<4, float, Q> result; + result.data = _mm_max_ps(v1.data, v2.data); + return result; + } + }; + + template + struct compute_max_vector<4, int, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, int, Q> call(vec<4, int, Q> const& v1, vec<4, int, Q> const& v2) + { + vec<4, int, Q> result; + result.data = _mm_max_epi32(v1.data, v2.data); + return result; + } + }; + + template + struct compute_max_vector<4, uint, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, uint, Q> call(vec<4, uint, Q> const& v1, vec<4, uint, Q> const& v2) + { + vec<4, uint, Q> result; + result.data = _mm_max_epu32(v1.data, v2.data); + return result; + } + }; + + template + struct compute_clamp_vector<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& x, vec<4, float, Q> const& minVal, vec<4, float, Q> const& maxVal) + { + vec<4, float, Q> result; + result.data = _mm_min_ps(_mm_max_ps(x.data, minVal.data), maxVal.data); + return result; + } + }; + + template + struct compute_clamp_vector<4, int, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, int, Q> call(vec<4, int, Q> const& x, vec<4, int, Q> const& minVal, vec<4, int, Q> const& maxVal) + { + vec<4, int, Q> result; + result.data = _mm_min_epi32(_mm_max_epi32(x.data, minVal.data), maxVal.data); + return result; + } + }; + + template + struct compute_clamp_vector<4, uint, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, uint, Q> call(vec<4, uint, Q> const& x, vec<4, uint, Q> const& minVal, vec<4, uint, Q> const& maxVal) + { + vec<4, uint, Q> result; + result.data = _mm_min_epu32(_mm_max_epu32(x.data, minVal.data), maxVal.data); + return result; + } + }; + + template + struct compute_mix_vector<4, float, bool, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& x, vec<4, float, Q> const& y, vec<4, bool, Q> const& a) + { + __m128i const Load = _mm_set_epi32(-static_cast(a.w), -static_cast(a.z), -static_cast(a.y), -static_cast(a.x)); + __m128 const Mask = _mm_castsi128_ps(Load); + + vec<4, float, Q> Result; +# if 0 && GLM_ARCH & GLM_ARCH_AVX + Result.data = _mm_blendv_ps(x.data, y.data, Mask); +# else + Result.data = _mm_or_ps(_mm_and_ps(Mask, y.data), _mm_andnot_ps(Mask, x.data)); +# endif + return Result; + } + }; +/* FIXME + template + struct compute_step_vector + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& edge, vec<4, float, Q> const& x) + { + vec<4, float, Q> Result; + result.data = glm_vec4_step(edge.data, x.data); + return result; + } + }; +*/ + template + struct compute_smoothstep_vector<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& edge0, vec<4, float, Q> const& edge1, vec<4, float, Q> const& x) + { + vec<4, float, Q> Result; + Result.data = glm_vec4_smoothstep(edge0.data, edge1.data, x.data); + return Result; + } + }; +}//namespace detail +}//namespace glm + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_exponential.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_exponential.inl new file mode 100644 index 0000000000000000000000000000000000000000..2040d41f8a3dfe17cc129601e0d25b7ba56a2e55 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_exponential.inl @@ -0,0 +1,152 @@ +/// @ref core +/// @file glm/detail/func_exponential.inl + +#include "../vector_relational.hpp" +#include "_vectorize.hpp" +#include +#include +#include + +namespace glm{ +namespace detail +{ +# if GLM_HAS_CXX11_STL + using std::log2; +# else + template + genType log2(genType Value) + { + return std::log(Value) * static_cast(1.4426950408889634073599246810019); + } +# endif + + template + struct compute_log2 + { + GLM_FUNC_QUALIFIER static vec call(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'log2' only accept floating-point inputs. Include for integer inputs."); + + return detail::functor1::call(log2, v); + } + }; + + template + struct compute_sqrt + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + return detail::functor1::call(std::sqrt, x); + } + }; + + template + struct compute_inversesqrt + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + return static_cast(1) / sqrt(x); + } + }; + + template + struct compute_inversesqrt + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + vec tmp(x); + vec xhalf(tmp * 0.5f); + vec* p = reinterpret_cast*>(const_cast*>(&x)); + vec i = vec(0x5f375a86) - (*p >> vec(1)); + vec* ptmp = reinterpret_cast*>(&i); + tmp = *ptmp; + tmp = tmp * (1.5f - xhalf * tmp * tmp); + return tmp; + } + }; +}//namespace detail + + // pow + using std::pow; + template + GLM_FUNC_QUALIFIER vec pow(vec const& base, vec const& exponent) + { + return detail::functor2::call(pow, base, exponent); + } + + // exp + using std::exp; + template + GLM_FUNC_QUALIFIER vec exp(vec const& x) + { + return detail::functor1::call(exp, x); + } + + // log + using std::log; + template + GLM_FUNC_QUALIFIER vec log(vec const& x) + { + return detail::functor1::call(log, x); + } + +# if GLM_HAS_CXX11_STL + using std::exp2; +# else + //exp2, ln2 = 0.69314718055994530941723212145818f + template + GLM_FUNC_QUALIFIER genType exp2(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'exp2' only accept floating-point inputs"); + + return std::exp(static_cast(0.69314718055994530941723212145818) * x); + } +# endif + + template + GLM_FUNC_QUALIFIER vec exp2(vec const& x) + { + return detail::functor1::call(exp2, x); + } + + // log2, ln2 = 0.69314718055994530941723212145818f + template + GLM_FUNC_QUALIFIER genType log2(genType x) + { + return log2(vec<1, genType>(x)).x; + } + + template + GLM_FUNC_QUALIFIER vec log2(vec const& x) + { + return detail::compute_log2::is_iec559, detail::is_aligned::value>::call(x); + } + + // sqrt + using std::sqrt; + template + GLM_FUNC_QUALIFIER vec sqrt(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'sqrt' only accept floating-point inputs"); + return detail::compute_sqrt::value>::call(x); + } + + // inversesqrt + template + GLM_FUNC_QUALIFIER genType inversesqrt(genType x) + { + return static_cast(1) / sqrt(x); + } + + template + GLM_FUNC_QUALIFIER vec inversesqrt(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'inversesqrt' only accept floating-point inputs"); + return detail::compute_inversesqrt::value>::call(x); + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "func_exponential_simd.inl" +#endif + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_exponential_simd.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_exponential_simd.inl new file mode 100644 index 0000000000000000000000000000000000000000..fb78951727f1c5e419418fbac9394322f579f1c4 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_exponential_simd.inl @@ -0,0 +1,37 @@ +/// @ref core +/// @file glm/detail/func_exponential_simd.inl + +#include "../simd/exponential.h" + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +namespace glm{ +namespace detail +{ + template + struct compute_sqrt<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v) + { + vec<4, float, Q> Result; + Result.data = _mm_sqrt_ps(v.data); + return Result; + } + }; + +# if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE + template<> + struct compute_sqrt<4, float, aligned_lowp, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, aligned_lowp> call(vec<4, float, aligned_lowp> const& v) + { + vec<4, float, aligned_lowp> Result; + Result.data = glm_vec4_sqrt_lowp(v.data); + return Result; + } + }; +# endif +}//namespace detail +}//namespace glm + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_geometric.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_geometric.inl new file mode 100644 index 0000000000000000000000000000000000000000..404c99056ab473840f9307630b32770868d9cd93 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_geometric.inl @@ -0,0 +1,243 @@ +#include "../exponential.hpp" +#include "../common.hpp" + +namespace glm{ +namespace detail +{ + template + struct compute_length + { + GLM_FUNC_QUALIFIER static T call(vec const& v) + { + return sqrt(dot(v, v)); + } + }; + + template + struct compute_distance + { + GLM_FUNC_QUALIFIER static T call(vec const& p0, vec const& p1) + { + return length(p1 - p0); + } + }; + + template + struct compute_dot{}; + + template + struct compute_dot, T, Aligned> + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static T call(vec<1, T, Q> const& a, vec<1, T, Q> const& b) + { + return a.x * b.x; + } + }; + + template + struct compute_dot, T, Aligned> + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static T call(vec<2, T, Q> const& a, vec<2, T, Q> const& b) + { + vec<2, T, Q> tmp(a * b); + return tmp.x + tmp.y; + } + }; + + template + struct compute_dot, T, Aligned> + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static T call(vec<3, T, Q> const& a, vec<3, T, Q> const& b) + { + vec<3, T, Q> tmp(a * b); + return tmp.x + tmp.y + tmp.z; + } + }; + + template + struct compute_dot, T, Aligned> + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static T call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + vec<4, T, Q> tmp(a * b); + return (tmp.x + tmp.y) + (tmp.z + tmp.w); + } + }; + + template + struct compute_cross + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<3, T, Q> call(vec<3, T, Q> const& x, vec<3, T, Q> const& y) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'cross' accepts only floating-point inputs"); + + return vec<3, T, Q>( + x.y * y.z - y.y * x.z, + x.z * y.x - y.z * x.x, + x.x * y.y - y.x * x.y); + } + }; + + template + struct compute_normalize + { + GLM_FUNC_QUALIFIER static vec call(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'normalize' accepts only floating-point inputs"); + + return v * inversesqrt(dot(v, v)); + } + }; + + template + struct compute_faceforward + { + GLM_FUNC_QUALIFIER static vec call(vec const& N, vec const& I, vec const& Nref) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'normalize' accepts only floating-point inputs"); + + return dot(Nref, I) < static_cast(0) ? N : -N; + } + }; + + template + struct compute_reflect + { + GLM_FUNC_QUALIFIER static vec call(vec const& I, vec const& N) + { + return I - N * dot(N, I) * static_cast(2); + } + }; + + template + struct compute_refract + { + GLM_FUNC_QUALIFIER static vec call(vec const& I, vec const& N, T eta) + { + T const dotValue(dot(N, I)); + T const k(static_cast(1) - eta * eta * (static_cast(1) - dotValue * dotValue)); + vec const Result = + (k >= static_cast(0)) ? (eta * I - (eta * dotValue + std::sqrt(k)) * N) : vec(0); + return Result; + } + }; +}//namespace detail + + // length + template + GLM_FUNC_QUALIFIER genType length(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'length' accepts only floating-point inputs"); + + return abs(x); + } + + template + GLM_FUNC_QUALIFIER T length(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'length' accepts only floating-point inputs"); + + return detail::compute_length::value>::call(v); + } + + // distance + template + GLM_FUNC_QUALIFIER genType distance(genType const& p0, genType const& p1) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'distance' accepts only floating-point inputs"); + + return length(p1 - p0); + } + + template + GLM_FUNC_QUALIFIER T distance(vec const& p0, vec const& p1) + { + return detail::compute_distance::value>::call(p0, p1); + } + + // dot + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T dot(T x, T y) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'dot' accepts only floating-point inputs"); + return x * y; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T dot(vec const& x, vec const& y) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'dot' accepts only floating-point inputs"); + return detail::compute_dot, T, detail::is_aligned::value>::call(x, y); + } + + // cross + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> cross(vec<3, T, Q> const& x, vec<3, T, Q> const& y) + { + return detail::compute_cross::value>::call(x, y); + } +/* + // normalize + template + GLM_FUNC_QUALIFIER genType normalize(genType const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'normalize' accepts only floating-point inputs"); + + return x < genType(0) ? genType(-1) : genType(1); + } +*/ + template + GLM_FUNC_QUALIFIER vec normalize(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'normalize' accepts only floating-point inputs"); + + return detail::compute_normalize::value>::call(x); + } + + // faceforward + template + GLM_FUNC_QUALIFIER genType faceforward(genType const& N, genType const& I, genType const& Nref) + { + return dot(Nref, I) < static_cast(0) ? N : -N; + } + + template + GLM_FUNC_QUALIFIER vec faceforward(vec const& N, vec const& I, vec const& Nref) + { + return detail::compute_faceforward::value>::call(N, I, Nref); + } + + // reflect + template + GLM_FUNC_QUALIFIER genType reflect(genType const& I, genType const& N) + { + return I - N * dot(N, I) * genType(2); + } + + template + GLM_FUNC_QUALIFIER vec reflect(vec const& I, vec const& N) + { + return detail::compute_reflect::value>::call(I, N); + } + + // refract + template + GLM_FUNC_QUALIFIER genType refract(genType const& I, genType const& N, genType eta) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'refract' accepts only floating-point inputs"); + genType const dotValue(dot(N, I)); + genType const k(static_cast(1) - eta * eta * (static_cast(1) - dotValue * dotValue)); + return (eta * I - (eta * dotValue + sqrt(k)) * N) * static_cast(k >= static_cast(0)); + } + + template + GLM_FUNC_QUALIFIER vec refract(vec const& I, vec const& N, T eta) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'refract' accepts only floating-point inputs"); + return detail::compute_refract::value>::call(I, N, eta); + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "func_geometric_simd.inl" +#endif diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_geometric_simd.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_geometric_simd.inl new file mode 100644 index 0000000000000000000000000000000000000000..2076dae055c3c689046e258f726440041b4afd85 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_geometric_simd.inl @@ -0,0 +1,163 @@ +/// @ref core +/// @file glm/detail/func_geometric_simd.inl + +#include "../simd/geometric.h" + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +namespace glm{ +namespace detail +{ + template + struct compute_length<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static float call(vec<4, float, Q> const& v) + { + return _mm_cvtss_f32(glm_vec4_length(v.data)); + } + }; + + template + struct compute_distance<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static float call(vec<4, float, Q> const& p0, vec<4, float, Q> const& p1) + { + return _mm_cvtss_f32(glm_vec4_distance(p0.data, p1.data)); + } + }; + + template + struct compute_dot, float, true> + { + GLM_FUNC_QUALIFIER static float call(vec<4, float, Q> const& x, vec<4, float, Q> const& y) + { + return _mm_cvtss_f32(glm_vec1_dot(x.data, y.data)); + } + }; + + template + struct compute_cross + { + GLM_FUNC_QUALIFIER static vec<3, float, Q> call(vec<3, float, Q> const& a, vec<3, float, Q> const& b) + { + __m128 const set0 = _mm_set_ps(0.0f, a.z, a.y, a.x); + __m128 const set1 = _mm_set_ps(0.0f, b.z, b.y, b.x); + __m128 const xpd0 = glm_vec4_cross(set0, set1); + + vec<4, float, Q> Result; + Result.data = xpd0; + return vec<3, float, Q>(Result); + } + }; + + template + struct compute_normalize<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v) + { + vec<4, float, Q> Result; + Result.data = glm_vec4_normalize(v.data); + return Result; + } + }; + + template + struct compute_faceforward<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& N, vec<4, float, Q> const& I, vec<4, float, Q> const& Nref) + { + vec<4, float, Q> Result; + Result.data = glm_vec4_faceforward(N.data, I.data, Nref.data); + return Result; + } + }; + + template + struct compute_reflect<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& I, vec<4, float, Q> const& N) + { + vec<4, float, Q> Result; + Result.data = glm_vec4_reflect(I.data, N.data); + return Result; + } + }; + + template + struct compute_refract<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& I, vec<4, float, Q> const& N, float eta) + { + vec<4, float, Q> Result; + Result.data = glm_vec4_refract(I.data, N.data, _mm_set1_ps(eta)); + return Result; + } + }; +}//namespace detail +}//namespace glm + +#elif GLM_ARCH & GLM_ARCH_NEON_BIT +namespace glm{ +namespace detail +{ + template + struct compute_length<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static float call(vec<4, float, Q> const& v) + { + return sqrt(compute_dot, float, true>::call(v, v)); + } + }; + + template + struct compute_distance<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static float call(vec<4, float, Q> const& p0, vec<4, float, Q> const& p1) + { + return compute_length<4, float, Q, true>::call(p1 - p0); + } + }; + + + template + struct compute_dot, float, true> + { + GLM_FUNC_QUALIFIER static float call(vec<4, float, Q> const& x, vec<4, float, Q> const& y) + { +#if GLM_ARCH & GLM_ARCH_ARMV8_BIT + float32x4_t v = vmulq_f32(x.data, y.data); + return vaddvq_f32(v); +#else // Armv7a with Neon + float32x4_t p = vmulq_f32(x.data, y.data); + float32x2_t v = vpadd_f32(vget_low_f32(p), vget_high_f32(p)); + v = vpadd_f32(v, v); + return vget_lane_f32(v, 0); +#endif + } + }; + + template + struct compute_normalize<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v) + { + float32x4_t p = vmulq_f32(v.data, v.data); +#if GLM_ARCH & GLM_ARCH_ARMV8_BIT + p = vpaddq_f32(p, p); + p = vpaddq_f32(p, p); +#else + float32x2_t t = vpadd_f32(vget_low_f32(p), vget_high_f32(p)); + t = vpadd_f32(t, t); + p = vcombine_f32(t, t); +#endif + + float32x4_t vd = vrsqrteq_f32(p); + vec<4, float, Q> Result; + Result.data = vmulq_f32(v.data, vd); + return Result; + } + }; +}//namespace detail +}//namespace glm + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_integer.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_integer.inl new file mode 100644 index 0000000000000000000000000000000000000000..a28c743e25366ce48e669f78b972e7522852dcca --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_integer.inl @@ -0,0 +1,372 @@ +/// @ref core + +#include "_vectorize.hpp" +#if(GLM_ARCH & GLM_ARCH_X86 && GLM_COMPILER & GLM_COMPILER_VC) +# include +# pragma intrinsic(_BitScanReverse) +#endif//(GLM_ARCH & GLM_ARCH_X86 && GLM_COMPILER & GLM_COMPILER_VC) +#include + +#if !GLM_HAS_EXTENDED_INTEGER_TYPE +# if GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +# if (GLM_COMPILER & GLM_COMPILER_CLANG) +# pragma clang diagnostic ignored "-Wc++11-long-long" +# endif +#endif + +namespace glm{ +namespace detail +{ + template + GLM_FUNC_QUALIFIER T mask(T Bits) + { + return Bits >= static_cast(sizeof(T) * 8) ? ~static_cast(0) : (static_cast(1) << Bits) - static_cast(1); + } + + template + struct compute_bitfieldReverseStep + { + GLM_FUNC_QUALIFIER static vec call(vec const& v, T, T) + { + return v; + } + }; + + template + struct compute_bitfieldReverseStep + { + GLM_FUNC_QUALIFIER static vec call(vec const& v, T Mask, T Shift) + { + return (v & Mask) << Shift | (v & (~Mask)) >> Shift; + } + }; + + template + struct compute_bitfieldBitCountStep + { + GLM_FUNC_QUALIFIER static vec call(vec const& v, T, T) + { + return v; + } + }; + + template + struct compute_bitfieldBitCountStep + { + GLM_FUNC_QUALIFIER static vec call(vec const& v, T Mask, T Shift) + { + return (v & Mask) + ((v >> Shift) & Mask); + } + }; + + template + struct compute_findLSB + { + GLM_FUNC_QUALIFIER static int call(genIUType Value) + { + if(Value == 0) + return -1; + + return glm::bitCount(~Value & (Value - static_cast(1))); + } + }; + +# if GLM_HAS_BITSCAN_WINDOWS + template + struct compute_findLSB + { + GLM_FUNC_QUALIFIER static int call(genIUType Value) + { + unsigned long Result(0); + unsigned char IsNotNull = _BitScanForward(&Result, *reinterpret_cast(&Value)); + return IsNotNull ? int(Result) : -1; + } + }; + +# if !((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_MODEL == GLM_MODEL_32)) + template + struct compute_findLSB + { + GLM_FUNC_QUALIFIER static int call(genIUType Value) + { + unsigned long Result(0); + unsigned char IsNotNull = _BitScanForward64(&Result, *reinterpret_cast(&Value)); + return IsNotNull ? int(Result) : -1; + } + }; +# endif +# endif//GLM_HAS_BITSCAN_WINDOWS + + template + struct compute_findMSB_step_vec + { + GLM_FUNC_QUALIFIER static vec call(vec const& x, T Shift) + { + return x | (x >> Shift); + } + }; + + template + struct compute_findMSB_step_vec + { + GLM_FUNC_QUALIFIER static vec call(vec const& x, T) + { + return x; + } + }; + + template + struct compute_findMSB_vec + { + GLM_FUNC_QUALIFIER static vec call(vec const& v) + { + vec x(v); + x = compute_findMSB_step_vec= 8>::call(x, static_cast( 1)); + x = compute_findMSB_step_vec= 8>::call(x, static_cast( 2)); + x = compute_findMSB_step_vec= 8>::call(x, static_cast( 4)); + x = compute_findMSB_step_vec= 16>::call(x, static_cast( 8)); + x = compute_findMSB_step_vec= 32>::call(x, static_cast(16)); + x = compute_findMSB_step_vec= 64>::call(x, static_cast(32)); + return vec(sizeof(T) * 8 - 1) - glm::bitCount(~x); + } + }; + +# if GLM_HAS_BITSCAN_WINDOWS + template + GLM_FUNC_QUALIFIER int compute_findMSB_32(genIUType Value) + { + unsigned long Result(0); + unsigned char IsNotNull = _BitScanReverse(&Result, *reinterpret_cast(&Value)); + return IsNotNull ? int(Result) : -1; + } + + template + struct compute_findMSB_vec + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + return detail::functor1::call(compute_findMSB_32, x); + } + }; + +# if !((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_MODEL == GLM_MODEL_32)) + template + GLM_FUNC_QUALIFIER int compute_findMSB_64(genIUType Value) + { + unsigned long Result(0); + unsigned char IsNotNull = _BitScanReverse64(&Result, *reinterpret_cast(&Value)); + return IsNotNull ? int(Result) : -1; + } + + template + struct compute_findMSB_vec + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + return detail::functor1::call(compute_findMSB_64, x); + } + }; +# endif +# endif//GLM_HAS_BITSCAN_WINDOWS +}//namespace detail + + // uaddCarry + GLM_FUNC_QUALIFIER uint uaddCarry(uint const& x, uint const& y, uint & Carry) + { + detail::uint64 const Value64(static_cast(x) + static_cast(y)); + detail::uint64 const Max32((static_cast(1) << static_cast(32)) - static_cast(1)); + Carry = Value64 > Max32 ? 1u : 0u; + return static_cast(Value64 % (Max32 + static_cast(1))); + } + + template + GLM_FUNC_QUALIFIER vec uaddCarry(vec const& x, vec const& y, vec& Carry) + { + vec Value64(vec(x) + vec(y)); + vec Max32((static_cast(1) << static_cast(32)) - static_cast(1)); + Carry = mix(vec(0), vec(1), greaterThan(Value64, Max32)); + return vec(Value64 % (Max32 + static_cast(1))); + } + + // usubBorrow + GLM_FUNC_QUALIFIER uint usubBorrow(uint const& x, uint const& y, uint & Borrow) + { + Borrow = x >= y ? static_cast(0) : static_cast(1); + if(y >= x) + return y - x; + else + return static_cast((static_cast(1) << static_cast(32)) + (static_cast(y) - static_cast(x))); + } + + template + GLM_FUNC_QUALIFIER vec usubBorrow(vec const& x, vec const& y, vec& Borrow) + { + Borrow = mix(vec(1), vec(0), greaterThanEqual(x, y)); + vec const YgeX(y - x); + vec const XgeY(vec((static_cast(1) << static_cast(32)) + (vec(y) - vec(x)))); + return mix(XgeY, YgeX, greaterThanEqual(y, x)); + } + + // umulExtended + GLM_FUNC_QUALIFIER void umulExtended(uint const& x, uint const& y, uint & msb, uint & lsb) + { + detail::uint64 Value64 = static_cast(x) * static_cast(y); + msb = static_cast(Value64 >> static_cast(32)); + lsb = static_cast(Value64); + } + + template + GLM_FUNC_QUALIFIER void umulExtended(vec const& x, vec const& y, vec& msb, vec& lsb) + { + vec Value64(vec(x) * vec(y)); + msb = vec(Value64 >> static_cast(32)); + lsb = vec(Value64); + } + + // imulExtended + GLM_FUNC_QUALIFIER void imulExtended(int x, int y, int& msb, int& lsb) + { + detail::int64 Value64 = static_cast(x) * static_cast(y); + msb = static_cast(Value64 >> static_cast(32)); + lsb = static_cast(Value64); + } + + template + GLM_FUNC_QUALIFIER void imulExtended(vec const& x, vec const& y, vec& msb, vec& lsb) + { + vec Value64(vec(x) * vec(y)); + lsb = vec(Value64 & static_cast(0xFFFFFFFF)); + msb = vec((Value64 >> static_cast(32)) & static_cast(0xFFFFFFFF)); + } + + // bitfieldExtract + template + GLM_FUNC_QUALIFIER genIUType bitfieldExtract(genIUType Value, int Offset, int Bits) + { + return bitfieldExtract(vec<1, genIUType>(Value), Offset, Bits).x; + } + + template + GLM_FUNC_QUALIFIER vec bitfieldExtract(vec const& Value, int Offset, int Bits) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldExtract' only accept integer inputs"); + + return (Value >> static_cast(Offset)) & static_cast(detail::mask(Bits)); + } + + // bitfieldInsert + template + GLM_FUNC_QUALIFIER genIUType bitfieldInsert(genIUType const& Base, genIUType const& Insert, int Offset, int Bits) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldInsert' only accept integer values"); + + return bitfieldInsert(vec<1, genIUType>(Base), vec<1, genIUType>(Insert), Offset, Bits).x; + } + + template + GLM_FUNC_QUALIFIER vec bitfieldInsert(vec const& Base, vec const& Insert, int Offset, int Bits) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldInsert' only accept integer values"); + + T const Mask = detail::mask(static_cast(Bits)) << Offset; + return (Base & ~Mask) | ((Insert << static_cast(Offset)) & Mask); + } + + // bitfieldReverse + template + GLM_FUNC_QUALIFIER genIUType bitfieldReverse(genIUType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldReverse' only accept integer values"); + + return bitfieldReverse(glm::vec<1, genIUType, glm::defaultp>(x)).x; + } + + template + GLM_FUNC_QUALIFIER vec bitfieldReverse(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldReverse' only accept integer values"); + + vec x(v); + x = detail::compute_bitfieldReverseStep::value, sizeof(T) * 8>= 2>::call(x, static_cast(0x5555555555555555ull), static_cast( 1)); + x = detail::compute_bitfieldReverseStep::value, sizeof(T) * 8>= 4>::call(x, static_cast(0x3333333333333333ull), static_cast( 2)); + x = detail::compute_bitfieldReverseStep::value, sizeof(T) * 8>= 8>::call(x, static_cast(0x0F0F0F0F0F0F0F0Full), static_cast( 4)); + x = detail::compute_bitfieldReverseStep::value, sizeof(T) * 8>= 16>::call(x, static_cast(0x00FF00FF00FF00FFull), static_cast( 8)); + x = detail::compute_bitfieldReverseStep::value, sizeof(T) * 8>= 32>::call(x, static_cast(0x0000FFFF0000FFFFull), static_cast(16)); + x = detail::compute_bitfieldReverseStep::value, sizeof(T) * 8>= 64>::call(x, static_cast(0x00000000FFFFFFFFull), static_cast(32)); + return x; + } + + // bitCount + template + GLM_FUNC_QUALIFIER int bitCount(genIUType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitCount' only accept integer values"); + + return bitCount(glm::vec<1, genIUType, glm::defaultp>(x)).x; + } + + template + GLM_FUNC_QUALIFIER vec bitCount(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitCount' only accept integer values"); + +# if GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(push) +# pragma warning(disable : 4310) //cast truncates constant value +# endif + + vec::type, Q> x(*reinterpret_cast::type, Q> const *>(&v)); + x = detail::compute_bitfieldBitCountStep::type, Q, detail::is_aligned::value, sizeof(T) * 8>= 2>::call(x, typename detail::make_unsigned::type(0x5555555555555555ull), typename detail::make_unsigned::type( 1)); + x = detail::compute_bitfieldBitCountStep::type, Q, detail::is_aligned::value, sizeof(T) * 8>= 4>::call(x, typename detail::make_unsigned::type(0x3333333333333333ull), typename detail::make_unsigned::type( 2)); + x = detail::compute_bitfieldBitCountStep::type, Q, detail::is_aligned::value, sizeof(T) * 8>= 8>::call(x, typename detail::make_unsigned::type(0x0F0F0F0F0F0F0F0Full), typename detail::make_unsigned::type( 4)); + x = detail::compute_bitfieldBitCountStep::type, Q, detail::is_aligned::value, sizeof(T) * 8>= 16>::call(x, typename detail::make_unsigned::type(0x00FF00FF00FF00FFull), typename detail::make_unsigned::type( 8)); + x = detail::compute_bitfieldBitCountStep::type, Q, detail::is_aligned::value, sizeof(T) * 8>= 32>::call(x, typename detail::make_unsigned::type(0x0000FFFF0000FFFFull), typename detail::make_unsigned::type(16)); + x = detail::compute_bitfieldBitCountStep::type, Q, detail::is_aligned::value, sizeof(T) * 8>= 64>::call(x, typename detail::make_unsigned::type(0x00000000FFFFFFFFull), typename detail::make_unsigned::type(32)); + return vec(x); + +# if GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(pop) +# endif + } + + // findLSB + template + GLM_FUNC_QUALIFIER int findLSB(genIUType Value) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'findLSB' only accept integer values"); + + return detail::compute_findLSB::call(Value); + } + + template + GLM_FUNC_QUALIFIER vec findLSB(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'findLSB' only accept integer values"); + + return detail::functor1::call(findLSB, x); + } + + // findMSB + template + GLM_FUNC_QUALIFIER int findMSB(genIUType v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'findMSB' only accept integer values"); + + return findMSB(vec<1, genIUType>(v)).x; + } + + template + GLM_FUNC_QUALIFIER vec findMSB(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'findMSB' only accept integer values"); + + return detail::compute_findMSB_vec::call(v); + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "func_integer_simd.inl" +#endif + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_integer_simd.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_integer_simd.inl new file mode 100644 index 0000000000000000000000000000000000000000..8be6c9ce4dc143cedd3565899b6c44b7fea3bde8 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_integer_simd.inl @@ -0,0 +1,65 @@ +#include "../simd/integer.h" + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +namespace glm{ +namespace detail +{ + template + struct compute_bitfieldReverseStep<4, uint, Q, true, true> + { + GLM_FUNC_QUALIFIER static vec<4, uint, Q> call(vec<4, uint, Q> const& v, uint Mask, uint Shift) + { + __m128i const set0 = v.data; + + __m128i const set1 = _mm_set1_epi32(static_cast(Mask)); + __m128i const and1 = _mm_and_si128(set0, set1); + __m128i const sft1 = _mm_slli_epi32(and1, Shift); + + __m128i const set2 = _mm_andnot_si128(set0, _mm_set1_epi32(-1)); + __m128i const and2 = _mm_and_si128(set0, set2); + __m128i const sft2 = _mm_srai_epi32(and2, Shift); + + __m128i const or0 = _mm_or_si128(sft1, sft2); + + return or0; + } + }; + + template + struct compute_bitfieldBitCountStep<4, uint, Q, true, true> + { + GLM_FUNC_QUALIFIER static vec<4, uint, Q> call(vec<4, uint, Q> const& v, uint Mask, uint Shift) + { + __m128i const set0 = v.data; + + __m128i const set1 = _mm_set1_epi32(static_cast(Mask)); + __m128i const and0 = _mm_and_si128(set0, set1); + __m128i const sft0 = _mm_slli_epi32(set0, Shift); + __m128i const and1 = _mm_and_si128(sft0, set1); + __m128i const add0 = _mm_add_epi32(and0, and1); + + return add0; + } + }; +}//namespace detail + +# if GLM_ARCH & GLM_ARCH_AVX_BIT + template<> + GLM_FUNC_QUALIFIER int bitCount(uint x) + { + return _mm_popcnt_u32(x); + } + +# if(GLM_MODEL == GLM_MODEL_64) + template<> + GLM_FUNC_QUALIFIER int bitCount(detail::uint64 x) + { + return static_cast(_mm_popcnt_u64(x)); + } +# endif//GLM_MODEL +# endif//GLM_ARCH + +}//namespace glm + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_matrix.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_matrix.inl new file mode 100644 index 0000000000000000000000000000000000000000..c2d568ff471d55e52971aa05a89b97f4af0485d6 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_matrix.inl @@ -0,0 +1,443 @@ +#include "../geometric.hpp" +#include + +namespace glm{ +namespace detail +{ + template + struct compute_matrixCompMult + { + GLM_FUNC_QUALIFIER static mat call(mat const& x, mat const& y) + { + mat Result; + for(length_t i = 0; i < Result.length(); ++i) + Result[i] = x[i] * y[i]; + return Result; + } + }; + + template + struct compute_matrixCompMult_type { + GLM_FUNC_QUALIFIER static mat call(mat const& x, mat const& y) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, + "'matrixCompMult' only accept floating-point inputs, include to discard this restriction."); + return detail::compute_matrixCompMult::value>::call(x, y); + } + }; + + template + struct compute_outerProduct { + GLM_FUNC_QUALIFIER static typename detail::outerProduct_trait::type call(vec const& c, vec const& r) + { + typename detail::outerProduct_trait::type m; + for(length_t i = 0; i < m.length(); ++i) + m[i] = c * r[i]; + return m; + } + }; + + template + struct compute_outerProduct_type { + GLM_FUNC_QUALIFIER static typename detail::outerProduct_trait::type call(vec const& c, vec const& r) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, + "'outerProduct' only accept floating-point inputs, include to discard this restriction."); + + return detail::compute_outerProduct::call(c, r); + } + }; + + template + struct compute_transpose{}; + + template + struct compute_transpose<2, 2, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<2, 2, T, Q> call(mat<2, 2, T, Q> const& m) + { + mat<2, 2, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + return Result; + } + }; + + template + struct compute_transpose<2, 3, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<3, 2, T, Q> call(mat<2, 3, T, Q> const& m) + { + mat<3,2, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + Result[2][0] = m[0][2]; + Result[2][1] = m[1][2]; + return Result; + } + }; + + template + struct compute_transpose<2, 4, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<4, 2, T, Q> call(mat<2, 4, T, Q> const& m) + { + mat<4, 2, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + Result[2][0] = m[0][2]; + Result[2][1] = m[1][2]; + Result[3][0] = m[0][3]; + Result[3][1] = m[1][3]; + return Result; + } + }; + + template + struct compute_transpose<3, 2, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<2, 3, T, Q> call(mat<3, 2, T, Q> const& m) + { + mat<2, 3, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[0][2] = m[2][0]; + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + Result[1][2] = m[2][1]; + return Result; + } + }; + + template + struct compute_transpose<3, 3, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<3, 3, T, Q> call(mat<3, 3, T, Q> const& m) + { + mat<3, 3, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[0][2] = m[2][0]; + + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + Result[1][2] = m[2][1]; + + Result[2][0] = m[0][2]; + Result[2][1] = m[1][2]; + Result[2][2] = m[2][2]; + return Result; + } + }; + + template + struct compute_transpose<3, 4, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<4, 3, T, Q> call(mat<3, 4, T, Q> const& m) + { + mat<4, 3, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[0][2] = m[2][0]; + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + Result[1][2] = m[2][1]; + Result[2][0] = m[0][2]; + Result[2][1] = m[1][2]; + Result[2][2] = m[2][2]; + Result[3][0] = m[0][3]; + Result[3][1] = m[1][3]; + Result[3][2] = m[2][3]; + return Result; + } + }; + + template + struct compute_transpose<4, 2, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<2, 4, T, Q> call(mat<4, 2, T, Q> const& m) + { + mat<2, 4, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[0][2] = m[2][0]; + Result[0][3] = m[3][0]; + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + Result[1][2] = m[2][1]; + Result[1][3] = m[3][1]; + return Result; + } + }; + + template + struct compute_transpose<4, 3, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<3, 4, T, Q> call(mat<4, 3, T, Q> const& m) + { + mat<3, 4, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[0][2] = m[2][0]; + Result[0][3] = m[3][0]; + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + Result[1][2] = m[2][1]; + Result[1][3] = m[3][1]; + Result[2][0] = m[0][2]; + Result[2][1] = m[1][2]; + Result[2][2] = m[2][2]; + Result[2][3] = m[3][2]; + return Result; + } + }; + + template + struct compute_transpose<4, 4, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<4, 4, T, Q> call(mat<4, 4, T, Q> const& m) + { + mat<4, 4, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[0][2] = m[2][0]; + Result[0][3] = m[3][0]; + + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + Result[1][2] = m[2][1]; + Result[1][3] = m[3][1]; + + Result[2][0] = m[0][2]; + Result[2][1] = m[1][2]; + Result[2][2] = m[2][2]; + Result[2][3] = m[3][2]; + + Result[3][0] = m[0][3]; + Result[3][1] = m[1][3]; + Result[3][2] = m[2][3]; + Result[3][3] = m[3][3]; + return Result; + } + }; + + template + struct compute_transpose_type { + GLM_FUNC_QUALIFIER static mat call(mat const& m) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, + "'transpose' only accept floating-point inputs, include to discard this restriction."); + return detail::compute_transpose::value>::call(m); + } + }; + + template + struct compute_determinant{}; + + template + struct compute_determinant<2, 2, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static T call(mat<2, 2, T, Q> const& m) + { + return m[0][0] * m[1][1] - m[1][0] * m[0][1]; + } + }; + + template + struct compute_determinant<3, 3, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static T call(mat<3, 3, T, Q> const& m) + { + return + + m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2]) + - m[1][0] * (m[0][1] * m[2][2] - m[2][1] * m[0][2]) + + m[2][0] * (m[0][1] * m[1][2] - m[1][1] * m[0][2]); + } + }; + + template + struct compute_determinant<4, 4, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static T call(mat<4, 4, T, Q> const& m) + { + T SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + T SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + T SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + T SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + T SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + T SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + + vec<4, T, Q> DetCof( + + (m[1][1] * SubFactor00 - m[1][2] * SubFactor01 + m[1][3] * SubFactor02), + - (m[1][0] * SubFactor00 - m[1][2] * SubFactor03 + m[1][3] * SubFactor04), + + (m[1][0] * SubFactor01 - m[1][1] * SubFactor03 + m[1][3] * SubFactor05), + - (m[1][0] * SubFactor02 - m[1][1] * SubFactor04 + m[1][2] * SubFactor05)); + + return + m[0][0] * DetCof[0] + m[0][1] * DetCof[1] + + m[0][2] * DetCof[2] + m[0][3] * DetCof[3]; + } + }; + + template + struct compute_determinant_type{ + + GLM_FUNC_QUALIFIER static T call(mat const& m) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, + "'determinant' only accept floating-point inputs, include to discard this restriction."); + return detail::compute_determinant::value>::call(m); + } + }; + + template + struct compute_inverse{}; + + template + struct compute_inverse<2, 2, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<2, 2, T, Q> call(mat<2, 2, T, Q> const& m) + { + T OneOverDeterminant = static_cast(1) / ( + + m[0][0] * m[1][1] + - m[1][0] * m[0][1]); + + mat<2, 2, T, Q> Inverse( + + m[1][1] * OneOverDeterminant, + - m[0][1] * OneOverDeterminant, + - m[1][0] * OneOverDeterminant, + + m[0][0] * OneOverDeterminant); + + return Inverse; + } + }; + + template + struct compute_inverse<3, 3, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<3, 3, T, Q> call(mat<3, 3, T, Q> const& m) + { + T OneOverDeterminant = static_cast(1) / ( + + m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2]) + - m[1][0] * (m[0][1] * m[2][2] - m[2][1] * m[0][2]) + + m[2][0] * (m[0][1] * m[1][2] - m[1][1] * m[0][2])); + + mat<3, 3, T, Q> Inverse; + Inverse[0][0] = + (m[1][1] * m[2][2] - m[2][1] * m[1][2]) * OneOverDeterminant; + Inverse[1][0] = - (m[1][0] * m[2][2] - m[2][0] * m[1][2]) * OneOverDeterminant; + Inverse[2][0] = + (m[1][0] * m[2][1] - m[2][0] * m[1][1]) * OneOverDeterminant; + Inverse[0][1] = - (m[0][1] * m[2][2] - m[2][1] * m[0][2]) * OneOverDeterminant; + Inverse[1][1] = + (m[0][0] * m[2][2] - m[2][0] * m[0][2]) * OneOverDeterminant; + Inverse[2][1] = - (m[0][0] * m[2][1] - m[2][0] * m[0][1]) * OneOverDeterminant; + Inverse[0][2] = + (m[0][1] * m[1][2] - m[1][1] * m[0][2]) * OneOverDeterminant; + Inverse[1][2] = - (m[0][0] * m[1][2] - m[1][0] * m[0][2]) * OneOverDeterminant; + Inverse[2][2] = + (m[0][0] * m[1][1] - m[1][0] * m[0][1]) * OneOverDeterminant; + + return Inverse; + } + }; + + template + struct compute_inverse<4, 4, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<4, 4, T, Q> call(mat<4, 4, T, Q> const& m) + { + T Coef00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + T Coef02 = m[1][2] * m[3][3] - m[3][2] * m[1][3]; + T Coef03 = m[1][2] * m[2][3] - m[2][2] * m[1][3]; + + T Coef04 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + T Coef06 = m[1][1] * m[3][3] - m[3][1] * m[1][3]; + T Coef07 = m[1][1] * m[2][3] - m[2][1] * m[1][3]; + + T Coef08 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + T Coef10 = m[1][1] * m[3][2] - m[3][1] * m[1][2]; + T Coef11 = m[1][1] * m[2][2] - m[2][1] * m[1][2]; + + T Coef12 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + T Coef14 = m[1][0] * m[3][3] - m[3][0] * m[1][3]; + T Coef15 = m[1][0] * m[2][3] - m[2][0] * m[1][3]; + + T Coef16 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + T Coef18 = m[1][0] * m[3][2] - m[3][0] * m[1][2]; + T Coef19 = m[1][0] * m[2][2] - m[2][0] * m[1][2]; + + T Coef20 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + T Coef22 = m[1][0] * m[3][1] - m[3][0] * m[1][1]; + T Coef23 = m[1][0] * m[2][1] - m[2][0] * m[1][1]; + + vec<4, T, Q> Fac0(Coef00, Coef00, Coef02, Coef03); + vec<4, T, Q> Fac1(Coef04, Coef04, Coef06, Coef07); + vec<4, T, Q> Fac2(Coef08, Coef08, Coef10, Coef11); + vec<4, T, Q> Fac3(Coef12, Coef12, Coef14, Coef15); + vec<4, T, Q> Fac4(Coef16, Coef16, Coef18, Coef19); + vec<4, T, Q> Fac5(Coef20, Coef20, Coef22, Coef23); + + vec<4, T, Q> Vec0(m[1][0], m[0][0], m[0][0], m[0][0]); + vec<4, T, Q> Vec1(m[1][1], m[0][1], m[0][1], m[0][1]); + vec<4, T, Q> Vec2(m[1][2], m[0][2], m[0][2], m[0][2]); + vec<4, T, Q> Vec3(m[1][3], m[0][3], m[0][3], m[0][3]); + + vec<4, T, Q> Inv0(Vec1 * Fac0 - Vec2 * Fac1 + Vec3 * Fac2); + vec<4, T, Q> Inv1(Vec0 * Fac0 - Vec2 * Fac3 + Vec3 * Fac4); + vec<4, T, Q> Inv2(Vec0 * Fac1 - Vec1 * Fac3 + Vec3 * Fac5); + vec<4, T, Q> Inv3(Vec0 * Fac2 - Vec1 * Fac4 + Vec2 * Fac5); + + vec<4, T, Q> SignA(+1, -1, +1, -1); + vec<4, T, Q> SignB(-1, +1, -1, +1); + mat<4, 4, T, Q> Inverse(Inv0 * SignA, Inv1 * SignB, Inv2 * SignA, Inv3 * SignB); + + vec<4, T, Q> Row0(Inverse[0][0], Inverse[1][0], Inverse[2][0], Inverse[3][0]); + + vec<4, T, Q> Dot0(m[0] * Row0); + T Dot1 = (Dot0.x + Dot0.y) + (Dot0.z + Dot0.w); + + T OneOverDeterminant = static_cast(1) / Dot1; + + return Inverse * OneOverDeterminant; + } + }; +}//namespace detail + + template + GLM_FUNC_QUALIFIER mat matrixCompMult(mat const& x, mat const& y) + { + return detail::compute_matrixCompMult_type::is_iec559, detail::is_aligned::value>::call(x, y); + } + + template + GLM_FUNC_QUALIFIER typename detail::outerProduct_trait::type outerProduct(vec const& c, vec const& r) + { + return detail::compute_outerProduct_type::is_iec559>::call(c, r); + } + + template + GLM_FUNC_QUALIFIER typename mat::transpose_type transpose(mat const& m) + { + return detail::compute_transpose_type::is_iec559, detail::is_aligned::value>::call(m); + } + + template + GLM_FUNC_QUALIFIER T determinant(mat const& m) + { + return detail::compute_determinant_type::is_iec559, detail::is_aligned::value>::call(m); + } + + template + GLM_FUNC_QUALIFIER mat inverse(mat const& m) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'inverse' only accept floating-point inputs"); + return detail::compute_inverse::value>::call(m); + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "func_matrix_simd.inl" +#endif + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_matrix_simd.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_matrix_simd.inl new file mode 100644 index 0000000000000000000000000000000000000000..b9bb4615de676a19b04bbb3e6402f7a107aa85ef --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_matrix_simd.inl @@ -0,0 +1,252 @@ +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +#include "type_mat4x4.hpp" +#include "../geometric.hpp" +#include "../simd/matrix.h" +#include + +namespace glm{ +namespace detail +{ +# if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE + template + struct compute_matrixCompMult<4, 4, float, Q, true> + { + GLM_STATIC_ASSERT(detail::is_aligned::value, "Specialization requires aligned"); + + GLM_FUNC_QUALIFIER static mat<4, 4, float, Q> call(mat<4, 4, float, Q> const& x, mat<4, 4, float, Q> const& y) + { + mat<4, 4, float, Q> Result; + glm_mat4_matrixCompMult( + &x[0].data, + &y[0].data, + &Result[0].data); + return Result; + } + }; +# endif + + template + struct compute_transpose<4, 4, float, Q, true> + { + GLM_FUNC_QUALIFIER static mat<4, 4, float, Q> call(mat<4, 4, float, Q> const& m) + { + mat<4, 4, float, Q> Result; + glm_mat4_transpose(&m[0].data, &Result[0].data); + return Result; + } + }; + + template + struct compute_determinant<4, 4, float, Q, true> + { + GLM_FUNC_QUALIFIER static float call(mat<4, 4, float, Q> const& m) + { + return _mm_cvtss_f32(glm_mat4_determinant(&m[0].data)); + } + }; + + template + struct compute_inverse<4, 4, float, Q, true> + { + GLM_FUNC_QUALIFIER static mat<4, 4, float, Q> call(mat<4, 4, float, Q> const& m) + { + mat<4, 4, float, Q> Result; + glm_mat4_inverse(&m[0].data, &Result[0].data); + return Result; + } + }; +}//namespace detail + +# if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE + template<> + GLM_FUNC_QUALIFIER mat<4, 4, float, aligned_lowp> outerProduct<4, 4, float, aligned_lowp>(vec<4, float, aligned_lowp> const& c, vec<4, float, aligned_lowp> const& r) + { + __m128 NativeResult[4]; + glm_mat4_outerProduct(c.data, r.data, NativeResult); + mat<4, 4, float, aligned_lowp> Result; + std::memcpy(&Result[0], &NativeResult[0], sizeof(Result)); + return Result; + } + + template<> + GLM_FUNC_QUALIFIER mat<4, 4, float, aligned_mediump> outerProduct<4, 4, float, aligned_mediump>(vec<4, float, aligned_mediump> const& c, vec<4, float, aligned_mediump> const& r) + { + __m128 NativeResult[4]; + glm_mat4_outerProduct(c.data, r.data, NativeResult); + mat<4, 4, float, aligned_mediump> Result; + std::memcpy(&Result[0], &NativeResult[0], sizeof(Result)); + return Result; + } + + template<> + GLM_FUNC_QUALIFIER mat<4, 4, float, aligned_highp> outerProduct<4, 4, float, aligned_highp>(vec<4, float, aligned_highp> const& c, vec<4, float, aligned_highp> const& r) + { + __m128 NativeResult[4]; + glm_mat4_outerProduct(c.data, r.data, NativeResult); + mat<4, 4, float, aligned_highp> Result; + std::memcpy(&Result[0], &NativeResult[0], sizeof(Result)); + return Result; + } +# endif +}//namespace glm + +#elif GLM_ARCH & GLM_ARCH_NEON_BIT + +namespace glm { +#if GLM_LANG & GLM_LANG_CXX11_FLAG + template + GLM_FUNC_QUALIFIER + typename std::enable_if::value, mat<4, 4, float, Q>>::type + operator*(mat<4, 4, float, Q> const & m1, mat<4, 4, float, Q> const & m2) + { + auto MulRow = [&](int l) { + float32x4_t const SrcA = m2[l].data; + + float32x4_t r = neon::mul_lane(m1[0].data, SrcA, 0); + r = neon::madd_lane(r, m1[1].data, SrcA, 1); + r = neon::madd_lane(r, m1[2].data, SrcA, 2); + r = neon::madd_lane(r, m1[3].data, SrcA, 3); + + return r; + }; + + mat<4, 4, float, aligned_highp> Result; + Result[0].data = MulRow(0); + Result[1].data = MulRow(1); + Result[2].data = MulRow(2); + Result[3].data = MulRow(3); + + return Result; + } +#endif // CXX11 + +namespace detail +{ + template + struct compute_inverse<4, 4, float, Q, true> + { + GLM_FUNC_QUALIFIER static mat<4, 4, float, Q> call(mat<4, 4, float, Q> const& m) + { + float32x4_t const& m0 = m[0].data; + float32x4_t const& m1 = m[1].data; + float32x4_t const& m2 = m[2].data; + float32x4_t const& m3 = m[3].data; + + // m[2][2] * m[3][3] - m[3][2] * m[2][3]; + // m[2][2] * m[3][3] - m[3][2] * m[2][3]; + // m[1][2] * m[3][3] - m[3][2] * m[1][3]; + // m[1][2] * m[2][3] - m[2][2] * m[1][3]; + + float32x4_t Fac0; + { + float32x4_t w0 = vcombine_f32(neon::dup_lane(m2, 2), neon::dup_lane(m1, 2)); + float32x4_t w1 = neon::copy_lane(neon::dupq_lane(m3, 3), 3, m2, 3); + float32x4_t w2 = neon::copy_lane(neon::dupq_lane(m3, 2), 3, m2, 2); + float32x4_t w3 = vcombine_f32(neon::dup_lane(m2, 3), neon::dup_lane(m1, 3)); + Fac0 = w0 * w1 - w2 * w3; + } + + // m[2][1] * m[3][3] - m[3][1] * m[2][3]; + // m[2][1] * m[3][3] - m[3][1] * m[2][3]; + // m[1][1] * m[3][3] - m[3][1] * m[1][3]; + // m[1][1] * m[2][3] - m[2][1] * m[1][3]; + + float32x4_t Fac1; + { + float32x4_t w0 = vcombine_f32(neon::dup_lane(m2, 1), neon::dup_lane(m1, 1)); + float32x4_t w1 = neon::copy_lane(neon::dupq_lane(m3, 3), 3, m2, 3); + float32x4_t w2 = neon::copy_lane(neon::dupq_lane(m3, 1), 3, m2, 1); + float32x4_t w3 = vcombine_f32(neon::dup_lane(m2, 3), neon::dup_lane(m1, 3)); + Fac1 = w0 * w1 - w2 * w3; + } + + // m[2][1] * m[3][2] - m[3][1] * m[2][2]; + // m[2][1] * m[3][2] - m[3][1] * m[2][2]; + // m[1][1] * m[3][2] - m[3][1] * m[1][2]; + // m[1][1] * m[2][2] - m[2][1] * m[1][2]; + + float32x4_t Fac2; + { + float32x4_t w0 = vcombine_f32(neon::dup_lane(m2, 1), neon::dup_lane(m1, 1)); + float32x4_t w1 = neon::copy_lane(neon::dupq_lane(m3, 2), 3, m2, 2); + float32x4_t w2 = neon::copy_lane(neon::dupq_lane(m3, 1), 3, m2, 1); + float32x4_t w3 = vcombine_f32(neon::dup_lane(m2, 2), neon::dup_lane(m1, 2)); + Fac2 = w0 * w1 - w2 * w3; + } + + // m[2][0] * m[3][3] - m[3][0] * m[2][3]; + // m[2][0] * m[3][3] - m[3][0] * m[2][3]; + // m[1][0] * m[3][3] - m[3][0] * m[1][3]; + // m[1][0] * m[2][3] - m[2][0] * m[1][3]; + + float32x4_t Fac3; + { + float32x4_t w0 = vcombine_f32(neon::dup_lane(m2, 0), neon::dup_lane(m1, 0)); + float32x4_t w1 = neon::copy_lane(neon::dupq_lane(m3, 3), 3, m2, 3); + float32x4_t w2 = neon::copy_lane(neon::dupq_lane(m3, 0), 3, m2, 0); + float32x4_t w3 = vcombine_f32(neon::dup_lane(m2, 3), neon::dup_lane(m1, 3)); + Fac3 = w0 * w1 - w2 * w3; + } + + // m[2][0] * m[3][2] - m[3][0] * m[2][2]; + // m[2][0] * m[3][2] - m[3][0] * m[2][2]; + // m[1][0] * m[3][2] - m[3][0] * m[1][2]; + // m[1][0] * m[2][2] - m[2][0] * m[1][2]; + + float32x4_t Fac4; + { + float32x4_t w0 = vcombine_f32(neon::dup_lane(m2, 0), neon::dup_lane(m1, 0)); + float32x4_t w1 = neon::copy_lane(neon::dupq_lane(m3, 2), 3, m2, 2); + float32x4_t w2 = neon::copy_lane(neon::dupq_lane(m3, 0), 3, m2, 0); + float32x4_t w3 = vcombine_f32(neon::dup_lane(m2, 2), neon::dup_lane(m1, 2)); + Fac4 = w0 * w1 - w2 * w3; + } + + // m[2][0] * m[3][1] - m[3][0] * m[2][1]; + // m[2][0] * m[3][1] - m[3][0] * m[2][1]; + // m[1][0] * m[3][1] - m[3][0] * m[1][1]; + // m[1][0] * m[2][1] - m[2][0] * m[1][1]; + + float32x4_t Fac5; + { + float32x4_t w0 = vcombine_f32(neon::dup_lane(m2, 0), neon::dup_lane(m1, 0)); + float32x4_t w1 = neon::copy_lane(neon::dupq_lane(m3, 1), 3, m2, 1); + float32x4_t w2 = neon::copy_lane(neon::dupq_lane(m3, 0), 3, m2, 0); + float32x4_t w3 = vcombine_f32(neon::dup_lane(m2, 1), neon::dup_lane(m1, 1)); + Fac5 = w0 * w1 - w2 * w3; + } + + float32x4_t Vec0 = neon::copy_lane(neon::dupq_lane(m0, 0), 0, m1, 0); // (m[1][0], m[0][0], m[0][0], m[0][0]); + float32x4_t Vec1 = neon::copy_lane(neon::dupq_lane(m0, 1), 0, m1, 1); // (m[1][1], m[0][1], m[0][1], m[0][1]); + float32x4_t Vec2 = neon::copy_lane(neon::dupq_lane(m0, 2), 0, m1, 2); // (m[1][2], m[0][2], m[0][2], m[0][2]); + float32x4_t Vec3 = neon::copy_lane(neon::dupq_lane(m0, 3), 0, m1, 3); // (m[1][3], m[0][3], m[0][3], m[0][3]); + + float32x4_t Inv0 = Vec1 * Fac0 - Vec2 * Fac1 + Vec3 * Fac2; + float32x4_t Inv1 = Vec0 * Fac0 - Vec2 * Fac3 + Vec3 * Fac4; + float32x4_t Inv2 = Vec0 * Fac1 - Vec1 * Fac3 + Vec3 * Fac5; + float32x4_t Inv3 = Vec0 * Fac2 - Vec1 * Fac4 + Vec2 * Fac5; + + float32x4_t r0 = float32x4_t{-1, +1, -1, +1} * Inv0; + float32x4_t r1 = float32x4_t{+1, -1, +1, -1} * Inv1; + float32x4_t r2 = float32x4_t{-1, +1, -1, +1} * Inv2; + float32x4_t r3 = float32x4_t{+1, -1, +1, -1} * Inv3; + + float32x4_t det = neon::mul_lane(r0, m0, 0); + det = neon::madd_lane(det, r1, m0, 1); + det = neon::madd_lane(det, r2, m0, 2); + det = neon::madd_lane(det, r3, m0, 3); + + float32x4_t rdet = vdupq_n_f32(1 / vgetq_lane_f32(det, 0)); + + mat<4, 4, float, Q> r; + r[0].data = vmulq_f32(r0, rdet); + r[1].data = vmulq_f32(r1, rdet); + r[2].data = vmulq_f32(r2, rdet); + r[3].data = vmulq_f32(r3, rdet); + return r; + } + }; +}//namespace detail +}//namespace glm +#endif diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_packing.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_packing.inl new file mode 100644 index 0000000000000000000000000000000000000000..234b093c081cc029ccf2094efbdb3d63b319431e --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_packing.inl @@ -0,0 +1,189 @@ +/// @ref core +/// @file glm/detail/func_packing.inl + +#include "../common.hpp" +#include "type_half.hpp" + +namespace glm +{ + GLM_FUNC_QUALIFIER uint packUnorm2x16(vec2 const& v) + { + union + { + unsigned short in[2]; + uint out; + } u; + + vec<2, unsigned short, defaultp> result(round(clamp(v, 0.0f, 1.0f) * 65535.0f)); + + u.in[0] = result[0]; + u.in[1] = result[1]; + + return u.out; + } + + GLM_FUNC_QUALIFIER vec2 unpackUnorm2x16(uint p) + { + union + { + uint in; + unsigned short out[2]; + } u; + + u.in = p; + + return vec2(u.out[0], u.out[1]) * 1.5259021896696421759365224689097e-5f; + } + + GLM_FUNC_QUALIFIER uint packSnorm2x16(vec2 const& v) + { + union + { + signed short in[2]; + uint out; + } u; + + vec<2, short, defaultp> result(round(clamp(v, -1.0f, 1.0f) * 32767.0f)); + + u.in[0] = result[0]; + u.in[1] = result[1]; + + return u.out; + } + + GLM_FUNC_QUALIFIER vec2 unpackSnorm2x16(uint p) + { + union + { + uint in; + signed short out[2]; + } u; + + u.in = p; + + return clamp(vec2(u.out[0], u.out[1]) * 3.0518509475997192297128208258309e-5f, -1.0f, 1.0f); + } + + GLM_FUNC_QUALIFIER uint packUnorm4x8(vec4 const& v) + { + union + { + unsigned char in[4]; + uint out; + } u; + + vec<4, unsigned char, defaultp> result(round(clamp(v, 0.0f, 1.0f) * 255.0f)); + + u.in[0] = result[0]; + u.in[1] = result[1]; + u.in[2] = result[2]; + u.in[3] = result[3]; + + return u.out; + } + + GLM_FUNC_QUALIFIER vec4 unpackUnorm4x8(uint p) + { + union + { + uint in; + unsigned char out[4]; + } u; + + u.in = p; + + return vec4(u.out[0], u.out[1], u.out[2], u.out[3]) * 0.0039215686274509803921568627451f; + } + + GLM_FUNC_QUALIFIER uint packSnorm4x8(vec4 const& v) + { + union + { + signed char in[4]; + uint out; + } u; + + vec<4, signed char, defaultp> result(round(clamp(v, -1.0f, 1.0f) * 127.0f)); + + u.in[0] = result[0]; + u.in[1] = result[1]; + u.in[2] = result[2]; + u.in[3] = result[3]; + + return u.out; + } + + GLM_FUNC_QUALIFIER glm::vec4 unpackSnorm4x8(uint p) + { + union + { + uint in; + signed char out[4]; + } u; + + u.in = p; + + return clamp(vec4(u.out[0], u.out[1], u.out[2], u.out[3]) * 0.0078740157480315f, -1.0f, 1.0f); + } + + GLM_FUNC_QUALIFIER double packDouble2x32(uvec2 const& v) + { + union + { + uint in[2]; + double out; + } u; + + u.in[0] = v[0]; + u.in[1] = v[1]; + + return u.out; + } + + GLM_FUNC_QUALIFIER uvec2 unpackDouble2x32(double v) + { + union + { + double in; + uint out[2]; + } u; + + u.in = v; + + return uvec2(u.out[0], u.out[1]); + } + + GLM_FUNC_QUALIFIER uint packHalf2x16(vec2 const& v) + { + union + { + signed short in[2]; + uint out; + } u; + + u.in[0] = detail::toFloat16(v.x); + u.in[1] = detail::toFloat16(v.y); + + return u.out; + } + + GLM_FUNC_QUALIFIER vec2 unpackHalf2x16(uint v) + { + union + { + uint in; + signed short out[2]; + } u; + + u.in = v; + + return vec2( + detail::toFloat32(u.out[0]), + detail::toFloat32(u.out[1])); + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "func_packing_simd.inl" +#endif + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_packing_simd.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_packing_simd.inl new file mode 100644 index 0000000000000000000000000000000000000000..fd0fe8b7d9b4a49f032fd678b7bd6a51624a6b53 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_packing_simd.inl @@ -0,0 +1,6 @@ +namespace glm{ +namespace detail +{ + +}//namespace detail +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_trigonometric.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_trigonometric.inl new file mode 100644 index 0000000000000000000000000000000000000000..e129dceac5cb2ae09dd4154cf3356173317b9801 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_trigonometric.inl @@ -0,0 +1,197 @@ +#include "_vectorize.hpp" +#include +#include + +namespace glm +{ + // radians + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType radians(genType degrees) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'radians' only accept floating-point input"); + + return degrees * static_cast(0.01745329251994329576923690768489); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec radians(vec const& v) + { + return detail::functor1::call(radians, v); + } + + // degrees + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType degrees(genType radians) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'degrees' only accept floating-point input"); + + return radians * static_cast(57.295779513082320876798154814105); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec degrees(vec const& v) + { + return detail::functor1::call(degrees, v); + } + + // sin + using ::std::sin; + + template + GLM_FUNC_QUALIFIER vec sin(vec const& v) + { + return detail::functor1::call(sin, v); + } + + // cos + using std::cos; + + template + GLM_FUNC_QUALIFIER vec cos(vec const& v) + { + return detail::functor1::call(cos, v); + } + + // tan + using std::tan; + + template + GLM_FUNC_QUALIFIER vec tan(vec const& v) + { + return detail::functor1::call(tan, v); + } + + // asin + using std::asin; + + template + GLM_FUNC_QUALIFIER vec asin(vec const& v) + { + return detail::functor1::call(asin, v); + } + + // acos + using std::acos; + + template + GLM_FUNC_QUALIFIER vec acos(vec const& v) + { + return detail::functor1::call(acos, v); + } + + // atan + template + GLM_FUNC_QUALIFIER genType atan(genType y, genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'atan' only accept floating-point input"); + + return ::std::atan2(y, x); + } + + template + GLM_FUNC_QUALIFIER vec atan(vec const& a, vec const& b) + { + return detail::functor2::call(::std::atan2, a, b); + } + + using std::atan; + + template + GLM_FUNC_QUALIFIER vec atan(vec const& v) + { + return detail::functor1::call(atan, v); + } + + // sinh + using std::sinh; + + template + GLM_FUNC_QUALIFIER vec sinh(vec const& v) + { + return detail::functor1::call(sinh, v); + } + + // cosh + using std::cosh; + + template + GLM_FUNC_QUALIFIER vec cosh(vec const& v) + { + return detail::functor1::call(cosh, v); + } + + // tanh + using std::tanh; + + template + GLM_FUNC_QUALIFIER vec tanh(vec const& v) + { + return detail::functor1::call(tanh, v); + } + + // asinh +# if GLM_HAS_CXX11_STL + using std::asinh; +# else + template + GLM_FUNC_QUALIFIER genType asinh(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'asinh' only accept floating-point input"); + + return (x < static_cast(0) ? static_cast(-1) : (x > static_cast(0) ? static_cast(1) : static_cast(0))) * log(std::abs(x) + sqrt(static_cast(1) + x * x)); + } +# endif + + template + GLM_FUNC_QUALIFIER vec asinh(vec const& v) + { + return detail::functor1::call(asinh, v); + } + + // acosh +# if GLM_HAS_CXX11_STL + using std::acosh; +# else + template + GLM_FUNC_QUALIFIER genType acosh(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acosh' only accept floating-point input"); + + if(x < static_cast(1)) + return static_cast(0); + return log(x + sqrt(x * x - static_cast(1))); + } +# endif + + template + GLM_FUNC_QUALIFIER vec acosh(vec const& v) + { + return detail::functor1::call(acosh, v); + } + + // atanh +# if GLM_HAS_CXX11_STL + using std::atanh; +# else + template + GLM_FUNC_QUALIFIER genType atanh(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'atanh' only accept floating-point input"); + + if(std::abs(x) >= static_cast(1)) + return 0; + return static_cast(0.5) * log((static_cast(1) + x) / (static_cast(1) - x)); + } +# endif + + template + GLM_FUNC_QUALIFIER vec atanh(vec const& v) + { + return detail::functor1::call(atanh, v); + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "func_trigonometric_simd.inl" +#endif + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_trigonometric_simd.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_trigonometric_simd.inl new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_vector_relational.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_vector_relational.inl new file mode 100644 index 0000000000000000000000000000000000000000..80c9e87fcb97ea042c1aaf42fd6424ebc0bc6e32 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_vector_relational.inl @@ -0,0 +1,87 @@ +namespace glm +{ + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec lessThan(vec const& x, vec const& y) + { + vec Result(true); + for(length_t i = 0; i < L; ++i) + Result[i] = x[i] < y[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec lessThanEqual(vec const& x, vec const& y) + { + vec Result(true); + for(length_t i = 0; i < L; ++i) + Result[i] = x[i] <= y[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec greaterThan(vec const& x, vec const& y) + { + vec Result(true); + for(length_t i = 0; i < L; ++i) + Result[i] = x[i] > y[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec greaterThanEqual(vec const& x, vec const& y) + { + vec Result(true); + for(length_t i = 0; i < L; ++i) + Result[i] = x[i] >= y[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(vec const& x, vec const& y) + { + vec Result(true); + for(length_t i = 0; i < L; ++i) + Result[i] = x[i] == y[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y) + { + vec Result(true); + for(length_t i = 0; i < L; ++i) + Result[i] = x[i] != y[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool any(vec const& v) + { + bool Result = false; + for(length_t i = 0; i < L; ++i) + Result = Result || v[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool all(vec const& v) + { + bool Result = true; + for(length_t i = 0; i < L; ++i) + Result = Result && v[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec not_(vec const& v) + { + vec Result(true); + for(length_t i = 0; i < L; ++i) + Result[i] = !v[i]; + return Result; + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "func_vector_relational_simd.inl" +#endif diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_vector_relational_simd.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_vector_relational_simd.inl new file mode 100644 index 0000000000000000000000000000000000000000..fd0fe8b7d9b4a49f032fd678b7bd6a51624a6b53 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/func_vector_relational_simd.inl @@ -0,0 +1,6 @@ +namespace glm{ +namespace detail +{ + +}//namespace detail +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/glm.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/glm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e0755bd65d4675232490a4a9ff944506e632e5f5 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/glm.cpp @@ -0,0 +1,263 @@ +/// @ref core +/// @file glm/glm.cpp + +#ifndef GLM_ENABLE_EXPERIMENTAL +#define GLM_ENABLE_EXPERIMENTAL +#endif +#include +#include +#include +#include +#include +#include + +namespace glm +{ +// tvec1 type explicit instantiation +template struct vec<1, uint8, lowp>; +template struct vec<1, uint16, lowp>; +template struct vec<1, uint32, lowp>; +template struct vec<1, uint64, lowp>; +template struct vec<1, int8, lowp>; +template struct vec<1, int16, lowp>; +template struct vec<1, int32, lowp>; +template struct vec<1, int64, lowp>; +template struct vec<1, float32, lowp>; +template struct vec<1, float64, lowp>; + +template struct vec<1, uint8, mediump>; +template struct vec<1, uint16, mediump>; +template struct vec<1, uint32, mediump>; +template struct vec<1, uint64, mediump>; +template struct vec<1, int8, mediump>; +template struct vec<1, int16, mediump>; +template struct vec<1, int32, mediump>; +template struct vec<1, int64, mediump>; +template struct vec<1, float32, mediump>; +template struct vec<1, float64, mediump>; + +template struct vec<1, uint8, highp>; +template struct vec<1, uint16, highp>; +template struct vec<1, uint32, highp>; +template struct vec<1, uint64, highp>; +template struct vec<1, int8, highp>; +template struct vec<1, int16, highp>; +template struct vec<1, int32, highp>; +template struct vec<1, int64, highp>; +template struct vec<1, float32, highp>; +template struct vec<1, float64, highp>; + +// tvec2 type explicit instantiation +template struct vec<2, uint8, lowp>; +template struct vec<2, uint16, lowp>; +template struct vec<2, uint32, lowp>; +template struct vec<2, uint64, lowp>; +template struct vec<2, int8, lowp>; +template struct vec<2, int16, lowp>; +template struct vec<2, int32, lowp>; +template struct vec<2, int64, lowp>; +template struct vec<2, float32, lowp>; +template struct vec<2, float64, lowp>; + +template struct vec<2, uint8, mediump>; +template struct vec<2, uint16, mediump>; +template struct vec<2, uint32, mediump>; +template struct vec<2, uint64, mediump>; +template struct vec<2, int8, mediump>; +template struct vec<2, int16, mediump>; +template struct vec<2, int32, mediump>; +template struct vec<2, int64, mediump>; +template struct vec<2, float32, mediump>; +template struct vec<2, float64, mediump>; + +template struct vec<2, uint8, highp>; +template struct vec<2, uint16, highp>; +template struct vec<2, uint32, highp>; +template struct vec<2, uint64, highp>; +template struct vec<2, int8, highp>; +template struct vec<2, int16, highp>; +template struct vec<2, int32, highp>; +template struct vec<2, int64, highp>; +template struct vec<2, float32, highp>; +template struct vec<2, float64, highp>; + +// tvec3 type explicit instantiation +template struct vec<3, uint8, lowp>; +template struct vec<3, uint16, lowp>; +template struct vec<3, uint32, lowp>; +template struct vec<3, uint64, lowp>; +template struct vec<3, int8, lowp>; +template struct vec<3, int16, lowp>; +template struct vec<3, int32, lowp>; +template struct vec<3, int64, lowp>; +template struct vec<3, float32, lowp>; +template struct vec<3, float64, lowp>; + +template struct vec<3, uint8, mediump>; +template struct vec<3, uint16, mediump>; +template struct vec<3, uint32, mediump>; +template struct vec<3, uint64, mediump>; +template struct vec<3, int8, mediump>; +template struct vec<3, int16, mediump>; +template struct vec<3, int32, mediump>; +template struct vec<3, int64, mediump>; +template struct vec<3, float32, mediump>; +template struct vec<3, float64, mediump>; + +template struct vec<3, uint8, highp>; +template struct vec<3, uint16, highp>; +template struct vec<3, uint32, highp>; +template struct vec<3, uint64, highp>; +template struct vec<3, int8, highp>; +template struct vec<3, int16, highp>; +template struct vec<3, int32, highp>; +template struct vec<3, int64, highp>; +template struct vec<3, float32, highp>; +template struct vec<3, float64, highp>; + +// tvec4 type explicit instantiation +template struct vec<4, uint8, lowp>; +template struct vec<4, uint16, lowp>; +template struct vec<4, uint32, lowp>; +template struct vec<4, uint64, lowp>; +template struct vec<4, int8, lowp>; +template struct vec<4, int16, lowp>; +template struct vec<4, int32, lowp>; +template struct vec<4, int64, lowp>; +template struct vec<4, float32, lowp>; +template struct vec<4, float64, lowp>; + +template struct vec<4, uint8, mediump>; +template struct vec<4, uint16, mediump>; +template struct vec<4, uint32, mediump>; +template struct vec<4, uint64, mediump>; +template struct vec<4, int8, mediump>; +template struct vec<4, int16, mediump>; +template struct vec<4, int32, mediump>; +template struct vec<4, int64, mediump>; +template struct vec<4, float32, mediump>; +template struct vec<4, float64, mediump>; + +template struct vec<4, uint8, highp>; +template struct vec<4, uint16, highp>; +template struct vec<4, uint32, highp>; +template struct vec<4, uint64, highp>; +template struct vec<4, int8, highp>; +template struct vec<4, int16, highp>; +template struct vec<4, int32, highp>; +template struct vec<4, int64, highp>; +template struct vec<4, float32, highp>; +template struct vec<4, float64, highp>; + +// tmat2x2 type explicit instantiation +template struct mat<2, 2, float32, lowp>; +template struct mat<2, 2, float64, lowp>; + +template struct mat<2, 2, float32, mediump>; +template struct mat<2, 2, float64, mediump>; + +template struct mat<2, 2, float32, highp>; +template struct mat<2, 2, float64, highp>; + +// tmat2x3 type explicit instantiation +template struct mat<2, 3, float32, lowp>; +template struct mat<2, 3, float64, lowp>; + +template struct mat<2, 3, float32, mediump>; +template struct mat<2, 3, float64, mediump>; + +template struct mat<2, 3, float32, highp>; +template struct mat<2, 3, float64, highp>; + +// tmat2x4 type explicit instantiation +template struct mat<2, 4, float32, lowp>; +template struct mat<2, 4, float64, lowp>; + +template struct mat<2, 4, float32, mediump>; +template struct mat<2, 4, float64, mediump>; + +template struct mat<2, 4, float32, highp>; +template struct mat<2, 4, float64, highp>; + +// tmat3x2 type explicit instantiation +template struct mat<3, 2, float32, lowp>; +template struct mat<3, 2, float64, lowp>; + +template struct mat<3, 2, float32, mediump>; +template struct mat<3, 2, float64, mediump>; + +template struct mat<3, 2, float32, highp>; +template struct mat<3, 2, float64, highp>; + +// tmat3x3 type explicit instantiation +template struct mat<3, 3, float32, lowp>; +template struct mat<3, 3, float64, lowp>; + +template struct mat<3, 3, float32, mediump>; +template struct mat<3, 3, float64, mediump>; + +template struct mat<3, 3, float32, highp>; +template struct mat<3, 3, float64, highp>; + +// tmat3x4 type explicit instantiation +template struct mat<3, 4, float32, lowp>; +template struct mat<3, 4, float64, lowp>; + +template struct mat<3, 4, float32, mediump>; +template struct mat<3, 4, float64, mediump>; + +template struct mat<3, 4, float32, highp>; +template struct mat<3, 4, float64, highp>; + +// tmat4x2 type explicit instantiation +template struct mat<4, 2, float32, lowp>; +template struct mat<4, 2, float64, lowp>; + +template struct mat<4, 2, float32, mediump>; +template struct mat<4, 2, float64, mediump>; + +template struct mat<4, 2, float32, highp>; +template struct mat<4, 2, float64, highp>; + +// tmat4x3 type explicit instantiation +template struct mat<4, 3, float32, lowp>; +template struct mat<4, 3, float64, lowp>; + +template struct mat<4, 3, float32, mediump>; +template struct mat<4, 3, float64, mediump>; + +template struct mat<4, 3, float32, highp>; +template struct mat<4, 3, float64, highp>; + +// tmat4x4 type explicit instantiation +template struct mat<4, 4, float32, lowp>; +template struct mat<4, 4, float64, lowp>; + +template struct mat<4, 4, float32, mediump>; +template struct mat<4, 4, float64, mediump>; + +template struct mat<4, 4, float32, highp>; +template struct mat<4, 4, float64, highp>; + +// tquat type explicit instantiation +template struct qua; +template struct qua; + +template struct qua; +template struct qua; + +template struct qua; +template struct qua; + +//tdualquat type explicit instantiation +template struct tdualquat; +template struct tdualquat; + +template struct tdualquat; +template struct tdualquat; + +template struct tdualquat; +template struct tdualquat; + +}//namespace glm + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/qualifier.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/qualifier.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a6c96cca5c2e27fdf8a454889ac34d4577a699b2 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/qualifier.hpp @@ -0,0 +1,229 @@ +#pragma once + +#include "setup.hpp" + +namespace glm +{ + /// Qualify GLM types in term of alignment (packed, aligned) and precision in term of ULPs (lowp, mediump, highp) + enum qualifier + { + packed_highp, ///< Typed data is tightly packed in memory and operations are executed with high precision in term of ULPs + packed_mediump, ///< Typed data is tightly packed in memory and operations are executed with medium precision in term of ULPs for higher performance + packed_lowp, ///< Typed data is tightly packed in memory and operations are executed with low precision in term of ULPs to maximize performance + +# if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE + aligned_highp, ///< Typed data is aligned in memory allowing SIMD optimizations and operations are executed with high precision in term of ULPs + aligned_mediump, ///< Typed data is aligned in memory allowing SIMD optimizations and operations are executed with high precision in term of ULPs for higher performance + aligned_lowp, // ///< Typed data is aligned in memory allowing SIMD optimizations and operations are executed with high precision in term of ULPs to maximize performance + aligned = aligned_highp, ///< By default aligned qualifier is also high precision +# endif + + highp = packed_highp, ///< By default highp qualifier is also packed + mediump = packed_mediump, ///< By default mediump qualifier is also packed + lowp = packed_lowp, ///< By default lowp qualifier is also packed + packed = packed_highp, ///< By default packed qualifier is also high precision + +# if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE && defined(GLM_FORCE_DEFAULT_ALIGNED_GENTYPES) + defaultp = aligned_highp +# else + defaultp = highp +# endif + }; + + typedef qualifier precision; + + template struct vec; + template struct mat; + template struct qua; + +# if GLM_HAS_TEMPLATE_ALIASES + template using tvec1 = vec<1, T, Q>; + template using tvec2 = vec<2, T, Q>; + template using tvec3 = vec<3, T, Q>; + template using tvec4 = vec<4, T, Q>; + template using tmat2x2 = mat<2, 2, T, Q>; + template using tmat2x3 = mat<2, 3, T, Q>; + template using tmat2x4 = mat<2, 4, T, Q>; + template using tmat3x2 = mat<3, 2, T, Q>; + template using tmat3x3 = mat<3, 3, T, Q>; + template using tmat3x4 = mat<3, 4, T, Q>; + template using tmat4x2 = mat<4, 2, T, Q>; + template using tmat4x3 = mat<4, 3, T, Q>; + template using tmat4x4 = mat<4, 4, T, Q>; + template using tquat = qua; +# endif + +namespace detail +{ + template + struct is_aligned + { + static const bool value = false; + }; + +# if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE + template<> + struct is_aligned + { + static const bool value = true; + }; + + template<> + struct is_aligned + { + static const bool value = true; + }; + + template<> + struct is_aligned + { + static const bool value = true; + }; +# endif + + template + struct storage + { + typedef struct type { + T data[L]; + } type; + }; + +# if GLM_HAS_ALIGNOF + template + struct storage + { + typedef struct alignas(L * sizeof(T)) type { + T data[L]; + } type; + }; + + template + struct storage<3, T, true> + { + typedef struct alignas(4 * sizeof(T)) type { + T data[4]; + } type; + }; +# endif + +# if GLM_ARCH & GLM_ARCH_SSE2_BIT + template<> + struct storage<4, float, true> + { + typedef glm_f32vec4 type; + }; + + template<> + struct storage<4, int, true> + { + typedef glm_i32vec4 type; + }; + + template<> + struct storage<4, unsigned int, true> + { + typedef glm_u32vec4 type; + }; + + template<> + struct storage<2, double, true> + { + typedef glm_f64vec2 type; + }; + + template<> + struct storage<2, detail::int64, true> + { + typedef glm_i64vec2 type; + }; + + template<> + struct storage<2, detail::uint64, true> + { + typedef glm_u64vec2 type; + }; +# endif +# if (GLM_ARCH & GLM_ARCH_AVX_BIT) + template<> + struct storage<4, double, true> + { + typedef glm_f64vec4 type; + }; +# endif + +# if (GLM_ARCH & GLM_ARCH_AVX2_BIT) + template<> + struct storage<4, detail::int64, true> + { + typedef glm_i64vec4 type; + }; + + template<> + struct storage<4, detail::uint64, true> + { + typedef glm_u64vec4 type; + }; +# endif + +# if GLM_ARCH & GLM_ARCH_NEON_BIT + template<> + struct storage<4, float, true> + { + typedef glm_f32vec4 type; + }; + + template<> + struct storage<4, int, true> + { + typedef glm_i32vec4 type; + }; + + template<> + struct storage<4, unsigned int, true> + { + typedef glm_u32vec4 type; + }; +# endif + + enum genTypeEnum + { + GENTYPE_VEC, + GENTYPE_MAT, + GENTYPE_QUAT + }; + + template + struct genTypeTrait + {}; + + template + struct genTypeTrait > + { + static const genTypeEnum GENTYPE = GENTYPE_MAT; + }; + + template + struct init_gentype + { + }; + + template + struct init_gentype + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static genType identity() + { + return genType(1, 0, 0, 0); + } + }; + + template + struct init_gentype + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static genType identity() + { + return genType(1); + } + }; +}//namespace detail +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/setup.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/setup.hpp new file mode 100644 index 0000000000000000000000000000000000000000..77b1add308839175c564901a7e4a3a8f9ef51f5a --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/setup.hpp @@ -0,0 +1,1184 @@ +#ifndef GLM_SETUP_INCLUDED + +#include +#include + +#define GLM_VERSION_MAJOR 0 +#define GLM_VERSION_MINOR 9 +#define GLM_VERSION_PATCH 9 +#define GLM_VERSION_REVISION 9 +#define GLM_VERSION 999 +#define GLM_VERSION_MESSAGE "GLM: version 0.9.9.9" + +#define GLM_SETUP_INCLUDED GLM_VERSION + +/////////////////////////////////////////////////////////////////////////////////// +// Active states + +#define GLM_DISABLE 0 +#define GLM_ENABLE 1 + +/////////////////////////////////////////////////////////////////////////////////// +// Messages + +#if defined(GLM_FORCE_MESSAGES) +# define GLM_MESSAGES GLM_ENABLE +#else +# define GLM_MESSAGES GLM_DISABLE +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Detect the platform + +#include "../simd/platform.h" + +/////////////////////////////////////////////////////////////////////////////////// +// Build model + +#if defined(_M_ARM64) || defined(__LP64__) || defined(_M_X64) || defined(__ppc64__) || defined(__x86_64__) +# define GLM_MODEL GLM_MODEL_64 +#elif defined(__i386__) || defined(__ppc__) || defined(__ILP32__) || defined(_M_ARM) +# define GLM_MODEL GLM_MODEL_32 +#else +# define GLM_MODEL GLM_MODEL_32 +#endif// + +#if !defined(GLM_MODEL) && GLM_COMPILER != 0 +# error "GLM_MODEL undefined, your compiler may not be supported by GLM. Add #define GLM_MODEL 0 to ignore this message." +#endif//GLM_MODEL + +/////////////////////////////////////////////////////////////////////////////////// +// C++ Version + +// User defines: GLM_FORCE_CXX98, GLM_FORCE_CXX03, GLM_FORCE_CXX11, GLM_FORCE_CXX14, GLM_FORCE_CXX17, GLM_FORCE_CXX2A + +#define GLM_LANG_CXX98_FLAG (1 << 1) +#define GLM_LANG_CXX03_FLAG (1 << 2) +#define GLM_LANG_CXX0X_FLAG (1 << 3) +#define GLM_LANG_CXX11_FLAG (1 << 4) +#define GLM_LANG_CXX14_FLAG (1 << 5) +#define GLM_LANG_CXX17_FLAG (1 << 6) +#define GLM_LANG_CXX2A_FLAG (1 << 7) +#define GLM_LANG_CXXMS_FLAG (1 << 8) +#define GLM_LANG_CXXGNU_FLAG (1 << 9) + +#define GLM_LANG_CXX98 GLM_LANG_CXX98_FLAG +#define GLM_LANG_CXX03 (GLM_LANG_CXX98 | GLM_LANG_CXX03_FLAG) +#define GLM_LANG_CXX0X (GLM_LANG_CXX03 | GLM_LANG_CXX0X_FLAG) +#define GLM_LANG_CXX11 (GLM_LANG_CXX0X | GLM_LANG_CXX11_FLAG) +#define GLM_LANG_CXX14 (GLM_LANG_CXX11 | GLM_LANG_CXX14_FLAG) +#define GLM_LANG_CXX17 (GLM_LANG_CXX14 | GLM_LANG_CXX17_FLAG) +#define GLM_LANG_CXX2A (GLM_LANG_CXX17 | GLM_LANG_CXX2A_FLAG) +#define GLM_LANG_CXXMS GLM_LANG_CXXMS_FLAG +#define GLM_LANG_CXXGNU GLM_LANG_CXXGNU_FLAG + +#if (defined(_MSC_EXTENSIONS)) +# define GLM_LANG_EXT GLM_LANG_CXXMS_FLAG +#elif ((GLM_COMPILER & (GLM_COMPILER_CLANG | GLM_COMPILER_GCC)) && (GLM_ARCH & GLM_ARCH_SIMD_BIT)) +# define GLM_LANG_EXT GLM_LANG_CXXMS_FLAG +#else +# define GLM_LANG_EXT 0 +#endif + +#if (defined(GLM_FORCE_CXX_UNKNOWN)) +# define GLM_LANG 0 +#elif defined(GLM_FORCE_CXX2A) +# define GLM_LANG (GLM_LANG_CXX2A | GLM_LANG_EXT) +# define GLM_LANG_STL11_FORCED +#elif defined(GLM_FORCE_CXX17) +# define GLM_LANG (GLM_LANG_CXX17 | GLM_LANG_EXT) +# define GLM_LANG_STL11_FORCED +#elif defined(GLM_FORCE_CXX14) +# define GLM_LANG (GLM_LANG_CXX14 | GLM_LANG_EXT) +# define GLM_LANG_STL11_FORCED +#elif defined(GLM_FORCE_CXX11) +# define GLM_LANG (GLM_LANG_CXX11 | GLM_LANG_EXT) +# define GLM_LANG_STL11_FORCED +#elif defined(GLM_FORCE_CXX03) +# define GLM_LANG (GLM_LANG_CXX03 | GLM_LANG_EXT) +#elif defined(GLM_FORCE_CXX98) +# define GLM_LANG (GLM_LANG_CXX98 | GLM_LANG_EXT) +#else +# if GLM_COMPILER & GLM_COMPILER_VC && defined(_MSVC_LANG) +# if GLM_COMPILER >= GLM_COMPILER_VC15_7 +# define GLM_LANG_PLATFORM _MSVC_LANG +# elif GLM_COMPILER >= GLM_COMPILER_VC15 +# if _MSVC_LANG > 201402L +# define GLM_LANG_PLATFORM 201402L +# else +# define GLM_LANG_PLATFORM _MSVC_LANG +# endif +# else +# define GLM_LANG_PLATFORM 0 +# endif +# else +# define GLM_LANG_PLATFORM 0 +# endif + +# if __cplusplus > 201703L || GLM_LANG_PLATFORM > 201703L +# define GLM_LANG (GLM_LANG_CXX2A | GLM_LANG_EXT) +# elif __cplusplus == 201703L || GLM_LANG_PLATFORM == 201703L +# define GLM_LANG (GLM_LANG_CXX17 | GLM_LANG_EXT) +# elif __cplusplus == 201402L || __cplusplus == 201406L || __cplusplus == 201500L || GLM_LANG_PLATFORM == 201402L +# define GLM_LANG (GLM_LANG_CXX14 | GLM_LANG_EXT) +# elif __cplusplus == 201103L || GLM_LANG_PLATFORM == 201103L +# define GLM_LANG (GLM_LANG_CXX11 | GLM_LANG_EXT) +# elif defined(__INTEL_CXX11_MODE__) || defined(_MSC_VER) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define GLM_LANG (GLM_LANG_CXX0X | GLM_LANG_EXT) +# elif __cplusplus == 199711L +# define GLM_LANG (GLM_LANG_CXX98 | GLM_LANG_EXT) +# else +# define GLM_LANG (0 | GLM_LANG_EXT) +# endif +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Has of C++ features + +// http://clang.llvm.org/cxx_status.html +// http://gcc.gnu.org/projects/cxx0x.html +// http://msdn.microsoft.com/en-us/library/vstudio/hh567368(v=vs.120).aspx + +// Android has multiple STLs but C++11 STL detection doesn't always work #284 #564 +#if GLM_PLATFORM == GLM_PLATFORM_ANDROID && !defined(GLM_LANG_STL11_FORCED) +# define GLM_HAS_CXX11_STL 0 +#elif (GLM_COMPILER & GLM_COMPILER_CUDA_RTC) == GLM_COMPILER_CUDA_RTC +# define GLM_HAS_CXX11_STL 0 +#elif (GLM_COMPILER & GLM_COMPILER_HIP) +# define GLM_HAS_CXX11_STL 0 +#elif GLM_COMPILER & GLM_COMPILER_CLANG +# if (defined(_LIBCPP_VERSION) || (GLM_LANG & GLM_LANG_CXX11_FLAG) || defined(GLM_LANG_STL11_FORCED)) +# define GLM_HAS_CXX11_STL 1 +# else +# define GLM_HAS_CXX11_STL 0 +# endif +#elif GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_CXX11_STL 1 +#else +# define GLM_HAS_CXX11_STL ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + ((GLM_COMPILER & GLM_COMPILER_GCC) && (GLM_COMPILER >= GLM_COMPILER_GCC48)) || \ + ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC12)) || \ + ((GLM_PLATFORM != GLM_PLATFORM_WINDOWS) && (GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_COMPILER >= GLM_COMPILER_INTEL15)))) +#endif + +// N1720 +#if GLM_COMPILER & GLM_COMPILER_CLANG +# define GLM_HAS_STATIC_ASSERT __has_feature(cxx_static_assert) +#elif GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_STATIC_ASSERT 1 +#else +# define GLM_HAS_STATIC_ASSERT ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + ((GLM_COMPILER & GLM_COMPILER_CUDA)) || \ + ((GLM_COMPILER & GLM_COMPILER_VC)) || \ + ((GLM_COMPILER & GLM_COMPILER_HIP)))) +#endif + +// N1988 +#if GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_EXTENDED_INTEGER_TYPE 1 +#else +# define GLM_HAS_EXTENDED_INTEGER_TYPE (\ + ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (GLM_COMPILER & GLM_COMPILER_VC)) || \ + ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (GLM_COMPILER & GLM_COMPILER_CUDA)) || \ + ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (GLM_COMPILER & GLM_COMPILER_CLANG)) || \ + ((GLM_COMPILER & GLM_COMPILER_HIP))) +#endif + +// N2672 Initializer lists http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2672.htm +#if GLM_COMPILER & GLM_COMPILER_CLANG +# define GLM_HAS_INITIALIZER_LISTS __has_feature(cxx_generalized_initializers) +#elif GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_INITIALIZER_LISTS 1 +#else +# define GLM_HAS_INITIALIZER_LISTS ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC15)) || \ + ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_COMPILER >= GLM_COMPILER_INTEL14)) || \ + ((GLM_COMPILER & GLM_COMPILER_CUDA)) || \ + ((GLM_COMPILER & GLM_COMPILER_HIP)))) +#endif + +// N2544 Unrestricted unions http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf +#if GLM_COMPILER & GLM_COMPILER_CLANG +# define GLM_HAS_UNRESTRICTED_UNIONS __has_feature(cxx_unrestricted_unions) +#elif GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_UNRESTRICTED_UNIONS 1 +#else +# define GLM_HAS_UNRESTRICTED_UNIONS (GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + (GLM_COMPILER & GLM_COMPILER_VC) || \ + ((GLM_COMPILER & GLM_COMPILER_CUDA)) || \ + ((GLM_COMPILER & GLM_COMPILER_HIP))) +#endif + +// N2346 +#if GLM_COMPILER & GLM_COMPILER_CLANG +# define GLM_HAS_DEFAULTED_FUNCTIONS __has_feature(cxx_defaulted_functions) +#elif GLM_COMPILER & GLM_COMPILER_CUDA + // Do not use defaulted functions for CUDA compiler when function qualifiers are present +# define GLM_HAS_DEFAULTED_FUNCTIONS 0 +#elif GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_DEFAULTED_FUNCTIONS 1 +#else +# define GLM_HAS_DEFAULTED_FUNCTIONS ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC12)) || \ + ((GLM_COMPILER & GLM_COMPILER_INTEL)) || \ + ((GLM_COMPILER & GLM_COMPILER_HIP)))) +#endif + +// N2118 +#if GLM_COMPILER & GLM_COMPILER_CLANG +# define GLM_HAS_RVALUE_REFERENCES __has_feature(cxx_rvalue_references) +#elif GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_RVALUE_REFERENCES 1 +#else +# define GLM_HAS_RVALUE_REFERENCES ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + ((GLM_COMPILER & GLM_COMPILER_VC)) || \ + ((GLM_COMPILER & GLM_COMPILER_CUDA)) || \ + ((GLM_COMPILER & GLM_COMPILER_HIP)))) +#endif + +// N2437 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2437.pdf +#if GLM_COMPILER & GLM_COMPILER_CLANG +# define GLM_HAS_EXPLICIT_CONVERSION_OPERATORS __has_feature(cxx_explicit_conversions) +#elif GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_EXPLICIT_CONVERSION_OPERATORS 1 +#else +# define GLM_HAS_EXPLICIT_CONVERSION_OPERATORS ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_COMPILER >= GLM_COMPILER_INTEL14)) || \ + ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC12)) || \ + ((GLM_COMPILER & GLM_COMPILER_CUDA)) || \ + ((GLM_COMPILER & GLM_COMPILER_HIP)))) +#endif + +// N2258 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2258.pdf +#if GLM_COMPILER & GLM_COMPILER_CLANG +# define GLM_HAS_TEMPLATE_ALIASES __has_feature(cxx_alias_templates) +#elif GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_TEMPLATE_ALIASES 1 +#else +# define GLM_HAS_TEMPLATE_ALIASES ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + ((GLM_COMPILER & GLM_COMPILER_INTEL)) || \ + ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC12)) || \ + ((GLM_COMPILER & GLM_COMPILER_CUDA)) || \ + ((GLM_COMPILER & GLM_COMPILER_HIP)))) +#endif + +// N2930 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2930.html +#if GLM_COMPILER & GLM_COMPILER_CLANG +# define GLM_HAS_RANGE_FOR __has_feature(cxx_range_for) +#elif GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_RANGE_FOR 1 +#else +# define GLM_HAS_RANGE_FOR ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + ((GLM_COMPILER & GLM_COMPILER_INTEL)) || \ + ((GLM_COMPILER & GLM_COMPILER_VC)) || \ + ((GLM_COMPILER & GLM_COMPILER_CUDA)) || \ + ((GLM_COMPILER & GLM_COMPILER_HIP)))) +#endif + +// N2341 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2341.pdf +#if GLM_COMPILER & GLM_COMPILER_CLANG +# define GLM_HAS_ALIGNOF __has_feature(cxx_alignas) +#elif GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_ALIGNOF 1 +#else +# define GLM_HAS_ALIGNOF ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_COMPILER >= GLM_COMPILER_INTEL15)) || \ + ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC14)) || \ + ((GLM_COMPILER & GLM_COMPILER_CUDA)) || \ + ((GLM_COMPILER & GLM_COMPILER_HIP)))) +#endif + +// N2235 Generalized Constant Expressions http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf +// N3652 Extended Constant Expressions http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3652.html +#if (GLM_ARCH & GLM_ARCH_SIMD_BIT) // Compiler SIMD intrinsics don't support constexpr... +# define GLM_HAS_CONSTEXPR 0 +#elif (GLM_COMPILER & GLM_COMPILER_CLANG) +# define GLM_HAS_CONSTEXPR __has_feature(cxx_relaxed_constexpr) +#elif (GLM_LANG & GLM_LANG_CXX14_FLAG) +# define GLM_HAS_CONSTEXPR 1 +#else +# define GLM_HAS_CONSTEXPR ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && GLM_HAS_INITIALIZER_LISTS && (\ + ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_COMPILER >= GLM_COMPILER_INTEL17)) || \ + ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC15)))) +#endif + +#if GLM_HAS_CONSTEXPR +# define GLM_CONSTEXPR constexpr +#else +# define GLM_CONSTEXPR +#endif + +// +#if GLM_HAS_CONSTEXPR +# if (GLM_COMPILER & GLM_COMPILER_CLANG) +# if __has_feature(cxx_if_constexpr) +# define GLM_HAS_IF_CONSTEXPR 1 +# else +# define GLM_HAS_IF_CONSTEXPR 0 +# endif +# elif (GLM_LANG & GLM_LANG_CXX17_FLAG) +# define GLM_HAS_IF_CONSTEXPR 1 +# else +# define GLM_HAS_IF_CONSTEXPR 0 +# endif +#else +# define GLM_HAS_IF_CONSTEXPR 0 +#endif + +#if GLM_HAS_IF_CONSTEXPR +# define GLM_IF_CONSTEXPR if constexpr +#else +# define GLM_IF_CONSTEXPR if +#endif + +// +#if GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_ASSIGNABLE 1 +#else +# define GLM_HAS_ASSIGNABLE ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC15)) || \ + ((GLM_COMPILER & GLM_COMPILER_GCC) && (GLM_COMPILER >= GLM_COMPILER_GCC49)))) +#endif + +// +#define GLM_HAS_TRIVIAL_QUERIES 0 + +// +#if GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_MAKE_SIGNED 1 +#else +# define GLM_HAS_MAKE_SIGNED ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC12)) || \ + ((GLM_COMPILER & GLM_COMPILER_CUDA)) || \ + ((GLM_COMPILER & GLM_COMPILER_HIP)))) +#endif + +// +#if defined(GLM_FORCE_INTRINSICS) +# define GLM_HAS_BITSCAN_WINDOWS ((GLM_PLATFORM & GLM_PLATFORM_WINDOWS) && (\ + ((GLM_COMPILER & GLM_COMPILER_INTEL)) || \ + ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC14) && (GLM_ARCH & GLM_ARCH_X86_BIT)))) +#else +# define GLM_HAS_BITSCAN_WINDOWS 0 +#endif + +#if GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_NOEXCEPT 1 +#else +# define GLM_HAS_NOEXCEPT 0 +#endif + +#if GLM_HAS_NOEXCEPT +# define GLM_NOEXCEPT noexcept +#else +# define GLM_NOEXCEPT +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// OpenMP +#ifdef _OPENMP +# if GLM_COMPILER & GLM_COMPILER_GCC +# if GLM_COMPILER >= GLM_COMPILER_GCC61 +# define GLM_HAS_OPENMP 45 +# elif GLM_COMPILER >= GLM_COMPILER_GCC49 +# define GLM_HAS_OPENMP 40 +# elif GLM_COMPILER >= GLM_COMPILER_GCC47 +# define GLM_HAS_OPENMP 31 +# else +# define GLM_HAS_OPENMP 0 +# endif +# elif GLM_COMPILER & GLM_COMPILER_CLANG +# if GLM_COMPILER >= GLM_COMPILER_CLANG38 +# define GLM_HAS_OPENMP 31 +# else +# define GLM_HAS_OPENMP 0 +# endif +# elif GLM_COMPILER & GLM_COMPILER_VC +# define GLM_HAS_OPENMP 20 +# elif GLM_COMPILER & GLM_COMPILER_INTEL +# if GLM_COMPILER >= GLM_COMPILER_INTEL16 +# define GLM_HAS_OPENMP 40 +# else +# define GLM_HAS_OPENMP 0 +# endif +# else +# define GLM_HAS_OPENMP 0 +# endif +#else +# define GLM_HAS_OPENMP 0 +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// nullptr + +#if GLM_LANG & GLM_LANG_CXX0X_FLAG +# define GLM_CONFIG_NULLPTR GLM_ENABLE +#else +# define GLM_CONFIG_NULLPTR GLM_DISABLE +#endif + +#if GLM_CONFIG_NULLPTR == GLM_ENABLE +# define GLM_NULLPTR nullptr +#else +# define GLM_NULLPTR 0 +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Static assert + +#if GLM_HAS_STATIC_ASSERT +# define GLM_STATIC_ASSERT(x, message) static_assert(x, message) +#elif GLM_COMPILER & GLM_COMPILER_VC +# define GLM_STATIC_ASSERT(x, message) typedef char __CASSERT__##__LINE__[(x) ? 1 : -1] +#else +# define GLM_STATIC_ASSERT(x, message) assert(x) +#endif//GLM_LANG + +/////////////////////////////////////////////////////////////////////////////////// +// Qualifiers + +// User defines: GLM_CUDA_FORCE_DEVICE_FUNC, GLM_CUDA_FORCE_HOST_FUNC + +#if (GLM_COMPILER & GLM_COMPILER_CUDA) || (GLM_COMPILER & GLM_COMPILER_HIP) +# if defined(GLM_CUDA_FORCE_DEVICE_FUNC) && defined(GLM_CUDA_FORCE_HOST_FUNC) +# error "GLM error: GLM_CUDA_FORCE_DEVICE_FUNC and GLM_CUDA_FORCE_HOST_FUNC should not be defined at the same time, GLM by default generates both device and host code for CUDA compiler." +# endif//defined(GLM_CUDA_FORCE_DEVICE_FUNC) && defined(GLM_CUDA_FORCE_HOST_FUNC) + +# if defined(GLM_CUDA_FORCE_DEVICE_FUNC) +# define GLM_CUDA_FUNC_DEF __device__ +# define GLM_CUDA_FUNC_DECL __device__ +# elif defined(GLM_CUDA_FORCE_HOST_FUNC) +# define GLM_CUDA_FUNC_DEF __host__ +# define GLM_CUDA_FUNC_DECL __host__ +# else +# define GLM_CUDA_FUNC_DEF __device__ __host__ +# define GLM_CUDA_FUNC_DECL __device__ __host__ +# endif//defined(GLM_CUDA_FORCE_XXXX_FUNC) +#else +# define GLM_CUDA_FUNC_DEF +# define GLM_CUDA_FUNC_DECL +#endif + +#if defined(GLM_FORCE_INLINE) +# if GLM_COMPILER & GLM_COMPILER_VC +# define GLM_INLINE __forceinline +# define GLM_NEVER_INLINE __declspec(noinline) +# elif GLM_COMPILER & (GLM_COMPILER_GCC | GLM_COMPILER_CLANG) +# define GLM_INLINE inline __attribute__((__always_inline__)) +# define GLM_NEVER_INLINE __attribute__((__noinline__)) +# elif (GLM_COMPILER & GLM_COMPILER_CUDA) || (GLM_COMPILER & GLM_COMPILER_HIP) +# define GLM_INLINE __forceinline__ +# define GLM_NEVER_INLINE __noinline__ +# else +# define GLM_INLINE inline +# define GLM_NEVER_INLINE +# endif//GLM_COMPILER +#else +# define GLM_INLINE inline +# define GLM_NEVER_INLINE +#endif//defined(GLM_FORCE_INLINE) + +#define GLM_FUNC_DECL GLM_CUDA_FUNC_DECL +#define GLM_FUNC_QUALIFIER GLM_CUDA_FUNC_DEF GLM_INLINE + +/////////////////////////////////////////////////////////////////////////////////// +// Swizzle operators + +// User defines: GLM_FORCE_SWIZZLE + +#define GLM_SWIZZLE_DISABLED 0 +#define GLM_SWIZZLE_OPERATOR 1 +#define GLM_SWIZZLE_FUNCTION 2 + +#if defined(GLM_SWIZZLE) +# pragma message("GLM: GLM_SWIZZLE is deprecated, use GLM_FORCE_SWIZZLE instead.") +# define GLM_FORCE_SWIZZLE +#endif + +#if defined(GLM_FORCE_SWIZZLE) && (GLM_LANG & GLM_LANG_CXXMS_FLAG) && !defined(GLM_FORCE_XYZW_ONLY) +# define GLM_CONFIG_SWIZZLE GLM_SWIZZLE_OPERATOR +#elif defined(GLM_FORCE_SWIZZLE) +# define GLM_CONFIG_SWIZZLE GLM_SWIZZLE_FUNCTION +#else +# define GLM_CONFIG_SWIZZLE GLM_SWIZZLE_DISABLED +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Allows using not basic types as genType + +// #define GLM_FORCE_UNRESTRICTED_GENTYPE + +#ifdef GLM_FORCE_UNRESTRICTED_GENTYPE +# define GLM_CONFIG_UNRESTRICTED_GENTYPE GLM_ENABLE +#else +# define GLM_CONFIG_UNRESTRICTED_GENTYPE GLM_DISABLE +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Clip control, define GLM_FORCE_DEPTH_ZERO_TO_ONE before including GLM +// to use a clip space between 0 to 1. +// Coordinate system, define GLM_FORCE_LEFT_HANDED before including GLM +// to use left handed coordinate system by default. + +#define GLM_CLIP_CONTROL_ZO_BIT (1 << 0) // ZERO_TO_ONE +#define GLM_CLIP_CONTROL_NO_BIT (1 << 1) // NEGATIVE_ONE_TO_ONE +#define GLM_CLIP_CONTROL_LH_BIT (1 << 2) // LEFT_HANDED, For DirectX, Metal, Vulkan +#define GLM_CLIP_CONTROL_RH_BIT (1 << 3) // RIGHT_HANDED, For OpenGL, default in GLM + +#define GLM_CLIP_CONTROL_LH_ZO (GLM_CLIP_CONTROL_LH_BIT | GLM_CLIP_CONTROL_ZO_BIT) +#define GLM_CLIP_CONTROL_LH_NO (GLM_CLIP_CONTROL_LH_BIT | GLM_CLIP_CONTROL_NO_BIT) +#define GLM_CLIP_CONTROL_RH_ZO (GLM_CLIP_CONTROL_RH_BIT | GLM_CLIP_CONTROL_ZO_BIT) +#define GLM_CLIP_CONTROL_RH_NO (GLM_CLIP_CONTROL_RH_BIT | GLM_CLIP_CONTROL_NO_BIT) + +#ifdef GLM_FORCE_DEPTH_ZERO_TO_ONE +# ifdef GLM_FORCE_LEFT_HANDED +# define GLM_CONFIG_CLIP_CONTROL GLM_CLIP_CONTROL_LH_ZO +# else +# define GLM_CONFIG_CLIP_CONTROL GLM_CLIP_CONTROL_RH_ZO +# endif +#else +# ifdef GLM_FORCE_LEFT_HANDED +# define GLM_CONFIG_CLIP_CONTROL GLM_CLIP_CONTROL_LH_NO +# else +# define GLM_CONFIG_CLIP_CONTROL GLM_CLIP_CONTROL_RH_NO +# endif +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Qualifiers + +#if (GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS)) +# define GLM_DEPRECATED __declspec(deprecated) +# define GLM_ALIGNED_TYPEDEF(type, name, alignment) typedef __declspec(align(alignment)) type name +#elif GLM_COMPILER & (GLM_COMPILER_GCC | GLM_COMPILER_CLANG | GLM_COMPILER_INTEL) +# define GLM_DEPRECATED __attribute__((__deprecated__)) +# define GLM_ALIGNED_TYPEDEF(type, name, alignment) typedef type name __attribute__((aligned(alignment))) +#elif (GLM_COMPILER & GLM_COMPILER_CUDA) || (GLM_COMPILER & GLM_COMPILER_HIP) +# define GLM_DEPRECATED +# define GLM_ALIGNED_TYPEDEF(type, name, alignment) typedef type name __align__(x) +#else +# define GLM_DEPRECATED +# define GLM_ALIGNED_TYPEDEF(type, name, alignment) typedef type name +#endif + +/////////////////////////////////////////////////////////////////////////////////// + +#ifdef GLM_FORCE_EXPLICIT_CTOR +# define GLM_EXPLICIT explicit +#else +# define GLM_EXPLICIT +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// SYCL + +#if GLM_COMPILER==GLM_COMPILER_SYCL + +#include +#include + +namespace glm { +namespace std { + // Import SYCL's functions into the namespace glm::std to force their usages. + // It's important to use the math built-in function (sin, exp, ...) + // of SYCL instead the std ones. + using namespace cl::sycl; + + /////////////////////////////////////////////////////////////////////////////// + // Import some "harmless" std's stuffs used by glm into + // the new glm::std namespace. + template + using numeric_limits = ::std::numeric_limits; + + using ::std::size_t; + + using ::std::uint8_t; + using ::std::uint16_t; + using ::std::uint32_t; + using ::std::uint64_t; + + using ::std::int8_t; + using ::std::int16_t; + using ::std::int32_t; + using ::std::int64_t; + + using ::std::make_unsigned; + /////////////////////////////////////////////////////////////////////////////// +} //namespace std +} //namespace glm + +#endif + +/////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////// +// Length type: all length functions returns a length_t type. +// When GLM_FORCE_SIZE_T_LENGTH is defined, length_t is a typedef of size_t otherwise +// length_t is a typedef of int like GLSL defines it. + +#define GLM_LENGTH_INT 1 +#define GLM_LENGTH_SIZE_T 2 + +#ifdef GLM_FORCE_SIZE_T_LENGTH +# define GLM_CONFIG_LENGTH_TYPE GLM_LENGTH_SIZE_T +#else +# define GLM_CONFIG_LENGTH_TYPE GLM_LENGTH_INT +#endif + +namespace glm +{ + using std::size_t; +# if GLM_CONFIG_LENGTH_TYPE == GLM_LENGTH_SIZE_T + typedef size_t length_t; +# else + typedef int length_t; +# endif +}//namespace glm + +/////////////////////////////////////////////////////////////////////////////////// +// constexpr + +#if GLM_HAS_CONSTEXPR +# define GLM_CONFIG_CONSTEXP GLM_ENABLE + + namespace glm + { + template + constexpr std::size_t countof(T const (&)[N]) + { + return N; + } + }//namespace glm +# define GLM_COUNTOF(arr) glm::countof(arr) +#elif defined(_MSC_VER) +# define GLM_CONFIG_CONSTEXP GLM_DISABLE + +# define GLM_COUNTOF(arr) _countof(arr) +#else +# define GLM_CONFIG_CONSTEXP GLM_DISABLE + +# define GLM_COUNTOF(arr) sizeof(arr) / sizeof(arr[0]) +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// uint + +namespace glm{ +namespace detail +{ + template + struct is_int + { + enum test {value = 0}; + }; + + template<> + struct is_int + { + enum test {value = ~0}; + }; + + template<> + struct is_int + { + enum test {value = ~0}; + }; +}//namespace detail + + typedef unsigned int uint; +}//namespace glm + +/////////////////////////////////////////////////////////////////////////////////// +// 64-bit int + +#if GLM_HAS_EXTENDED_INTEGER_TYPE +# include +#endif + +namespace glm{ +namespace detail +{ +# if GLM_HAS_EXTENDED_INTEGER_TYPE + typedef std::uint64_t uint64; + typedef std::int64_t int64; +# elif (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) // C99 detected, 64 bit types available + typedef uint64_t uint64; + typedef int64_t int64; +# elif GLM_COMPILER & GLM_COMPILER_VC + typedef unsigned __int64 uint64; + typedef signed __int64 int64; +# elif GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic ignored "-Wlong-long" + __extension__ typedef unsigned long long uint64; + __extension__ typedef signed long long int64; +# elif (GLM_COMPILER & GLM_COMPILER_CLANG) +# pragma clang diagnostic ignored "-Wc++11-long-long" + typedef unsigned long long uint64; + typedef signed long long int64; +# else//unknown compiler + typedef unsigned long long uint64; + typedef signed long long int64; +# endif +}//namespace detail +}//namespace glm + +/////////////////////////////////////////////////////////////////////////////////// +// make_unsigned + +#if GLM_HAS_MAKE_SIGNED +# include + +namespace glm{ +namespace detail +{ + using std::make_unsigned; +}//namespace detail +}//namespace glm + +#else + +namespace glm{ +namespace detail +{ + template + struct make_unsigned + {}; + + template<> + struct make_unsigned + { + typedef unsigned char type; + }; + + template<> + struct make_unsigned + { + typedef unsigned char type; + }; + + template<> + struct make_unsigned + { + typedef unsigned short type; + }; + + template<> + struct make_unsigned + { + typedef unsigned int type; + }; + + template<> + struct make_unsigned + { + typedef unsigned long type; + }; + + template<> + struct make_unsigned + { + typedef uint64 type; + }; + + template<> + struct make_unsigned + { + typedef unsigned char type; + }; + + template<> + struct make_unsigned + { + typedef unsigned short type; + }; + + template<> + struct make_unsigned + { + typedef unsigned int type; + }; + + template<> + struct make_unsigned + { + typedef unsigned long type; + }; + + template<> + struct make_unsigned + { + typedef uint64 type; + }; +}//namespace detail +}//namespace glm +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Only use x, y, z, w as vector type components + +#ifdef GLM_FORCE_XYZW_ONLY +# define GLM_CONFIG_XYZW_ONLY GLM_ENABLE +#else +# define GLM_CONFIG_XYZW_ONLY GLM_DISABLE +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Configure the use of defaulted initialized types + +#define GLM_CTOR_INIT_DISABLE 0 +#define GLM_CTOR_INITIALIZER_LIST 1 +#define GLM_CTOR_INITIALISATION 2 + +#if defined(GLM_FORCE_CTOR_INIT) && GLM_HAS_INITIALIZER_LISTS +# define GLM_CONFIG_CTOR_INIT GLM_CTOR_INITIALIZER_LIST +#elif defined(GLM_FORCE_CTOR_INIT) && !GLM_HAS_INITIALIZER_LISTS +# define GLM_CONFIG_CTOR_INIT GLM_CTOR_INITIALISATION +#else +# define GLM_CONFIG_CTOR_INIT GLM_CTOR_INIT_DISABLE +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Use SIMD instruction sets + +#if GLM_HAS_ALIGNOF && (GLM_LANG & GLM_LANG_CXXMS_FLAG) && (GLM_ARCH & GLM_ARCH_SIMD_BIT) +# define GLM_CONFIG_SIMD GLM_ENABLE +#else +# define GLM_CONFIG_SIMD GLM_DISABLE +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Configure the use of defaulted function + +#if GLM_HAS_DEFAULTED_FUNCTIONS +# define GLM_CONFIG_DEFAULTED_FUNCTIONS GLM_ENABLE +# define GLM_DEFAULT = default +#else +# define GLM_CONFIG_DEFAULTED_FUNCTIONS GLM_DISABLE +# define GLM_DEFAULT +#endif + +#if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INIT_DISABLE && GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_ENABLE +# define GLM_CONFIG_DEFAULTED_DEFAULT_CTOR GLM_ENABLE +# define GLM_DEFAULT_CTOR GLM_DEFAULT +#else +# define GLM_CONFIG_DEFAULTED_DEFAULT_CTOR GLM_DISABLE +# define GLM_DEFAULT_CTOR +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Configure the use of aligned gentypes + +#ifdef GLM_FORCE_ALIGNED // Legacy define +# define GLM_FORCE_DEFAULT_ALIGNED_GENTYPES +#endif + +#ifdef GLM_FORCE_DEFAULT_ALIGNED_GENTYPES +# define GLM_FORCE_ALIGNED_GENTYPES +#endif + +#if GLM_HAS_ALIGNOF && (GLM_LANG & GLM_LANG_CXXMS_FLAG) && (defined(GLM_FORCE_ALIGNED_GENTYPES) || (GLM_CONFIG_SIMD == GLM_ENABLE)) +# define GLM_CONFIG_ALIGNED_GENTYPES GLM_ENABLE +#else +# define GLM_CONFIG_ALIGNED_GENTYPES GLM_DISABLE +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Configure the use of anonymous structure as implementation detail + +#if ((GLM_CONFIG_SIMD == GLM_ENABLE) || (GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR) || (GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE)) +# define GLM_CONFIG_ANONYMOUS_STRUCT GLM_ENABLE +#else +# define GLM_CONFIG_ANONYMOUS_STRUCT GLM_DISABLE +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Silent warnings + +#ifdef GLM_FORCE_SILENT_WARNINGS +# define GLM_SILENT_WARNINGS GLM_ENABLE +#else +# define GLM_SILENT_WARNINGS GLM_DISABLE +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Precision + +#define GLM_HIGHP 1 +#define GLM_MEDIUMP 2 +#define GLM_LOWP 3 + +#if defined(GLM_FORCE_PRECISION_HIGHP_BOOL) || defined(GLM_PRECISION_HIGHP_BOOL) +# define GLM_CONFIG_PRECISION_BOOL GLM_HIGHP +#elif defined(GLM_FORCE_PRECISION_MEDIUMP_BOOL) || defined(GLM_PRECISION_MEDIUMP_BOOL) +# define GLM_CONFIG_PRECISION_BOOL GLM_MEDIUMP +#elif defined(GLM_FORCE_PRECISION_LOWP_BOOL) || defined(GLM_PRECISION_LOWP_BOOL) +# define GLM_CONFIG_PRECISION_BOOL GLM_LOWP +#else +# define GLM_CONFIG_PRECISION_BOOL GLM_HIGHP +#endif + +#if defined(GLM_FORCE_PRECISION_HIGHP_INT) || defined(GLM_PRECISION_HIGHP_INT) +# define GLM_CONFIG_PRECISION_INT GLM_HIGHP +#elif defined(GLM_FORCE_PRECISION_MEDIUMP_INT) || defined(GLM_PRECISION_MEDIUMP_INT) +# define GLM_CONFIG_PRECISION_INT GLM_MEDIUMP +#elif defined(GLM_FORCE_PRECISION_LOWP_INT) || defined(GLM_PRECISION_LOWP_INT) +# define GLM_CONFIG_PRECISION_INT GLM_LOWP +#else +# define GLM_CONFIG_PRECISION_INT GLM_HIGHP +#endif + +#if defined(GLM_FORCE_PRECISION_HIGHP_UINT) || defined(GLM_PRECISION_HIGHP_UINT) +# define GLM_CONFIG_PRECISION_UINT GLM_HIGHP +#elif defined(GLM_FORCE_PRECISION_MEDIUMP_UINT) || defined(GLM_PRECISION_MEDIUMP_UINT) +# define GLM_CONFIG_PRECISION_UINT GLM_MEDIUMP +#elif defined(GLM_FORCE_PRECISION_LOWP_UINT) || defined(GLM_PRECISION_LOWP_UINT) +# define GLM_CONFIG_PRECISION_UINT GLM_LOWP +#else +# define GLM_CONFIG_PRECISION_UINT GLM_HIGHP +#endif + +#if defined(GLM_FORCE_PRECISION_HIGHP_FLOAT) || defined(GLM_PRECISION_HIGHP_FLOAT) +# define GLM_CONFIG_PRECISION_FLOAT GLM_HIGHP +#elif defined(GLM_FORCE_PRECISION_MEDIUMP_FLOAT) || defined(GLM_PRECISION_MEDIUMP_FLOAT) +# define GLM_CONFIG_PRECISION_FLOAT GLM_MEDIUMP +#elif defined(GLM_FORCE_PRECISION_LOWP_FLOAT) || defined(GLM_PRECISION_LOWP_FLOAT) +# define GLM_CONFIG_PRECISION_FLOAT GLM_LOWP +#else +# define GLM_CONFIG_PRECISION_FLOAT GLM_HIGHP +#endif + +#if defined(GLM_FORCE_PRECISION_HIGHP_DOUBLE) || defined(GLM_PRECISION_HIGHP_DOUBLE) +# define GLM_CONFIG_PRECISION_DOUBLE GLM_HIGHP +#elif defined(GLM_FORCE_PRECISION_MEDIUMP_DOUBLE) || defined(GLM_PRECISION_MEDIUMP_DOUBLE) +# define GLM_CONFIG_PRECISION_DOUBLE GLM_MEDIUMP +#elif defined(GLM_FORCE_PRECISION_LOWP_DOUBLE) || defined(GLM_PRECISION_LOWP_DOUBLE) +# define GLM_CONFIG_PRECISION_DOUBLE GLM_LOWP +#else +# define GLM_CONFIG_PRECISION_DOUBLE GLM_HIGHP +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Check inclusions of different versions of GLM + +#elif ((GLM_SETUP_INCLUDED != GLM_VERSION) && !defined(GLM_FORCE_IGNORE_VERSION)) +# error "GLM error: A different version of GLM is already included. Define GLM_FORCE_IGNORE_VERSION before including GLM headers to ignore this error." +#elif GLM_SETUP_INCLUDED == GLM_VERSION + +/////////////////////////////////////////////////////////////////////////////////// +// Messages + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_MESSAGE_DISPLAYED) +# define GLM_MESSAGE_DISPLAYED +# define GLM_STR_HELPER(x) #x +# define GLM_STR(x) GLM_STR_HELPER(x) + + // Report GLM version +# pragma message (GLM_STR(GLM_VERSION_MESSAGE)) + + // Report C++ language +# if (GLM_LANG & GLM_LANG_CXX2A_FLAG) && (GLM_LANG & GLM_LANG_EXT) +# pragma message("GLM: C++ 2A with extensions") +# elif (GLM_LANG & GLM_LANG_CXX2A_FLAG) +# pragma message("GLM: C++ 2A") +# elif (GLM_LANG & GLM_LANG_CXX17_FLAG) && (GLM_LANG & GLM_LANG_EXT) +# pragma message("GLM: C++ 17 with extensions") +# elif (GLM_LANG & GLM_LANG_CXX17_FLAG) +# pragma message("GLM: C++ 17") +# elif (GLM_LANG & GLM_LANG_CXX14_FLAG) && (GLM_LANG & GLM_LANG_EXT) +# pragma message("GLM: C++ 14 with extensions") +# elif (GLM_LANG & GLM_LANG_CXX14_FLAG) +# pragma message("GLM: C++ 14") +# elif (GLM_LANG & GLM_LANG_CXX11_FLAG) && (GLM_LANG & GLM_LANG_EXT) +# pragma message("GLM: C++ 11 with extensions") +# elif (GLM_LANG & GLM_LANG_CXX11_FLAG) +# pragma message("GLM: C++ 11") +# elif (GLM_LANG & GLM_LANG_CXX0X_FLAG) && (GLM_LANG & GLM_LANG_EXT) +# pragma message("GLM: C++ 0x with extensions") +# elif (GLM_LANG & GLM_LANG_CXX0X_FLAG) +# pragma message("GLM: C++ 0x") +# elif (GLM_LANG & GLM_LANG_CXX03_FLAG) && (GLM_LANG & GLM_LANG_EXT) +# pragma message("GLM: C++ 03 with extensions") +# elif (GLM_LANG & GLM_LANG_CXX03_FLAG) +# pragma message("GLM: C++ 03") +# elif (GLM_LANG & GLM_LANG_CXX98_FLAG) && (GLM_LANG & GLM_LANG_EXT) +# pragma message("GLM: C++ 98 with extensions") +# elif (GLM_LANG & GLM_LANG_CXX98_FLAG) +# pragma message("GLM: C++ 98") +# else +# pragma message("GLM: C++ language undetected") +# endif//GLM_LANG + + // Report compiler detection +# if GLM_COMPILER & GLM_COMPILER_CUDA +# pragma message("GLM: CUDA compiler detected") +# elif GLM_COMPILER & GLM_COMPILER_HIP +# pragma message("GLM: HIP compiler detected") +# elif GLM_COMPILER & GLM_COMPILER_VC +# pragma message("GLM: Visual C++ compiler detected") +# elif GLM_COMPILER & GLM_COMPILER_CLANG +# pragma message("GLM: Clang compiler detected") +# elif GLM_COMPILER & GLM_COMPILER_INTEL +# pragma message("GLM: Intel Compiler detected") +# elif GLM_COMPILER & GLM_COMPILER_GCC +# pragma message("GLM: GCC compiler detected") +# else +# pragma message("GLM: Compiler not detected") +# endif + + // Report build target +# if (GLM_ARCH & GLM_ARCH_AVX2_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: x86 64 bits with AVX2 instruction set build target") +# elif (GLM_ARCH & GLM_ARCH_AVX2_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: x86 32 bits with AVX2 instruction set build target") + +# elif (GLM_ARCH & GLM_ARCH_AVX_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: x86 64 bits with AVX instruction set build target") +# elif (GLM_ARCH & GLM_ARCH_AVX_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: x86 32 bits with AVX instruction set build target") + +# elif (GLM_ARCH & GLM_ARCH_SSE42_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: x86 64 bits with SSE4.2 instruction set build target") +# elif (GLM_ARCH & GLM_ARCH_SSE42_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: x86 32 bits with SSE4.2 instruction set build target") + +# elif (GLM_ARCH & GLM_ARCH_SSE41_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: x86 64 bits with SSE4.1 instruction set build target") +# elif (GLM_ARCH & GLM_ARCH_SSE41_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: x86 32 bits with SSE4.1 instruction set build target") + +# elif (GLM_ARCH & GLM_ARCH_SSSE3_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: x86 64 bits with SSSE3 instruction set build target") +# elif (GLM_ARCH & GLM_ARCH_SSSE3_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: x86 32 bits with SSSE3 instruction set build target") + +# elif (GLM_ARCH & GLM_ARCH_SSE3_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: x86 64 bits with SSE3 instruction set build target") +# elif (GLM_ARCH & GLM_ARCH_SSE3_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: x86 32 bits with SSE3 instruction set build target") + +# elif (GLM_ARCH & GLM_ARCH_SSE2_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: x86 64 bits with SSE2 instruction set build target") +# elif (GLM_ARCH & GLM_ARCH_SSE2_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: x86 32 bits with SSE2 instruction set build target") + +# elif (GLM_ARCH & GLM_ARCH_X86_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: x86 64 bits build target") +# elif (GLM_ARCH & GLM_ARCH_X86_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: x86 32 bits build target") + +# elif (GLM_ARCH & GLM_ARCH_NEON_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: ARM 64 bits with Neon instruction set build target") +# elif (GLM_ARCH & GLM_ARCH_NEON_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: ARM 32 bits with Neon instruction set build target") + +# elif (GLM_ARCH & GLM_ARCH_ARM_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: ARM 64 bits build target") +# elif (GLM_ARCH & GLM_ARCH_ARM_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: ARM 32 bits build target") + +# elif (GLM_ARCH & GLM_ARCH_MIPS_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: MIPS 64 bits build target") +# elif (GLM_ARCH & GLM_ARCH_MIPS_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: MIPS 32 bits build target") + +# elif (GLM_ARCH & GLM_ARCH_PPC_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: PowerPC 64 bits build target") +# elif (GLM_ARCH & GLM_ARCH_PPC_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: PowerPC 32 bits build target") +# else +# pragma message("GLM: Unknown build target") +# endif//GLM_ARCH + + // Report platform name +# if(GLM_PLATFORM & GLM_PLATFORM_QNXNTO) +# pragma message("GLM: QNX platform detected") +//# elif(GLM_PLATFORM & GLM_PLATFORM_IOS) +//# pragma message("GLM: iOS platform detected") +# elif(GLM_PLATFORM & GLM_PLATFORM_APPLE) +# pragma message("GLM: Apple platform detected") +# elif(GLM_PLATFORM & GLM_PLATFORM_WINCE) +# pragma message("GLM: WinCE platform detected") +# elif(GLM_PLATFORM & GLM_PLATFORM_WINDOWS) +# pragma message("GLM: Windows platform detected") +# elif(GLM_PLATFORM & GLM_PLATFORM_CHROME_NACL) +# pragma message("GLM: Native Client detected") +# elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID) +# pragma message("GLM: Android platform detected") +# elif(GLM_PLATFORM & GLM_PLATFORM_LINUX) +# pragma message("GLM: Linux platform detected") +# elif(GLM_PLATFORM & GLM_PLATFORM_UNIX) +# pragma message("GLM: UNIX platform detected") +# elif(GLM_PLATFORM & GLM_PLATFORM_UNKNOWN) +# pragma message("GLM: platform unknown") +# else +# pragma message("GLM: platform not detected") +# endif + + // Report whether only xyzw component are used +# if defined GLM_FORCE_XYZW_ONLY +# pragma message("GLM: GLM_FORCE_XYZW_ONLY is defined. Only x, y, z and w component are available in vector type. This define disables swizzle operators and SIMD instruction sets.") +# endif + + // Report swizzle operator support +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR +# pragma message("GLM: GLM_FORCE_SWIZZLE is defined, swizzling operators enabled.") +# elif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION +# pragma message("GLM: GLM_FORCE_SWIZZLE is defined, swizzling functions enabled. Enable compiler C++ language extensions to enable swizzle operators.") +# else +# pragma message("GLM: GLM_FORCE_SWIZZLE is undefined. swizzling functions or operators are disabled.") +# endif + + // Report .length() type +# if GLM_CONFIG_LENGTH_TYPE == GLM_LENGTH_SIZE_T +# pragma message("GLM: GLM_FORCE_SIZE_T_LENGTH is defined. .length() returns a glm::length_t, a typedef of std::size_t.") +# else +# pragma message("GLM: GLM_FORCE_SIZE_T_LENGTH is undefined. .length() returns a glm::length_t, a typedef of int following GLSL.") +# endif + +# if GLM_CONFIG_UNRESTRICTED_GENTYPE == GLM_ENABLE +# pragma message("GLM: GLM_FORCE_UNRESTRICTED_GENTYPE is defined. Removes GLSL restrictions on valid function genTypes.") +# else +# pragma message("GLM: GLM_FORCE_UNRESTRICTED_GENTYPE is undefined. Follows strictly GLSL on valid function genTypes.") +# endif + +# if GLM_SILENT_WARNINGS == GLM_ENABLE +# pragma message("GLM: GLM_FORCE_SILENT_WARNINGS is defined. Ignores C++ warnings from using C++ language extensions.") +# else +# pragma message("GLM: GLM_FORCE_SILENT_WARNINGS is undefined. Shows C++ warnings from using C++ language extensions.") +# endif + +# ifdef GLM_FORCE_SINGLE_ONLY +# pragma message("GLM: GLM_FORCE_SINGLE_ONLY is defined. Using only single precision floating-point types.") +# endif + +# if defined(GLM_FORCE_ALIGNED_GENTYPES) && (GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE) +# undef GLM_FORCE_ALIGNED_GENTYPES +# pragma message("GLM: GLM_FORCE_ALIGNED_GENTYPES is defined, allowing aligned types. This prevents the use of C++ constexpr.") +# elif defined(GLM_FORCE_ALIGNED_GENTYPES) && (GLM_CONFIG_ALIGNED_GENTYPES == GLM_DISABLE) +# undef GLM_FORCE_ALIGNED_GENTYPES +# pragma message("GLM: GLM_FORCE_ALIGNED_GENTYPES is defined but is disabled. It requires C++11 and language extensions.") +# endif + +# if defined(GLM_FORCE_DEFAULT_ALIGNED_GENTYPES) +# if GLM_CONFIG_ALIGNED_GENTYPES == GLM_DISABLE +# undef GLM_FORCE_DEFAULT_ALIGNED_GENTYPES +# pragma message("GLM: GLM_FORCE_DEFAULT_ALIGNED_GENTYPES is defined but is disabled. It requires C++11 and language extensions.") +# elif GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE +# pragma message("GLM: GLM_FORCE_DEFAULT_ALIGNED_GENTYPES is defined. All gentypes (e.g. vec3) will be aligned and padded by default.") +# endif +# endif + +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT +# pragma message("GLM: GLM_FORCE_DEPTH_ZERO_TO_ONE is defined. Using zero to one depth clip space.") +# else +# pragma message("GLM: GLM_FORCE_DEPTH_ZERO_TO_ONE is undefined. Using negative one to one depth clip space.") +# endif + +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT +# pragma message("GLM: GLM_FORCE_LEFT_HANDED is defined. Using left handed coordinate system.") +# else +# pragma message("GLM: GLM_FORCE_LEFT_HANDED is undefined. Using right handed coordinate system.") +# endif +#endif//GLM_MESSAGES + +#endif//GLM_SETUP_INCLUDED diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_float.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_float.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c8037ebd7aa265cb56e3b809cf19df8fa807bcf8 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_float.hpp @@ -0,0 +1,68 @@ +#pragma once + +#include "setup.hpp" + +#if GLM_COMPILER == GLM_COMPILER_VC12 +# pragma warning(push) +# pragma warning(disable: 4512) // assignment operator could not be generated +#endif + +namespace glm{ +namespace detail +{ + template + union float_t + {}; + + // https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ + template <> + union float_t + { + typedef int int_type; + typedef float float_type; + + GLM_CONSTEXPR float_t(float_type Num = 0.0f) : f(Num) {} + + GLM_CONSTEXPR float_t& operator=(float_t const& x) + { + f = x.f; + return *this; + } + + // Portable extraction of components. + GLM_CONSTEXPR bool negative() const { return i < 0; } + GLM_CONSTEXPR int_type mantissa() const { return i & ((1 << 23) - 1); } + GLM_CONSTEXPR int_type exponent() const { return (i >> 23) & ((1 << 8) - 1); } + + int_type i; + float_type f; + }; + + template <> + union float_t + { + typedef detail::int64 int_type; + typedef double float_type; + + GLM_CONSTEXPR float_t(float_type Num = static_cast(0)) : f(Num) {} + + GLM_CONSTEXPR float_t& operator=(float_t const& x) + { + f = x.f; + return *this; + } + + // Portable extraction of components. + GLM_CONSTEXPR bool negative() const { return i < 0; } + GLM_CONSTEXPR int_type mantissa() const { return i & ((int_type(1) << 52) - 1); } + GLM_CONSTEXPR int_type exponent() const { return (i >> 52) & ((int_type(1) << 11) - 1); } + + int_type i; + float_type f; + }; +}//namespace detail +}//namespace glm + +#if GLM_COMPILER == GLM_COMPILER_VC12 +# pragma warning(pop) +#endif diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_half.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_half.hpp new file mode 100644 index 0000000000000000000000000000000000000000..40b8bec00d34143d2e1f0ff60a743aad9e30580f --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_half.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include "setup.hpp" + +namespace glm{ +namespace detail +{ + typedef short hdata; + + GLM_FUNC_DECL float toFloat32(hdata value); + GLM_FUNC_DECL hdata toFloat16(float const& value); + +}//namespace detail +}//namespace glm + +#include "type_half.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_half.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_half.inl new file mode 100644 index 0000000000000000000000000000000000000000..5d239cf22c250f31d0beb72aa3293763f1f51836 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_half.inl @@ -0,0 +1,241 @@ +namespace glm{ +namespace detail +{ + GLM_FUNC_QUALIFIER float overflow() + { + volatile float f = 1e10; + + for(int i = 0; i < 10; ++i) + f = f * f; // this will overflow before the for loop terminates + return f; + } + + union uif32 + { + GLM_FUNC_QUALIFIER uif32() : + i(0) + {} + + GLM_FUNC_QUALIFIER uif32(float f_) : + f(f_) + {} + + GLM_FUNC_QUALIFIER uif32(unsigned int i_) : + i(i_) + {} + + float f; + unsigned int i; + }; + + GLM_FUNC_QUALIFIER float toFloat32(hdata value) + { + int s = (value >> 15) & 0x00000001; + int e = (value >> 10) & 0x0000001f; + int m = value & 0x000003ff; + + if(e == 0) + { + if(m == 0) + { + // + // Plus or minus zero + // + + detail::uif32 result; + result.i = static_cast(s << 31); + return result.f; + } + else + { + // + // Denormalized number -- renormalize it + // + + while(!(m & 0x00000400)) + { + m <<= 1; + e -= 1; + } + + e += 1; + m &= ~0x00000400; + } + } + else if(e == 31) + { + if(m == 0) + { + // + // Positive or negative infinity + // + + uif32 result; + result.i = static_cast((s << 31) | 0x7f800000); + return result.f; + } + else + { + // + // Nan -- preserve sign and significand bits + // + + uif32 result; + result.i = static_cast((s << 31) | 0x7f800000 | (m << 13)); + return result.f; + } + } + + // + // Normalized number + // + + e = e + (127 - 15); + m = m << 13; + + // + // Assemble s, e and m. + // + + uif32 Result; + Result.i = static_cast((s << 31) | (e << 23) | m); + return Result.f; + } + + GLM_FUNC_QUALIFIER hdata toFloat16(float const& f) + { + uif32 Entry; + Entry.f = f; + int i = static_cast(Entry.i); + + // + // Our floating point number, f, is represented by the bit + // pattern in integer i. Disassemble that bit pattern into + // the sign, s, the exponent, e, and the significand, m. + // Shift s into the position where it will go in the + // resulting half number. + // Adjust e, accounting for the different exponent bias + // of float and half (127 versus 15). + // + + int s = (i >> 16) & 0x00008000; + int e = ((i >> 23) & 0x000000ff) - (127 - 15); + int m = i & 0x007fffff; + + // + // Now reassemble s, e and m into a half: + // + + if(e <= 0) + { + if(e < -10) + { + // + // E is less than -10. The absolute value of f is + // less than half_MIN (f may be a small normalized + // float, a denormalized float or a zero). + // + // We convert f to a half zero. + // + + return hdata(s); + } + + // + // E is between -10 and 0. F is a normalized float, + // whose magnitude is less than __half_NRM_MIN. + // + // We convert f to a denormalized half. + // + + m = (m | 0x00800000) >> (1 - e); + + // + // Round to nearest, round "0.5" up. + // + // Rounding may cause the significand to overflow and make + // our number normalized. Because of the way a half's bits + // are laid out, we don't have to treat this case separately; + // the code below will handle it correctly. + // + + if(m & 0x00001000) + m += 0x00002000; + + // + // Assemble the half from s, e (zero) and m. + // + + return hdata(s | (m >> 13)); + } + else if(e == 0xff - (127 - 15)) + { + if(m == 0) + { + // + // F is an infinity; convert f to a half + // infinity with the same sign as f. + // + + return hdata(s | 0x7c00); + } + else + { + // + // F is a NAN; we produce a half NAN that preserves + // the sign bit and the 10 leftmost bits of the + // significand of f, with one exception: If the 10 + // leftmost bits are all zero, the NAN would turn + // into an infinity, so we have to set at least one + // bit in the significand. + // + + m >>= 13; + + return hdata(s | 0x7c00 | m | (m == 0)); + } + } + else + { + // + // E is greater than zero. F is a normalized float. + // We try to convert f to a normalized half. + // + + // + // Round to nearest, round "0.5" up + // + + if(m & 0x00001000) + { + m += 0x00002000; + + if(m & 0x00800000) + { + m = 0; // overflow in significand, + e += 1; // adjust exponent + } + } + + // + // Handle exponent overflow + // + + if (e > 30) + { + overflow(); // Cause a hardware floating point overflow; + + return hdata(s | 0x7c00); + // if this returns, the half becomes an + } // infinity with the same sign as f. + + // + // Assemble the half from s, e and m. + // + + return hdata(s | (e << 10) | (m >> 13)); + } + } + +}//namespace detail +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat2x2.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat2x2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b2c918c3ab647f22cc263430d2a8bac215a96dd7 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat2x2.hpp @@ -0,0 +1,177 @@ +/// @ref core +/// @file glm/detail/type_mat2x2.hpp + +#pragma once + +#include "type_vec2.hpp" +#include +#include + +namespace glm +{ + template + struct mat<2, 2, T, Q> + { + typedef vec<2, T, Q> col_type; + typedef vec<2, T, Q> row_type; + typedef mat<2, 2, T, Q> type; + typedef mat<2, 2, T, Q> transpose_type; + typedef T value_type; + + private: + col_type value[2]; + + public: + // -- Accesses -- + + typedef length_t length_type; + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 2; } + + GLM_FUNC_DECL col_type & operator[](length_type i) GLM_NOEXCEPT; + GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const GLM_NOEXCEPT; + + // -- Constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT_CTOR; + template + GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<2, 2, T, P> const& m); + + GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T scalar); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + T const& x1, T const& y1, + T const& x2, T const& y2); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + col_type const& v1, + col_type const& v2); + + // -- Conversions -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR mat( + U const& x1, V const& y1, + M const& x2, N const& y2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR mat( + vec<2, U, Q> const& v1, + vec<2, V, Q> const& v2); + + // -- Matrix conversions -- + + template + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, U, P> const& m); + + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x); + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_DECL mat<2, 2, T, Q> & operator=(mat<2, 2, U, Q> const& m); + template + GLM_FUNC_DECL mat<2, 2, T, Q> & operator+=(U s); + template + GLM_FUNC_DECL mat<2, 2, T, Q> & operator+=(mat<2, 2, U, Q> const& m); + template + GLM_FUNC_DECL mat<2, 2, T, Q> & operator-=(U s); + template + GLM_FUNC_DECL mat<2, 2, T, Q> & operator-=(mat<2, 2, U, Q> const& m); + template + GLM_FUNC_DECL mat<2, 2, T, Q> & operator*=(U s); + template + GLM_FUNC_DECL mat<2, 2, T, Q> & operator*=(mat<2, 2, U, Q> const& m); + template + GLM_FUNC_DECL mat<2, 2, T, Q> & operator/=(U s); + template + GLM_FUNC_DECL mat<2, 2, T, Q> & operator/=(mat<2, 2, U, Q> const& m); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL mat<2, 2, T, Q> & operator++ (); + GLM_FUNC_DECL mat<2, 2, T, Q> & operator-- (); + GLM_FUNC_DECL mat<2, 2, T, Q> operator++(int); + GLM_FUNC_DECL mat<2, 2, T, Q> operator--(int); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator+(mat<2, 2, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator-(mat<2, 2, T, Q> const& m); + + // -- Binary operators -- + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator+(mat<2, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator+(T scalar, mat<2, 2, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator+(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator-(mat<2, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator-(T scalar, mat<2, 2, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator-(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator*(mat<2, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator*(T scalar, mat<2, 2, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<2, 2, T, Q>::col_type operator*(mat<2, 2, T, Q> const& m, typename mat<2, 2, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<2, 2, T, Q>::row_type operator*(typename mat<2, 2, T, Q>::col_type const& v, mat<2, 2, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator*(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator*(mat<2, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator*(mat<2, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator/(mat<2, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator/(T scalar, mat<2, 2, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<2, 2, T, Q>::col_type operator/(mat<2, 2, T, Q> const& m, typename mat<2, 2, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<2, 2, T, Q>::row_type operator/(typename mat<2, 2, T, Q>::col_type const& v, mat<2, 2, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator/(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL bool operator==(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL bool operator!=(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2); +} //namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_mat2x2.inl" +#endif diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat2x2.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat2x2.inl new file mode 100644 index 0000000000000000000000000000000000000000..55e94fe6036a5344b4c9e2041ec2de0204228d47 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat2x2.inl @@ -0,0 +1,536 @@ +#include "../matrix.hpp" + +namespace glm +{ + // -- Constructors -- + +# if GLM_CONFIG_DEFAULTED_DEFAULT_CTOR == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat() +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST + : value{col_type(1, 0), col_type(0, 1)} +# endif + { +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION + this->value[0] = col_type(1, 0); + this->value[1] = col_type(0, 1); +# endif + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<2, 2, T, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m[0]; + this->value[1] = m[1]; +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(T scalar) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(scalar, 0), col_type(0, scalar)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(scalar, 0); + this->value[1] = col_type(0, scalar); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat + ( + T const& x0, T const& y0, + T const& x1, T const& y1 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x0, y0), col_type(x1, y1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0); + this->value[1] = col_type(x1, y1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(col_type const& v0, col_type const& v1) +# if GLM_HAS_INITIALIZER_LISTS + : value{v0, v1} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = v0; + this->value[1] = v1; +# endif + } + + // -- Conversion constructors -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat + ( + X1 const& x1, Y1 const& y1, + X2 const& x2, Y2 const& y2 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(static_cast(x1), value_type(y1)), col_type(static_cast(x2), value_type(y2)) } +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(static_cast(x1), value_type(y1)); + this->value[1] = col_type(static_cast(x2), value_type(y2)); +# endif + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(vec<2, V1, Q> const& v1, vec<2, V2, Q> const& v2) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v1), col_type(v2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(v1); + this->value[1] = col_type(v2); +# endif + } + + // -- mat2x2 matrix conversions -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<2, 2, U, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<3, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<4, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<2, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<3, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<2, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<4, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<3, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<4, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + // -- Accesses -- + + template + GLM_FUNC_QUALIFIER typename mat<2, 2, T, Q>::col_type& mat<2, 2, T, Q>::operator[](typename mat<2, 2, T, Q>::length_type i) GLM_NOEXCEPT + { + assert(i < this->length()); + return this->value[i]; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<2, 2, T, Q>::col_type const& mat<2, 2, T, Q>::operator[](typename mat<2, 2, T, Q>::length_type i) const GLM_NOEXCEPT + { + assert(i < this->length()); + return this->value[i]; + } + + // -- Unary updatable operators -- + + template + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator=(mat<2, 2, U, Q> const& m) + { + this->value[0] = m[0]; + this->value[1] = m[1]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator+=(U scalar) + { + this->value[0] += scalar; + this->value[1] += scalar; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator+=(mat<2, 2, U, Q> const& m) + { + this->value[0] += m[0]; + this->value[1] += m[1]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator-=(U scalar) + { + this->value[0] -= scalar; + this->value[1] -= scalar; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator-=(mat<2, 2, U, Q> const& m) + { + this->value[0] -= m[0]; + this->value[1] -= m[1]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator*=(U scalar) + { + this->value[0] *= scalar; + this->value[1] *= scalar; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator*=(mat<2, 2, U, Q> const& m) + { + return (*this = *this * m); + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator/=(U scalar) + { + this->value[0] /= scalar; + this->value[1] /= scalar; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator/=(mat<2, 2, U, Q> const& m) + { + return *this *= inverse(m); + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator++() + { + ++this->value[0]; + ++this->value[1]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator--() + { + --this->value[0]; + --this->value[1]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> mat<2, 2, T, Q>::operator++(int) + { + mat<2, 2, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> mat<2, 2, T, Q>::operator--(int) + { + mat<2, 2, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator+(mat<2, 2, T, Q> const& m) + { + return m; + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator-(mat<2, 2, T, Q> const& m) + { + return mat<2, 2, T, Q>( + -m[0], + -m[1]); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator+(mat<2, 2, T, Q> const& m, T scalar) + { + return mat<2, 2, T, Q>( + m[0] + scalar, + m[1] + scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator+(T scalar, mat<2, 2, T, Q> const& m) + { + return mat<2, 2, T, Q>( + m[0] + scalar, + m[1] + scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator+(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2) + { + return mat<2, 2, T, Q>( + m1[0] + m2[0], + m1[1] + m2[1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator-(mat<2, 2, T, Q> const& m, T scalar) + { + return mat<2, 2, T, Q>( + m[0] - scalar, + m[1] - scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator-(T scalar, mat<2, 2, T, Q> const& m) + { + return mat<2, 2, T, Q>( + scalar - m[0], + scalar - m[1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator-(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2) + { + return mat<2, 2, T, Q>( + m1[0] - m2[0], + m1[1] - m2[1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator*(mat<2, 2, T, Q> const& m, T scalar) + { + return mat<2, 2, T, Q>( + m[0] * scalar, + m[1] * scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator*(T scalar, mat<2, 2, T, Q> const& m) + { + return mat<2, 2, T, Q>( + m[0] * scalar, + m[1] * scalar); + } + + template + GLM_FUNC_QUALIFIER typename mat<2, 2, T, Q>::col_type operator* + ( + mat<2, 2, T, Q> const& m, + typename mat<2, 2, T, Q>::row_type const& v + ) + { + return vec<2, T, Q>( + m[0][0] * v.x + m[1][0] * v.y, + m[0][1] * v.x + m[1][1] * v.y); + } + + template + GLM_FUNC_QUALIFIER typename mat<2, 2, T, Q>::row_type operator* + ( + typename mat<2, 2, T, Q>::col_type const& v, + mat<2, 2, T, Q> const& m + ) + { + return vec<2, T, Q>( + v.x * m[0][0] + v.y * m[0][1], + v.x * m[1][0] + v.y * m[1][1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator*(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2) + { + return mat<2, 2, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator*(mat<2, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2) + { + return mat<3, 2, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator*(mat<2, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2) + { + return mat<4, 2, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1], + m1[0][0] * m2[3][0] + m1[1][0] * m2[3][1], + m1[0][1] * m2[3][0] + m1[1][1] * m2[3][1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator/(mat<2, 2, T, Q> const& m, T scalar) + { + return mat<2, 2, T, Q>( + m[0] / scalar, + m[1] / scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator/(T scalar, mat<2, 2, T, Q> const& m) + { + return mat<2, 2, T, Q>( + scalar / m[0], + scalar / m[1]); + } + + template + GLM_FUNC_QUALIFIER typename mat<2, 2, T, Q>::col_type operator/(mat<2, 2, T, Q> const& m, typename mat<2, 2, T, Q>::row_type const& v) + { + return inverse(m) * v; + } + + template + GLM_FUNC_QUALIFIER typename mat<2, 2, T, Q>::row_type operator/(typename mat<2, 2, T, Q>::col_type const& v, mat<2, 2, T, Q> const& m) + { + return v * inverse(m); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator/(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2) + { + mat<2, 2, T, Q> m1_copy(m1); + return m1_copy /= m2; + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER bool operator==(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2) + { + return (m1[0] == m2[0]) && (m1[1] == m2[1]); + } + + template + GLM_FUNC_QUALIFIER bool operator!=(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2) + { + return (m1[0] != m2[0]) || (m1[1] != m2[1]); + } +} //namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat2x3.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat2x3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c02a913e2e732c3ad1b72bd781db8ecea60406ea --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat2x3.hpp @@ -0,0 +1,159 @@ +/// @ref core +/// @file glm/detail/type_mat2x3.hpp + +#pragma once + +#include "type_vec2.hpp" +#include "type_vec3.hpp" +#include +#include + +namespace glm +{ + template + struct mat<2, 3, T, Q> + { + typedef vec<3, T, Q> col_type; + typedef vec<2, T, Q> row_type; + typedef mat<2, 3, T, Q> type; + typedef mat<3, 2, T, Q> transpose_type; + typedef T value_type; + + private: + col_type value[2]; + + public: + // -- Accesses -- + + typedef length_t length_type; + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 2; } + + GLM_FUNC_DECL col_type & operator[](length_type i) GLM_NOEXCEPT; + GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const GLM_NOEXCEPT; + + // -- Constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT_CTOR; + template + GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<2, 3, T, P> const& m); + + GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T scalar); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + T x0, T y0, T z0, + T x1, T y1, T z1); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + col_type const& v0, + col_type const& v1); + + // -- Conversions -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR mat( + X1 x1, Y1 y1, Z1 z1, + X2 x2, Y2 y2, Z2 z2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR mat( + vec<3, U, Q> const& v1, + vec<3, V, Q> const& v2); + + // -- Matrix conversions -- + + template + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, U, P> const& m); + + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x); + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_DECL mat<2, 3, T, Q> & operator=(mat<2, 3, U, Q> const& m); + template + GLM_FUNC_DECL mat<2, 3, T, Q> & operator+=(U s); + template + GLM_FUNC_DECL mat<2, 3, T, Q> & operator+=(mat<2, 3, U, Q> const& m); + template + GLM_FUNC_DECL mat<2, 3, T, Q> & operator-=(U s); + template + GLM_FUNC_DECL mat<2, 3, T, Q> & operator-=(mat<2, 3, U, Q> const& m); + template + GLM_FUNC_DECL mat<2, 3, T, Q> & operator*=(U s); + template + GLM_FUNC_DECL mat<2, 3, T, Q> & operator/=(U s); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL mat<2, 3, T, Q> & operator++ (); + GLM_FUNC_DECL mat<2, 3, T, Q> & operator-- (); + GLM_FUNC_DECL mat<2, 3, T, Q> operator++(int); + GLM_FUNC_DECL mat<2, 3, T, Q> operator--(int); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator+(mat<2, 3, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator-(mat<2, 3, T, Q> const& m); + + // -- Binary operators -- + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator+(mat<2, 3, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator+(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator-(mat<2, 3, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator-(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator*(mat<2, 3, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator*(T scalar, mat<2, 3, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<2, 3, T, Q>::col_type operator*(mat<2, 3, T, Q> const& m, typename mat<2, 3, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<2, 3, T, Q>::row_type operator*(typename mat<2, 3, T, Q>::col_type const& v, mat<2, 3, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator*(mat<2, 3, T, Q> const& m1, mat<2, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator*(mat<2, 3, T, Q> const& m1, mat<3, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator*(mat<2, 3, T, Q> const& m1, mat<4, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator/(mat<2, 3, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator/(T scalar, mat<2, 3, T, Q> const& m); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL bool operator==(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL bool operator!=(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2); +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_mat2x3.inl" +#endif diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat2x3.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat2x3.inl new file mode 100644 index 0000000000000000000000000000000000000000..ee48e8f8cc27993cf0823dde44f355a3a7962db2 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat2x3.inl @@ -0,0 +1,510 @@ +namespace glm +{ + // -- Constructors -- + +# if GLM_CONFIG_DEFAULTED_DEFAULT_CTOR == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat() +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST + : value{col_type(1, 0, 0), col_type(0, 1, 0)} +# endif + { +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION + this->value[0] = col_type(1, 0, 0); + this->value[1] = col_type(0, 1, 0); +# endif + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<2, 3, T, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m.value[0]; + this->value[1] = m.value[1]; +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(T scalar) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(scalar, 0, 0), col_type(0, scalar, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(scalar, 0, 0); + this->value[1] = col_type(0, scalar, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat + ( + T x0, T y0, T z0, + T x1, T y1, T z1 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x0, y0, z0), col_type(x1, y1, z1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0, z0); + this->value[1] = col_type(x1, y1, z1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(col_type const& v0, col_type const& v1) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v0), col_type(v1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(v0); + this->value[1] = col_type(v1); +# endif + } + + // -- Conversion constructors -- + + template + template< + typename X1, typename Y1, typename Z1, + typename X2, typename Y2, typename Z2> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat + ( + X1 x1, Y1 y1, Z1 z1, + X2 x2, Y2 y2, Z2 z2 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x1, y1, z1), col_type(x2, y2, z2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x1, y1, z1); + this->value[1] = col_type(x2, y2, z2); +# endif + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(vec<3, V1, Q> const& v1, vec<3, V2, Q> const& v2) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v1), col_type(v2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(v1); + this->value[1] = col_type(v2); +# endif + } + + // -- Matrix conversions -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<2, 3, U, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<2, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<3, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<4, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<2, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<3, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<3, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<4, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<4, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + // -- Accesses -- + + template + GLM_FUNC_QUALIFIER typename mat<2, 3, T, Q>::col_type & mat<2, 3, T, Q>::operator[](typename mat<2, 3, T, Q>::length_type i) GLM_NOEXCEPT + { + assert(i < this->length()); + return this->value[i]; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<2, 3, T, Q>::col_type const& mat<2, 3, T, Q>::operator[](typename mat<2, 3, T, Q>::length_type i) const GLM_NOEXCEPT + { + assert(i < this->length()); + return this->value[i]; + } + + // -- Unary updatable operators -- + + template + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q>& mat<2, 3, T, Q>::operator=(mat<2, 3, U, Q> const& m) + { + this->value[0] = m[0]; + this->value[1] = m[1]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> & mat<2, 3, T, Q>::operator+=(U s) + { + this->value[0] += s; + this->value[1] += s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q>& mat<2, 3, T, Q>::operator+=(mat<2, 3, U, Q> const& m) + { + this->value[0] += m[0]; + this->value[1] += m[1]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q>& mat<2, 3, T, Q>::operator-=(U s) + { + this->value[0] -= s; + this->value[1] -= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q>& mat<2, 3, T, Q>::operator-=(mat<2, 3, U, Q> const& m) + { + this->value[0] -= m[0]; + this->value[1] -= m[1]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q>& mat<2, 3, T, Q>::operator*=(U s) + { + this->value[0] *= s; + this->value[1] *= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> & mat<2, 3, T, Q>::operator/=(U s) + { + this->value[0] /= s; + this->value[1] /= s; + return *this; + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> & mat<2, 3, T, Q>::operator++() + { + ++this->value[0]; + ++this->value[1]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> & mat<2, 3, T, Q>::operator--() + { + --this->value[0]; + --this->value[1]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> mat<2, 3, T, Q>::operator++(int) + { + mat<2, 3, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> mat<2, 3, T, Q>::operator--(int) + { + mat<2, 3, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator+(mat<2, 3, T, Q> const& m) + { + return m; + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator-(mat<2, 3, T, Q> const& m) + { + return mat<2, 3, T, Q>( + -m[0], + -m[1]); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator+(mat<2, 3, T, Q> const& m, T scalar) + { + return mat<2, 3, T, Q>( + m[0] + scalar, + m[1] + scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator+(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2) + { + return mat<2, 3, T, Q>( + m1[0] + m2[0], + m1[1] + m2[1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator-(mat<2, 3, T, Q> const& m, T scalar) + { + return mat<2, 3, T, Q>( + m[0] - scalar, + m[1] - scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator-(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2) + { + return mat<2, 3, T, Q>( + m1[0] - m2[0], + m1[1] - m2[1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator*(mat<2, 3, T, Q> const& m, T scalar) + { + return mat<2, 3, T, Q>( + m[0] * scalar, + m[1] * scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator*(T scalar, mat<2, 3, T, Q> const& m) + { + return mat<2, 3, T, Q>( + m[0] * scalar, + m[1] * scalar); + } + + template + GLM_FUNC_QUALIFIER typename mat<2, 3, T, Q>::col_type operator* + ( + mat<2, 3, T, Q> const& m, + typename mat<2, 3, T, Q>::row_type const& v) + { + return typename mat<2, 3, T, Q>::col_type( + m[0][0] * v.x + m[1][0] * v.y, + m[0][1] * v.x + m[1][1] * v.y, + m[0][2] * v.x + m[1][2] * v.y); + } + + template + GLM_FUNC_QUALIFIER typename mat<2, 3, T, Q>::row_type operator* + ( + typename mat<2, 3, T, Q>::col_type const& v, + mat<2, 3, T, Q> const& m) + { + return typename mat<2, 3, T, Q>::row_type( + v.x * m[0][0] + v.y * m[0][1] + v.z * m[0][2], + v.x * m[1][0] + v.y * m[1][1] + v.z * m[1][2]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator*(mat<2, 3, T, Q> const& m1, mat<2, 2, T, Q> const& m2) + { + return mat<2, 3, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator*(mat<2, 3, T, Q> const& m1, mat<3, 2, T, Q> const& m2) + { + T SrcA00 = m1[0][0]; + T SrcA01 = m1[0][1]; + T SrcA02 = m1[0][2]; + T SrcA10 = m1[1][0]; + T SrcA11 = m1[1][1]; + T SrcA12 = m1[1][2]; + + T SrcB00 = m2[0][0]; + T SrcB01 = m2[0][1]; + T SrcB10 = m2[1][0]; + T SrcB11 = m2[1][1]; + T SrcB20 = m2[2][0]; + T SrcB21 = m2[2][1]; + + mat<3, 3, T, Q> Result; + Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01; + Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01; + Result[0][2] = SrcA02 * SrcB00 + SrcA12 * SrcB01; + Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11; + Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11; + Result[1][2] = SrcA02 * SrcB10 + SrcA12 * SrcB11; + Result[2][0] = SrcA00 * SrcB20 + SrcA10 * SrcB21; + Result[2][1] = SrcA01 * SrcB20 + SrcA11 * SrcB21; + Result[2][2] = SrcA02 * SrcB20 + SrcA12 * SrcB21; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator*(mat<2, 3, T, Q> const& m1, mat<4, 2, T, Q> const& m2) + { + return mat<4, 3, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1], + m1[0][2] * m2[2][0] + m1[1][2] * m2[2][1], + m1[0][0] * m2[3][0] + m1[1][0] * m2[3][1], + m1[0][1] * m2[3][0] + m1[1][1] * m2[3][1], + m1[0][2] * m2[3][0] + m1[1][2] * m2[3][1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator/(mat<2, 3, T, Q> const& m, T scalar) + { + return mat<2, 3, T, Q>( + m[0] / scalar, + m[1] / scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator/(T scalar, mat<2, 3, T, Q> const& m) + { + return mat<2, 3, T, Q>( + scalar / m[0], + scalar / m[1]); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER bool operator==(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2) + { + return (m1[0] == m2[0]) && (m1[1] == m2[1]); + } + + template + GLM_FUNC_QUALIFIER bool operator!=(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2) + { + return (m1[0] != m2[0]) || (m1[1] != m2[1]); + } +} //namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat2x4.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat2x4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b66acb08d14cef5c5d3973c4b07628b5d6a028e8 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat2x4.hpp @@ -0,0 +1,161 @@ +/// @ref core +/// @file glm/detail/type_mat2x4.hpp + +#pragma once + +#include "type_vec2.hpp" +#include "type_vec4.hpp" +#include +#include + +namespace glm +{ + template + struct mat<2, 4, T, Q> + { + typedef vec<4, T, Q> col_type; + typedef vec<2, T, Q> row_type; + typedef mat<2, 4, T, Q> type; + typedef mat<4, 2, T, Q> transpose_type; + typedef T value_type; + + private: + col_type value[2]; + + public: + // -- Accesses -- + + typedef length_t length_type; + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 2; } + + GLM_FUNC_DECL col_type & operator[](length_type i) GLM_NOEXCEPT; + GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const GLM_NOEXCEPT; + + // -- Constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT_CTOR; + template + GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<2, 4, T, P> const& m); + + GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T scalar); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + T x0, T y0, T z0, T w0, + T x1, T y1, T z1, T w1); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + col_type const& v0, + col_type const& v1); + + // -- Conversions -- + + template< + typename X1, typename Y1, typename Z1, typename W1, + typename X2, typename Y2, typename Z2, typename W2> + GLM_FUNC_DECL GLM_CONSTEXPR mat( + X1 x1, Y1 y1, Z1 z1, W1 w1, + X2 x2, Y2 y2, Z2 z2, W2 w2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR mat( + vec<4, U, Q> const& v1, + vec<4, V, Q> const& v2); + + // -- Matrix conversions -- + + template + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, U, P> const& m); + + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x); + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_DECL mat<2, 4, T, Q> & operator=(mat<2, 4, U, Q> const& m); + template + GLM_FUNC_DECL mat<2, 4, T, Q> & operator+=(U s); + template + GLM_FUNC_DECL mat<2, 4, T, Q> & operator+=(mat<2, 4, U, Q> const& m); + template + GLM_FUNC_DECL mat<2, 4, T, Q> & operator-=(U s); + template + GLM_FUNC_DECL mat<2, 4, T, Q> & operator-=(mat<2, 4, U, Q> const& m); + template + GLM_FUNC_DECL mat<2, 4, T, Q> & operator*=(U s); + template + GLM_FUNC_DECL mat<2, 4, T, Q> & operator/=(U s); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL mat<2, 4, T, Q> & operator++ (); + GLM_FUNC_DECL mat<2, 4, T, Q> & operator-- (); + GLM_FUNC_DECL mat<2, 4, T, Q> operator++(int); + GLM_FUNC_DECL mat<2, 4, T, Q> operator--(int); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator+(mat<2, 4, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator-(mat<2, 4, T, Q> const& m); + + // -- Binary operators -- + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator+(mat<2, 4, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator+(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator-(mat<2, 4, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator-(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator*(mat<2, 4, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator*(T scalar, mat<2, 4, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<2, 4, T, Q>::col_type operator*(mat<2, 4, T, Q> const& m, typename mat<2, 4, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<2, 4, T, Q>::row_type operator*(typename mat<2, 4, T, Q>::col_type const& v, mat<2, 4, T, Q> const& m); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator*(mat<2, 4, T, Q> const& m1, mat<4, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator*(mat<2, 4, T, Q> const& m1, mat<2, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator*(mat<2, 4, T, Q> const& m1, mat<3, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator/(mat<2, 4, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator/(T scalar, mat<2, 4, T, Q> const& m); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL bool operator==(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL bool operator!=(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2); +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_mat2x4.inl" +#endif diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat2x4.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat2x4.inl new file mode 100644 index 0000000000000000000000000000000000000000..72f7d73ecaa9f249542f1270beb25573523c731c --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat2x4.inl @@ -0,0 +1,520 @@ +namespace glm +{ + // -- Constructors -- + +# if GLM_CONFIG_DEFAULTED_DEFAULT_CTOR == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat() +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST + : value{col_type(1, 0, 0, 0), col_type(0, 1, 0, 0)} +# endif + { +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION + this->value[0] = col_type(1, 0, 0, 0); + this->value[1] = col_type(0, 1, 0, 0); +# endif + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<2, 4, T, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m[0]; + this->value[1] = m[1]; +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(T s) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(s, 0, 0, 0), col_type(0, s, 0, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(s, 0, 0, 0); + this->value[1] = col_type(0, s, 0, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat + ( + T x0, T y0, T z0, T w0, + T x1, T y1, T z1, T w1 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x0, y0, z0, w0), col_type(x1, y1, z1, w1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0, z0, w0); + this->value[1] = col_type(x1, y1, z1, w1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(col_type const& v0, col_type const& v1) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v0), col_type(v1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = v0; + this->value[1] = v1; +# endif + } + + // -- Conversion constructors -- + + template + template< + typename X1, typename Y1, typename Z1, typename W1, + typename X2, typename Y2, typename Z2, typename W2> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat + ( + X1 x1, Y1 y1, Z1 z1, W1 w1, + X2 x2, Y2 y2, Z2 z2, W2 w2 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{ + col_type(x1, y1, z1, w1), + col_type(x2, y2, z2, w2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x1, y1, z1, w1); + this->value[1] = col_type(x2, y2, z2, w2); +# endif + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(vec<4, V1, Q> const& v1, vec<4, V2, Q> const& v2) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v1), col_type(v2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(v1); + this->value[1] = col_type(v2); +# endif + } + + // -- Matrix conversions -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<2, 4, U, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<2, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0, 0); + this->value[1] = col_type(m[1], 0, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<3, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<4, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<2, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<3, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0, 0); + this->value[1] = col_type(m[1], 0, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<3, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<4, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0, 0); + this->value[1] = col_type(m[1], 0, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<4, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); +# endif + } + + // -- Accesses -- + + template + GLM_FUNC_QUALIFIER typename mat<2, 4, T, Q>::col_type & mat<2, 4, T, Q>::operator[](typename mat<2, 4, T, Q>::length_type i) GLM_NOEXCEPT + { + assert(i < this->length()); + return this->value[i]; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<2, 4, T, Q>::col_type const& mat<2, 4, T, Q>::operator[](typename mat<2, 4, T, Q>::length_type i) const GLM_NOEXCEPT + { + assert(i < this->length()); + return this->value[i]; + } + + // -- Unary updatable operators -- + + template + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator=(mat<2, 4, U, Q> const& m) + { + this->value[0] = m[0]; + this->value[1] = m[1]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator+=(U s) + { + this->value[0] += s; + this->value[1] += s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator+=(mat<2, 4, U, Q> const& m) + { + this->value[0] += m[0]; + this->value[1] += m[1]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator-=(U s) + { + this->value[0] -= s; + this->value[1] -= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator-=(mat<2, 4, U, Q> const& m) + { + this->value[0] -= m[0]; + this->value[1] -= m[1]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator*=(U s) + { + this->value[0] *= s; + this->value[1] *= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> & mat<2, 4, T, Q>::operator/=(U s) + { + this->value[0] /= s; + this->value[1] /= s; + return *this; + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator++() + { + ++this->value[0]; + ++this->value[1]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator--() + { + --this->value[0]; + --this->value[1]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> mat<2, 4, T, Q>::operator++(int) + { + mat<2, 4, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> mat<2, 4, T, Q>::operator--(int) + { + mat<2, 4, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator+(mat<2, 4, T, Q> const& m) + { + return m; + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator-(mat<2, 4, T, Q> const& m) + { + return mat<2, 4, T, Q>( + -m[0], + -m[1]); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator+(mat<2, 4, T, Q> const& m, T scalar) + { + return mat<2, 4, T, Q>( + m[0] + scalar, + m[1] + scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator+(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2) + { + return mat<2, 4, T, Q>( + m1[0] + m2[0], + m1[1] + m2[1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator-(mat<2, 4, T, Q> const& m, T scalar) + { + return mat<2, 4, T, Q>( + m[0] - scalar, + m[1] - scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator-(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2) + { + return mat<2, 4, T, Q>( + m1[0] - m2[0], + m1[1] - m2[1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator*(mat<2, 4, T, Q> const& m, T scalar) + { + return mat<2, 4, T, Q>( + m[0] * scalar, + m[1] * scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator*(T scalar, mat<2, 4, T, Q> const& m) + { + return mat<2, 4, T, Q>( + m[0] * scalar, + m[1] * scalar); + } + + template + GLM_FUNC_QUALIFIER typename mat<2, 4, T, Q>::col_type operator*(mat<2, 4, T, Q> const& m, typename mat<2, 4, T, Q>::row_type const& v) + { + return typename mat<2, 4, T, Q>::col_type( + m[0][0] * v.x + m[1][0] * v.y, + m[0][1] * v.x + m[1][1] * v.y, + m[0][2] * v.x + m[1][2] * v.y, + m[0][3] * v.x + m[1][3] * v.y); + } + + template + GLM_FUNC_QUALIFIER typename mat<2, 4, T, Q>::row_type operator*(typename mat<2, 4, T, Q>::col_type const& v, mat<2, 4, T, Q> const& m) + { + return typename mat<2, 4, T, Q>::row_type( + v.x * m[0][0] + v.y * m[0][1] + v.z * m[0][2] + v.w * m[0][3], + v.x * m[1][0] + v.y * m[1][1] + v.z * m[1][2] + v.w * m[1][3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator*(mat<2, 4, T, Q> const& m1, mat<4, 2, T, Q> const& m2) + { + T SrcA00 = m1[0][0]; + T SrcA01 = m1[0][1]; + T SrcA02 = m1[0][2]; + T SrcA03 = m1[0][3]; + T SrcA10 = m1[1][0]; + T SrcA11 = m1[1][1]; + T SrcA12 = m1[1][2]; + T SrcA13 = m1[1][3]; + + T SrcB00 = m2[0][0]; + T SrcB01 = m2[0][1]; + T SrcB10 = m2[1][0]; + T SrcB11 = m2[1][1]; + T SrcB20 = m2[2][0]; + T SrcB21 = m2[2][1]; + T SrcB30 = m2[3][0]; + T SrcB31 = m2[3][1]; + + mat<4, 4, T, Q> Result; + Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01; + Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01; + Result[0][2] = SrcA02 * SrcB00 + SrcA12 * SrcB01; + Result[0][3] = SrcA03 * SrcB00 + SrcA13 * SrcB01; + Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11; + Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11; + Result[1][2] = SrcA02 * SrcB10 + SrcA12 * SrcB11; + Result[1][3] = SrcA03 * SrcB10 + SrcA13 * SrcB11; + Result[2][0] = SrcA00 * SrcB20 + SrcA10 * SrcB21; + Result[2][1] = SrcA01 * SrcB20 + SrcA11 * SrcB21; + Result[2][2] = SrcA02 * SrcB20 + SrcA12 * SrcB21; + Result[2][3] = SrcA03 * SrcB20 + SrcA13 * SrcB21; + Result[3][0] = SrcA00 * SrcB30 + SrcA10 * SrcB31; + Result[3][1] = SrcA01 * SrcB30 + SrcA11 * SrcB31; + Result[3][2] = SrcA02 * SrcB30 + SrcA12 * SrcB31; + Result[3][3] = SrcA03 * SrcB30 + SrcA13 * SrcB31; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator*(mat<2, 4, T, Q> const& m1, mat<2, 2, T, Q> const& m2) + { + return mat<2, 4, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1], + m1[0][3] * m2[0][0] + m1[1][3] * m2[0][1], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1], + m1[0][3] * m2[1][0] + m1[1][3] * m2[1][1]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator*(mat<2, 4, T, Q> const& m1, mat<3, 2, T, Q> const& m2) + { + return mat<3, 4, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1], + m1[0][3] * m2[0][0] + m1[1][3] * m2[0][1], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1], + m1[0][3] * m2[1][0] + m1[1][3] * m2[1][1], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1], + m1[0][2] * m2[2][0] + m1[1][2] * m2[2][1], + m1[0][3] * m2[2][0] + m1[1][3] * m2[2][1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator/(mat<2, 4, T, Q> const& m, T scalar) + { + return mat<2, 4, T, Q>( + m[0] / scalar, + m[1] / scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator/(T scalar, mat<2, 4, T, Q> const& m) + { + return mat<2, 4, T, Q>( + scalar / m[0], + scalar / m[1]); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER bool operator==(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2) + { + return (m1[0] == m2[0]) && (m1[1] == m2[1]); + } + + template + GLM_FUNC_QUALIFIER bool operator!=(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2) + { + return (m1[0] != m2[0]) || (m1[1] != m2[1]); + } +} //namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat3x2.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat3x2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0ddb65e49e02818020eae89972561d1ea65a8557 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat3x2.hpp @@ -0,0 +1,167 @@ +/// @ref core +/// @file glm/detail/type_mat3x2.hpp + +#pragma once + +#include "type_vec2.hpp" +#include "type_vec3.hpp" +#include +#include + +namespace glm +{ + template + struct mat<3, 2, T, Q> + { + typedef vec<2, T, Q> col_type; + typedef vec<3, T, Q> row_type; + typedef mat<3, 2, T, Q> type; + typedef mat<2, 3, T, Q> transpose_type; + typedef T value_type; + + private: + col_type value[3]; + + public: + // -- Accesses -- + + typedef length_t length_type; + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 3; } + + GLM_FUNC_DECL col_type & operator[](length_type i) GLM_NOEXCEPT; + GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const GLM_NOEXCEPT; + + // -- Constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT_CTOR; + template + GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<3, 2, T, P> const& m); + + GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T scalar); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + T x0, T y0, + T x1, T y1, + T x2, T y2); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + col_type const& v0, + col_type const& v1, + col_type const& v2); + + // -- Conversions -- + + template< + typename X1, typename Y1, + typename X2, typename Y2, + typename X3, typename Y3> + GLM_FUNC_DECL GLM_CONSTEXPR mat( + X1 x1, Y1 y1, + X2 x2, Y2 y2, + X3 x3, Y3 y3); + + template + GLM_FUNC_DECL GLM_CONSTEXPR mat( + vec<2, V1, Q> const& v1, + vec<2, V2, Q> const& v2, + vec<2, V3, Q> const& v3); + + // -- Matrix conversions -- + + template + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, U, P> const& m); + + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x); + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_DECL mat<3, 2, T, Q> & operator=(mat<3, 2, U, Q> const& m); + template + GLM_FUNC_DECL mat<3, 2, T, Q> & operator+=(U s); + template + GLM_FUNC_DECL mat<3, 2, T, Q> & operator+=(mat<3, 2, U, Q> const& m); + template + GLM_FUNC_DECL mat<3, 2, T, Q> & operator-=(U s); + template + GLM_FUNC_DECL mat<3, 2, T, Q> & operator-=(mat<3, 2, U, Q> const& m); + template + GLM_FUNC_DECL mat<3, 2, T, Q> & operator*=(U s); + template + GLM_FUNC_DECL mat<3, 2, T, Q> & operator/=(U s); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL mat<3, 2, T, Q> & operator++ (); + GLM_FUNC_DECL mat<3, 2, T, Q> & operator-- (); + GLM_FUNC_DECL mat<3, 2, T, Q> operator++(int); + GLM_FUNC_DECL mat<3, 2, T, Q> operator--(int); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator+(mat<3, 2, T, Q> const& m); + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator-(mat<3, 2, T, Q> const& m); + + // -- Binary operators -- + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator+(mat<3, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator+(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator-(mat<3, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator-(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator*(mat<3, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator*(T scalar, mat<3, 2, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<3, 2, T, Q>::col_type operator*(mat<3, 2, T, Q> const& m, typename mat<3, 2, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<3, 2, T, Q>::row_type operator*(typename mat<3, 2, T, Q>::col_type const& v, mat<3, 2, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator*(mat<3, 2, T, Q> const& m1, mat<2, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator*(mat<3, 2, T, Q> const& m1, mat<3, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator*(mat<3, 2, T, Q> const& m1, mat<4, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator/(mat<3, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator/(T scalar, mat<3, 2, T, Q> const& m); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL bool operator==(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL bool operator!=(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2); + +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_mat3x2.inl" +#endif diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat3x2.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat3x2.inl new file mode 100644 index 0000000000000000000000000000000000000000..fcf9447da84ea5adf149e321b0192a4ae15f1d3b --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat3x2.inl @@ -0,0 +1,532 @@ +namespace glm +{ + // -- Constructors -- + +# if GLM_CONFIG_DEFAULTED_DEFAULT_CTOR == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat() +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST + : value{col_type(1, 0), col_type(0, 1), col_type(0, 0)} +# endif + { +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION + this->value[0] = col_type(1, 0); + this->value[1] = col_type(0, 1); + this->value[2] = col_type(0, 0); +# endif + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<3, 2, T, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(T s) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(s, 0), col_type(0, s), col_type(0, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(s, 0); + this->value[1] = col_type(0, s); + this->value[2] = col_type(0, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat + ( + T x0, T y0, + T x1, T y1, + T x2, T y2 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x0, y0), col_type(x1, y1), col_type(x2, y2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0); + this->value[1] = col_type(x1, y1); + this->value[2] = col_type(x2, y2); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(col_type const& v0, col_type const& v1, col_type const& v2) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v0), col_type(v1), col_type(v2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = v0; + this->value[1] = v1; + this->value[2] = v2; +# endif + } + + // -- Conversion constructors -- + + template + template< + typename X0, typename Y0, + typename X1, typename Y1, + typename X2, typename Y2> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat + ( + X0 x0, Y0 y0, + X1 x1, Y1 y1, + X2 x2, Y2 y2 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x0, y0), col_type(x1, y1), col_type(x2, y2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0); + this->value[1] = col_type(x1, y1); + this->value[2] = col_type(x2, y2); +# endif + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(vec<2, V0, Q> const& v0, vec<2, V1, Q> const& v1, vec<2, V2, Q> const& v2) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v0), col_type(v1), col_type(v2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(v0); + this->value[1] = col_type(v1); + this->value[2] = col_type(v2); +# endif + } + + // -- Matrix conversions -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<3, 2, U, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<2, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<3, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<4, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<2, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<2, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<3, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<4, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<4, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + // -- Accesses -- + + template + GLM_FUNC_QUALIFIER typename mat<3, 2, T, Q>::col_type & mat<3, 2, T, Q>::operator[](typename mat<3, 2, T, Q>::length_type i) GLM_NOEXCEPT + { + assert(i < this->length()); + return this->value[i]; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<3, 2, T, Q>::col_type const& mat<3, 2, T, Q>::operator[](typename mat<3, 2, T, Q>::length_type i) const GLM_NOEXCEPT + { + assert(i < this->length()); + return this->value[i]; + } + + // -- Unary updatable operators -- + + template + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator=(mat<3, 2, U, Q> const& m) + { + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator+=(U s) + { + this->value[0] += s; + this->value[1] += s; + this->value[2] += s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator+=(mat<3, 2, U, Q> const& m) + { + this->value[0] += m[0]; + this->value[1] += m[1]; + this->value[2] += m[2]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator-=(U s) + { + this->value[0] -= s; + this->value[1] -= s; + this->value[2] -= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator-=(mat<3, 2, U, Q> const& m) + { + this->value[0] -= m[0]; + this->value[1] -= m[1]; + this->value[2] -= m[2]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator*=(U s) + { + this->value[0] *= s; + this->value[1] *= s; + this->value[2] *= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> & mat<3, 2, T, Q>::operator/=(U s) + { + this->value[0] /= s; + this->value[1] /= s; + this->value[2] /= s; + return *this; + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator++() + { + ++this->value[0]; + ++this->value[1]; + ++this->value[2]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator--() + { + --this->value[0]; + --this->value[1]; + --this->value[2]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> mat<3, 2, T, Q>::operator++(int) + { + mat<3, 2, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> mat<3, 2, T, Q>::operator--(int) + { + mat<3, 2, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator+(mat<3, 2, T, Q> const& m) + { + return m; + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator-(mat<3, 2, T, Q> const& m) + { + return mat<3, 2, T, Q>( + -m[0], + -m[1], + -m[2]); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator+(mat<3, 2, T, Q> const& m, T scalar) + { + return mat<3, 2, T, Q>( + m[0] + scalar, + m[1] + scalar, + m[2] + scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator+(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2) + { + return mat<3, 2, T, Q>( + m1[0] + m2[0], + m1[1] + m2[1], + m1[2] + m2[2]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator-(mat<3, 2, T, Q> const& m, T scalar) + { + return mat<3, 2, T, Q>( + m[0] - scalar, + m[1] - scalar, + m[2] - scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator-(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2) + { + return mat<3, 2, T, Q>( + m1[0] - m2[0], + m1[1] - m2[1], + m1[2] - m2[2]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator*(mat<3, 2, T, Q> const& m, T scalar) + { + return mat<3, 2, T, Q>( + m[0] * scalar, + m[1] * scalar, + m[2] * scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator*(T scalar, mat<3, 2, T, Q> const& m) + { + return mat<3, 2, T, Q>( + m[0] * scalar, + m[1] * scalar, + m[2] * scalar); + } + + template + GLM_FUNC_QUALIFIER typename mat<3, 2, T, Q>::col_type operator*(mat<3, 2, T, Q> const& m, typename mat<3, 2, T, Q>::row_type const& v) + { + return typename mat<3, 2, T, Q>::col_type( + m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z, + m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z); + } + + template + GLM_FUNC_QUALIFIER typename mat<3, 2, T, Q>::row_type operator*(typename mat<3, 2, T, Q>::col_type const& v, mat<3, 2, T, Q> const& m) + { + return typename mat<3, 2, T, Q>::row_type( + v.x * m[0][0] + v.y * m[0][1], + v.x * m[1][0] + v.y * m[1][1], + v.x * m[2][0] + v.y * m[2][1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator*(mat<3, 2, T, Q> const& m1, mat<2, 3, T, Q> const& m2) + { + const T SrcA00 = m1[0][0]; + const T SrcA01 = m1[0][1]; + const T SrcA10 = m1[1][0]; + const T SrcA11 = m1[1][1]; + const T SrcA20 = m1[2][0]; + const T SrcA21 = m1[2][1]; + + const T SrcB00 = m2[0][0]; + const T SrcB01 = m2[0][1]; + const T SrcB02 = m2[0][2]; + const T SrcB10 = m2[1][0]; + const T SrcB11 = m2[1][1]; + const T SrcB12 = m2[1][2]; + + mat<2, 2, T, Q> Result; + Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01 + SrcA20 * SrcB02; + Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01 + SrcA21 * SrcB02; + Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11 + SrcA20 * SrcB12; + Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11 + SrcA21 * SrcB12; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator*(mat<3, 2, T, Q> const& m1, mat<3, 3, T, Q> const& m2) + { + return mat<3, 2, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator*(mat<3, 2, T, Q> const& m1, mat<4, 3, T, Q> const& m2) + { + return mat<4, 2, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2], + m1[0][0] * m2[3][0] + m1[1][0] * m2[3][1] + m1[2][0] * m2[3][2], + m1[0][1] * m2[3][0] + m1[1][1] * m2[3][1] + m1[2][1] * m2[3][2]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator/(mat<3, 2, T, Q> const& m, T scalar) + { + return mat<3, 2, T, Q>( + m[0] / scalar, + m[1] / scalar, + m[2] / scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator/(T scalar, mat<3, 2, T, Q> const& m) + { + return mat<3, 2, T, Q>( + scalar / m[0], + scalar / m[1], + scalar / m[2]); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER bool operator==(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2) + { + return (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]); + } + + template + GLM_FUNC_QUALIFIER bool operator!=(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2) + { + return (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]); + } +} //namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat3x3.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat3x3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7aac3219494e3ca730d9bdb46f84bbe62d53d2ac --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat3x3.hpp @@ -0,0 +1,184 @@ +/// @ref core +/// @file glm/detail/type_mat3x3.hpp + +#pragma once + +#include "type_vec3.hpp" +#include +#include + +namespace glm +{ + template + struct mat<3, 3, T, Q> + { + typedef vec<3, T, Q> col_type; + typedef vec<3, T, Q> row_type; + typedef mat<3, 3, T, Q> type; + typedef mat<3, 3, T, Q> transpose_type; + typedef T value_type; + + private: + col_type value[3]; + + public: + // -- Accesses -- + + typedef length_t length_type; + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 3; } + + GLM_FUNC_DECL col_type & operator[](length_type i) GLM_NOEXCEPT; + GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const GLM_NOEXCEPT; + + // -- Constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT_CTOR; + template + GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<3, 3, T, P> const& m); + + GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T scalar); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + T x0, T y0, T z0, + T x1, T y1, T z1, + T x2, T y2, T z2); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + col_type const& v0, + col_type const& v1, + col_type const& v2); + + // -- Conversions -- + + template< + typename X1, typename Y1, typename Z1, + typename X2, typename Y2, typename Z2, + typename X3, typename Y3, typename Z3> + GLM_FUNC_DECL GLM_CONSTEXPR mat( + X1 x1, Y1 y1, Z1 z1, + X2 x2, Y2 y2, Z2 z2, + X3 x3, Y3 y3, Z3 z3); + + template + GLM_FUNC_DECL GLM_CONSTEXPR mat( + vec<3, V1, Q> const& v1, + vec<3, V2, Q> const& v2, + vec<3, V3, Q> const& v3); + + // -- Matrix conversions -- + + template + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, U, P> const& m); + + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x); + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_DECL mat<3, 3, T, Q> & operator=(mat<3, 3, U, Q> const& m); + template + GLM_FUNC_DECL mat<3, 3, T, Q> & operator+=(U s); + template + GLM_FUNC_DECL mat<3, 3, T, Q> & operator+=(mat<3, 3, U, Q> const& m); + template + GLM_FUNC_DECL mat<3, 3, T, Q> & operator-=(U s); + template + GLM_FUNC_DECL mat<3, 3, T, Q> & operator-=(mat<3, 3, U, Q> const& m); + template + GLM_FUNC_DECL mat<3, 3, T, Q> & operator*=(U s); + template + GLM_FUNC_DECL mat<3, 3, T, Q> & operator*=(mat<3, 3, U, Q> const& m); + template + GLM_FUNC_DECL mat<3, 3, T, Q> & operator/=(U s); + template + GLM_FUNC_DECL mat<3, 3, T, Q> & operator/=(mat<3, 3, U, Q> const& m); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL mat<3, 3, T, Q> & operator++(); + GLM_FUNC_DECL mat<3, 3, T, Q> & operator--(); + GLM_FUNC_DECL mat<3, 3, T, Q> operator++(int); + GLM_FUNC_DECL mat<3, 3, T, Q> operator--(int); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator+(mat<3, 3, T, Q> const& m); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator-(mat<3, 3, T, Q> const& m); + + // -- Binary operators -- + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator+(mat<3, 3, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator+(T scalar, mat<3, 3, T, Q> const& m); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator+(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator-(mat<3, 3, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator-(T scalar, mat<3, 3, T, Q> const& m); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator-(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator*(mat<3, 3, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator*(T scalar, mat<3, 3, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<3, 3, T, Q>::col_type operator*(mat<3, 3, T, Q> const& m, typename mat<3, 3, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<3, 3, T, Q>::row_type operator*(typename mat<3, 3, T, Q>::col_type const& v, mat<3, 3, T, Q> const& m); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator*(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator*(mat<3, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator*(mat<3, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator/(mat<3, 3, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator/(T scalar, mat<3, 3, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<3, 3, T, Q>::col_type operator/(mat<3, 3, T, Q> const& m, typename mat<3, 3, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<3, 3, T, Q>::row_type operator/(typename mat<3, 3, T, Q>::col_type const& v, mat<3, 3, T, Q> const& m); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator/(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator==(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL bool operator!=(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2); +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_mat3x3.inl" +#endif diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat3x3.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat3x3.inl new file mode 100644 index 0000000000000000000000000000000000000000..233473e31abde0266fa3248e043e6281c201ba66 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat3x3.inl @@ -0,0 +1,601 @@ +#include "../matrix.hpp" + +namespace glm +{ + // -- Constructors -- + +# if GLM_CONFIG_DEFAULTED_DEFAULT_CTOR == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat() +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST + : value{col_type(1, 0, 0), col_type(0, 1, 0), col_type(0, 0, 1)} +# endif + { +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION + this->value[0] = col_type(1, 0, 0); + this->value[1] = col_type(0, 1, 0); + this->value[2] = col_type(0, 0, 1); +# endif + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<3, 3, T, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(T s) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(s, 0, 0), col_type(0, s, 0), col_type(0, 0, s)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(s, 0, 0); + this->value[1] = col_type(0, s, 0); + this->value[2] = col_type(0, 0, s); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat + ( + T x0, T y0, T z0, + T x1, T y1, T z1, + T x2, T y2, T z2 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x0, y0, z0), col_type(x1, y1, z1), col_type(x2, y2, z2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0, z0); + this->value[1] = col_type(x1, y1, z1); + this->value[2] = col_type(x2, y2, z2); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(col_type const& v0, col_type const& v1, col_type const& v2) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v0), col_type(v1), col_type(v2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(v0); + this->value[1] = col_type(v1); + this->value[2] = col_type(v2); +# endif + } + + // -- Conversion constructors -- + + template + template< + typename X1, typename Y1, typename Z1, + typename X2, typename Y2, typename Z2, + typename X3, typename Y3, typename Z3> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat + ( + X1 x1, Y1 y1, Z1 z1, + X2 x2, Y2 y2, Z2 z2, + X3 x3, Y3 y3, Z3 z3 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x1, y1, z1), col_type(x2, y2, z2), col_type(x3, y3, z3)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x1, y1, z1); + this->value[1] = col_type(x2, y2, z2); + this->value[2] = col_type(x3, y3, z3); +# endif + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(vec<3, V1, Q> const& v1, vec<3, V2, Q> const& v2, vec<3, V3, Q> const& v3) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v1), col_type(v2), col_type(v3)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(v1); + this->value[1] = col_type(v2); + this->value[2] = col_type(v3); +# endif + } + + // -- Matrix conversions -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<3, 3, U, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<2, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(0, 0, 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(0, 0, 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<4, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<2, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0, 0, 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(0, 0, 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<3, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(m[2], 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<2, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0, 0, 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(0, 0, 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<4, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(m[2], 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<3, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<4, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + // -- Accesses -- + + template + GLM_FUNC_QUALIFIER typename mat<3, 3, T, Q>::col_type & mat<3, 3, T, Q>::operator[](typename mat<3, 3, T, Q>::length_type i) GLM_NOEXCEPT + { + assert(i < this->length()); + return this->value[i]; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<3, 3, T, Q>::col_type const& mat<3, 3, T, Q>::operator[](typename mat<3, 3, T, Q>::length_type i) const GLM_NOEXCEPT + { + assert(i < this->length()); + return this->value[i]; + } + + // -- Unary updatable operators -- + + template + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator=(mat<3, 3, U, Q> const& m) + { + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator+=(U s) + { + this->value[0] += s; + this->value[1] += s; + this->value[2] += s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator+=(mat<3, 3, U, Q> const& m) + { + this->value[0] += m[0]; + this->value[1] += m[1]; + this->value[2] += m[2]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator-=(U s) + { + this->value[0] -= s; + this->value[1] -= s; + this->value[2] -= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator-=(mat<3, 3, U, Q> const& m) + { + this->value[0] -= m[0]; + this->value[1] -= m[1]; + this->value[2] -= m[2]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator*=(U s) + { + this->value[0] *= s; + this->value[1] *= s; + this->value[2] *= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator*=(mat<3, 3, U, Q> const& m) + { + return (*this = *this * m); + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator/=(U s) + { + this->value[0] /= s; + this->value[1] /= s; + this->value[2] /= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator/=(mat<3, 3, U, Q> const& m) + { + return *this *= inverse(m); + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator++() + { + ++this->value[0]; + ++this->value[1]; + ++this->value[2]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator--() + { + --this->value[0]; + --this->value[1]; + --this->value[2]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> mat<3, 3, T, Q>::operator++(int) + { + mat<3, 3, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> mat<3, 3, T, Q>::operator--(int) + { + mat<3, 3, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator+(mat<3, 3, T, Q> const& m) + { + return m; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator-(mat<3, 3, T, Q> const& m) + { + return mat<3, 3, T, Q>( + -m[0], + -m[1], + -m[2]); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator+(mat<3, 3, T, Q> const& m, T scalar) + { + return mat<3, 3, T, Q>( + m[0] + scalar, + m[1] + scalar, + m[2] + scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator+(T scalar, mat<3, 3, T, Q> const& m) + { + return mat<3, 3, T, Q>( + m[0] + scalar, + m[1] + scalar, + m[2] + scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator+(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2) + { + return mat<3, 3, T, Q>( + m1[0] + m2[0], + m1[1] + m2[1], + m1[2] + m2[2]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator-(mat<3, 3, T, Q> const& m, T scalar) + { + return mat<3, 3, T, Q>( + m[0] - scalar, + m[1] - scalar, + m[2] - scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator-(T scalar, mat<3, 3, T, Q> const& m) + { + return mat<3, 3, T, Q>( + scalar - m[0], + scalar - m[1], + scalar - m[2]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator-(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2) + { + return mat<3, 3, T, Q>( + m1[0] - m2[0], + m1[1] - m2[1], + m1[2] - m2[2]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator*(mat<3, 3, T, Q> const& m, T scalar) + { + return mat<3, 3, T, Q>( + m[0] * scalar, + m[1] * scalar, + m[2] * scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator*(T scalar, mat<3, 3, T, Q> const& m) + { + return mat<3, 3, T, Q>( + m[0] * scalar, + m[1] * scalar, + m[2] * scalar); + } + + template + GLM_FUNC_QUALIFIER typename mat<3, 3, T, Q>::col_type operator*(mat<3, 3, T, Q> const& m, typename mat<3, 3, T, Q>::row_type const& v) + { + return typename mat<3, 3, T, Q>::col_type( + m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z, + m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z, + m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z); + } + + template + GLM_FUNC_QUALIFIER typename mat<3, 3, T, Q>::row_type operator*(typename mat<3, 3, T, Q>::col_type const& v, mat<3, 3, T, Q> const& m) + { + return typename mat<3, 3, T, Q>::row_type( + m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z, + m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z, + m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator*(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2) + { + T const SrcA00 = m1[0][0]; + T const SrcA01 = m1[0][1]; + T const SrcA02 = m1[0][2]; + T const SrcA10 = m1[1][0]; + T const SrcA11 = m1[1][1]; + T const SrcA12 = m1[1][2]; + T const SrcA20 = m1[2][0]; + T const SrcA21 = m1[2][1]; + T const SrcA22 = m1[2][2]; + + T const SrcB00 = m2[0][0]; + T const SrcB01 = m2[0][1]; + T const SrcB02 = m2[0][2]; + T const SrcB10 = m2[1][0]; + T const SrcB11 = m2[1][1]; + T const SrcB12 = m2[1][2]; + T const SrcB20 = m2[2][0]; + T const SrcB21 = m2[2][1]; + T const SrcB22 = m2[2][2]; + + mat<3, 3, T, Q> Result; + Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01 + SrcA20 * SrcB02; + Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01 + SrcA21 * SrcB02; + Result[0][2] = SrcA02 * SrcB00 + SrcA12 * SrcB01 + SrcA22 * SrcB02; + Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11 + SrcA20 * SrcB12; + Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11 + SrcA21 * SrcB12; + Result[1][2] = SrcA02 * SrcB10 + SrcA12 * SrcB11 + SrcA22 * SrcB12; + Result[2][0] = SrcA00 * SrcB20 + SrcA10 * SrcB21 + SrcA20 * SrcB22; + Result[2][1] = SrcA01 * SrcB20 + SrcA11 * SrcB21 + SrcA21 * SrcB22; + Result[2][2] = SrcA02 * SrcB20 + SrcA12 * SrcB21 + SrcA22 * SrcB22; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator*(mat<3, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2) + { + return mat<2, 3, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator*(mat<3, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2) + { + return mat<4, 3, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2], + m1[0][2] * m2[2][0] + m1[1][2] * m2[2][1] + m1[2][2] * m2[2][2], + m1[0][0] * m2[3][0] + m1[1][0] * m2[3][1] + m1[2][0] * m2[3][2], + m1[0][1] * m2[3][0] + m1[1][1] * m2[3][1] + m1[2][1] * m2[3][2], + m1[0][2] * m2[3][0] + m1[1][2] * m2[3][1] + m1[2][2] * m2[3][2]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator/(mat<3, 3, T, Q> const& m, T scalar) + { + return mat<3, 3, T, Q>( + m[0] / scalar, + m[1] / scalar, + m[2] / scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator/(T scalar, mat<3, 3, T, Q> const& m) + { + return mat<3, 3, T, Q>( + scalar / m[0], + scalar / m[1], + scalar / m[2]); + } + + template + GLM_FUNC_QUALIFIER typename mat<3, 3, T, Q>::col_type operator/(mat<3, 3, T, Q> const& m, typename mat<3, 3, T, Q>::row_type const& v) + { + return inverse(m) * v; + } + + template + GLM_FUNC_QUALIFIER typename mat<3, 3, T, Q>::row_type operator/(typename mat<3, 3, T, Q>::col_type const& v, mat<3, 3, T, Q> const& m) + { + return v * inverse(m); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator/(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2) + { + mat<3, 3, T, Q> m1_copy(m1); + return m1_copy /= m2; + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator==(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2) + { + return (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]); + } + + template + GLM_FUNC_QUALIFIER bool operator!=(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2) + { + return (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]); + } +} //namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat3x4.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat3x4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c8a1f2ccf0e831111f68d307fd3960ed61467d26 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat3x4.hpp @@ -0,0 +1,166 @@ +/// @ref core +/// @file glm/detail/type_mat3x4.hpp + +#pragma once + +#include "type_vec3.hpp" +#include "type_vec4.hpp" +#include +#include + +namespace glm +{ + template + struct mat<3, 4, T, Q> + { + typedef vec<4, T, Q> col_type; + typedef vec<3, T, Q> row_type; + typedef mat<3, 4, T, Q> type; + typedef mat<4, 3, T, Q> transpose_type; + typedef T value_type; + + private: + col_type value[3]; + + public: + // -- Accesses -- + + typedef length_t length_type; + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 3; } + + GLM_FUNC_DECL col_type & operator[](length_type i) GLM_NOEXCEPT; + GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const GLM_NOEXCEPT; + + // -- Constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT_CTOR; + template + GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<3, 4, T, P> const& m); + + GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T scalar); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + T x0, T y0, T z0, T w0, + T x1, T y1, T z1, T w1, + T x2, T y2, T z2, T w2); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + col_type const& v0, + col_type const& v1, + col_type const& v2); + + // -- Conversions -- + + template< + typename X1, typename Y1, typename Z1, typename W1, + typename X2, typename Y2, typename Z2, typename W2, + typename X3, typename Y3, typename Z3, typename W3> + GLM_FUNC_DECL GLM_CONSTEXPR mat( + X1 x1, Y1 y1, Z1 z1, W1 w1, + X2 x2, Y2 y2, Z2 z2, W2 w2, + X3 x3, Y3 y3, Z3 z3, W3 w3); + + template + GLM_FUNC_DECL GLM_CONSTEXPR mat( + vec<4, V1, Q> const& v1, + vec<4, V2, Q> const& v2, + vec<4, V3, Q> const& v3); + + // -- Matrix conversions -- + + template + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, U, P> const& m); + + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x); + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_DECL mat<3, 4, T, Q> & operator=(mat<3, 4, U, Q> const& m); + template + GLM_FUNC_DECL mat<3, 4, T, Q> & operator+=(U s); + template + GLM_FUNC_DECL mat<3, 4, T, Q> & operator+=(mat<3, 4, U, Q> const& m); + template + GLM_FUNC_DECL mat<3, 4, T, Q> & operator-=(U s); + template + GLM_FUNC_DECL mat<3, 4, T, Q> & operator-=(mat<3, 4, U, Q> const& m); + template + GLM_FUNC_DECL mat<3, 4, T, Q> & operator*=(U s); + template + GLM_FUNC_DECL mat<3, 4, T, Q> & operator/=(U s); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL mat<3, 4, T, Q> & operator++(); + GLM_FUNC_DECL mat<3, 4, T, Q> & operator--(); + GLM_FUNC_DECL mat<3, 4, T, Q> operator++(int); + GLM_FUNC_DECL mat<3, 4, T, Q> operator--(int); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator+(mat<3, 4, T, Q> const& m); + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator-(mat<3, 4, T, Q> const& m); + + // -- Binary operators -- + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator+(mat<3, 4, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator+(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator-(mat<3, 4, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator-(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator*(mat<3, 4, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator*(T scalar, mat<3, 4, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<3, 4, T, Q>::col_type operator*(mat<3, 4, T, Q> const& m, typename mat<3, 4, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<3, 4, T, Q>::row_type operator*(typename mat<3, 4, T, Q>::col_type const& v, mat<3, 4, T, Q> const& m); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator*(mat<3, 4, T, Q> const& m1, mat<4, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator*(mat<3, 4, T, Q> const& m1, mat<2, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator*(mat<3, 4, T, Q> const& m1, mat<3, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator/(mat<3, 4, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator/(T scalar, mat<3, 4, T, Q> const& m); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL bool operator==(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL bool operator!=(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2); +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_mat3x4.inl" +#endif diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat3x4.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat3x4.inl new file mode 100644 index 0000000000000000000000000000000000000000..43ab3fdd885b597094b21c0386186f707f60f5ba --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat3x4.inl @@ -0,0 +1,578 @@ +namespace glm +{ + // -- Constructors -- + +# if GLM_CONFIG_DEFAULTED_DEFAULT_CTOR == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat() +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST + : value{col_type(1, 0, 0, 0), col_type(0, 1, 0, 0), col_type(0, 0, 1, 0)} +# endif + { +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION + this->value[0] = col_type(1, 0, 0, 0); + this->value[1] = col_type(0, 1, 0, 0); + this->value[2] = col_type(0, 0, 1, 0); +# endif + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<3, 4, T, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(T s) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(s, 0, 0, 0), col_type(0, s, 0, 0), col_type(0, 0, s, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(s, 0, 0, 0); + this->value[1] = col_type(0, s, 0, 0); + this->value[2] = col_type(0, 0, s, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat + ( + T x0, T y0, T z0, T w0, + T x1, T y1, T z1, T w1, + T x2, T y2, T z2, T w2 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{ + col_type(x0, y0, z0, w0), + col_type(x1, y1, z1, w1), + col_type(x2, y2, z2, w2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0, z0, w0); + this->value[1] = col_type(x1, y1, z1, w1); + this->value[2] = col_type(x2, y2, z2, w2); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(col_type const& v0, col_type const& v1, col_type const& v2) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v0), col_type(v1), col_type(v2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = v0; + this->value[1] = v1; + this->value[2] = v2; +# endif + } + + // -- Conversion constructors -- + + template + template< + typename X0, typename Y0, typename Z0, typename W0, + typename X1, typename Y1, typename Z1, typename W1, + typename X2, typename Y2, typename Z2, typename W2> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat + ( + X0 x0, Y0 y0, Z0 z0, W0 w0, + X1 x1, Y1 y1, Z1 z1, W1 w1, + X2 x2, Y2 y2, Z2 z2, W2 w2 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{ + col_type(x0, y0, z0, w0), + col_type(x1, y1, z1, w1), + col_type(x2, y2, z2, w2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0, z0, w0); + this->value[1] = col_type(x1, y1, z1, w1); + this->value[2] = col_type(x2, y2, z2, w2); +# endif + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(vec<4, V1, Q> const& v0, vec<4, V2, Q> const& v1, vec<4, V3, Q> const& v2) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v0), col_type(v1), col_type(v2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(v0); + this->value[1] = col_type(v1); + this->value[2] = col_type(v2); +# endif + } + + // -- Matrix conversions -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<3, 4, U, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<2, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0), col_type(0, 0, 1, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0, 0); + this->value[1] = col_type(m[1], 0, 0); + this->value[2] = col_type(0, 0, 1, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<3, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(m[2], 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<4, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<2, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(0, 0, 1, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(0, 0, 1, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<3, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0), col_type(m[2], 1, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0, 0); + this->value[1] = col_type(m[1], 0, 0); + this->value[2] = col_type(m[2], 1, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<2, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0, 0, 1, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(0, 0, 1, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<4, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0), col_type(m[2], 1, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0, 0); + this->value[1] = col_type(m[1], 0, 0); + this->value[2] = col_type(m[2], 1, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<4, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(m[2], 0); +# endif + } + + // -- Accesses -- + + template + GLM_FUNC_QUALIFIER typename mat<3, 4, T, Q>::col_type & mat<3, 4, T, Q>::operator[](typename mat<3, 4, T, Q>::length_type i) GLM_NOEXCEPT + { + assert(i < this->length()); + return this->value[i]; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<3, 4, T, Q>::col_type const& mat<3, 4, T, Q>::operator[](typename mat<3, 4, T, Q>::length_type i) const GLM_NOEXCEPT + { + assert(i < this->length()); + return this->value[i]; + } + + // -- Unary updatable operators -- + + template + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator=(mat<3, 4, U, Q> const& m) + { + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator+=(U s) + { + this->value[0] += s; + this->value[1] += s; + this->value[2] += s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator+=(mat<3, 4, U, Q> const& m) + { + this->value[0] += m[0]; + this->value[1] += m[1]; + this->value[2] += m[2]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator-=(U s) + { + this->value[0] -= s; + this->value[1] -= s; + this->value[2] -= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator-=(mat<3, 4, U, Q> const& m) + { + this->value[0] -= m[0]; + this->value[1] -= m[1]; + this->value[2] -= m[2]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator*=(U s) + { + this->value[0] *= s; + this->value[1] *= s; + this->value[2] *= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> & mat<3, 4, T, Q>::operator/=(U s) + { + this->value[0] /= s; + this->value[1] /= s; + this->value[2] /= s; + return *this; + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator++() + { + ++this->value[0]; + ++this->value[1]; + ++this->value[2]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator--() + { + --this->value[0]; + --this->value[1]; + --this->value[2]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> mat<3, 4, T, Q>::operator++(int) + { + mat<3, 4, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> mat<3, 4, T, Q>::operator--(int) + { + mat<3, 4, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator+(mat<3, 4, T, Q> const& m) + { + return m; + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator-(mat<3, 4, T, Q> const& m) + { + return mat<3, 4, T, Q>( + -m[0], + -m[1], + -m[2]); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator+(mat<3, 4, T, Q> const& m, T scalar) + { + return mat<3, 4, T, Q>( + m[0] + scalar, + m[1] + scalar, + m[2] + scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator+(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2) + { + return mat<3, 4, T, Q>( + m1[0] + m2[0], + m1[1] + m2[1], + m1[2] + m2[2]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator-(mat<3, 4, T, Q> const& m, T scalar) + { + return mat<3, 4, T, Q>( + m[0] - scalar, + m[1] - scalar, + m[2] - scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator-(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2) + { + return mat<3, 4, T, Q>( + m1[0] - m2[0], + m1[1] - m2[1], + m1[2] - m2[2]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator*(mat<3, 4, T, Q> const& m, T scalar) + { + return mat<3, 4, T, Q>( + m[0] * scalar, + m[1] * scalar, + m[2] * scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator*(T scalar, mat<3, 4, T, Q> const& m) + { + return mat<3, 4, T, Q>( + m[0] * scalar, + m[1] * scalar, + m[2] * scalar); + } + + template + GLM_FUNC_QUALIFIER typename mat<3, 4, T, Q>::col_type operator* + ( + mat<3, 4, T, Q> const& m, + typename mat<3, 4, T, Q>::row_type const& v + ) + { + return typename mat<3, 4, T, Q>::col_type( + m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z, + m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z, + m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z, + m[0][3] * v.x + m[1][3] * v.y + m[2][3] * v.z); + } + + template + GLM_FUNC_QUALIFIER typename mat<3, 4, T, Q>::row_type operator* + ( + typename mat<3, 4, T, Q>::col_type const& v, + mat<3, 4, T, Q> const& m + ) + { + return typename mat<3, 4, T, Q>::row_type( + v.x * m[0][0] + v.y * m[0][1] + v.z * m[0][2] + v.w * m[0][3], + v.x * m[1][0] + v.y * m[1][1] + v.z * m[1][2] + v.w * m[1][3], + v.x * m[2][0] + v.y * m[2][1] + v.z * m[2][2] + v.w * m[2][3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator*(mat<3, 4, T, Q> const& m1, mat<4, 3, T, Q> const& m2) + { + const T SrcA00 = m1[0][0]; + const T SrcA01 = m1[0][1]; + const T SrcA02 = m1[0][2]; + const T SrcA03 = m1[0][3]; + const T SrcA10 = m1[1][0]; + const T SrcA11 = m1[1][1]; + const T SrcA12 = m1[1][2]; + const T SrcA13 = m1[1][3]; + const T SrcA20 = m1[2][0]; + const T SrcA21 = m1[2][1]; + const T SrcA22 = m1[2][2]; + const T SrcA23 = m1[2][3]; + + const T SrcB00 = m2[0][0]; + const T SrcB01 = m2[0][1]; + const T SrcB02 = m2[0][2]; + const T SrcB10 = m2[1][0]; + const T SrcB11 = m2[1][1]; + const T SrcB12 = m2[1][2]; + const T SrcB20 = m2[2][0]; + const T SrcB21 = m2[2][1]; + const T SrcB22 = m2[2][2]; + const T SrcB30 = m2[3][0]; + const T SrcB31 = m2[3][1]; + const T SrcB32 = m2[3][2]; + + mat<4, 4, T, Q> Result; + Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01 + SrcA20 * SrcB02; + Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01 + SrcA21 * SrcB02; + Result[0][2] = SrcA02 * SrcB00 + SrcA12 * SrcB01 + SrcA22 * SrcB02; + Result[0][3] = SrcA03 * SrcB00 + SrcA13 * SrcB01 + SrcA23 * SrcB02; + Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11 + SrcA20 * SrcB12; + Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11 + SrcA21 * SrcB12; + Result[1][2] = SrcA02 * SrcB10 + SrcA12 * SrcB11 + SrcA22 * SrcB12; + Result[1][3] = SrcA03 * SrcB10 + SrcA13 * SrcB11 + SrcA23 * SrcB12; + Result[2][0] = SrcA00 * SrcB20 + SrcA10 * SrcB21 + SrcA20 * SrcB22; + Result[2][1] = SrcA01 * SrcB20 + SrcA11 * SrcB21 + SrcA21 * SrcB22; + Result[2][2] = SrcA02 * SrcB20 + SrcA12 * SrcB21 + SrcA22 * SrcB22; + Result[2][3] = SrcA03 * SrcB20 + SrcA13 * SrcB21 + SrcA23 * SrcB22; + Result[3][0] = SrcA00 * SrcB30 + SrcA10 * SrcB31 + SrcA20 * SrcB32; + Result[3][1] = SrcA01 * SrcB30 + SrcA11 * SrcB31 + SrcA21 * SrcB32; + Result[3][2] = SrcA02 * SrcB30 + SrcA12 * SrcB31 + SrcA22 * SrcB32; + Result[3][3] = SrcA03 * SrcB30 + SrcA13 * SrcB31 + SrcA23 * SrcB32; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator*(mat<3, 4, T, Q> const& m1, mat<2, 3, T, Q> const& m2) + { + return mat<2, 4, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2], + m1[0][3] * m2[0][0] + m1[1][3] * m2[0][1] + m1[2][3] * m2[0][2], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2], + m1[0][3] * m2[1][0] + m1[1][3] * m2[1][1] + m1[2][3] * m2[1][2]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator*(mat<3, 4, T, Q> const& m1, mat<3, 3, T, Q> const& m2) + { + return mat<3, 4, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2], + m1[0][3] * m2[0][0] + m1[1][3] * m2[0][1] + m1[2][3] * m2[0][2], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2], + m1[0][3] * m2[1][0] + m1[1][3] * m2[1][1] + m1[2][3] * m2[1][2], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2], + m1[0][2] * m2[2][0] + m1[1][2] * m2[2][1] + m1[2][2] * m2[2][2], + m1[0][3] * m2[2][0] + m1[1][3] * m2[2][1] + m1[2][3] * m2[2][2]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator/(mat<3, 4, T, Q> const& m, T scalar) + { + return mat<3, 4, T, Q>( + m[0] / scalar, + m[1] / scalar, + m[2] / scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator/(T scalar, mat<3, 4, T, Q> const& m) + { + return mat<3, 4, T, Q>( + scalar / m[0], + scalar / m[1], + scalar / m[2]); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER bool operator==(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2) + { + return (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]); + } + + template + GLM_FUNC_QUALIFIER bool operator!=(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2) + { + return (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]); + } +} //namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat4x2.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat4x2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..df51af705cd7933eca327dc309738270313acabf --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat4x2.hpp @@ -0,0 +1,171 @@ +/// @ref core +/// @file glm/detail/type_mat4x2.hpp + +#pragma once + +#include "type_vec2.hpp" +#include "type_vec4.hpp" +#include +#include + +namespace glm +{ + template + struct mat<4, 2, T, Q> + { + typedef vec<2, T, Q> col_type; + typedef vec<4, T, Q> row_type; + typedef mat<4, 2, T, Q> type; + typedef mat<2, 4, T, Q> transpose_type; + typedef T value_type; + + private: + col_type value[4]; + + public: + // -- Accesses -- + + typedef length_t length_type; + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 4; } + + GLM_FUNC_DECL col_type & operator[](length_type i) GLM_NOEXCEPT; + GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const GLM_NOEXCEPT; + + // -- Constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT_CTOR; + template + GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<4, 2, T, P> const& m); + + GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T scalar); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + T x0, T y0, + T x1, T y1, + T x2, T y2, + T x3, T y3); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + col_type const& v0, + col_type const& v1, + col_type const& v2, + col_type const& v3); + + // -- Conversions -- + + template< + typename X0, typename Y0, + typename X1, typename Y1, + typename X2, typename Y2, + typename X3, typename Y3> + GLM_FUNC_DECL GLM_CONSTEXPR mat( + X0 x0, Y0 y0, + X1 x1, Y1 y1, + X2 x2, Y2 y2, + X3 x3, Y3 y3); + + template + GLM_FUNC_DECL GLM_CONSTEXPR mat( + vec<2, V1, Q> const& v1, + vec<2, V2, Q> const& v2, + vec<2, V3, Q> const& v3, + vec<2, V4, Q> const& v4); + + // -- Matrix conversions -- + + template + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, U, P> const& m); + + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x); + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_DECL mat<4, 2, T, Q> & operator=(mat<4, 2, U, Q> const& m); + template + GLM_FUNC_DECL mat<4, 2, T, Q> & operator+=(U s); + template + GLM_FUNC_DECL mat<4, 2, T, Q> & operator+=(mat<4, 2, U, Q> const& m); + template + GLM_FUNC_DECL mat<4, 2, T, Q> & operator-=(U s); + template + GLM_FUNC_DECL mat<4, 2, T, Q> & operator-=(mat<4, 2, U, Q> const& m); + template + GLM_FUNC_DECL mat<4, 2, T, Q> & operator*=(U s); + template + GLM_FUNC_DECL mat<4, 2, T, Q> & operator/=(U s); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL mat<4, 2, T, Q> & operator++ (); + GLM_FUNC_DECL mat<4, 2, T, Q> & operator-- (); + GLM_FUNC_DECL mat<4, 2, T, Q> operator++(int); + GLM_FUNC_DECL mat<4, 2, T, Q> operator--(int); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator+(mat<4, 2, T, Q> const& m); + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator-(mat<4, 2, T, Q> const& m); + + // -- Binary operators -- + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator+(mat<4, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator+(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator-(mat<4, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator-(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator*(mat<4, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator*(T scalar, mat<4, 2, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<4, 2, T, Q>::col_type operator*(mat<4, 2, T, Q> const& m, typename mat<4, 2, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<4, 2, T, Q>::row_type operator*(typename mat<4, 2, T, Q>::col_type const& v, mat<4, 2, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator*(mat<4, 2, T, Q> const& m1, mat<2, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator*(mat<4, 2, T, Q> const& m1, mat<3, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator*(mat<4, 2, T, Q> const& m1, mat<4, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator/(mat<4, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator/(T scalar, mat<4, 2, T, Q> const& m); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL bool operator==(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL bool operator!=(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2); +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_mat4x2.inl" +#endif diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat4x2.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat4x2.inl new file mode 100644 index 0000000000000000000000000000000000000000..8fc4c3b32e4fcac06eb9ea8dd92497ef360b3ec6 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat4x2.inl @@ -0,0 +1,574 @@ +namespace glm +{ + // -- Constructors -- + +# if GLM_CONFIG_DEFAULTED_DEFAULT_CTOR == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat() +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST + : value{col_type(1, 0), col_type(0, 1), col_type(0, 0), col_type(0, 0)} +# endif + { +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION + this->value[0] = col_type(1, 0); + this->value[1] = col_type(0, 1); + this->value[2] = col_type(0, 0); + this->value[3] = col_type(0, 0); +# endif + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<4, 2, T, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; + this->value[3] = m[3]; +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(T s) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(s, 0), col_type(0, s), col_type(0, 0), col_type(0, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(s, 0); + this->value[1] = col_type(0, s); + this->value[2] = col_type(0, 0); + this->value[3] = col_type(0, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat + ( + T x0, T y0, + T x1, T y1, + T x2, T y2, + T x3, T y3 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x0, y0), col_type(x1, y1), col_type(x2, y2), col_type(x3, y3)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0); + this->value[1] = col_type(x1, y1); + this->value[2] = col_type(x2, y2); + this->value[3] = col_type(x3, y3); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(col_type const& v0, col_type const& v1, col_type const& v2, col_type const& v3) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v0), col_type(v1), col_type(v2), col_type(v3)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = v0; + this->value[1] = v1; + this->value[2] = v2; + this->value[3] = v3; +# endif + } + + // -- Conversion constructors -- + + template + template< + typename X0, typename Y0, + typename X1, typename Y1, + typename X2, typename Y2, + typename X3, typename Y3> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat + ( + X0 x0, Y0 y0, + X1 x1, Y1 y1, + X2 x2, Y2 y2, + X3 x3, Y3 y3 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x0, y0), col_type(x1, y1), col_type(x2, y2), col_type(x3, y3)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0); + this->value[1] = col_type(x1, y1); + this->value[2] = col_type(x2, y2); + this->value[3] = col_type(x3, y3); +# endif + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(vec<2, V0, Q> const& v0, vec<2, V1, Q> const& v1, vec<2, V2, Q> const& v2, vec<2, V3, Q> const& v3) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v0), col_type(v1), col_type(v2), col_type(v3)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(v0); + this->value[1] = col_type(v1); + this->value[2] = col_type(v2); + this->value[3] = col_type(v3); +# endif + } + + // -- Conversion -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<4, 2, U, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); + this->value[3] = col_type(m[3]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<2, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(0); + this->value[3] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<3, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); + this->value[3] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<4, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); + this->value[3] = col_type(m[3]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<2, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(0); + this->value[3] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<3, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); + this->value[3] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<2, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(0); + this->value[3] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<4, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); + this->value[3] = col_type(m[3]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<3, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); + this->value[3] = col_type(0); +# endif + } + + // -- Accesses -- + + template + GLM_FUNC_QUALIFIER typename mat<4, 2, T, Q>::col_type & mat<4, 2, T, Q>::operator[](typename mat<4, 2, T, Q>::length_type i) GLM_NOEXCEPT + { + assert(i < this->length()); + return this->value[i]; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<4, 2, T, Q>::col_type const& mat<4, 2, T, Q>::operator[](typename mat<4, 2, T, Q>::length_type i) const GLM_NOEXCEPT + { + assert(i < this->length()); + return this->value[i]; + } + + // -- Unary updatable operators -- + + template + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q>& mat<4, 2, T, Q>::operator=(mat<4, 2, U, Q> const& m) + { + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; + this->value[3] = m[3]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator+=(U s) + { + this->value[0] += s; + this->value[1] += s; + this->value[2] += s; + this->value[3] += s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator+=(mat<4, 2, U, Q> const& m) + { + this->value[0] += m[0]; + this->value[1] += m[1]; + this->value[2] += m[2]; + this->value[3] += m[3]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator-=(U s) + { + this->value[0] -= s; + this->value[1] -= s; + this->value[2] -= s; + this->value[3] -= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator-=(mat<4, 2, U, Q> const& m) + { + this->value[0] -= m[0]; + this->value[1] -= m[1]; + this->value[2] -= m[2]; + this->value[3] -= m[3]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator*=(U s) + { + this->value[0] *= s; + this->value[1] *= s; + this->value[2] *= s; + this->value[3] *= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator/=(U s) + { + this->value[0] /= s; + this->value[1] /= s; + this->value[2] /= s; + this->value[3] /= s; + return *this; + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator++() + { + ++this->value[0]; + ++this->value[1]; + ++this->value[2]; + ++this->value[3]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator--() + { + --this->value[0]; + --this->value[1]; + --this->value[2]; + --this->value[3]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> mat<4, 2, T, Q>::operator++(int) + { + mat<4, 2, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> mat<4, 2, T, Q>::operator--(int) + { + mat<4, 2, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator+(mat<4, 2, T, Q> const& m) + { + return m; + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator-(mat<4, 2, T, Q> const& m) + { + return mat<4, 2, T, Q>( + -m[0], + -m[1], + -m[2], + -m[3]); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator+(mat<4, 2, T, Q> const& m, T scalar) + { + return mat<4, 2, T, Q>( + m[0] + scalar, + m[1] + scalar, + m[2] + scalar, + m[3] + scalar); + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator+(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2) + { + return mat<4, 2, T, Q>( + m1[0] + m2[0], + m1[1] + m2[1], + m1[2] + m2[2], + m1[3] + m2[3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator-(mat<4, 2, T, Q> const& m, T scalar) + { + return mat<4, 2, T, Q>( + m[0] - scalar, + m[1] - scalar, + m[2] - scalar, + m[3] - scalar); + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator-(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2) + { + return mat<4, 2, T, Q>( + m1[0] - m2[0], + m1[1] - m2[1], + m1[2] - m2[2], + m1[3] - m2[3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator*(mat<4, 2, T, Q> const& m, T scalar) + { + return mat<4, 2, T, Q>( + m[0] * scalar, + m[1] * scalar, + m[2] * scalar, + m[3] * scalar); + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator*(T scalar, mat<4, 2, T, Q> const& m) + { + return mat<4, 2, T, Q>( + m[0] * scalar, + m[1] * scalar, + m[2] * scalar, + m[3] * scalar); + } + + template + GLM_FUNC_QUALIFIER typename mat<4, 2, T, Q>::col_type operator*(mat<4, 2, T, Q> const& m, typename mat<4, 2, T, Q>::row_type const& v) + { + return typename mat<4, 2, T, Q>::col_type( + m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z + m[3][0] * v.w, + m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z + m[3][1] * v.w); + } + + template + GLM_FUNC_QUALIFIER typename mat<4, 2, T, Q>::row_type operator*(typename mat<4, 2, T, Q>::col_type const& v, mat<4, 2, T, Q> const& m) + { + return typename mat<4, 2, T, Q>::row_type( + v.x * m[0][0] + v.y * m[0][1], + v.x * m[1][0] + v.y * m[1][1], + v.x * m[2][0] + v.y * m[2][1], + v.x * m[3][0] + v.y * m[3][1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator*(mat<4, 2, T, Q> const& m1, mat<2, 4, T, Q> const& m2) + { + T const SrcA00 = m1[0][0]; + T const SrcA01 = m1[0][1]; + T const SrcA10 = m1[1][0]; + T const SrcA11 = m1[1][1]; + T const SrcA20 = m1[2][0]; + T const SrcA21 = m1[2][1]; + T const SrcA30 = m1[3][0]; + T const SrcA31 = m1[3][1]; + + T const SrcB00 = m2[0][0]; + T const SrcB01 = m2[0][1]; + T const SrcB02 = m2[0][2]; + T const SrcB03 = m2[0][3]; + T const SrcB10 = m2[1][0]; + T const SrcB11 = m2[1][1]; + T const SrcB12 = m2[1][2]; + T const SrcB13 = m2[1][3]; + + mat<2, 2, T, Q> Result; + Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01 + SrcA20 * SrcB02 + SrcA30 * SrcB03; + Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01 + SrcA21 * SrcB02 + SrcA31 * SrcB03; + Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11 + SrcA20 * SrcB12 + SrcA30 * SrcB13; + Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11 + SrcA21 * SrcB12 + SrcA31 * SrcB13; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator*(mat<4, 2, T, Q> const& m1, mat<3, 4, T, Q> const& m2) + { + return mat<3, 2, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2] + m1[3][0] * m2[2][3], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2] + m1[3][1] * m2[2][3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator*(mat<4, 2, T, Q> const& m1, mat<4, 4, T, Q> const& m2) + { + return mat<4, 2, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2] + m1[3][0] * m2[2][3], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2] + m1[3][1] * m2[2][3], + m1[0][0] * m2[3][0] + m1[1][0] * m2[3][1] + m1[2][0] * m2[3][2] + m1[3][0] * m2[3][3], + m1[0][1] * m2[3][0] + m1[1][1] * m2[3][1] + m1[2][1] * m2[3][2] + m1[3][1] * m2[3][3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator/(mat<4, 2, T, Q> const& m, T scalar) + { + return mat<4, 2, T, Q>( + m[0] / scalar, + m[1] / scalar, + m[2] / scalar, + m[3] / scalar); + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator/(T scalar, mat<4, 2, T, Q> const& m) + { + return mat<4, 2, T, Q>( + scalar / m[0], + scalar / m[1], + scalar / m[2], + scalar / m[3]); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER bool operator==(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2) + { + return (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]) && (m1[3] == m2[3]); + } + + template + GLM_FUNC_QUALIFIER bool operator!=(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2) + { + return (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]) || (m1[3] != m2[3]); + } +} //namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat4x3.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat4x3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..42c0281e28eba714f2e3ad7447803e07436a179c --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat4x3.hpp @@ -0,0 +1,171 @@ +/// @ref core +/// @file glm/detail/type_mat4x3.hpp + +#pragma once + +#include "type_vec3.hpp" +#include "type_vec4.hpp" +#include +#include + +namespace glm +{ + template + struct mat<4, 3, T, Q> + { + typedef vec<3, T, Q> col_type; + typedef vec<4, T, Q> row_type; + typedef mat<4, 3, T, Q> type; + typedef mat<3, 4, T, Q> transpose_type; + typedef T value_type; + + private: + col_type value[4]; + + public: + // -- Accesses -- + + typedef length_t length_type; + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 4; } + + GLM_FUNC_DECL col_type & operator[](length_type i) GLM_NOEXCEPT; + GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const GLM_NOEXCEPT; + + // -- Constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT_CTOR; + template + GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<4, 3, T, P> const& m); + + GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T const& x); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + T const& x0, T const& y0, T const& z0, + T const& x1, T const& y1, T const& z1, + T const& x2, T const& y2, T const& z2, + T const& x3, T const& y3, T const& z3); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + col_type const& v0, + col_type const& v1, + col_type const& v2, + col_type const& v3); + + // -- Conversions -- + + template< + typename X1, typename Y1, typename Z1, + typename X2, typename Y2, typename Z2, + typename X3, typename Y3, typename Z3, + typename X4, typename Y4, typename Z4> + GLM_FUNC_DECL GLM_CONSTEXPR mat( + X1 const& x1, Y1 const& y1, Z1 const& z1, + X2 const& x2, Y2 const& y2, Z2 const& z2, + X3 const& x3, Y3 const& y3, Z3 const& z3, + X4 const& x4, Y4 const& y4, Z4 const& z4); + + template + GLM_FUNC_DECL GLM_CONSTEXPR mat( + vec<3, V1, Q> const& v1, + vec<3, V2, Q> const& v2, + vec<3, V3, Q> const& v3, + vec<3, V4, Q> const& v4); + + // -- Matrix conversions -- + + template + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, U, P> const& m); + + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x); + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_DECL mat<4, 3, T, Q> & operator=(mat<4, 3, U, Q> const& m); + template + GLM_FUNC_DECL mat<4, 3, T, Q> & operator+=(U s); + template + GLM_FUNC_DECL mat<4, 3, T, Q> & operator+=(mat<4, 3, U, Q> const& m); + template + GLM_FUNC_DECL mat<4, 3, T, Q> & operator-=(U s); + template + GLM_FUNC_DECL mat<4, 3, T, Q> & operator-=(mat<4, 3, U, Q> const& m); + template + GLM_FUNC_DECL mat<4, 3, T, Q> & operator*=(U s); + template + GLM_FUNC_DECL mat<4, 3, T, Q> & operator/=(U s); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL mat<4, 3, T, Q>& operator++(); + GLM_FUNC_DECL mat<4, 3, T, Q>& operator--(); + GLM_FUNC_DECL mat<4, 3, T, Q> operator++(int); + GLM_FUNC_DECL mat<4, 3, T, Q> operator--(int); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator+(mat<4, 3, T, Q> const& m); + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator-(mat<4, 3, T, Q> const& m); + + // -- Binary operators -- + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator+(mat<4, 3, T, Q> const& m, T const& s); + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator+(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator-(mat<4, 3, T, Q> const& m, T const& s); + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator-(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator*(mat<4, 3, T, Q> const& m, T const& s); + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator*(T const& s, mat<4, 3, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<4, 3, T, Q>::col_type operator*(mat<4, 3, T, Q> const& m, typename mat<4, 3, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<4, 3, T, Q>::row_type operator*(typename mat<4, 3, T, Q>::col_type const& v, mat<4, 3, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator*(mat<4, 3, T, Q> const& m1, mat<2, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator*(mat<4, 3, T, Q> const& m1, mat<3, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator*(mat<4, 3, T, Q> const& m1, mat<4, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator/(mat<4, 3, T, Q> const& m, T const& s); + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator/(T const& s, mat<4, 3, T, Q> const& m); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL bool operator==(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL bool operator!=(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2); +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_mat4x3.inl" +#endif //GLM_EXTERNAL_TEMPLATE diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat4x3.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat4x3.inl new file mode 100644 index 0000000000000000000000000000000000000000..994a9332bdae4ef8bb89e8cb8a3772931683c143 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat4x3.inl @@ -0,0 +1,598 @@ +namespace glm +{ + // -- Constructors -- + +# if GLM_CONFIG_DEFAULTED_DEFAULT_CTOR == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat() +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST + : value{col_type(1, 0, 0), col_type(0, 1, 0), col_type(0, 0, 1), col_type(0, 0, 0)} +# endif + { +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION + this->value[0] = col_type(1, 0, 0); + this->value[1] = col_type(0, 1, 0); + this->value[2] = col_type(0, 0, 1); + this->value[3] = col_type(0, 0, 0); +# endif + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<4, 3, T, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; + this->value[3] = m[3]; +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(T const& s) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(s, 0, 0), col_type(0, s, 0), col_type(0, 0, s), col_type(0, 0, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(s, 0, 0); + this->value[1] = col_type(0, s, 0); + this->value[2] = col_type(0, 0, s); + this->value[3] = col_type(0, 0, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat + ( + T const& x0, T const& y0, T const& z0, + T const& x1, T const& y1, T const& z1, + T const& x2, T const& y2, T const& z2, + T const& x3, T const& y3, T const& z3 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x0, y0, z0), col_type(x1, y1, z1), col_type(x2, y2, z2), col_type(x3, y3, z3)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0, z0); + this->value[1] = col_type(x1, y1, z1); + this->value[2] = col_type(x2, y2, z2); + this->value[3] = col_type(x3, y3, z3); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(col_type const& v0, col_type const& v1, col_type const& v2, col_type const& v3) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v0), col_type(v1), col_type(v2), col_type(v3)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = v0; + this->value[1] = v1; + this->value[2] = v2; + this->value[3] = v3; +# endif + } + + // -- Conversion constructors -- + + template + template< + typename X0, typename Y0, typename Z0, + typename X1, typename Y1, typename Z1, + typename X2, typename Y2, typename Z2, + typename X3, typename Y3, typename Z3> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat + ( + X0 const& x0, Y0 const& y0, Z0 const& z0, + X1 const& x1, Y1 const& y1, Z1 const& z1, + X2 const& x2, Y2 const& y2, Z2 const& z2, + X3 const& x3, Y3 const& y3, Z3 const& z3 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x0, y0, z0), col_type(x1, y1, z1), col_type(x2, y2, z2), col_type(x3, y3, z3)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0, z0); + this->value[1] = col_type(x1, y1, z1); + this->value[2] = col_type(x2, y2, z2); + this->value[3] = col_type(x3, y3, z3); +# endif + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(vec<3, V1, Q> const& v1, vec<3, V2, Q> const& v2, vec<3, V3, Q> const& v3, vec<3, V4, Q> const& v4) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v1), col_type(v2), col_type(v3), col_type(v4)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(v1); + this->value[1] = col_type(v2); + this->value[2] = col_type(v3); + this->value[3] = col_type(v4); +# endif + } + + // -- Matrix conversions -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<4, 3, U, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); + this->value[3] = col_type(m[3]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<2, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(0, 0, 1), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(0, 0, 1); + this->value[3] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<3, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); + this->value[3] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<4, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); + this->value[3] = col_type(m[3]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<2, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0, 0, 1), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(0, 0, 1); + this->value[3] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<3, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 1), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(m[2], 1); + this->value[3] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<2, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0, 0, 1), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(0, 0, 1); + this->value[3] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<4, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 1), col_type(m[3], 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(m[2], 1); + this->value[3] = col_type(m[3], 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<3, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); + this->value[3] = col_type(0); +# endif + } + + // -- Accesses -- + + template + GLM_FUNC_QUALIFIER typename mat<4, 3, T, Q>::col_type & mat<4, 3, T, Q>::operator[](typename mat<4, 3, T, Q>::length_type i) GLM_NOEXCEPT + { + assert(i < this->length()); + return this->value[i]; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<4, 3, T, Q>::col_type const& mat<4, 3, T, Q>::operator[](typename mat<4, 3, T, Q>::length_type i) const GLM_NOEXCEPT + { + assert(i < this->length()); + return this->value[i]; + } + + // -- Unary updatable operators -- + + template + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q>& mat<4, 3, T, Q>::operator=(mat<4, 3, U, Q> const& m) + { + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; + this->value[3] = m[3]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator+=(U s) + { + this->value[0] += s; + this->value[1] += s; + this->value[2] += s; + this->value[3] += s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator+=(mat<4, 3, U, Q> const& m) + { + this->value[0] += m[0]; + this->value[1] += m[1]; + this->value[2] += m[2]; + this->value[3] += m[3]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator-=(U s) + { + this->value[0] -= s; + this->value[1] -= s; + this->value[2] -= s; + this->value[3] -= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator-=(mat<4, 3, U, Q> const& m) + { + this->value[0] -= m[0]; + this->value[1] -= m[1]; + this->value[2] -= m[2]; + this->value[3] -= m[3]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator*=(U s) + { + this->value[0] *= s; + this->value[1] *= s; + this->value[2] *= s; + this->value[3] *= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator/=(U s) + { + this->value[0] /= s; + this->value[1] /= s; + this->value[2] /= s; + this->value[3] /= s; + return *this; + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator++() + { + ++this->value[0]; + ++this->value[1]; + ++this->value[2]; + ++this->value[3]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator--() + { + --this->value[0]; + --this->value[1]; + --this->value[2]; + --this->value[3]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> mat<4, 3, T, Q>::operator++(int) + { + mat<4, 3, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> mat<4, 3, T, Q>::operator--(int) + { + mat<4, 3, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator+(mat<4, 3, T, Q> const& m) + { + return m; + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator-(mat<4, 3, T, Q> const& m) + { + return mat<4, 3, T, Q>( + -m[0], + -m[1], + -m[2], + -m[3]); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator+(mat<4, 3, T, Q> const& m, T const& s) + { + return mat<4, 3, T, Q>( + m[0] + s, + m[1] + s, + m[2] + s, + m[3] + s); + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator+(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2) + { + return mat<4, 3, T, Q>( + m1[0] + m2[0], + m1[1] + m2[1], + m1[2] + m2[2], + m1[3] + m2[3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator-(mat<4, 3, T, Q> const& m, T const& s) + { + return mat<4, 3, T, Q>( + m[0] - s, + m[1] - s, + m[2] - s, + m[3] - s); + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator-(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2) + { + return mat<4, 3, T, Q>( + m1[0] - m2[0], + m1[1] - m2[1], + m1[2] - m2[2], + m1[3] - m2[3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator*(mat<4, 3, T, Q> const& m, T const& s) + { + return mat<4, 3, T, Q>( + m[0] * s, + m[1] * s, + m[2] * s, + m[3] * s); + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator*(T const& s, mat<4, 3, T, Q> const& m) + { + return mat<4, 3, T, Q>( + m[0] * s, + m[1] * s, + m[2] * s, + m[3] * s); + } + + template + GLM_FUNC_QUALIFIER typename mat<4, 3, T, Q>::col_type operator* + ( + mat<4, 3, T, Q> const& m, + typename mat<4, 3, T, Q>::row_type const& v) + { + return typename mat<4, 3, T, Q>::col_type( + m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z + m[3][0] * v.w, + m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z + m[3][1] * v.w, + m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z + m[3][2] * v.w); + } + + template + GLM_FUNC_QUALIFIER typename mat<4, 3, T, Q>::row_type operator* + ( + typename mat<4, 3, T, Q>::col_type const& v, + mat<4, 3, T, Q> const& m) + { + return typename mat<4, 3, T, Q>::row_type( + v.x * m[0][0] + v.y * m[0][1] + v.z * m[0][2], + v.x * m[1][0] + v.y * m[1][1] + v.z * m[1][2], + v.x * m[2][0] + v.y * m[2][1] + v.z * m[2][2], + v.x * m[3][0] + v.y * m[3][1] + v.z * m[3][2]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator*(mat<4, 3, T, Q> const& m1, mat<2, 4, T, Q> const& m2) + { + return mat<2, 3, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2] + m1[3][2] * m2[0][3], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2] + m1[3][2] * m2[1][3]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator*(mat<4, 3, T, Q> const& m1, mat<3, 4, T, Q> const& m2) + { + T const SrcA00 = m1[0][0]; + T const SrcA01 = m1[0][1]; + T const SrcA02 = m1[0][2]; + T const SrcA10 = m1[1][0]; + T const SrcA11 = m1[1][1]; + T const SrcA12 = m1[1][2]; + T const SrcA20 = m1[2][0]; + T const SrcA21 = m1[2][1]; + T const SrcA22 = m1[2][2]; + T const SrcA30 = m1[3][0]; + T const SrcA31 = m1[3][1]; + T const SrcA32 = m1[3][2]; + + T const SrcB00 = m2[0][0]; + T const SrcB01 = m2[0][1]; + T const SrcB02 = m2[0][2]; + T const SrcB03 = m2[0][3]; + T const SrcB10 = m2[1][0]; + T const SrcB11 = m2[1][1]; + T const SrcB12 = m2[1][2]; + T const SrcB13 = m2[1][3]; + T const SrcB20 = m2[2][0]; + T const SrcB21 = m2[2][1]; + T const SrcB22 = m2[2][2]; + T const SrcB23 = m2[2][3]; + + mat<3, 3, T, Q> Result; + Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01 + SrcA20 * SrcB02 + SrcA30 * SrcB03; + Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01 + SrcA21 * SrcB02 + SrcA31 * SrcB03; + Result[0][2] = SrcA02 * SrcB00 + SrcA12 * SrcB01 + SrcA22 * SrcB02 + SrcA32 * SrcB03; + Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11 + SrcA20 * SrcB12 + SrcA30 * SrcB13; + Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11 + SrcA21 * SrcB12 + SrcA31 * SrcB13; + Result[1][2] = SrcA02 * SrcB10 + SrcA12 * SrcB11 + SrcA22 * SrcB12 + SrcA32 * SrcB13; + Result[2][0] = SrcA00 * SrcB20 + SrcA10 * SrcB21 + SrcA20 * SrcB22 + SrcA30 * SrcB23; + Result[2][1] = SrcA01 * SrcB20 + SrcA11 * SrcB21 + SrcA21 * SrcB22 + SrcA31 * SrcB23; + Result[2][2] = SrcA02 * SrcB20 + SrcA12 * SrcB21 + SrcA22 * SrcB22 + SrcA32 * SrcB23; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator*(mat<4, 3, T, Q> const& m1, mat<4, 4, T, Q> const& m2) + { + return mat<4, 3, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2] + m1[3][2] * m2[0][3], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2] + m1[3][2] * m2[1][3], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2] + m1[3][0] * m2[2][3], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2] + m1[3][1] * m2[2][3], + m1[0][2] * m2[2][0] + m1[1][2] * m2[2][1] + m1[2][2] * m2[2][2] + m1[3][2] * m2[2][3], + m1[0][0] * m2[3][0] + m1[1][0] * m2[3][1] + m1[2][0] * m2[3][2] + m1[3][0] * m2[3][3], + m1[0][1] * m2[3][0] + m1[1][1] * m2[3][1] + m1[2][1] * m2[3][2] + m1[3][1] * m2[3][3], + m1[0][2] * m2[3][0] + m1[1][2] * m2[3][1] + m1[2][2] * m2[3][2] + m1[3][2] * m2[3][3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator/(mat<4, 3, T, Q> const& m, T const& s) + { + return mat<4, 3, T, Q>( + m[0] / s, + m[1] / s, + m[2] / s, + m[3] / s); + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator/(T const& s, mat<4, 3, T, Q> const& m) + { + return mat<4, 3, T, Q>( + s / m[0], + s / m[1], + s / m[2], + s / m[3]); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER bool operator==(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2) + { + return (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]) && (m1[3] == m2[3]); + } + + template + GLM_FUNC_QUALIFIER bool operator!=(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2) + { + return (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]) || (m1[3] != m2[3]); + } +} //namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat4x4.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat4x4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..dd3c5f814c83f4ce7f9dfc5c621e7c32c53ca500 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat4x4.hpp @@ -0,0 +1,189 @@ +/// @ref core +/// @file glm/detail/type_mat4x4.hpp + +#pragma once + +#include "type_vec4.hpp" +#include +#include + +namespace glm +{ + template + struct mat<4, 4, T, Q> + { + typedef vec<4, T, Q> col_type; + typedef vec<4, T, Q> row_type; + typedef mat<4, 4, T, Q> type; + typedef mat<4, 4, T, Q> transpose_type; + typedef T value_type; + + private: + col_type value[4]; + + public: + // -- Accesses -- + + typedef length_t length_type; + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length(){return 4;} + + GLM_FUNC_DECL col_type & operator[](length_type i) GLM_NOEXCEPT; + GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const GLM_NOEXCEPT; + + // -- Constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT_CTOR; + template + GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<4, 4, T, P> const& m); + + GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T const& x); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + T const& x0, T const& y0, T const& z0, T const& w0, + T const& x1, T const& y1, T const& z1, T const& w1, + T const& x2, T const& y2, T const& z2, T const& w2, + T const& x3, T const& y3, T const& z3, T const& w3); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + col_type const& v0, + col_type const& v1, + col_type const& v2, + col_type const& v3); + + // -- Conversions -- + + template< + typename X1, typename Y1, typename Z1, typename W1, + typename X2, typename Y2, typename Z2, typename W2, + typename X3, typename Y3, typename Z3, typename W3, + typename X4, typename Y4, typename Z4, typename W4> + GLM_FUNC_DECL GLM_CONSTEXPR mat( + X1 const& x1, Y1 const& y1, Z1 const& z1, W1 const& w1, + X2 const& x2, Y2 const& y2, Z2 const& z2, W2 const& w2, + X3 const& x3, Y3 const& y3, Z3 const& z3, W3 const& w3, + X4 const& x4, Y4 const& y4, Z4 const& z4, W4 const& w4); + + template + GLM_FUNC_DECL GLM_CONSTEXPR mat( + vec<4, V1, Q> const& v1, + vec<4, V2, Q> const& v2, + vec<4, V3, Q> const& v3, + vec<4, V4, Q> const& v4); + + // -- Matrix conversions -- + + template + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, U, P> const& m); + + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x); + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_DECL mat<4, 4, T, Q> & operator=(mat<4, 4, U, Q> const& m); + template + GLM_FUNC_DECL mat<4, 4, T, Q> & operator+=(U s); + template + GLM_FUNC_DECL mat<4, 4, T, Q> & operator+=(mat<4, 4, U, Q> const& m); + template + GLM_FUNC_DECL mat<4, 4, T, Q> & operator-=(U s); + template + GLM_FUNC_DECL mat<4, 4, T, Q> & operator-=(mat<4, 4, U, Q> const& m); + template + GLM_FUNC_DECL mat<4, 4, T, Q> & operator*=(U s); + template + GLM_FUNC_DECL mat<4, 4, T, Q> & operator*=(mat<4, 4, U, Q> const& m); + template + GLM_FUNC_DECL mat<4, 4, T, Q> & operator/=(U s); + template + GLM_FUNC_DECL mat<4, 4, T, Q> & operator/=(mat<4, 4, U, Q> const& m); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL mat<4, 4, T, Q> & operator++(); + GLM_FUNC_DECL mat<4, 4, T, Q> & operator--(); + GLM_FUNC_DECL mat<4, 4, T, Q> operator++(int); + GLM_FUNC_DECL mat<4, 4, T, Q> operator--(int); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator+(mat<4, 4, T, Q> const& m); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator-(mat<4, 4, T, Q> const& m); + + // -- Binary operators -- + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator+(mat<4, 4, T, Q> const& m, T const& s); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator+(T const& s, mat<4, 4, T, Q> const& m); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator+(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator-(mat<4, 4, T, Q> const& m, T const& s); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator-(T const& s, mat<4, 4, T, Q> const& m); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator-(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator*(mat<4, 4, T, Q> const& m, T const& s); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator*(T const& s, mat<4, 4, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<4, 4, T, Q>::col_type operator*(mat<4, 4, T, Q> const& m, typename mat<4, 4, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<4, 4, T, Q>::row_type operator*(typename mat<4, 4, T, Q>::col_type const& v, mat<4, 4, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator*(mat<4, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator*(mat<4, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator*(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator/(mat<4, 4, T, Q> const& m, T const& s); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator/(T const& s, mat<4, 4, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<4, 4, T, Q>::col_type operator/(mat<4, 4, T, Q> const& m, typename mat<4, 4, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<4, 4, T, Q>::row_type operator/(typename mat<4, 4, T, Q>::col_type const& v, mat<4, 4, T, Q> const& m); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator/(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL bool operator==(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL bool operator!=(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2); +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_mat4x4.inl" +#endif//GLM_EXTERNAL_TEMPLATE diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat4x4.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat4x4.inl new file mode 100644 index 0000000000000000000000000000000000000000..2a82bbab4d1c18a463b27c27cc36c77066c55c8d --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat4x4.inl @@ -0,0 +1,706 @@ +#include "../matrix.hpp" + +namespace glm +{ + // -- Constructors -- + +# if GLM_CONFIG_DEFAULTED_DEFAULT_CTOR == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat() +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST + : value{col_type(1, 0, 0, 0), col_type(0, 1, 0, 0), col_type(0, 0, 1, 0), col_type(0, 0, 0, 1)} +# endif + { +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION + this->value[0] = col_type(1, 0, 0, 0); + this->value[1] = col_type(0, 1, 0, 0); + this->value[2] = col_type(0, 0, 1, 0); + this->value[3] = col_type(0, 0, 0, 1); +# endif + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<4, 4, T, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; + this->value[3] = m[3]; +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(T const& s) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(s, 0, 0, 0), col_type(0, s, 0, 0), col_type(0, 0, s, 0), col_type(0, 0, 0, s)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(s, 0, 0, 0); + this->value[1] = col_type(0, s, 0, 0); + this->value[2] = col_type(0, 0, s, 0); + this->value[3] = col_type(0, 0, 0, s); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat + ( + T const& x0, T const& y0, T const& z0, T const& w0, + T const& x1, T const& y1, T const& z1, T const& w1, + T const& x2, T const& y2, T const& z2, T const& w2, + T const& x3, T const& y3, T const& z3, T const& w3 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{ + col_type(x0, y0, z0, w0), + col_type(x1, y1, z1, w1), + col_type(x2, y2, z2, w2), + col_type(x3, y3, z3, w3)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0, z0, w0); + this->value[1] = col_type(x1, y1, z1, w1); + this->value[2] = col_type(x2, y2, z2, w2); + this->value[3] = col_type(x3, y3, z3, w3); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(col_type const& v0, col_type const& v1, col_type const& v2, col_type const& v3) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v0), col_type(v1), col_type(v2), col_type(v3)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = v0; + this->value[1] = v1; + this->value[2] = v2; + this->value[3] = v3; +# endif + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<4, 4, U, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); + this->value[3] = col_type(m[3]); +# endif + } + + // -- Conversions -- + + template + template< + typename X1, typename Y1, typename Z1, typename W1, + typename X2, typename Y2, typename Z2, typename W2, + typename X3, typename Y3, typename Z3, typename W3, + typename X4, typename Y4, typename Z4, typename W4> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat + ( + X1 const& x1, Y1 const& y1, Z1 const& z1, W1 const& w1, + X2 const& x2, Y2 const& y2, Z2 const& z2, W2 const& w2, + X3 const& x3, Y3 const& y3, Z3 const& z3, W3 const& w3, + X4 const& x4, Y4 const& y4, Z4 const& z4, W4 const& w4 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x1, y1, z1, w1), col_type(x2, y2, z2, w2), col_type(x3, y3, z3, w3), col_type(x4, y4, z4, w4)} +# endif + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 1st parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 2nd parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 3rd parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 4th parameter type invalid."); + + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 5th parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 6th parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 7th parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 8th parameter type invalid."); + + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 9th parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 10th parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 11th parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 12th parameter type invalid."); + + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 13th parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 14th parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 15th parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 16th parameter type invalid."); + +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x1, y1, z1, w1); + this->value[1] = col_type(x2, y2, z2, w2); + this->value[2] = col_type(x3, y3, z3, w3); + this->value[3] = col_type(x4, y4, z4, w4); +# endif + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(vec<4, V1, Q> const& v1, vec<4, V2, Q> const& v2, vec<4, V3, Q> const& v3, vec<4, V4, Q> const& v4) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v1), col_type(v2), col_type(v3), col_type(v4)} +# endif + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 1st parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 2nd parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 3rd parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 4th parameter type invalid."); + +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(v1); + this->value[1] = col_type(v2); + this->value[2] = col_type(v3); + this->value[3] = col_type(v4); +# endif + } + + // -- Matrix conversions -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<2, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0), col_type(0, 0, 1, 0), col_type(0, 0, 0, 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0, 0); + this->value[1] = col_type(m[1], 0, 0); + this->value[2] = col_type(0, 0, 1, 0); + this->value[3] = col_type(0, 0, 0, 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<3, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 0), col_type(0, 0, 0, 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(m[2], 0); + this->value[3] = col_type(0, 0, 0, 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<2, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(0, 0, 1, 0), col_type(0, 0, 0, 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(0, 0, 1, 0); + this->value[3] = col_type(0, 0, 0, 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<3, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0), col_type(m[2], 1, 0), col_type(0, 0, 0, 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0, 0); + this->value[1] = col_type(m[1], 0, 0); + this->value[2] = col_type(m[2], 1, 0); + this->value[3] = col_type(0, 0, 0, 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<2, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0, 0, 1, 0), col_type(0, 0, 0, 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = col_type(0, 0, 1, 0); + this->value[3] = col_type(0, 0, 0, 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<4, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0), col_type(0, 0, 1, 0), col_type(0, 0, 0, 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0, 0); + this->value[1] = col_type(m[1], 0, 0); + this->value[2] = col_type(0, 0, 1, 0); + this->value[3] = col_type(0, 0, 0, 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<3, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(0, 0, 0, 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; + this->value[3] = col_type(0, 0, 0, 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<4, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 0), col_type(m[3], 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(m[2], 0); + this->value[3] = col_type(m[3], 1); +# endif + } + + // -- Accesses -- + + template + GLM_FUNC_QUALIFIER typename mat<4, 4, T, Q>::col_type & mat<4, 4, T, Q>::operator[](typename mat<4, 4, T, Q>::length_type i) GLM_NOEXCEPT + { + assert(i < this->length()); + return this->value[i]; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<4, 4, T, Q>::col_type const& mat<4, 4, T, Q>::operator[](typename mat<4, 4, T, Q>::length_type i) const GLM_NOEXCEPT + { + assert(i < this->length()); + return this->value[i]; + } + + // -- Unary arithmetic operators -- + + template + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q>& mat<4, 4, T, Q>::operator=(mat<4, 4, U, Q> const& m) + { + //memcpy could be faster + //memcpy(&this->value, &m.value, 16 * sizeof(valType)); + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; + this->value[3] = m[3]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q>& mat<4, 4, T, Q>::operator+=(U s) + { + this->value[0] += s; + this->value[1] += s; + this->value[2] += s; + this->value[3] += s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q>& mat<4, 4, T, Q>::operator+=(mat<4, 4, U, Q> const& m) + { + this->value[0] += m[0]; + this->value[1] += m[1]; + this->value[2] += m[2]; + this->value[3] += m[3]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator-=(U s) + { + this->value[0] -= s; + this->value[1] -= s; + this->value[2] -= s; + this->value[3] -= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator-=(mat<4, 4, U, Q> const& m) + { + this->value[0] -= m[0]; + this->value[1] -= m[1]; + this->value[2] -= m[2]; + this->value[3] -= m[3]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator*=(U s) + { + this->value[0] *= s; + this->value[1] *= s; + this->value[2] *= s; + this->value[3] *= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator*=(mat<4, 4, U, Q> const& m) + { + return (*this = *this * m); + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator/=(U s) + { + this->value[0] /= s; + this->value[1] /= s; + this->value[2] /= s; + this->value[3] /= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator/=(mat<4, 4, U, Q> const& m) + { + return *this *= inverse(m); + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator++() + { + ++this->value[0]; + ++this->value[1]; + ++this->value[2]; + ++this->value[3]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator--() + { + --this->value[0]; + --this->value[1]; + --this->value[2]; + --this->value[3]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> mat<4, 4, T, Q>::operator++(int) + { + mat<4, 4, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> mat<4, 4, T, Q>::operator--(int) + { + mat<4, 4, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary constant operators -- + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator+(mat<4, 4, T, Q> const& m) + { + return m; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator-(mat<4, 4, T, Q> const& m) + { + return mat<4, 4, T, Q>( + -m[0], + -m[1], + -m[2], + -m[3]); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator+(mat<4, 4, T, Q> const& m, T const& s) + { + return mat<4, 4, T, Q>( + m[0] + s, + m[1] + s, + m[2] + s, + m[3] + s); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator+(T const& s, mat<4, 4, T, Q> const& m) + { + return mat<4, 4, T, Q>( + m[0] + s, + m[1] + s, + m[2] + s, + m[3] + s); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator+(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2) + { + return mat<4, 4, T, Q>( + m1[0] + m2[0], + m1[1] + m2[1], + m1[2] + m2[2], + m1[3] + m2[3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator-(mat<4, 4, T, Q> const& m, T const& s) + { + return mat<4, 4, T, Q>( + m[0] - s, + m[1] - s, + m[2] - s, + m[3] - s); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator-(T const& s, mat<4, 4, T, Q> const& m) + { + return mat<4, 4, T, Q>( + s - m[0], + s - m[1], + s - m[2], + s - m[3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator-(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2) + { + return mat<4, 4, T, Q>( + m1[0] - m2[0], + m1[1] - m2[1], + m1[2] - m2[2], + m1[3] - m2[3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator*(mat<4, 4, T, Q> const& m, T const & s) + { + return mat<4, 4, T, Q>( + m[0] * s, + m[1] * s, + m[2] * s, + m[3] * s); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator*(T const& s, mat<4, 4, T, Q> const& m) + { + return mat<4, 4, T, Q>( + m[0] * s, + m[1] * s, + m[2] * s, + m[3] * s); + } + + template + GLM_FUNC_QUALIFIER typename mat<4, 4, T, Q>::col_type operator* + ( + mat<4, 4, T, Q> const& m, + typename mat<4, 4, T, Q>::row_type const& v + ) + { +/* + __m128 v0 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(0, 0, 0, 0)); + __m128 v1 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(1, 1, 1, 1)); + __m128 v2 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(2, 2, 2, 2)); + __m128 v3 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 m0 = _mm_mul_ps(m[0].data, v0); + __m128 m1 = _mm_mul_ps(m[1].data, v1); + __m128 a0 = _mm_add_ps(m0, m1); + + __m128 m2 = _mm_mul_ps(m[2].data, v2); + __m128 m3 = _mm_mul_ps(m[3].data, v3); + __m128 a1 = _mm_add_ps(m2, m3); + + __m128 a2 = _mm_add_ps(a0, a1); + + return typename mat<4, 4, T, Q>::col_type(a2); +*/ + + typename mat<4, 4, T, Q>::col_type const Mov0(v[0]); + typename mat<4, 4, T, Q>::col_type const Mov1(v[1]); + typename mat<4, 4, T, Q>::col_type const Mul0 = m[0] * Mov0; + typename mat<4, 4, T, Q>::col_type const Mul1 = m[1] * Mov1; + typename mat<4, 4, T, Q>::col_type const Add0 = Mul0 + Mul1; + typename mat<4, 4, T, Q>::col_type const Mov2(v[2]); + typename mat<4, 4, T, Q>::col_type const Mov3(v[3]); + typename mat<4, 4, T, Q>::col_type const Mul2 = m[2] * Mov2; + typename mat<4, 4, T, Q>::col_type const Mul3 = m[3] * Mov3; + typename mat<4, 4, T, Q>::col_type const Add1 = Mul2 + Mul3; + typename mat<4, 4, T, Q>::col_type const Add2 = Add0 + Add1; + return Add2; + +/* + return typename mat<4, 4, T, Q>::col_type( + m[0][0] * v[0] + m[1][0] * v[1] + m[2][0] * v[2] + m[3][0] * v[3], + m[0][1] * v[0] + m[1][1] * v[1] + m[2][1] * v[2] + m[3][1] * v[3], + m[0][2] * v[0] + m[1][2] * v[1] + m[2][2] * v[2] + m[3][2] * v[3], + m[0][3] * v[0] + m[1][3] * v[1] + m[2][3] * v[2] + m[3][3] * v[3]); +*/ + } + + template + GLM_FUNC_QUALIFIER typename mat<4, 4, T, Q>::row_type operator* + ( + typename mat<4, 4, T, Q>::col_type const& v, + mat<4, 4, T, Q> const& m + ) + { + return typename mat<4, 4, T, Q>::row_type( + m[0][0] * v[0] + m[0][1] * v[1] + m[0][2] * v[2] + m[0][3] * v[3], + m[1][0] * v[0] + m[1][1] * v[1] + m[1][2] * v[2] + m[1][3] * v[3], + m[2][0] * v[0] + m[2][1] * v[1] + m[2][2] * v[2] + m[2][3] * v[3], + m[3][0] * v[0] + m[3][1] * v[1] + m[3][2] * v[2] + m[3][3] * v[3]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator*(mat<4, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2) + { + return mat<2, 4, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2] + m1[3][2] * m2[0][3], + m1[0][3] * m2[0][0] + m1[1][3] * m2[0][1] + m1[2][3] * m2[0][2] + m1[3][3] * m2[0][3], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2] + m1[3][2] * m2[1][3], + m1[0][3] * m2[1][0] + m1[1][3] * m2[1][1] + m1[2][3] * m2[1][2] + m1[3][3] * m2[1][3]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator*(mat<4, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2) + { + return mat<3, 4, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2] + m1[3][2] * m2[0][3], + m1[0][3] * m2[0][0] + m1[1][3] * m2[0][1] + m1[2][3] * m2[0][2] + m1[3][3] * m2[0][3], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2] + m1[3][2] * m2[1][3], + m1[0][3] * m2[1][0] + m1[1][3] * m2[1][1] + m1[2][3] * m2[1][2] + m1[3][3] * m2[1][3], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2] + m1[3][0] * m2[2][3], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2] + m1[3][1] * m2[2][3], + m1[0][2] * m2[2][0] + m1[1][2] * m2[2][1] + m1[2][2] * m2[2][2] + m1[3][2] * m2[2][3], + m1[0][3] * m2[2][0] + m1[1][3] * m2[2][1] + m1[2][3] * m2[2][2] + m1[3][3] * m2[2][3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator*(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2) + { + typename mat<4, 4, T, Q>::col_type const SrcA0 = m1[0]; + typename mat<4, 4, T, Q>::col_type const SrcA1 = m1[1]; + typename mat<4, 4, T, Q>::col_type const SrcA2 = m1[2]; + typename mat<4, 4, T, Q>::col_type const SrcA3 = m1[3]; + + typename mat<4, 4, T, Q>::col_type const SrcB0 = m2[0]; + typename mat<4, 4, T, Q>::col_type const SrcB1 = m2[1]; + typename mat<4, 4, T, Q>::col_type const SrcB2 = m2[2]; + typename mat<4, 4, T, Q>::col_type const SrcB3 = m2[3]; + + mat<4, 4, T, Q> Result; + Result[0] = SrcA0 * SrcB0[0] + SrcA1 * SrcB0[1] + SrcA2 * SrcB0[2] + SrcA3 * SrcB0[3]; + Result[1] = SrcA0 * SrcB1[0] + SrcA1 * SrcB1[1] + SrcA2 * SrcB1[2] + SrcA3 * SrcB1[3]; + Result[2] = SrcA0 * SrcB2[0] + SrcA1 * SrcB2[1] + SrcA2 * SrcB2[2] + SrcA3 * SrcB2[3]; + Result[3] = SrcA0 * SrcB3[0] + SrcA1 * SrcB3[1] + SrcA2 * SrcB3[2] + SrcA3 * SrcB3[3]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator/(mat<4, 4, T, Q> const& m, T const& s) + { + return mat<4, 4, T, Q>( + m[0] / s, + m[1] / s, + m[2] / s, + m[3] / s); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator/(T const& s, mat<4, 4, T, Q> const& m) + { + return mat<4, 4, T, Q>( + s / m[0], + s / m[1], + s / m[2], + s / m[3]); + } + + template + GLM_FUNC_QUALIFIER typename mat<4, 4, T, Q>::col_type operator/(mat<4, 4, T, Q> const& m, typename mat<4, 4, T, Q>::row_type const& v) + { + return inverse(m) * v; + } + + template + GLM_FUNC_QUALIFIER typename mat<4, 4, T, Q>::row_type operator/(typename mat<4, 4, T, Q>::col_type const& v, mat<4, 4, T, Q> const& m) + { + return v * inverse(m); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator/(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2) + { + mat<4, 4, T, Q> m1_copy(m1); + return m1_copy /= m2; + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER bool operator==(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2) + { + return (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]) && (m1[3] == m2[3]); + } + + template + GLM_FUNC_QUALIFIER bool operator!=(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2) + { + return (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]) || (m1[3] != m2[3]); + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "type_mat4x4_simd.inl" +#endif diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat4x4_simd.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat4x4_simd.inl new file mode 100644 index 0000000000000000000000000000000000000000..fb3a16f062901d31b8ed8c493efd17e1cf87468f --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_mat4x4_simd.inl @@ -0,0 +1,6 @@ +/// @ref core + +namespace glm +{ + +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_quat.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_quat.hpp new file mode 100644 index 0000000000000000000000000000000000000000..376c0dc89333770c8d8da2c368ccc3dbee7b3234 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_quat.hpp @@ -0,0 +1,191 @@ +/// @ref core +/// @file glm/detail/type_quat.hpp + +#pragma once + +// Dependency: +#include "../detail/type_mat3x3.hpp" +#include "../detail/type_mat4x4.hpp" +#include "../detail/type_vec3.hpp" +#include "../detail/type_vec4.hpp" +#include "../ext/vector_relational.hpp" +#include "../ext/quaternion_relational.hpp" +#include "../gtc/constants.hpp" +#include "../gtc/matrix_transform.hpp" + +namespace glm +{ + template + struct qua + { + // -- Implementation detail -- + + typedef qua type; + typedef T value_type; + + // -- Data -- + +# if GLM_SILENT_WARNINGS == GLM_ENABLE +# if GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpedantic" +# elif GLM_COMPILER & GLM_COMPILER_CLANG +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wgnu-anonymous-struct" +# pragma clang diagnostic ignored "-Wnested-anon-types" +# elif GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(push) +# pragma warning(disable: 4201) // nonstandard extension used : nameless struct/union +# endif +# endif + +# if GLM_LANG & GLM_LANG_CXXMS_FLAG + union + { +# ifdef GLM_FORCE_QUAT_DATA_XYZW + struct { T x, y, z, w; }; +# else + struct { T w, x, y, z; }; +# endif + + typename detail::storage<4, T, detail::is_aligned::value>::type data; + }; +# else +# ifdef GLM_FORCE_QUAT_DATA_XYZW + T x, y, z, w; +# else + T w, x, y, z; +# endif +# endif + +# if GLM_SILENT_WARNINGS == GLM_ENABLE +# if GLM_COMPILER & GLM_COMPILER_CLANG +# pragma clang diagnostic pop +# elif GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic pop +# elif GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(pop) +# endif +# endif + + // -- Component accesses -- + + typedef length_t length_type; + + /// Return the count of components of a quaternion + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length(){return 4;} + + GLM_FUNC_DECL GLM_CONSTEXPR T & operator[](length_type i); + GLM_FUNC_DECL GLM_CONSTEXPR T const& operator[](length_type i) const; + + // -- Implicit basic constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR qua() GLM_DEFAULT_CTOR; + GLM_FUNC_DECL GLM_CONSTEXPR qua(qua const& q) GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR qua(qua const& q); + + // -- Explicit basic constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR qua(T s, vec<3, T, Q> const& v); + +# ifdef GLM_FORCE_QUAT_DATA_XYZW + GLM_FUNC_DECL GLM_CONSTEXPR qua(T x, T y, T z, T w); +# else + GLM_FUNC_DECL GLM_CONSTEXPR qua(T w, T x, T y, T z); +# endif + + // -- Conversion constructors -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT qua(qua const& q); + + /// Explicit conversion operators +# if GLM_HAS_EXPLICIT_CONVERSION_OPERATORS + GLM_FUNC_DECL explicit operator mat<3, 3, T, Q>() const; + GLM_FUNC_DECL explicit operator mat<4, 4, T, Q>() const; +# endif + + /// Create a quaternion from two normalized axis + /// + /// @param u A first normalized axis + /// @param v A second normalized axis + /// @see gtc_quaternion + /// @see http://lolengine.net/blog/2013/09/18/beautiful-maths-quaternion-from-vectors + GLM_FUNC_DECL qua(vec<3, T, Q> const& u, vec<3, T, Q> const& v); + + /// Build a quaternion from euler angles (pitch, yaw, roll), in radians. + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT qua(vec<3, T, Q> const& eulerAngles); + GLM_FUNC_DECL GLM_EXPLICIT qua(mat<3, 3, T, Q> const& q); + GLM_FUNC_DECL GLM_EXPLICIT qua(mat<4, 4, T, Q> const& q); + + // -- Unary arithmetic operators -- + + GLM_FUNC_DECL GLM_CONSTEXPR qua& operator=(qua const& q) GLM_DEFAULT; + + template + GLM_FUNC_DECL GLM_CONSTEXPR qua& operator=(qua const& q); + template + GLM_FUNC_DECL GLM_CONSTEXPR qua& operator+=(qua const& q); + template + GLM_FUNC_DECL GLM_CONSTEXPR qua& operator-=(qua const& q); + template + GLM_FUNC_DECL GLM_CONSTEXPR qua& operator*=(qua const& q); + template + GLM_FUNC_DECL GLM_CONSTEXPR qua& operator*=(U s); + template + GLM_FUNC_DECL GLM_CONSTEXPR qua& operator/=(U s); + }; + + // -- Unary bit operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR qua operator+(qua const& q); + + template + GLM_FUNC_DECL GLM_CONSTEXPR qua operator-(qua const& q); + + // -- Binary operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR qua operator+(qua const& q, qua const& p); + + template + GLM_FUNC_DECL GLM_CONSTEXPR qua operator-(qua const& q, qua const& p); + + template + GLM_FUNC_DECL GLM_CONSTEXPR qua operator*(qua const& q, qua const& p); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator*(qua const& q, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v, qua const& q); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator*(qua const& q, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v, qua const& q); + + template + GLM_FUNC_DECL GLM_CONSTEXPR qua operator*(qua const& q, T const& s); + + template + GLM_FUNC_DECL GLM_CONSTEXPR qua operator*(T const& s, qua const& q); + + template + GLM_FUNC_DECL GLM_CONSTEXPR qua operator/(qua const& q, T const& s); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator==(qua const& q1, qua const& q2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator!=(qua const& q1, qua const& q2); +} //namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_quat.inl" +#endif//GLM_EXTERNAL_TEMPLATE diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_quat.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_quat.inl new file mode 100644 index 0000000000000000000000000000000000000000..52deed45454c768bbd2325d852b63ba90dc1d358 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_quat.inl @@ -0,0 +1,412 @@ +#include "../trigonometric.hpp" +#include "../exponential.hpp" +#include "../ext/quaternion_common.hpp" +#include "../ext/quaternion_geometric.hpp" +#include + +namespace glm{ +namespace detail +{ + template + struct genTypeTrait > + { + static const genTypeEnum GENTYPE = GENTYPE_QUAT; + }; + + template + struct compute_dot, T, Aligned> + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static T call(qua const& a, qua const& b) + { + vec<4, T, Q> tmp(a.w * b.w, a.x * b.x, a.y * b.y, a.z * b.z); + return (tmp.x + tmp.y) + (tmp.z + tmp.w); + } + }; + + template + struct compute_quat_add + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static qua call(qua const& q, qua const& p) + { + return qua(q.w + p.w, q.x + p.x, q.y + p.y, q.z + p.z); + } + }; + + template + struct compute_quat_sub + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static qua call(qua const& q, qua const& p) + { + return qua(q.w - p.w, q.x - p.x, q.y - p.y, q.z - p.z); + } + }; + + template + struct compute_quat_mul_scalar + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static qua call(qua const& q, T s) + { + return qua(q.w * s, q.x * s, q.y * s, q.z * s); + } + }; + + template + struct compute_quat_div_scalar + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static qua call(qua const& q, T s) + { + return qua(q.w / s, q.x / s, q.y / s, q.z / s); + } + }; + + template + struct compute_quat_mul_vec4 + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(qua const& q, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(q * vec<3, T, Q>(v), v.w); + } + }; +}//namespace detail + + // -- Component accesses -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T & qua::operator[](typename qua::length_type i) + { + assert(i >= 0 && i < this->length()); +# ifdef GLM_FORCE_QUAT_DATA_XYZW + return (&x)[i]; +# else + return (&w)[i]; +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T const& qua::operator[](typename qua::length_type i) const + { + assert(i >= 0 && i < this->length()); +# ifdef GLM_FORCE_QUAT_DATA_XYZW + return (&x)[i]; +# else + return (&w)[i]; +# endif + } + + // -- Implicit basic constructors -- + +# if GLM_CONFIG_DEFAULTED_DEFAULT_CTOR == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua::qua() +# if GLM_CONFIG_CTOR_INIT != GLM_CTOR_INIT_DISABLE +# ifdef GLM_FORCE_QUAT_DATA_XYZW + : x(0), y(0), z(0), w(1) +# else + : w(1), x(0), y(0), z(0) +# endif +# endif + {} +# endif + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua::qua(qua const& q) +# ifdef GLM_FORCE_QUAT_DATA_XYZW + : x(q.x), y(q.y), z(q.z), w(q.w) +# else + : w(q.w), x(q.x), y(q.y), z(q.z) +# endif + {} +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua::qua(qua const& q) +# ifdef GLM_FORCE_QUAT_DATA_XYZW + : x(q.x), y(q.y), z(q.z), w(q.w) +# else + : w(q.w), x(q.x), y(q.y), z(q.z) +# endif + {} + + // -- Explicit basic constructors -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua::qua(T s, vec<3, T, Q> const& v) +# ifdef GLM_FORCE_QUAT_DATA_XYZW + : x(v.x), y(v.y), z(v.z), w(s) +# else + : w(s), x(v.x), y(v.y), z(v.z) +# endif + {} + + template +# ifdef GLM_FORCE_QUAT_DATA_XYZW + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua::qua(T _x, T _y, T _z, T _w) + : x(_x), y(_y), z(_z), w(_w) +# else + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua::qua(T _w, T _x, T _y, T _z) + : w(_w), x(_x), y(_y), z(_z) +# endif + {} + + // -- Conversion constructors -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua::qua(qua const& q) +# ifdef GLM_FORCE_QUAT_DATA_XYZW + : x(static_cast(q.x)), y(static_cast(q.y)), z(static_cast(q.z)), w(static_cast(q.w)) +# else + : w(static_cast(q.w)), x(static_cast(q.x)), y(static_cast(q.y)), z(static_cast(q.z)) +# endif + {} + + //template + //GLM_FUNC_QUALIFIER qua::qua + //( + // valType const& pitch, + // valType const& yaw, + // valType const& roll + //) + //{ + // vec<3, valType> eulerAngle(pitch * valType(0.5), yaw * valType(0.5), roll * valType(0.5)); + // vec<3, valType> c = glm::cos(eulerAngle * valType(0.5)); + // vec<3, valType> s = glm::sin(eulerAngle * valType(0.5)); + // + // this->w = c.x * c.y * c.z + s.x * s.y * s.z; + // this->x = s.x * c.y * c.z - c.x * s.y * s.z; + // this->y = c.x * s.y * c.z + s.x * c.y * s.z; + // this->z = c.x * c.y * s.z - s.x * s.y * c.z; + //} + + template + GLM_FUNC_QUALIFIER qua::qua(vec<3, T, Q> const& u, vec<3, T, Q> const& v) + { + T norm_u_norm_v = sqrt(dot(u, u) * dot(v, v)); + T real_part = norm_u_norm_v + dot(u, v); + vec<3, T, Q> t; + + if(real_part < static_cast(1.e-6f) * norm_u_norm_v) + { + // If u and v are exactly opposite, rotate 180 degrees + // around an arbitrary orthogonal axis. Axis normalisation + // can happen later, when we normalise the quaternion. + real_part = static_cast(0); + t = abs(u.x) > abs(u.z) ? vec<3, T, Q>(-u.y, u.x, static_cast(0)) : vec<3, T, Q>(static_cast(0), -u.z, u.y); + } + else + { + // Otherwise, build quaternion the standard way. + t = cross(u, v); + } + + *this = normalize(qua(real_part, t.x, t.y, t.z)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua::qua(vec<3, T, Q> const& eulerAngle) + { + vec<3, T, Q> c = glm::cos(eulerAngle * T(0.5)); + vec<3, T, Q> s = glm::sin(eulerAngle * T(0.5)); + + this->w = c.x * c.y * c.z + s.x * s.y * s.z; + this->x = s.x * c.y * c.z - c.x * s.y * s.z; + this->y = c.x * s.y * c.z + s.x * c.y * s.z; + this->z = c.x * c.y * s.z - s.x * s.y * c.z; + } + + template + GLM_FUNC_QUALIFIER qua::qua(mat<3, 3, T, Q> const& m) + { + *this = quat_cast(m); + } + + template + GLM_FUNC_QUALIFIER qua::qua(mat<4, 4, T, Q> const& m) + { + *this = quat_cast(m); + } + +# if GLM_HAS_EXPLICIT_CONVERSION_OPERATORS + template + GLM_FUNC_QUALIFIER qua::operator mat<3, 3, T, Q>() const + { + return mat3_cast(*this); + } + + template + GLM_FUNC_QUALIFIER qua::operator mat<4, 4, T, Q>() const + { + return mat4_cast(*this); + } +# endif//GLM_HAS_EXPLICIT_CONVERSION_OPERATORS + + // -- Unary arithmetic operators -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua & qua::operator=(qua const& q) + { + this->w = q.w; + this->x = q.x; + this->y = q.y; + this->z = q.z; + return *this; + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua & qua::operator=(qua const& q) + { + this->w = static_cast(q.w); + this->x = static_cast(q.x); + this->y = static_cast(q.y); + this->z = static_cast(q.z); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua & qua::operator+=(qua const& q) + { + return (*this = detail::compute_quat_add::value>::call(*this, qua(q))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua & qua::operator-=(qua const& q) + { + return (*this = detail::compute_quat_sub::value>::call(*this, qua(q))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua & qua::operator*=(qua const& r) + { + qua const p(*this); + qua const q(r); + + this->w = p.w * q.w - p.x * q.x - p.y * q.y - p.z * q.z; + this->x = p.w * q.x + p.x * q.w + p.y * q.z - p.z * q.y; + this->y = p.w * q.y + p.y * q.w + p.z * q.x - p.x * q.z; + this->z = p.w * q.z + p.z * q.w + p.x * q.y - p.y * q.x; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua & qua::operator*=(U s) + { + return (*this = detail::compute_quat_mul_scalar::value>::call(*this, static_cast(s))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua & qua::operator/=(U s) + { + return (*this = detail::compute_quat_div_scalar::value>::call(*this, static_cast(s))); + } + + // -- Unary bit operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua operator+(qua const& q) + { + return q; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua operator-(qua const& q) + { + return qua(-q.w, -q.x, -q.y, -q.z); + } + + // -- Binary operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua operator+(qua const& q, qua const& p) + { + return qua(q) += p; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua operator-(qua const& q, qua const& p) + { + return qua(q) -= p; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua operator*(qua const& q, qua const& p) + { + return qua(q) *= p; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator*(qua const& q, vec<3, T, Q> const& v) + { + vec<3, T, Q> const QuatVector(q.x, q.y, q.z); + vec<3, T, Q> const uv(glm::cross(QuatVector, v)); + vec<3, T, Q> const uuv(glm::cross(QuatVector, uv)); + + return v + ((uv * q.w) + uuv) * static_cast(2); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v, qua const& q) + { + return glm::inverse(q) * v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator*(qua const& q, vec<4, T, Q> const& v) + { + return detail::compute_quat_mul_vec4::value>::call(q, v); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v, qua const& q) + { + return glm::inverse(q) * v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua operator*(qua const& q, T const& s) + { + return qua( + q.w * s, q.x * s, q.y * s, q.z * s); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua operator*(T const& s, qua const& q) + { + return q * s; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua operator/(qua const& q, T const& s) + { + return qua( + q.w / s, q.x / s, q.y / s, q.z / s); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator==(qua const& q1, qua const& q2) + { + return q1.x == q2.x && q1.y == q2.y && q1.z == q2.z && q1.w == q2.w; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator!=(qua const& q1, qua const& q2) + { + return q1.x != q2.x || q1.y != q2.y || q1.z != q2.z || q1.w != q2.w; + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "type_quat_simd.inl" +#endif + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_quat_simd.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_quat_simd.inl new file mode 100644 index 0000000000000000000000000000000000000000..a77b56c57e1c56bede26be9e3e21c04aef8ff204 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_quat_simd.inl @@ -0,0 +1,187 @@ +/// @ref core + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +namespace glm{ +namespace detail +{ +/* + template + struct compute_quat_mul + { + static qua call(qua const& q1, qua const& q2) + { + // SSE2 STATS: 11 shuffle, 8 mul, 8 add + // SSE4 STATS: 3 shuffle, 4 mul, 4 dpps + + __m128 const mul0 = _mm_mul_ps(q1.data, _mm_shuffle_ps(q2.data, q2.data, _MM_SHUFFLE(0, 1, 2, 3))); + __m128 const mul1 = _mm_mul_ps(q1.data, _mm_shuffle_ps(q2.data, q2.data, _MM_SHUFFLE(1, 0, 3, 2))); + __m128 const mul2 = _mm_mul_ps(q1.data, _mm_shuffle_ps(q2.data, q2.data, _MM_SHUFFLE(2, 3, 0, 1))); + __m128 const mul3 = _mm_mul_ps(q1.data, q2.data); + +# if GLM_ARCH & GLM_ARCH_SSE41_BIT + __m128 const add0 = _mm_dp_ps(mul0, _mm_set_ps(1.0f, -1.0f, 1.0f, 1.0f), 0xff); + __m128 const add1 = _mm_dp_ps(mul1, _mm_set_ps(1.0f, 1.0f, 1.0f, -1.0f), 0xff); + __m128 const add2 = _mm_dp_ps(mul2, _mm_set_ps(1.0f, 1.0f, -1.0f, 1.0f), 0xff); + __m128 const add3 = _mm_dp_ps(mul3, _mm_set_ps(1.0f, -1.0f, -1.0f, -1.0f), 0xff); +# else + __m128 const mul4 = _mm_mul_ps(mul0, _mm_set_ps(1.0f, -1.0f, 1.0f, 1.0f)); + __m128 const add0 = _mm_add_ps(mul0, _mm_movehl_ps(mul4, mul4)); + __m128 const add4 = _mm_add_ss(add0, _mm_shuffle_ps(add0, add0, 1)); + + __m128 const mul5 = _mm_mul_ps(mul1, _mm_set_ps(1.0f, 1.0f, 1.0f, -1.0f)); + __m128 const add1 = _mm_add_ps(mul1, _mm_movehl_ps(mul5, mul5)); + __m128 const add5 = _mm_add_ss(add1, _mm_shuffle_ps(add1, add1, 1)); + + __m128 const mul6 = _mm_mul_ps(mul2, _mm_set_ps(1.0f, 1.0f, -1.0f, 1.0f)); + __m128 const add2 = _mm_add_ps(mul6, _mm_movehl_ps(mul6, mul6)); + __m128 const add6 = _mm_add_ss(add2, _mm_shuffle_ps(add2, add2, 1)); + + __m128 const mul7 = _mm_mul_ps(mul3, _mm_set_ps(1.0f, -1.0f, -1.0f, -1.0f)); + __m128 const add3 = _mm_add_ps(mul3, _mm_movehl_ps(mul7, mul7)); + __m128 const add7 = _mm_add_ss(add3, _mm_shuffle_ps(add3, add3, 1)); + #endif + + // This SIMD code is a politically correct way of doing this, but in every test I've tried it has been slower than + // the final code below. I'll keep this here for reference - maybe somebody else can do something better... + // + //__m128 xxyy = _mm_shuffle_ps(add4, add5, _MM_SHUFFLE(0, 0, 0, 0)); + //__m128 zzww = _mm_shuffle_ps(add6, add7, _MM_SHUFFLE(0, 0, 0, 0)); + // + //return _mm_shuffle_ps(xxyy, zzww, _MM_SHUFFLE(2, 0, 2, 0)); + + qua Result; + _mm_store_ss(&Result.x, add4); + _mm_store_ss(&Result.y, add5); + _mm_store_ss(&Result.z, add6); + _mm_store_ss(&Result.w, add7); + return Result; + } + }; +*/ + + template + struct compute_quat_add + { + static qua call(qua const& q, qua const& p) + { + qua Result; + Result.data = _mm_add_ps(q.data, p.data); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX_BIT + template + struct compute_quat_add + { + static qua call(qua const& a, qua const& b) + { + qua Result; + Result.data = _mm256_add_pd(a.data, b.data); + return Result; + } + }; +# endif + + template + struct compute_quat_sub + { + static qua call(qua const& q, qua const& p) + { + qua Result; + Result.data = _mm_sub_ps(q.data, p.data); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX_BIT + template + struct compute_quat_sub + { + static qua call(qua const& a, qua const& b) + { + qua Result; + Result.data = _mm256_sub_pd(a.data, b.data); + return Result; + } + }; +# endif + + template + struct compute_quat_mul_scalar + { + static qua call(qua const& q, float s) + { + vec<4, float, Q> Result; + Result.data = _mm_mul_ps(q.data, _mm_set_ps1(s)); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX_BIT + template + struct compute_quat_mul_scalar + { + static qua call(qua const& q, double s) + { + qua Result; + Result.data = _mm256_mul_pd(q.data, _mm_set_ps1(s)); + return Result; + } + }; +# endif + + template + struct compute_quat_div_scalar + { + static qua call(qua const& q, float s) + { + vec<4, float, Q> Result; + Result.data = _mm_div_ps(q.data, _mm_set_ps1(s)); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX_BIT + template + struct compute_quat_div_scalar + { + static qua call(qua const& q, double s) + { + qua Result; + Result.data = _mm256_div_pd(q.data, _mm_set_ps1(s)); + return Result; + } + }; +# endif + + template + struct compute_quat_mul_vec4 + { + static vec<4, float, Q> call(qua const& q, vec<4, float, Q> const& v) + { + __m128 const q_wwww = _mm_shuffle_ps(q.data, q.data, _MM_SHUFFLE(3, 3, 3, 3)); + __m128 const q_swp0 = _mm_shuffle_ps(q.data, q.data, _MM_SHUFFLE(3, 0, 2, 1)); + __m128 const q_swp1 = _mm_shuffle_ps(q.data, q.data, _MM_SHUFFLE(3, 1, 0, 2)); + __m128 const v_swp0 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(3, 0, 2, 1)); + __m128 const v_swp1 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(3, 1, 0, 2)); + + __m128 uv = _mm_sub_ps(_mm_mul_ps(q_swp0, v_swp1), _mm_mul_ps(q_swp1, v_swp0)); + __m128 uv_swp0 = _mm_shuffle_ps(uv, uv, _MM_SHUFFLE(3, 0, 2, 1)); + __m128 uv_swp1 = _mm_shuffle_ps(uv, uv, _MM_SHUFFLE(3, 1, 0, 2)); + __m128 uuv = _mm_sub_ps(_mm_mul_ps(q_swp0, uv_swp1), _mm_mul_ps(q_swp1, uv_swp0)); + + __m128 const two = _mm_set1_ps(2.0f); + uv = _mm_mul_ps(uv, _mm_mul_ps(q_wwww, two)); + uuv = _mm_mul_ps(uuv, two); + + vec<4, float, Q> Result; + Result.data = _mm_add_ps(v.data, _mm_add_ps(uv, uuv)); + return Result; + } + }; +}//namespace detail +}//namespace glm + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_vec1.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_vec1.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ed381cc4951af4681058f6b848f1a8334262ae91 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_vec1.hpp @@ -0,0 +1,308 @@ +/// @ref core +/// @file glm/detail/type_vec1.hpp + +#pragma once + +#include "qualifier.hpp" +#if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR +# include "_swizzle.hpp" +#elif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION +# include "_swizzle_func.hpp" +#endif +#include + +namespace glm +{ + template + struct vec<1, T, Q> + { + // -- Implementation detail -- + + typedef T value_type; + typedef vec<1, T, Q> type; + typedef vec<1, bool, Q> bool_type; + + // -- Data -- + +# if GLM_SILENT_WARNINGS == GLM_ENABLE +# if GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpedantic" +# elif GLM_COMPILER & GLM_COMPILER_CLANG +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wgnu-anonymous-struct" +# pragma clang diagnostic ignored "-Wnested-anon-types" +# elif GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(push) +# pragma warning(disable: 4201) // nonstandard extension used : nameless struct/union +# endif +# endif + +# if GLM_CONFIG_XYZW_ONLY + T x; +# elif GLM_CONFIG_ANONYMOUS_STRUCT == GLM_ENABLE + union + { + T x; + T r; + T s; + + typename detail::storage<1, T, detail::is_aligned::value>::type data; +/* +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + _GLM_SWIZZLE1_2_MEMBERS(T, Q, x) + _GLM_SWIZZLE1_2_MEMBERS(T, Q, r) + _GLM_SWIZZLE1_2_MEMBERS(T, Q, s) + _GLM_SWIZZLE1_3_MEMBERS(T, Q, x) + _GLM_SWIZZLE1_3_MEMBERS(T, Q, r) + _GLM_SWIZZLE1_3_MEMBERS(T, Q, s) + _GLM_SWIZZLE1_4_MEMBERS(T, Q, x) + _GLM_SWIZZLE1_4_MEMBERS(T, Q, r) + _GLM_SWIZZLE1_4_MEMBERS(T, Q, s) +# endif +*/ + }; +# else + union {T x, r, s;}; +/* +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION + GLM_SWIZZLE_GEN_VEC_FROM_VEC1(T, Q) +# endif +*/ +# endif + +# if GLM_SILENT_WARNINGS == GLM_ENABLE +# if GLM_COMPILER & GLM_COMPILER_CLANG +# pragma clang diagnostic pop +# elif GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic pop +# elif GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(pop) +# endif +# endif + + // -- Component accesses -- + + /// Return the count of components of the vector + typedef length_t length_type; + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length(){return 1;} + + GLM_FUNC_DECL GLM_CONSTEXPR T & operator[](length_type i); + GLM_FUNC_DECL GLM_CONSTEXPR T const& operator[](length_type i) const; + + // -- Implicit basic constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR vec() GLM_DEFAULT_CTOR; + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec const& v) GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, T, P> const& v); + + // -- Explicit basic constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR explicit vec(T scalar); + + // -- Conversion vector constructors -- + + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<2, U, P> const& v); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<3, U, P> const& v); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<4, U, P> const& v); + + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<1, U, P> const& v); + + // -- Swizzle constructors -- +/* +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<1, T, Q, E0, -1,-2,-3> const& that) + { + *this = that(); + } +# endif//GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR +*/ + // -- Unary arithmetic operators -- + + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator=(vec const& v) GLM_DEFAULT; + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator+=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator+=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator-=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator-=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator*=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator*=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator/=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator/=(vec<1, U, Q> const& v); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator++(); + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator--(); + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator++(int); + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator--(int); + + // -- Unary bit operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator%=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator%=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator&=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator&=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator|=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator|=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator^=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator^=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator<<=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator<<=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator>>=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator>>=(vec<1, U, Q> const& v); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator+(vec<1, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator-(vec<1, T, Q> const& v); + + // -- Binary operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator+(vec<1, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator+(T scalar, vec<1, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator+(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator-(vec<1, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator-(T scalar, vec<1, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator-(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator*(vec<1, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator*(T scalar, vec<1, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator*(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator/(vec<1, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator/(T scalar, vec<1, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator/(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator%(vec<1, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator%(T scalar, vec<1, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator%(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator&(vec<1, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator&(T scalar, vec<1, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator&(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator|(vec<1, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator|(T scalar, vec<1, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator|(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator^(vec<1, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator^(T scalar, vec<1, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator^(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator<<(vec<1, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator<<(T scalar, vec<1, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator<<(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator>>(vec<1, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator>>(T scalar, vec<1, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator>>(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator~(vec<1, T, Q> const& v); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator==(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator!=(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, bool, Q> operator&&(vec<1, bool, Q> const& v1, vec<1, bool, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, bool, Q> operator||(vec<1, bool, Q> const& v1, vec<1, bool, Q> const& v2); +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_vec1.inl" +#endif//GLM_EXTERNAL_TEMPLATE diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_vec1.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_vec1.inl new file mode 100644 index 0000000000000000000000000000000000000000..e8c91a4b8947c38b57ec0637746026a1cfe6f487 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_vec1.inl @@ -0,0 +1,553 @@ +/// @ref core + +#include "./compute_vector_relational.hpp" + +namespace glm +{ + // -- Implicit basic constructors -- + +# if GLM_CONFIG_DEFAULTED_DEFAULT_CTOR == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec() +# if GLM_CONFIG_CTOR_INIT != GLM_CTOR_INIT_DISABLE + : x(0) +# endif + {} +# endif + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec(vec<1, T, Q> const& v) + : x(v.x) + {} +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec(vec<1, T, P> const& v) + : x(v.x) + {} + + // -- Explicit basic constructors -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec(T scalar) + : x(scalar) + {} + + // -- Conversion vector constructors -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec(vec<1, U, P> const& v) + : x(static_cast(v.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec(vec<2, U, P> const& v) + : x(static_cast(v.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec(vec<3, U, P> const& v) + : x(static_cast(v.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec(vec<4, U, P> const& v) + : x(static_cast(v.x)) + {} + + // -- Component accesses -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T & vec<1, T, Q>::operator[](typename vec<1, T, Q>::length_type) + { + return x; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T const& vec<1, T, Q>::operator[](typename vec<1, T, Q>::length_type) const + { + return x; + } + + // -- Unary arithmetic operators -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator=(vec<1, T, Q> const& v) + { + this->x = v.x; + return *this; + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator=(vec<1, U, Q> const& v) + { + this->x = static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator+=(U scalar) + { + this->x += static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator+=(vec<1, U, Q> const& v) + { + this->x += static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator-=(U scalar) + { + this->x -= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator-=(vec<1, U, Q> const& v) + { + this->x -= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator*=(U scalar) + { + this->x *= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator*=(vec<1, U, Q> const& v) + { + this->x *= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator/=(U scalar) + { + this->x /= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator/=(vec<1, U, Q> const& v) + { + this->x /= static_cast(v.x); + return *this; + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator++() + { + ++this->x; + return *this; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator--() + { + --this->x; + return *this; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> vec<1, T, Q>::operator++(int) + { + vec<1, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> vec<1, T, Q>::operator--(int) + { + vec<1, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary bit operators -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator%=(U scalar) + { + this->x %= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator%=(vec<1, U, Q> const& v) + { + this->x %= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator&=(U scalar) + { + this->x &= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator&=(vec<1, U, Q> const& v) + { + this->x &= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator|=(U scalar) + { + this->x |= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator|=(vec<1, U, Q> const& v) + { + this->x |= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator^=(U scalar) + { + this->x ^= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator^=(vec<1, U, Q> const& v) + { + this->x ^= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator<<=(U scalar) + { + this->x <<= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator<<=(vec<1, U, Q> const& v) + { + this->x <<= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator>>=(U scalar) + { + this->x >>= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator>>=(vec<1, U, Q> const& v) + { + this->x >>= static_cast(v.x); + return *this; + } + + // -- Unary constant operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator+(vec<1, T, Q> const& v) + { + return v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator-(vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + -v.x); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator+(vec<1, T, Q> const& v, T scalar) + { + return vec<1, T, Q>( + v.x + scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator+(T scalar, vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + scalar + v.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator+(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<1, T, Q>( + v1.x + v2.x); + } + + //operator- + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator-(vec<1, T, Q> const& v, T scalar) + { + return vec<1, T, Q>( + v.x - scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator-(T scalar, vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + scalar - v.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator-(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<1, T, Q>( + v1.x - v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator*(vec<1, T, Q> const& v, T scalar) + { + return vec<1, T, Q>( + v.x * scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator*(T scalar, vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + scalar * v.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator*(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<1, T, Q>( + v1.x * v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator/(vec<1, T, Q> const& v, T scalar) + { + return vec<1, T, Q>( + v.x / scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator/(T scalar, vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + scalar / v.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator/(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<1, T, Q>( + v1.x / v2.x); + } + + // -- Binary bit operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator%(vec<1, T, Q> const& v, T scalar) + { + return vec<1, T, Q>( + v.x % scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator%(T scalar, vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + scalar % v.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator%(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<1, T, Q>( + v1.x % v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator&(vec<1, T, Q> const& v, T scalar) + { + return vec<1, T, Q>( + v.x & scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator&(T scalar, vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + scalar & v.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator&(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<1, T, Q>( + v1.x & v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator|(vec<1, T, Q> const& v, T scalar) + { + return vec<1, T, Q>( + v.x | scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator|(T scalar, vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + scalar | v.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator|(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<1, T, Q>( + v1.x | v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator^(vec<1, T, Q> const& v, T scalar) + { + return vec<1, T, Q>( + v.x ^ scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator^(T scalar, vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + scalar ^ v.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator^(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<1, T, Q>( + v1.x ^ v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator<<(vec<1, T, Q> const& v, T scalar) + { + return vec<1, T, Q>( + static_cast(v.x << scalar)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator<<(T scalar, vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + static_cast(scalar << v.x)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator<<(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<1, T, Q>( + static_cast(v1.x << v2.x)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator>>(vec<1, T, Q> const& v, T scalar) + { + return vec<1, T, Q>( + static_cast(v.x >> scalar)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator>>(T scalar, vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + static_cast(scalar >> v.x)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator>>(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<1, T, Q>( + static_cast(v1.x >> v2.x)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator~(vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + ~v.x); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator==(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return detail::compute_equal::is_iec559>::call(v1.x, v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator!=(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return !(v1 == v2); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, bool, Q> operator&&(vec<1, bool, Q> const& v1, vec<1, bool, Q> const& v2) + { + return vec<1, bool, Q>(v1.x && v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, bool, Q> operator||(vec<1, bool, Q> const& v1, vec<1, bool, Q> const& v2) + { + return vec<1, bool, Q>(v1.x || v2.x); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_vec2.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_vec2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5aa969d7ba3c2dd89897c14bd6f9407584749f3d --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_vec2.hpp @@ -0,0 +1,402 @@ +/// @ref core +/// @file glm/detail/type_vec2.hpp + +#pragma once + +#include "qualifier.hpp" +#if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR +# include "_swizzle.hpp" +#elif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION +# include "_swizzle_func.hpp" +#endif +#include + +namespace glm +{ + template + struct vec<2, T, Q> + { + // -- Implementation detail -- + + typedef T value_type; + typedef vec<2, T, Q> type; + typedef vec<2, bool, Q> bool_type; + + // -- Data -- + +# if GLM_SILENT_WARNINGS == GLM_ENABLE +# if GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpedantic" +# elif GLM_COMPILER & GLM_COMPILER_CLANG +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wgnu-anonymous-struct" +# pragma clang diagnostic ignored "-Wnested-anon-types" +# elif GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(push) +# pragma warning(disable: 4201) // nonstandard extension used : nameless struct/union +# endif +# endif + +# if GLM_CONFIG_XYZW_ONLY + T x, y; +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION + GLM_SWIZZLE_GEN_VEC_FROM_VEC2_COMP(T, Q, x, y) +# endif//GLM_CONFIG_SWIZZLE +# elif GLM_CONFIG_ANONYMOUS_STRUCT == GLM_ENABLE + union + { + struct{ T x, y; }; + struct{ T r, g; }; + struct{ T s, t; }; + + typename detail::storage<2, T, detail::is_aligned::value>::type data; + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + GLM_SWIZZLE2_2_MEMBERS(T, Q, x, y) + GLM_SWIZZLE2_2_MEMBERS(T, Q, r, g) + GLM_SWIZZLE2_2_MEMBERS(T, Q, s, t) + GLM_SWIZZLE2_3_MEMBERS(T, Q, x, y) + GLM_SWIZZLE2_3_MEMBERS(T, Q, r, g) + GLM_SWIZZLE2_3_MEMBERS(T, Q, s, t) + GLM_SWIZZLE2_4_MEMBERS(T, Q, x, y) + GLM_SWIZZLE2_4_MEMBERS(T, Q, r, g) + GLM_SWIZZLE2_4_MEMBERS(T, Q, s, t) +# endif + }; +# else + union {T x, r, s;}; + union {T y, g, t;}; + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION + GLM_SWIZZLE_GEN_VEC_FROM_VEC2(T, Q) +# endif//GLM_CONFIG_SWIZZLE +# endif + +# if GLM_SILENT_WARNINGS == GLM_ENABLE +# if GLM_COMPILER & GLM_COMPILER_CLANG +# pragma clang diagnostic pop +# elif GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic pop +# elif GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(pop) +# endif +# endif + + // -- Component accesses -- + + /// Return the count of components of the vector + typedef length_t length_type; + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length(){return 2;} + + GLM_FUNC_DECL GLM_CONSTEXPR T& operator[](length_type i); + GLM_FUNC_DECL GLM_CONSTEXPR T const& operator[](length_type i) const; + + // -- Implicit basic constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR vec() GLM_DEFAULT_CTOR; + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec const& v) GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, T, P> const& v); + + // -- Explicit basic constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR explicit vec(T scalar); + GLM_FUNC_DECL GLM_CONSTEXPR vec(T x, T y); + + // -- Conversion constructors -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR explicit vec(vec<1, U, P> const& v); + + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(A x, B y); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, Q> const& x, B y); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(A x, vec<1, B, Q> const& y); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, Q> const& x, vec<1, B, Q> const& y); + + // -- Conversion vector constructors -- + + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<3, U, P> const& v); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<4, U, P> const& v); + + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<2, U, P> const& v); + + // -- Swizzle constructors -- +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<2, T, Q, E0, E1,-1,-2> const& that) + { + *this = that(); + } +# endif//GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + + // -- Unary arithmetic operators -- + + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator=(vec const& v) GLM_DEFAULT; + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator=(vec<2, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator+=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator+=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator+=(vec<2, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator-=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator-=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator-=(vec<2, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator*=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator*=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator*=(vec<2, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator/=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator/=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator/=(vec<2, U, Q> const& v); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator++(); + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator--(); + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator++(int); + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator--(int); + + // -- Unary bit operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator%=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator%=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator%=(vec<2, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator&=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator&=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator&=(vec<2, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator|=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator|=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator|=(vec<2, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator^=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator^=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator^=(vec<2, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator<<=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator<<=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator<<=(vec<2, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator>>=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator>>=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator>>=(vec<2, U, Q> const& v); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v); + + // -- Binary operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator+(T scalar, vec<2, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator+(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator-(T scalar, vec<2, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator-(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator*(vec<2, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator*(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator*(T scalar, vec<2, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator*(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator*(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator/(vec<2, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator/(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator/(T scalar, vec<2, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator/(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator/(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator%(vec<2, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator%(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator%(T scalar, vec<2, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator%(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator%(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator&(vec<2, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator&(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator&(T scalar, vec<2, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator&(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator&(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator|(vec<2, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator|(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator|(T scalar, vec<2, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator|(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator|(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator^(vec<2, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator^(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator^(T scalar, vec<2, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator^(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator^(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<2, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator<<(T scalar, vec<2, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<2, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator>>(T scalar, vec<2, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator~(vec<2, T, Q> const& v); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator==(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator!=(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, bool, Q> operator&&(vec<2, bool, Q> const& v1, vec<2, bool, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, bool, Q> operator||(vec<2, bool, Q> const& v1, vec<2, bool, Q> const& v2); +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_vec2.inl" +#endif//GLM_EXTERNAL_TEMPLATE diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_vec2.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_vec2.inl new file mode 100644 index 0000000000000000000000000000000000000000..55ab64d455785a384293ce8d4494cde0a55d6bdd --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_vec2.inl @@ -0,0 +1,915 @@ +/// @ref core + +#include "./compute_vector_relational.hpp" + +namespace glm +{ + // -- Implicit basic constructors -- + +# if GLM_CONFIG_DEFAULTED_DEFAULT_CTOR == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec() +# if GLM_CONFIG_CTOR_INIT != GLM_CTOR_INIT_DISABLE + : x(0), y(0) +# endif + {} +# endif + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<2, T, Q> const& v) + : x(v.x), y(v.y) + {} +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<2, T, P> const& v) + : x(v.x), y(v.y) + {} + + // -- Explicit basic constructors -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(T scalar) + : x(scalar), y(scalar) + {} + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(T _x, T _y) + : x(_x), y(_y) + {} + + // -- Conversion scalar constructors -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<1, U, P> const& v) + : x(static_cast(v.x)) + , y(static_cast(v.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(A _x, B _y) + : x(static_cast(_x)) + , y(static_cast(_y)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<1, A, Q> const& _x, B _y) + : x(static_cast(_x.x)) + , y(static_cast(_y)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(A _x, vec<1, B, Q> const& _y) + : x(static_cast(_x)) + , y(static_cast(_y.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<1, A, Q> const& _x, vec<1, B, Q> const& _y) + : x(static_cast(_x.x)) + , y(static_cast(_y.x)) + {} + + // -- Conversion vector constructors -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<2, U, P> const& v) + : x(static_cast(v.x)) + , y(static_cast(v.y)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<3, U, P> const& v) + : x(static_cast(v.x)) + , y(static_cast(v.y)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<4, U, P> const& v) + : x(static_cast(v.x)) + , y(static_cast(v.y)) + {} + + // -- Component accesses -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T & vec<2, T, Q>::operator[](typename vec<2, T, Q>::length_type i) + { + assert(i >= 0 && i < this->length()); + switch(i) + { + default: + case 0: + return x; + case 1: + return y; + } + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T const& vec<2, T, Q>::operator[](typename vec<2, T, Q>::length_type i) const + { + assert(i >= 0 && i < this->length()); + switch(i) + { + default: + case 0: + return x; + case 1: + return y; + } + } + + // -- Unary arithmetic operators -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator=(vec<2, T, Q> const& v) + { + this->x = v.x; + this->y = v.y; + return *this; + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator=(vec<2, U, Q> const& v) + { + this->x = static_cast(v.x); + this->y = static_cast(v.y); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator+=(U scalar) + { + this->x += static_cast(scalar); + this->y += static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator+=(vec<1, U, Q> const& v) + { + this->x += static_cast(v.x); + this->y += static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator+=(vec<2, U, Q> const& v) + { + this->x += static_cast(v.x); + this->y += static_cast(v.y); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator-=(U scalar) + { + this->x -= static_cast(scalar); + this->y -= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator-=(vec<1, U, Q> const& v) + { + this->x -= static_cast(v.x); + this->y -= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator-=(vec<2, U, Q> const& v) + { + this->x -= static_cast(v.x); + this->y -= static_cast(v.y); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator*=(U scalar) + { + this->x *= static_cast(scalar); + this->y *= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator*=(vec<1, U, Q> const& v) + { + this->x *= static_cast(v.x); + this->y *= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator*=(vec<2, U, Q> const& v) + { + this->x *= static_cast(v.x); + this->y *= static_cast(v.y); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator/=(U scalar) + { + this->x /= static_cast(scalar); + this->y /= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator/=(vec<1, U, Q> const& v) + { + this->x /= static_cast(v.x); + this->y /= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator/=(vec<2, U, Q> const& v) + { + this->x /= static_cast(v.x); + this->y /= static_cast(v.y); + return *this; + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator++() + { + ++this->x; + ++this->y; + return *this; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator--() + { + --this->x; + --this->y; + return *this; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> vec<2, T, Q>::operator++(int) + { + vec<2, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> vec<2, T, Q>::operator--(int) + { + vec<2, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary bit operators -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator%=(U scalar) + { + this->x %= static_cast(scalar); + this->y %= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator%=(vec<1, U, Q> const& v) + { + this->x %= static_cast(v.x); + this->y %= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator%=(vec<2, U, Q> const& v) + { + this->x %= static_cast(v.x); + this->y %= static_cast(v.y); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator&=(U scalar) + { + this->x &= static_cast(scalar); + this->y &= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator&=(vec<1, U, Q> const& v) + { + this->x &= static_cast(v.x); + this->y &= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator&=(vec<2, U, Q> const& v) + { + this->x &= static_cast(v.x); + this->y &= static_cast(v.y); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator|=(U scalar) + { + this->x |= static_cast(scalar); + this->y |= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator|=(vec<1, U, Q> const& v) + { + this->x |= static_cast(v.x); + this->y |= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator|=(vec<2, U, Q> const& v) + { + this->x |= static_cast(v.x); + this->y |= static_cast(v.y); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator^=(U scalar) + { + this->x ^= static_cast(scalar); + this->y ^= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator^=(vec<1, U, Q> const& v) + { + this->x ^= static_cast(v.x); + this->y ^= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator^=(vec<2, U, Q> const& v) + { + this->x ^= static_cast(v.x); + this->y ^= static_cast(v.y); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator<<=(U scalar) + { + this->x <<= static_cast(scalar); + this->y <<= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator<<=(vec<1, U, Q> const& v) + { + this->x <<= static_cast(v.x); + this->y <<= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator<<=(vec<2, U, Q> const& v) + { + this->x <<= static_cast(v.x); + this->y <<= static_cast(v.y); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator>>=(U scalar) + { + this->x >>= static_cast(scalar); + this->y >>= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator>>=(vec<1, U, Q> const& v) + { + this->x >>= static_cast(v.x); + this->y >>= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator>>=(vec<2, U, Q> const& v) + { + this->x >>= static_cast(v.x); + this->y >>= static_cast(v.y); + return *this; + } + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v) + { + return v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + -v.x, + -v.y); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v, T scalar) + { + return vec<2, T, Q>( + v.x + scalar, + v.y + scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x + v2.x, + v1.y + v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator+(T scalar, vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + scalar + v.x, + scalar + v.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator+(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x + v2.x, + v1.x + v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x + v2.x, + v1.y + v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v, T scalar) + { + return vec<2, T, Q>( + v.x - scalar, + v.y - scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x - v2.x, + v1.y - v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator-(T scalar, vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + scalar - v.x, + scalar - v.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator-(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x - v2.x, + v1.x - v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x - v2.x, + v1.y - v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator*(vec<2, T, Q> const& v, T scalar) + { + return vec<2, T, Q>( + v.x * scalar, + v.y * scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator*(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x * v2.x, + v1.y * v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator*(T scalar, vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + scalar * v.x, + scalar * v.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator*(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x * v2.x, + v1.x * v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator*(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x * v2.x, + v1.y * v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator/(vec<2, T, Q> const& v, T scalar) + { + return vec<2, T, Q>( + v.x / scalar, + v.y / scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator/(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x / v2.x, + v1.y / v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator/(T scalar, vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + scalar / v.x, + scalar / v.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator/(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x / v2.x, + v1.x / v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator/(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x / v2.x, + v1.y / v2.y); + } + + // -- Binary bit operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator%(vec<2, T, Q> const& v, T scalar) + { + return vec<2, T, Q>( + v.x % scalar, + v.y % scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator%(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x % v2.x, + v1.y % v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator%(T scalar, vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + scalar % v.x, + scalar % v.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator%(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x % v2.x, + v1.x % v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator%(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x % v2.x, + v1.y % v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator&(vec<2, T, Q> const& v, T scalar) + { + return vec<2, T, Q>( + v.x & scalar, + v.y & scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator&(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x & v2.x, + v1.y & v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator&(T scalar, vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + scalar & v.x, + scalar & v.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator&(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x & v2.x, + v1.x & v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator&(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x & v2.x, + v1.y & v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator|(vec<2, T, Q> const& v, T scalar) + { + return vec<2, T, Q>( + v.x | scalar, + v.y | scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator|(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x | v2.x, + v1.y | v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator|(T scalar, vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + scalar | v.x, + scalar | v.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator|(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x | v2.x, + v1.x | v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator|(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x | v2.x, + v1.y | v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator^(vec<2, T, Q> const& v, T scalar) + { + return vec<2, T, Q>( + v.x ^ scalar, + v.y ^ scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator^(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x ^ v2.x, + v1.y ^ v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator^(T scalar, vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + scalar ^ v.x, + scalar ^ v.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator^(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x ^ v2.x, + v1.x ^ v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator^(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x ^ v2.x, + v1.y ^ v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<2, T, Q> const& v, T scalar) + { + return vec<2, T, Q>( + v.x << scalar, + v.y << scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x << v2.x, + v1.y << v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator<<(T scalar, vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + scalar << v.x, + scalar << v.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x << v2.x, + v1.x << v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x << v2.x, + v1.y << v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<2, T, Q> const& v, T scalar) + { + return vec<2, T, Q>( + v.x >> scalar, + v.y >> scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x >> v2.x, + v1.y >> v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator>>(T scalar, vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + scalar >> v.x, + scalar >> v.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x >> v2.x, + v1.x >> v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x >> v2.x, + v1.y >> v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator~(vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + ~v.x, + ~v.y); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator==(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return + detail::compute_equal::is_iec559>::call(v1.x, v2.x) && + detail::compute_equal::is_iec559>::call(v1.y, v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator!=(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return !(v1 == v2); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, bool, Q> operator&&(vec<2, bool, Q> const& v1, vec<2, bool, Q> const& v2) + { + return vec<2, bool, Q>(v1.x && v2.x, v1.y && v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, bool, Q> operator||(vec<2, bool, Q> const& v1, vec<2, bool, Q> const& v2) + { + return vec<2, bool, Q>(v1.x || v2.x, v1.y || v2.y); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_vec3.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_vec3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..cfc500060f3412b9b29bf2a8b965b13dd03d1c42 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_vec3.hpp @@ -0,0 +1,435 @@ +/// @ref core +/// @file glm/detail/type_vec3.hpp + +#pragma once + +#include "qualifier.hpp" +#if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR +# include "_swizzle.hpp" +#elif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION +# include "_swizzle_func.hpp" +#endif +#include + +namespace glm +{ + template + struct vec<3, T, Q> + { + // -- Implementation detail -- + + typedef T value_type; + typedef vec<3, T, Q> type; + typedef vec<3, bool, Q> bool_type; + + // -- Data -- + +# if GLM_SILENT_WARNINGS == GLM_ENABLE +# if GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpedantic" +# elif GLM_COMPILER & GLM_COMPILER_CLANG +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wgnu-anonymous-struct" +# pragma clang diagnostic ignored "-Wnested-anon-types" +# elif GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(push) +# pragma warning(disable: 4201) // nonstandard extension used : nameless struct/union +# if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE +# pragma warning(disable: 4324) // structure was padded due to alignment specifier +# endif +# endif +# endif + +# if GLM_CONFIG_XYZW_ONLY + T x, y, z; +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION + GLM_SWIZZLE_GEN_VEC_FROM_VEC3_COMP(T, Q, x, y, z) +# endif//GLM_CONFIG_SWIZZLE +# elif GLM_CONFIG_ANONYMOUS_STRUCT == GLM_ENABLE + union + { + struct{ T x, y, z; }; + struct{ T r, g, b; }; + struct{ T s, t, p; }; + + typename detail::storage<3, T, detail::is_aligned::value>::type data; + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + GLM_SWIZZLE3_2_MEMBERS(T, Q, x, y, z) + GLM_SWIZZLE3_2_MEMBERS(T, Q, r, g, b) + GLM_SWIZZLE3_2_MEMBERS(T, Q, s, t, p) + GLM_SWIZZLE3_3_MEMBERS(T, Q, x, y, z) + GLM_SWIZZLE3_3_MEMBERS(T, Q, r, g, b) + GLM_SWIZZLE3_3_MEMBERS(T, Q, s, t, p) + GLM_SWIZZLE3_4_MEMBERS(T, Q, x, y, z) + GLM_SWIZZLE3_4_MEMBERS(T, Q, r, g, b) + GLM_SWIZZLE3_4_MEMBERS(T, Q, s, t, p) +# endif + }; +# else + union { T x, r, s; }; + union { T y, g, t; }; + union { T z, b, p; }; + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION + GLM_SWIZZLE_GEN_VEC_FROM_VEC3(T, Q) +# endif//GLM_CONFIG_SWIZZLE +# endif//GLM_LANG + +# if GLM_SILENT_WARNINGS == GLM_ENABLE +# if GLM_COMPILER & GLM_COMPILER_CLANG +# pragma clang diagnostic pop +# elif GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic pop +# elif GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(pop) +# endif +# endif + + // -- Component accesses -- + + /// Return the count of components of the vector + typedef length_t length_type; + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length(){return 3;} + + GLM_FUNC_DECL GLM_CONSTEXPR T & operator[](length_type i); + GLM_FUNC_DECL GLM_CONSTEXPR T const& operator[](length_type i) const; + + // -- Implicit basic constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR vec() GLM_DEFAULT_CTOR; + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec const& v) GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<3, T, P> const& v); + + // -- Explicit basic constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR explicit vec(T scalar); + GLM_FUNC_DECL GLM_CONSTEXPR vec(T a, T b, T c); + + // -- Conversion scalar constructors -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR explicit vec(vec<1, U, P> const& v); + + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(X x, Y y, Z z); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, Y _y, Z _z); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, vec<1, Y, Q> const& _y, Z _z); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, Z _z); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, Y _y, vec<1, Z, Q> const& _z); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, Y _y, vec<1, Z, Q> const& _z); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z); + + // -- Conversion vector constructors -- + + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, A, P> const& _xy, B _z); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, A, P> const& _xy, vec<1, B, P> const& _z); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(A _x, vec<2, B, P> const& _yz); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, P> const& _x, vec<2, B, P> const& _yz); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<4, U, P> const& v); + + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<3, U, P> const& v); + + // -- Swizzle constructors -- +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<3, T, Q, E0, E1, E2, -1> const& that) + { + *this = that(); + } + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<2, T, Q, E0, E1, -1, -2> const& v, T const& scalar) + { + *this = vec(v(), scalar); + } + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(T const& scalar, detail::_swizzle<2, T, Q, E0, E1, -1, -2> const& v) + { + *this = vec(scalar, v()); + } +# endif//GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + + // -- Unary arithmetic operators -- + + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q>& operator=(vec<3, T, Q> const& v) GLM_DEFAULT; + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator=(vec<3, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator+=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator+=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator+=(vec<3, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator-=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator-=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator-=(vec<3, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator*=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator*=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator*=(vec<3, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator/=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator/=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator/=(vec<3, U, Q> const& v); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator++(); + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator--(); + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator++(int); + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator--(int); + + // -- Unary bit operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator%=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator%=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator%=(vec<3, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator&=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator&=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator&=(vec<3, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator|=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator|=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator|=(vec<3, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator^=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator^=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator^=(vec<3, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator<<=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator<<=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator<<=(vec<3, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator>>=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator>>=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator>>=(vec<3, U, Q> const& v); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v); + + // -- Binary operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator+(T scalar, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator+(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator-(T scalar, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator-(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator*(T scalar, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator*(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator/(vec<3, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator/(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator/(T scalar, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator/(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator/(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator%(vec<3, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator%(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator%(T scalar, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator%(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator%(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator&(vec<3, T, Q> const& v1, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator&(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator&(T scalar, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator&(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator&(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator|(vec<3, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator|(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator|(T scalar, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator|(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator|(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator^(vec<3, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator^(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator^(T scalar, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator^(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator^(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<3, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator<<(T scalar, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<3, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator>>(T scalar, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator~(vec<3, T, Q> const& v); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator==(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator!=(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, bool, Q> operator&&(vec<3, bool, Q> const& v1, vec<3, bool, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, bool, Q> operator||(vec<3, bool, Q> const& v1, vec<3, bool, Q> const& v2); +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_vec3.inl" +#endif//GLM_EXTERNAL_TEMPLATE diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_vec3.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_vec3.inl new file mode 100644 index 0000000000000000000000000000000000000000..8d15db85e55c6c00756b6fa9805d5f2360bb1210 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_vec3.inl @@ -0,0 +1,1070 @@ +/// @ref core + +#include "compute_vector_relational.hpp" + +namespace glm +{ + // -- Implicit basic constructors -- + +# if GLM_CONFIG_DEFAULTED_DEFAULT_CTOR == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec() +# if GLM_CONFIG_CTOR_INIT != GLM_CTOR_INIT_DISABLE + : x(0), y(0), z(0) +# endif + {} +# endif + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<3, T, Q> const& v) + : x(v.x), y(v.y), z(v.z) + {} +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<3, T, P> const& v) + : x(v.x), y(v.y), z(v.z) + {} + + // -- Explicit basic constructors -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(T scalar) + : x(scalar), y(scalar), z(scalar) + {} + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(T _x, T _y, T _z) + : x(_x), y(_y), z(_z) + {} + + // -- Conversion scalar constructors -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<1, U, P> const& v) + : x(static_cast(v.x)) + , y(static_cast(v.x)) + , z(static_cast(v.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(X _x, Y _y, Z _z) + : x(static_cast(_x)) + , y(static_cast(_y)) + , z(static_cast(_z)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<1, X, Q> const& _x, Y _y, Z _z) + : x(static_cast(_x.x)) + , y(static_cast(_y)) + , z(static_cast(_z)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(X _x, vec<1, Y, Q> const& _y, Z _z) + : x(static_cast(_x)) + , y(static_cast(_y.x)) + , z(static_cast(_z)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, Z _z) + : x(static_cast(_x.x)) + , y(static_cast(_y.x)) + , z(static_cast(_z)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(X _x, Y _y, vec<1, Z, Q> const& _z) + : x(static_cast(_x)) + , y(static_cast(_y)) + , z(static_cast(_z.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<1, X, Q> const& _x, Y _y, vec<1, Z, Q> const& _z) + : x(static_cast(_x.x)) + , y(static_cast(_y)) + , z(static_cast(_z.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(X _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z) + : x(static_cast(_x)) + , y(static_cast(_y.x)) + , z(static_cast(_z.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z) + : x(static_cast(_x.x)) + , y(static_cast(_y.x)) + , z(static_cast(_z.x)) + {} + + // -- Conversion vector constructors -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<2, A, P> const& _xy, B _z) + : x(static_cast(_xy.x)) + , y(static_cast(_xy.y)) + , z(static_cast(_z)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<2, A, P> const& _xy, vec<1, B, P> const& _z) + : x(static_cast(_xy.x)) + , y(static_cast(_xy.y)) + , z(static_cast(_z.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(A _x, vec<2, B, P> const& _yz) + : x(static_cast(_x)) + , y(static_cast(_yz.x)) + , z(static_cast(_yz.y)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<1, A, P> const& _x, vec<2, B, P> const& _yz) + : x(static_cast(_x.x)) + , y(static_cast(_yz.x)) + , z(static_cast(_yz.y)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<3, U, P> const& v) + : x(static_cast(v.x)) + , y(static_cast(v.y)) + , z(static_cast(v.z)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<4, U, P> const& v) + : x(static_cast(v.x)) + , y(static_cast(v.y)) + , z(static_cast(v.z)) + {} + + // -- Component accesses -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T & vec<3, T, Q>::operator[](typename vec<3, T, Q>::length_type i) + { + assert(i >= 0 && i < this->length()); + switch(i) + { + default: + case 0: + return x; + case 1: + return y; + case 2: + return z; + } + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T const& vec<3, T, Q>::operator[](typename vec<3, T, Q>::length_type i) const + { + assert(i >= 0 && i < this->length()); + switch(i) + { + default: + case 0: + return x; + case 1: + return y; + case 2: + return z; + } + } + + // -- Unary arithmetic operators -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>& vec<3, T, Q>::operator=(vec<3, T, Q> const& v) + { + this->x = v.x; + this->y = v.y; + this->z = v.z; + return *this; + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>& vec<3, T, Q>::operator=(vec<3, U, Q> const& v) + { + this->x = static_cast(v.x); + this->y = static_cast(v.y); + this->z = static_cast(v.z); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator+=(U scalar) + { + this->x += static_cast(scalar); + this->y += static_cast(scalar); + this->z += static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator+=(vec<1, U, Q> const& v) + { + this->x += static_cast(v.x); + this->y += static_cast(v.x); + this->z += static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator+=(vec<3, U, Q> const& v) + { + this->x += static_cast(v.x); + this->y += static_cast(v.y); + this->z += static_cast(v.z); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator-=(U scalar) + { + this->x -= static_cast(scalar); + this->y -= static_cast(scalar); + this->z -= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator-=(vec<1, U, Q> const& v) + { + this->x -= static_cast(v.x); + this->y -= static_cast(v.x); + this->z -= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator-=(vec<3, U, Q> const& v) + { + this->x -= static_cast(v.x); + this->y -= static_cast(v.y); + this->z -= static_cast(v.z); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator*=(U scalar) + { + this->x *= static_cast(scalar); + this->y *= static_cast(scalar); + this->z *= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator*=(vec<1, U, Q> const& v) + { + this->x *= static_cast(v.x); + this->y *= static_cast(v.x); + this->z *= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator*=(vec<3, U, Q> const& v) + { + this->x *= static_cast(v.x); + this->y *= static_cast(v.y); + this->z *= static_cast(v.z); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator/=(U v) + { + this->x /= static_cast(v); + this->y /= static_cast(v); + this->z /= static_cast(v); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator/=(vec<1, U, Q> const& v) + { + this->x /= static_cast(v.x); + this->y /= static_cast(v.x); + this->z /= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator/=(vec<3, U, Q> const& v) + { + this->x /= static_cast(v.x); + this->y /= static_cast(v.y); + this->z /= static_cast(v.z); + return *this; + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator++() + { + ++this->x; + ++this->y; + ++this->z; + return *this; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator--() + { + --this->x; + --this->y; + --this->z; + return *this; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> vec<3, T, Q>::operator++(int) + { + vec<3, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> vec<3, T, Q>::operator--(int) + { + vec<3, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary bit operators -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator%=(U scalar) + { + this->x %= scalar; + this->y %= scalar; + this->z %= scalar; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator%=(vec<1, U, Q> const& v) + { + this->x %= v.x; + this->y %= v.x; + this->z %= v.x; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator%=(vec<3, U, Q> const& v) + { + this->x %= v.x; + this->y %= v.y; + this->z %= v.z; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator&=(U scalar) + { + this->x &= scalar; + this->y &= scalar; + this->z &= scalar; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator&=(vec<1, U, Q> const& v) + { + this->x &= v.x; + this->y &= v.x; + this->z &= v.x; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator&=(vec<3, U, Q> const& v) + { + this->x &= v.x; + this->y &= v.y; + this->z &= v.z; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator|=(U scalar) + { + this->x |= scalar; + this->y |= scalar; + this->z |= scalar; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator|=(vec<1, U, Q> const& v) + { + this->x |= v.x; + this->y |= v.x; + this->z |= v.x; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator|=(vec<3, U, Q> const& v) + { + this->x |= v.x; + this->y |= v.y; + this->z |= v.z; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator^=(U scalar) + { + this->x ^= scalar; + this->y ^= scalar; + this->z ^= scalar; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator^=(vec<1, U, Q> const& v) + { + this->x ^= v.x; + this->y ^= v.x; + this->z ^= v.x; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator^=(vec<3, U, Q> const& v) + { + this->x ^= v.x; + this->y ^= v.y; + this->z ^= v.z; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator<<=(U scalar) + { + this->x <<= scalar; + this->y <<= scalar; + this->z <<= scalar; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator<<=(vec<1, U, Q> const& v) + { + this->x <<= static_cast(v.x); + this->y <<= static_cast(v.x); + this->z <<= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator<<=(vec<3, U, Q> const& v) + { + this->x <<= static_cast(v.x); + this->y <<= static_cast(v.y); + this->z <<= static_cast(v.z); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator>>=(U scalar) + { + this->x >>= static_cast(scalar); + this->y >>= static_cast(scalar); + this->z >>= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator>>=(vec<1, U, Q> const& v) + { + this->x >>= static_cast(v.x); + this->y >>= static_cast(v.x); + this->z >>= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator>>=(vec<3, U, Q> const& v) + { + this->x >>= static_cast(v.x); + this->y >>= static_cast(v.y); + this->z >>= static_cast(v.z); + return *this; + } + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v) + { + return v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + -v.x, + -v.y, + -v.z); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v, T scalar) + { + return vec<3, T, Q>( + v.x + scalar, + v.y + scalar, + v.z + scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) + { + return vec<3, T, Q>( + v.x + scalar.x, + v.y + scalar.x, + v.z + scalar.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator+(T scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar + v.x, + scalar + v.y, + scalar + v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator+(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar.x + v.x, + scalar.x + v.y, + scalar.x + v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return vec<3, T, Q>( + v1.x + v2.x, + v1.y + v2.y, + v1.z + v2.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v, T scalar) + { + return vec<3, T, Q>( + v.x - scalar, + v.y - scalar, + v.z - scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) + { + return vec<3, T, Q>( + v.x - scalar.x, + v.y - scalar.x, + v.z - scalar.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator-(T scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar - v.x, + scalar - v.y, + scalar - v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator-(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar.x - v.x, + scalar.x - v.y, + scalar.x - v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return vec<3, T, Q>( + v1.x - v2.x, + v1.y - v2.y, + v1.z - v2.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v, T scalar) + { + return vec<3, T, Q>( + v.x * scalar, + v.y * scalar, + v.z * scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) + { + return vec<3, T, Q>( + v.x * scalar.x, + v.y * scalar.x, + v.z * scalar.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator*(T scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar * v.x, + scalar * v.y, + scalar * v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator*(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar.x * v.x, + scalar.x * v.y, + scalar.x * v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return vec<3, T, Q>( + v1.x * v2.x, + v1.y * v2.y, + v1.z * v2.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator/(vec<3, T, Q> const& v, T scalar) + { + return vec<3, T, Q>( + v.x / scalar, + v.y / scalar, + v.z / scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator/(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) + { + return vec<3, T, Q>( + v.x / scalar.x, + v.y / scalar.x, + v.z / scalar.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator/(T scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar / v.x, + scalar / v.y, + scalar / v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator/(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar.x / v.x, + scalar.x / v.y, + scalar.x / v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator/(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return vec<3, T, Q>( + v1.x / v2.x, + v1.y / v2.y, + v1.z / v2.z); + } + + // -- Binary bit operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator%(vec<3, T, Q> const& v, T scalar) + { + return vec<3, T, Q>( + v.x % scalar, + v.y % scalar, + v.z % scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator%(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) + { + return vec<3, T, Q>( + v.x % scalar.x, + v.y % scalar.x, + v.z % scalar.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator%(T scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar % v.x, + scalar % v.y, + scalar % v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator%(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar.x % v.x, + scalar.x % v.y, + scalar.x % v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator%(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return vec<3, T, Q>( + v1.x % v2.x, + v1.y % v2.y, + v1.z % v2.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator&(vec<3, T, Q> const& v, T scalar) + { + return vec<3, T, Q>( + v.x & scalar, + v.y & scalar, + v.z & scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator&(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) + { + return vec<3, T, Q>( + v.x & scalar.x, + v.y & scalar.x, + v.z & scalar.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator&(T scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar & v.x, + scalar & v.y, + scalar & v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator&(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar.x & v.x, + scalar.x & v.y, + scalar.x & v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator&(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return vec<3, T, Q>( + v1.x & v2.x, + v1.y & v2.y, + v1.z & v2.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator|(vec<3, T, Q> const& v, T scalar) + { + return vec<3, T, Q>( + v.x | scalar, + v.y | scalar, + v.z | scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator|(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) + { + return vec<3, T, Q>( + v.x | scalar.x, + v.y | scalar.x, + v.z | scalar.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator|(T scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar | v.x, + scalar | v.y, + scalar | v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator|(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar.x | v.x, + scalar.x | v.y, + scalar.x | v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator|(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return vec<3, T, Q>( + v1.x | v2.x, + v1.y | v2.y, + v1.z | v2.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator^(vec<3, T, Q> const& v, T scalar) + { + return vec<3, T, Q>( + v.x ^ scalar, + v.y ^ scalar, + v.z ^ scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator^(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) + { + return vec<3, T, Q>( + v.x ^ scalar.x, + v.y ^ scalar.x, + v.z ^ scalar.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator^(T scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar ^ v.x, + scalar ^ v.y, + scalar ^ v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator^(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar.x ^ v.x, + scalar.x ^ v.y, + scalar.x ^ v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator^(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return vec<3, T, Q>( + v1.x ^ v2.x, + v1.y ^ v2.y, + v1.z ^ v2.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<3, T, Q> const& v, T scalar) + { + return vec<3, T, Q>( + v.x << scalar, + v.y << scalar, + v.z << scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) + { + return vec<3, T, Q>( + v.x << scalar.x, + v.y << scalar.x, + v.z << scalar.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator<<(T scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar << v.x, + scalar << v.y, + scalar << v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar.x << v.x, + scalar.x << v.y, + scalar.x << v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return vec<3, T, Q>( + v1.x << v2.x, + v1.y << v2.y, + v1.z << v2.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<3, T, Q> const& v, T scalar) + { + return vec<3, T, Q>( + v.x >> scalar, + v.y >> scalar, + v.z >> scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) + { + return vec<3, T, Q>( + v.x >> scalar.x, + v.y >> scalar.x, + v.z >> scalar.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator>>(T scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar >> v.x, + scalar >> v.y, + scalar >> v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar.x >> v.x, + scalar.x >> v.y, + scalar.x >> v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return vec<3, T, Q>( + v1.x >> v2.x, + v1.y >> v2.y, + v1.z >> v2.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator~(vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + ~v.x, + ~v.y, + ~v.z); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator==(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return + detail::compute_equal::is_iec559>::call(v1.x, v2.x) && + detail::compute_equal::is_iec559>::call(v1.y, v2.y) && + detail::compute_equal::is_iec559>::call(v1.z, v2.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator!=(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return !(v1 == v2); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, bool, Q> operator&&(vec<3, bool, Q> const& v1, vec<3, bool, Q> const& v2) + { + return vec<3, bool, Q>(v1.x && v2.x, v1.y && v2.y, v1.z && v2.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, bool, Q> operator||(vec<3, bool, Q> const& v1, vec<3, bool, Q> const& v2) + { + return vec<3, bool, Q>(v1.x || v2.x, v1.y || v2.y, v1.z || v2.z); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_vec4.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_vec4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e78f5a568a73d18a7731fbfa0b6c65aa3752f6da --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_vec4.hpp @@ -0,0 +1,508 @@ +/// @ref core +/// @file glm/detail/type_vec4.hpp + +#pragma once + +#include "qualifier.hpp" +#if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR +# include "_swizzle.hpp" +#elif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION +# include "_swizzle_func.hpp" +#endif +#include + +namespace glm +{ + template + struct vec<4, T, Q> + { + // -- Implementation detail -- + + typedef T value_type; + typedef vec<4, T, Q> type; + typedef vec<4, bool, Q> bool_type; + + // -- Data -- + +# if GLM_SILENT_WARNINGS == GLM_ENABLE +# if GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpedantic" +# elif GLM_COMPILER & GLM_COMPILER_CLANG +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wgnu-anonymous-struct" +# pragma clang diagnostic ignored "-Wnested-anon-types" +# elif GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(push) +# pragma warning(disable: 4201) // nonstandard extension used : nameless struct/union +# endif +# endif + +# if GLM_CONFIG_XYZW_ONLY + T x, y, z, w; +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION + GLM_SWIZZLE_GEN_VEC_FROM_VEC4_COMP(T, Q, x, y, z, w) +# endif//GLM_CONFIG_SWIZZLE +# elif GLM_CONFIG_ANONYMOUS_STRUCT == GLM_ENABLE + union + { + struct { T x, y, z, w; }; + struct { T r, g, b, a; }; + struct { T s, t, p, q; }; + + typename detail::storage<4, T, detail::is_aligned::value>::type data; + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + GLM_SWIZZLE4_2_MEMBERS(T, Q, x, y, z, w) + GLM_SWIZZLE4_2_MEMBERS(T, Q, r, g, b, a) + GLM_SWIZZLE4_2_MEMBERS(T, Q, s, t, p, q) + GLM_SWIZZLE4_3_MEMBERS(T, Q, x, y, z, w) + GLM_SWIZZLE4_3_MEMBERS(T, Q, r, g, b, a) + GLM_SWIZZLE4_3_MEMBERS(T, Q, s, t, p, q) + GLM_SWIZZLE4_4_MEMBERS(T, Q, x, y, z, w) + GLM_SWIZZLE4_4_MEMBERS(T, Q, r, g, b, a) + GLM_SWIZZLE4_4_MEMBERS(T, Q, s, t, p, q) +# endif + }; +# else + union { T x, r, s; }; + union { T y, g, t; }; + union { T z, b, p; }; + union { T w, a, q; }; + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION + GLM_SWIZZLE_GEN_VEC_FROM_VEC4(T, Q) +# endif +# endif + +# if GLM_SILENT_WARNINGS == GLM_ENABLE +# if GLM_COMPILER & GLM_COMPILER_CLANG +# pragma clang diagnostic pop +# elif GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic pop +# elif GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(pop) +# endif +# endif + + // -- Component accesses -- + + typedef length_t length_type; + + /// Return the count of components of the vector + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length(){return 4;} + + GLM_FUNC_DECL GLM_CONSTEXPR T & operator[](length_type i); + GLM_FUNC_DECL GLM_CONSTEXPR T const& operator[](length_type i) const; + + // -- Implicit basic constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR vec() GLM_DEFAULT_CTOR; + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<4, T, Q> const& v) GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<4, T, P> const& v); + + // -- Explicit basic constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR explicit vec(T scalar); + GLM_FUNC_DECL GLM_CONSTEXPR vec(T x, T y, T z, T w); + + // -- Conversion scalar constructors -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR explicit vec(vec<1, U, P> const& v); + + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, Y _y, Z _z, W _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, Y _y, Z _z, W _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, vec<1, Y, Q> const& _y, Z _z, W _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, Z _z, W _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, Y _y, vec<1, Z, Q> const& _z, W _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, Y _y, vec<1, Z, Q> const& _z, W _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, W _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, W _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, Y _y, Z _z, vec<1, W, Q> const& _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, vec<1, Y, Q> const& _y, Z _z, vec<1, W, Q> const& _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, Z _z, vec<1, W, Q> const& _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, Y _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, Y _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w); + + // -- Conversion vector constructors -- + + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, A, P> const& _xy, B _z, C _w); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, A, P> const& _xy, vec<1, B, P> const& _z, C _w); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, A, P> const& _xy, B _z, vec<1, C, P> const& _w); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, A, P> const& _xy, vec<1, B, P> const& _z, vec<1, C, P> const& _w); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(A _x, vec<2, B, P> const& _yz, C _w); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, P> const& _x, vec<2, B, P> const& _yz, C _w); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(A _x, vec<2, B, P> const& _yz, vec<1, C, P> const& _w); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, P> const& _x, vec<2, B, P> const& _yz, vec<1, C, P> const& _w); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(A _x, B _y, vec<2, C, P> const& _zw); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, P> const& _x, B _y, vec<2, C, P> const& _zw); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(A _x, vec<1, B, P> const& _y, vec<2, C, P> const& _zw); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, P> const& _x, vec<1, B, P> const& _y, vec<2, C, P> const& _zw); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<3, A, P> const& _xyz, B _w); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<3, A, P> const& _xyz, vec<1, B, P> const& _w); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(A _x, vec<3, B, P> const& _yzw); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, P> const& _x, vec<3, B, P> const& _yzw); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, A, P> const& _xy, vec<2, B, P> const& _zw); + + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<4, U, P> const& v); + + // -- Swizzle constructors -- +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<4, T, Q, E0, E1, E2, E3> const& that) + { + *this = that(); + } + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<2, T, Q, E0, E1, -1, -2> const& v, detail::_swizzle<2, T, Q, F0, F1, -1, -2> const& u) + { + *this = vec<4, T, Q>(v(), u()); + } + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(T const& x, T const& y, detail::_swizzle<2, T, Q, E0, E1, -1, -2> const& v) + { + *this = vec<4, T, Q>(x, y, v()); + } + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(T const& x, detail::_swizzle<2, T, Q, E0, E1, -1, -2> const& v, T const& w) + { + *this = vec<4, T, Q>(x, v(), w); + } + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<2, T, Q, E0, E1, -1, -2> const& v, T const& z, T const& w) + { + *this = vec<4, T, Q>(v(), z, w); + } + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<3, T, Q, E0, E1, E2, -1> const& v, T const& w) + { + *this = vec<4, T, Q>(v(), w); + } + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(T const& x, detail::_swizzle<3, T, Q, E0, E1, E2, -1> const& v) + { + *this = vec<4, T, Q>(x, v()); + } +# endif//GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + + // -- Unary arithmetic operators -- + + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator=(vec<4, T, Q> const& v) GLM_DEFAULT; + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator=(vec<4, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator+=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator+=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator+=(vec<4, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator-=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator-=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator-=(vec<4, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator*=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator*=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator*=(vec<4, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator/=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator/=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator/=(vec<4, U, Q> const& v); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator++(); + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator--(); + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator++(int); + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator--(int); + + // -- Unary bit operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator%=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator%=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator%=(vec<4, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator&=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator&=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator&=(vec<4, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator|=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator|=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator|=(vec<4, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator^=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator^=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator^=(vec<4, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator<<=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator<<=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator<<=(vec<4, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator>>=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator>>=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator>>=(vec<4, U, Q> const& v); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v); + + // -- Binary operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v, T const & scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator+(T scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator+(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v, T const & scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator-(T scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator-(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v, T const & scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator*(T scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator*(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator/(vec<4, T, Q> const& v, T const & scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator/(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator/(T scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator/(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator/(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator%(vec<4, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator%(vec<4, T, Q> const& v, vec<1, T, Q> const& scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator%(T scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator%(vec<1, T, Q> const& scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator%(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator&(vec<4, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator&(vec<4, T, Q> const& v, vec<1, T, Q> const& scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator&(T scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator&(vec<1, T, Q> const& scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator&(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator|(vec<4, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator|(vec<4, T, Q> const& v, vec<1, T, Q> const& scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator|(T scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator|(vec<1, T, Q> const& scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator|(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator^(vec<4, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator^(vec<4, T, Q> const& v, vec<1, T, Q> const& scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator^(T scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator^(vec<1, T, Q> const& scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator^(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<4, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<4, T, Q> const& v, vec<1, T, Q> const& scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator<<(T scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<1, T, Q> const& scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<4, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<4, T, Q> const& v, vec<1, T, Q> const& scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator>>(T scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<1, T, Q> const& scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator~(vec<4, T, Q> const& v); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator==(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator!=(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, bool, Q> operator&&(vec<4, bool, Q> const& v1, vec<4, bool, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, bool, Q> operator||(vec<4, bool, Q> const& v1, vec<4, bool, Q> const& v2); +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_vec4.inl" +#endif//GLM_EXTERNAL_TEMPLATE diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_vec4.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_vec4.inl new file mode 100644 index 0000000000000000000000000000000000000000..f520c095c384f7d73aae9b9e3549f23a9182d19a --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_vec4.inl @@ -0,0 +1,1142 @@ +/// @ref core + +#include "compute_vector_relational.hpp" + +namespace glm{ +namespace detail +{ + template + struct compute_vec4_add + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + return vec<4, T, Q>(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); + } + }; + + template + struct compute_vec4_sub + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + return vec<4, T, Q>(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); + } + }; + + template + struct compute_vec4_mul + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + return vec<4, T, Q>(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); + } + }; + + template + struct compute_vec4_div + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + return vec<4, T, Q>(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w); + } + }; + + template + struct compute_vec4_mod + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + return vec<4, T, Q>(a.x % b.x, a.y % b.y, a.z % b.z, a.w % b.w); + } + }; + + template + struct compute_vec4_and + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + return vec<4, T, Q>(a.x & b.x, a.y & b.y, a.z & b.z, a.w & b.w); + } + }; + + template + struct compute_vec4_or + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + return vec<4, T, Q>(a.x | b.x, a.y | b.y, a.z | b.z, a.w | b.w); + } + }; + + template + struct compute_vec4_xor + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + return vec<4, T, Q>(a.x ^ b.x, a.y ^ b.y, a.z ^ b.z, a.w ^ b.w); + } + }; + + template + struct compute_vec4_shift_left + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + return vec<4, T, Q>(a.x << b.x, a.y << b.y, a.z << b.z, a.w << b.w); + } + }; + + template + struct compute_vec4_shift_right + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + return vec<4, T, Q>(a.x >> b.x, a.y >> b.y, a.z >> b.z, a.w >> b.w); + } + }; + + template + struct compute_vec4_equal + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static bool call(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return + detail::compute_equal::is_iec559>::call(v1.x, v2.x) && + detail::compute_equal::is_iec559>::call(v1.y, v2.y) && + detail::compute_equal::is_iec559>::call(v1.z, v2.z) && + detail::compute_equal::is_iec559>::call(v1.w, v2.w); + } + }; + + template + struct compute_vec4_nequal + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static bool call(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return !compute_vec4_equal::value, sizeof(T) * 8, detail::is_aligned::value>::call(v1, v2); + } + }; + + template + struct compute_vec4_bitwise_not + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& v) + { + return vec<4, T, Q>(~v.x, ~v.y, ~v.z, ~v.w); + } + }; +}//namespace detail + + // -- Implicit basic constructors -- + +# if GLM_CONFIG_DEFAULTED_DEFAULT_CTOR == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec() +# if GLM_CONFIG_CTOR_INIT != GLM_CTOR_INIT_DISABLE + : x(0), y(0), z(0), w(0) +# endif + {} +# endif + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<4, T, Q> const& v) + : x(v.x), y(v.y), z(v.z), w(v.w) + {} +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<4, T, P> const& v) + : x(v.x), y(v.y), z(v.z), w(v.w) + {} + + // -- Explicit basic constructors -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(T scalar) + : x(scalar), y(scalar), z(scalar), w(scalar) + {} + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(T _x, T _y, T _z, T _w) + : x(_x), y(_y), z(_z), w(_w) + {} + + // -- Conversion scalar constructors -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, U, P> const& v) + : x(static_cast(v.x)) + , y(static_cast(v.x)) + , z(static_cast(v.x)) + , w(static_cast(v.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(X _x, Y _y, Z _z, W _w) + : x(static_cast(_x)) + , y(static_cast(_y)) + , z(static_cast(_z)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, Y _y, Z _z, W _w) + : x(static_cast(_x.x)) + , y(static_cast(_y)) + , z(static_cast(_z)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(X _x, vec<1, Y, Q> const& _y, Z _z, W _w) + : x(static_cast(_x)) + , y(static_cast(_y.x)) + , z(static_cast(_z)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, Z _z, W _w) + : x(static_cast(_x.x)) + , y(static_cast(_y.x)) + , z(static_cast(_z)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(X _x, Y _y, vec<1, Z, Q> const& _z, W _w) + : x(static_cast(_x)) + , y(static_cast(_y)) + , z(static_cast(_z.x)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, Y _y, vec<1, Z, Q> const& _z, W _w) + : x(static_cast(_x.x)) + , y(static_cast(_y)) + , z(static_cast(_z.x)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(X _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, W _w) + : x(static_cast(_x)) + , y(static_cast(_y.x)) + , z(static_cast(_z.x)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, W _w) + : x(static_cast(_x.x)) + , y(static_cast(_y.x)) + , z(static_cast(_z.x)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, Y _y, Z _z, vec<1, W, Q> const& _w) + : x(static_cast(_x.x)) + , y(static_cast(_y)) + , z(static_cast(_z)) + , w(static_cast(_w.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(X _x, vec<1, Y, Q> const& _y, Z _z, vec<1, W, Q> const& _w) + : x(static_cast(_x)) + , y(static_cast(_y.x)) + , z(static_cast(_z)) + , w(static_cast(_w.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, Z _z, vec<1, W, Q> const& _w) + : x(static_cast(_x.x)) + , y(static_cast(_y.x)) + , z(static_cast(_z)) + , w(static_cast(_w.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(X _x, Y _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w) + : x(static_cast(_x)) + , y(static_cast(_y)) + , z(static_cast(_z.x)) + , w(static_cast(_w.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, Y _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w) + : x(static_cast(_x.x)) + , y(static_cast(_y)) + , z(static_cast(_z.x)) + , w(static_cast(_w.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(X _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w) + : x(static_cast(_x)) + , y(static_cast(_y.x)) + , z(static_cast(_z.x)) + , w(static_cast(_w.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w) + : x(static_cast(_x.x)) + , y(static_cast(_y.x)) + , z(static_cast(_z.x)) + , w(static_cast(_w.x)) + {} + + // -- Conversion vector constructors -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<2, A, P> const& _xy, B _z, C _w) + : x(static_cast(_xy.x)) + , y(static_cast(_xy.y)) + , z(static_cast(_z)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<2, A, P> const& _xy, vec<1, B, P> const& _z, C _w) + : x(static_cast(_xy.x)) + , y(static_cast(_xy.y)) + , z(static_cast(_z.x)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<2, A, P> const& _xy, B _z, vec<1, C, P> const& _w) + : x(static_cast(_xy.x)) + , y(static_cast(_xy.y)) + , z(static_cast(_z)) + , w(static_cast(_w.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<2, A, P> const& _xy, vec<1, B, P> const& _z, vec<1, C, P> const& _w) + : x(static_cast(_xy.x)) + , y(static_cast(_xy.y)) + , z(static_cast(_z.x)) + , w(static_cast(_w.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(A _x, vec<2, B, P> const& _yz, C _w) + : x(static_cast(_x)) + , y(static_cast(_yz.x)) + , z(static_cast(_yz.y)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, A, P> const& _x, vec<2, B, P> const& _yz, C _w) + : x(static_cast(_x.x)) + , y(static_cast(_yz.x)) + , z(static_cast(_yz.y)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(A _x, vec<2, B, P> const& _yz, vec<1, C, P> const& _w) + : x(static_cast(_x)) + , y(static_cast(_yz.x)) + , z(static_cast(_yz.y)) + , w(static_cast(_w.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, A, P> const& _x, vec<2, B, P> const& _yz, vec<1, C, P> const& _w) + : x(static_cast(_x.x)) + , y(static_cast(_yz.x)) + , z(static_cast(_yz.y)) + , w(static_cast(_w.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(A _x, B _y, vec<2, C, P> const& _zw) + : x(static_cast(_x)) + , y(static_cast(_y)) + , z(static_cast(_zw.x)) + , w(static_cast(_zw.y)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, A, P> const& _x, B _y, vec<2, C, P> const& _zw) + : x(static_cast(_x.x)) + , y(static_cast(_y)) + , z(static_cast(_zw.x)) + , w(static_cast(_zw.y)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(A _x, vec<1, B, P> const& _y, vec<2, C, P> const& _zw) + : x(static_cast(_x)) + , y(static_cast(_y.x)) + , z(static_cast(_zw.x)) + , w(static_cast(_zw.y)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, A, P> const& _x, vec<1, B, P> const& _y, vec<2, C, P> const& _zw) + : x(static_cast(_x.x)) + , y(static_cast(_y.x)) + , z(static_cast(_zw.x)) + , w(static_cast(_zw.y)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<3, A, P> const& _xyz, B _w) + : x(static_cast(_xyz.x)) + , y(static_cast(_xyz.y)) + , z(static_cast(_xyz.z)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<3, A, P> const& _xyz, vec<1, B, P> const& _w) + : x(static_cast(_xyz.x)) + , y(static_cast(_xyz.y)) + , z(static_cast(_xyz.z)) + , w(static_cast(_w.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(A _x, vec<3, B, P> const& _yzw) + : x(static_cast(_x)) + , y(static_cast(_yzw.x)) + , z(static_cast(_yzw.y)) + , w(static_cast(_yzw.z)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, A, P> const& _x, vec<3, B, P> const& _yzw) + : x(static_cast(_x.x)) + , y(static_cast(_yzw.x)) + , z(static_cast(_yzw.y)) + , w(static_cast(_yzw.z)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<2, A, P> const& _xy, vec<2, B, P> const& _zw) + : x(static_cast(_xy.x)) + , y(static_cast(_xy.y)) + , z(static_cast(_zw.x)) + , w(static_cast(_zw.y)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<4, U, P> const& v) + : x(static_cast(v.x)) + , y(static_cast(v.y)) + , z(static_cast(v.z)) + , w(static_cast(v.w)) + {} + + // -- Component accesses -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T& vec<4, T, Q>::operator[](typename vec<4, T, Q>::length_type i) + { + assert(i >= 0 && i < this->length()); + switch(i) + { + default: + case 0: + return x; + case 1: + return y; + case 2: + return z; + case 3: + return w; + } + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T const& vec<4, T, Q>::operator[](typename vec<4, T, Q>::length_type i) const + { + assert(i >= 0 && i < this->length()); + switch(i) + { + default: + case 0: + return x; + case 1: + return y; + case 2: + return z; + case 3: + return w; + } + } + + // -- Unary arithmetic operators -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>& vec<4, T, Q>::operator=(vec<4, T, Q> const& v) + { + this->x = v.x; + this->y = v.y; + this->z = v.z; + this->w = v.w; + return *this; + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>& vec<4, T, Q>::operator=(vec<4, U, Q> const& v) + { + this->x = static_cast(v.x); + this->y = static_cast(v.y); + this->z = static_cast(v.z); + this->w = static_cast(v.w); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator+=(U scalar) + { + return (*this = detail::compute_vec4_add::value>::call(*this, vec<4, T, Q>(scalar))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator+=(vec<1, U, Q> const& v) + { + return (*this = detail::compute_vec4_add::value>::call(*this, vec<4, T, Q>(v.x))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator+=(vec<4, U, Q> const& v) + { + return (*this = detail::compute_vec4_add::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator-=(U scalar) + { + return (*this = detail::compute_vec4_sub::value>::call(*this, vec<4, T, Q>(scalar))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator-=(vec<1, U, Q> const& v) + { + return (*this = detail::compute_vec4_sub::value>::call(*this, vec<4, T, Q>(v.x))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator-=(vec<4, U, Q> const& v) + { + return (*this = detail::compute_vec4_sub::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator*=(U scalar) + { + return (*this = detail::compute_vec4_mul::value>::call(*this, vec<4, T, Q>(scalar))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator*=(vec<1, U, Q> const& v) + { + return (*this = detail::compute_vec4_mul::value>::call(*this, vec<4, T, Q>(v.x))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator*=(vec<4, U, Q> const& v) + { + return (*this = detail::compute_vec4_mul::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator/=(U scalar) + { + return (*this = detail::compute_vec4_div::value>::call(*this, vec<4, T, Q>(scalar))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator/=(vec<1, U, Q> const& v) + { + return (*this = detail::compute_vec4_div::value>::call(*this, vec<4, T, Q>(v.x))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator/=(vec<4, U, Q> const& v) + { + return (*this = detail::compute_vec4_div::value>::call(*this, vec<4, T, Q>(v))); + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator++() + { + ++this->x; + ++this->y; + ++this->z; + ++this->w; + return *this; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator--() + { + --this->x; + --this->y; + --this->z; + --this->w; + return *this; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> vec<4, T, Q>::operator++(int) + { + vec<4, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> vec<4, T, Q>::operator--(int) + { + vec<4, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary bit operators -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator%=(U scalar) + { + return (*this = detail::compute_vec4_mod::value>::call(*this, vec<4, T, Q>(scalar))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator%=(vec<1, U, Q> const& v) + { + return (*this = detail::compute_vec4_mod::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator%=(vec<4, U, Q> const& v) + { + return (*this = detail::compute_vec4_mod::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator&=(U scalar) + { + return (*this = detail::compute_vec4_and::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(scalar))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator&=(vec<1, U, Q> const& v) + { + return (*this = detail::compute_vec4_and::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator&=(vec<4, U, Q> const& v) + { + return (*this = detail::compute_vec4_and::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator|=(U scalar) + { + return (*this = detail::compute_vec4_or::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(scalar))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator|=(vec<1, U, Q> const& v) + { + return (*this = detail::compute_vec4_or::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator|=(vec<4, U, Q> const& v) + { + return (*this = detail::compute_vec4_or::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator^=(U scalar) + { + return (*this = detail::compute_vec4_xor::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(scalar))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator^=(vec<1, U, Q> const& v) + { + return (*this = detail::compute_vec4_xor::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator^=(vec<4, U, Q> const& v) + { + return (*this = detail::compute_vec4_xor::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator<<=(U scalar) + { + return (*this = detail::compute_vec4_shift_left::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(scalar))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator<<=(vec<1, U, Q> const& v) + { + return (*this = detail::compute_vec4_shift_left::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator<<=(vec<4, U, Q> const& v) + { + return (*this = detail::compute_vec4_shift_left::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator>>=(U scalar) + { + return (*this = detail::compute_vec4_shift_right::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(scalar))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator>>=(vec<1, U, Q> const& v) + { + return (*this = detail::compute_vec4_shift_right::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator>>=(vec<4, U, Q> const& v) + { + return (*this = detail::compute_vec4_shift_right::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); + } + + // -- Unary constant operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v) + { + return v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v) + { + return vec<4, T, Q>(0) -= v; + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v, T const & scalar) + { + return vec<4, T, Q>(v) += scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<4, T, Q>(v1) += v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator+(T scalar, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(v) += scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator+(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v2) += v1; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1) += v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v, T const & scalar) + { + return vec<4, T, Q>(v) -= scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<4, T, Q>(v1) -= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator-(T scalar, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(scalar) -= v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator-(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1.x) -= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1) -= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v, T const & scalar) + { + return vec<4, T, Q>(v) *= scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<4, T, Q>(v1) *= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator*(T scalar, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(v) *= scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator*(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v2) *= v1; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1) *= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator/(vec<4, T, Q> const& v, T const & scalar) + { + return vec<4, T, Q>(v) /= scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator/(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<4, T, Q>(v1) /= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator/(T scalar, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(scalar) /= v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator/(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1.x) /= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator/(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1) /= v2; + } + + // -- Binary bit operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator%(vec<4, T, Q> const& v, T scalar) + { + return vec<4, T, Q>(v) %= scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator%(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<4, T, Q>(v1) %= v2.x; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator%(T scalar, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(scalar) %= v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator%(vec<1, T, Q> const& scalar, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(scalar.x) %= v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator%(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1) %= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator&(vec<4, T, Q> const& v, T scalar) + { + return vec<4, T, Q>(v) &= scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator&(vec<4, T, Q> const& v, vec<1, T, Q> const& scalar) + { + return vec<4, T, Q>(v) &= scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator&(T scalar, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(scalar) &= v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator&(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1.x) &= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator&(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1) &= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator|(vec<4, T, Q> const& v, T scalar) + { + return vec<4, T, Q>(v) |= scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator|(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<4, T, Q>(v1) |= v2.x; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator|(T scalar, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(scalar) |= v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator|(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1.x) |= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator|(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1) |= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator^(vec<4, T, Q> const& v, T scalar) + { + return vec<4, T, Q>(v) ^= scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator^(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<4, T, Q>(v1) ^= v2.x; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator^(T scalar, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(scalar) ^= v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator^(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1.x) ^= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator^(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1) ^= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<4, T, Q> const& v, T scalar) + { + return vec<4, T, Q>(v) <<= scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<4, T, Q>(v1) <<= v2.x; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator<<(T scalar, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(scalar) <<= v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1.x) <<= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1) <<= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<4, T, Q> const& v, T scalar) + { + return vec<4, T, Q>(v) >>= scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<4, T, Q>(v1) >>= v2.x; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator>>(T scalar, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(scalar) >>= v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1.x) >>= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1) >>= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator~(vec<4, T, Q> const& v) + { + return detail::compute_vec4_bitwise_not::value, sizeof(T) * 8, detail::is_aligned::value>::call(v); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator==(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return detail::compute_vec4_equal::value, sizeof(T) * 8, detail::is_aligned::value>::call(v1, v2); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator!=(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return detail::compute_vec4_nequal::value, sizeof(T) * 8, detail::is_aligned::value>::call(v1, v2); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, bool, Q> operator&&(vec<4, bool, Q> const& v1, vec<4, bool, Q> const& v2) + { + return vec<4, bool, Q>(v1.x && v2.x, v1.y && v2.y, v1.z && v2.z, v1.w && v2.w); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, bool, Q> operator||(vec<4, bool, Q> const& v1, vec<4, bool, Q> const& v2) + { + return vec<4, bool, Q>(v1.x || v2.x, v1.y || v2.y, v1.z || v2.z, v1.w || v2.w); + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "type_vec4_simd.inl" +#endif diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_vec4_simd.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_vec4_simd.inl new file mode 100644 index 0000000000000000000000000000000000000000..fb5839a6b120cf93478f4ad3c415b8deebfb44aa --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/detail/type_vec4_simd.inl @@ -0,0 +1,788 @@ +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +namespace glm{ +namespace detail +{ +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + template + struct _swizzle_base1<4, float, Q, E0,E1,E2,E3, true> : public _swizzle_base0 + { + GLM_FUNC_QUALIFIER vec<4, float, Q> operator ()() const + { + __m128 data = *reinterpret_cast<__m128 const*>(&this->_buffer); + + vec<4, float, Q> Result; +# if GLM_ARCH & GLM_ARCH_AVX_BIT + Result.data = _mm_permute_ps(data, _MM_SHUFFLE(E3, E2, E1, E0)); +# else + Result.data = _mm_shuffle_ps(data, data, _MM_SHUFFLE(E3, E2, E1, E0)); +# endif + return Result; + } + }; + + template + struct _swizzle_base1<4, int, Q, E0,E1,E2,E3, true> : public _swizzle_base0 + { + GLM_FUNC_QUALIFIER vec<4, int, Q> operator ()() const + { + __m128i data = *reinterpret_cast<__m128i const*>(&this->_buffer); + + vec<4, int, Q> Result; + Result.data = _mm_shuffle_epi32(data, _MM_SHUFFLE(E3, E2, E1, E0)); + return Result; + } + }; + + template + struct _swizzle_base1<4, uint, Q, E0,E1,E2,E3, true> : public _swizzle_base0 + { + GLM_FUNC_QUALIFIER vec<4, uint, Q> operator ()() const + { + __m128i data = *reinterpret_cast<__m128i const*>(&this->_buffer); + + vec<4, uint, Q> Result; + Result.data = _mm_shuffle_epi32(data, _MM_SHUFFLE(E3, E2, E1, E0)); + return Result; + } + }; +# endif// GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + + template + struct compute_vec4_add + { + static vec<4, float, Q> call(vec<4, float, Q> const& a, vec<4, float, Q> const& b) + { + vec<4, float, Q> Result; + Result.data = _mm_add_ps(a.data, b.data); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX_BIT + template + struct compute_vec4_add + { + static vec<4, double, Q> call(vec<4, double, Q> const& a, vec<4, double, Q> const& b) + { + vec<4, double, Q> Result; + Result.data = _mm256_add_pd(a.data, b.data); + return Result; + } + }; +# endif + + template + struct compute_vec4_sub + { + static vec<4, float, Q> call(vec<4, float, Q> const& a, vec<4, float, Q> const& b) + { + vec<4, float, Q> Result; + Result.data = _mm_sub_ps(a.data, b.data); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX_BIT + template + struct compute_vec4_sub + { + static vec<4, double, Q> call(vec<4, double, Q> const& a, vec<4, double, Q> const& b) + { + vec<4, double, Q> Result; + Result.data = _mm256_sub_pd(a.data, b.data); + return Result; + } + }; +# endif + + template + struct compute_vec4_mul + { + static vec<4, float, Q> call(vec<4, float, Q> const& a, vec<4, float, Q> const& b) + { + vec<4, float, Q> Result; + Result.data = _mm_mul_ps(a.data, b.data); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX_BIT + template + struct compute_vec4_mul + { + static vec<4, double, Q> call(vec<4, double, Q> const& a, vec<4, double, Q> const& b) + { + vec<4, double, Q> Result; + Result.data = _mm256_mul_pd(a.data, b.data); + return Result; + } + }; +# endif + + template + struct compute_vec4_div + { + static vec<4, float, Q> call(vec<4, float, Q> const& a, vec<4, float, Q> const& b) + { + vec<4, float, Q> Result; + Result.data = _mm_div_ps(a.data, b.data); + return Result; + } + }; + + # if GLM_ARCH & GLM_ARCH_AVX_BIT + template + struct compute_vec4_div + { + static vec<4, double, Q> call(vec<4, double, Q> const& a, vec<4, double, Q> const& b) + { + vec<4, double, Q> Result; + Result.data = _mm256_div_pd(a.data, b.data); + return Result; + } + }; +# endif + + template<> + struct compute_vec4_div + { + static vec<4, float, aligned_lowp> call(vec<4, float, aligned_lowp> const& a, vec<4, float, aligned_lowp> const& b) + { + vec<4, float, aligned_lowp> Result; + Result.data = _mm_mul_ps(a.data, _mm_rcp_ps(b.data)); + return Result; + } + }; + + template + struct compute_vec4_and + { + static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + vec<4, T, Q> Result; + Result.data = _mm_and_si128(a.data, b.data); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX2_BIT + template + struct compute_vec4_and + { + static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + vec<4, T, Q> Result; + Result.data = _mm256_and_si256(a.data, b.data); + return Result; + } + }; +# endif + + template + struct compute_vec4_or + { + static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + vec<4, T, Q> Result; + Result.data = _mm_or_si128(a.data, b.data); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX2_BIT + template + struct compute_vec4_or + { + static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + vec<4, T, Q> Result; + Result.data = _mm256_or_si256(a.data, b.data); + return Result; + } + }; +# endif + + template + struct compute_vec4_xor + { + static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + vec<4, T, Q> Result; + Result.data = _mm_xor_si128(a.data, b.data); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX2_BIT + template + struct compute_vec4_xor + { + static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + vec<4, T, Q> Result; + Result.data = _mm256_xor_si256(a.data, b.data); + return Result; + } + }; +# endif + + template + struct compute_vec4_shift_left + { + static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + vec<4, T, Q> Result; + Result.data = _mm_sll_epi32(a.data, b.data); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX2_BIT + template + struct compute_vec4_shift_left + { + static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + vec<4, T, Q> Result; + Result.data = _mm256_sll_epi64(a.data, b.data); + return Result; + } + }; +# endif + + template + struct compute_vec4_shift_right + { + static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + vec<4, T, Q> Result; + Result.data = _mm_srl_epi32(a.data, b.data); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX2_BIT + template + struct compute_vec4_shift_right + { + static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + vec<4, T, Q> Result; + Result.data = _mm256_srl_epi64(a.data, b.data); + return Result; + } + }; +# endif + + template + struct compute_vec4_bitwise_not + { + static vec<4, T, Q> call(vec<4, T, Q> const& v) + { + vec<4, T, Q> Result; + Result.data = _mm_xor_si128(v.data, _mm_set1_epi32(-1)); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX2_BIT + template + struct compute_vec4_bitwise_not + { + static vec<4, T, Q> call(vec<4, T, Q> const& v) + { + vec<4, T, Q> Result; + Result.data = _mm256_xor_si256(v.data, _mm_set1_epi32(-1)); + return Result; + } + }; +# endif + + template + struct compute_vec4_equal + { + static bool call(vec<4, float, Q> const& v1, vec<4, float, Q> const& v2) + { + return _mm_movemask_ps(_mm_cmpneq_ps(v1.data, v2.data)) == 0; + } + }; + +# if GLM_ARCH & GLM_ARCH_SSE41_BIT + template + struct compute_vec4_equal + { + static bool call(vec<4, int, Q> const& v1, vec<4, int, Q> const& v2) + { + //return _mm_movemask_epi8(_mm_cmpeq_epi32(v1.data, v2.data)) != 0; + __m128i neq = _mm_xor_si128(v1.data, v2.data); + return _mm_test_all_zeros(neq, neq) == 0; + } + }; +# endif + + template + struct compute_vec4_nequal + { + static bool call(vec<4, float, Q> const& v1, vec<4, float, Q> const& v2) + { + return _mm_movemask_ps(_mm_cmpneq_ps(v1.data, v2.data)) != 0; + } + }; + +# if GLM_ARCH & GLM_ARCH_SSE41_BIT + template + struct compute_vec4_nequal + { + static bool call(vec<4, int, Q> const& v1, vec<4, int, Q> const& v2) + { + //return _mm_movemask_epi8(_mm_cmpneq_epi32(v1.data, v2.data)) != 0; + __m128i neq = _mm_xor_si128(v1.data, v2.data); + return _mm_test_all_zeros(neq, neq) != 0; + } + }; +# endif +}//namespace detail + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_lowp>::vec(float _s) : + data(_mm_set1_ps(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_mediump>::vec(float _s) : + data(_mm_set1_ps(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(float _s) : + data(_mm_set1_ps(_s)) + {} + +# if GLM_ARCH & GLM_ARCH_AVX_BIT + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, double, aligned_lowp>::vec(double _s) : + data(_mm256_set1_pd(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, double, aligned_mediump>::vec(double _s) : + data(_mm256_set1_pd(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, double, aligned_highp>::vec(double _s) : + data(_mm256_set1_pd(_s)) + {} +# endif + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_lowp>::vec(int _s) : + data(_mm_set1_epi32(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_mediump>::vec(int _s) : + data(_mm_set1_epi32(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_highp>::vec(int _s) : + data(_mm_set1_epi32(_s)) + {} + +# if GLM_ARCH & GLM_ARCH_AVX2_BIT + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, detail::int64, aligned_lowp>::vec(detail::int64 _s) : + data(_mm256_set1_epi64x(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, detail::int64, aligned_mediump>::vec(detail::int64 _s) : + data(_mm256_set1_epi64x(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, detail::int64, aligned_highp>::vec(detail::int64 _s) : + data(_mm256_set1_epi64x(_s)) + {} +# endif + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_lowp>::vec(float _x, float _y, float _z, float _w) : + data(_mm_set_ps(_w, _z, _y, _x)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_mediump>::vec(float _x, float _y, float _z, float _w) : + data(_mm_set_ps(_w, _z, _y, _x)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(float _x, float _y, float _z, float _w) : + data(_mm_set_ps(_w, _z, _y, _x)) + {} + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_lowp>::vec(int _x, int _y, int _z, int _w) : + data(_mm_set_epi32(_w, _z, _y, _x)) + {} + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_mediump>::vec(int _x, int _y, int _z, int _w) : + data(_mm_set_epi32(_w, _z, _y, _x)) + {} + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_highp>::vec(int _x, int _y, int _z, int _w) : + data(_mm_set_epi32(_w, _z, _y, _x)) + {} + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_lowp>::vec(int _x, int _y, int _z, int _w) : + data(_mm_cvtepi32_ps(_mm_set_epi32(_w, _z, _y, _x))) + {} + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_mediump>::vec(int _x, int _y, int _z, int _w) : + data(_mm_cvtepi32_ps(_mm_set_epi32(_w, _z, _y, _x))) + {} + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(int _x, int _y, int _z, int _w) : + data(_mm_cvtepi32_ps(_mm_set_epi32(_w, _z, _y, _x))) + {} +}//namespace glm + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT + +#if GLM_ARCH & GLM_ARCH_NEON_BIT +namespace glm { +namespace detail { + + template + struct compute_vec4_add + { + static + vec<4, float, Q> + call(vec<4, float, Q> const& a, vec<4, float, Q> const& b) + { + vec<4, float, Q> Result; + Result.data = vaddq_f32(a.data, b.data); + return Result; + } + }; + + template + struct compute_vec4_add + { + static + vec<4, uint, Q> + call(vec<4, uint, Q> const& a, vec<4, uint, Q> const& b) + { + vec<4, uint, Q> Result; + Result.data = vaddq_u32(a.data, b.data); + return Result; + } + }; + + template + struct compute_vec4_add + { + static + vec<4, int, Q> + call(vec<4, int, Q> const& a, vec<4, int, Q> const& b) + { + vec<4, int, Q> Result; + Result.data = vaddq_s32(a.data, b.data); + return Result; + } + }; + + template + struct compute_vec4_sub + { + static vec<4, float, Q> call(vec<4, float, Q> const& a, vec<4, float, Q> const& b) + { + vec<4, float, Q> Result; + Result.data = vsubq_f32(a.data, b.data); + return Result; + } + }; + + template + struct compute_vec4_sub + { + static vec<4, uint, Q> call(vec<4, uint, Q> const& a, vec<4, uint, Q> const& b) + { + vec<4, uint, Q> Result; + Result.data = vsubq_u32(a.data, b.data); + return Result; + } + }; + + template + struct compute_vec4_sub + { + static vec<4, int, Q> call(vec<4, int, Q> const& a, vec<4, int, Q> const& b) + { + vec<4, int, Q> Result; + Result.data = vsubq_s32(a.data, b.data); + return Result; + } + }; + + template + struct compute_vec4_mul + { + static vec<4, float, Q> call(vec<4, float, Q> const& a, vec<4, float, Q> const& b) + { + vec<4, float, Q> Result; + Result.data = vmulq_f32(a.data, b.data); + return Result; + } + }; + + template + struct compute_vec4_mul + { + static vec<4, uint, Q> call(vec<4, uint, Q> const& a, vec<4, uint, Q> const& b) + { + vec<4, uint, Q> Result; + Result.data = vmulq_u32(a.data, b.data); + return Result; + } + }; + + template + struct compute_vec4_mul + { + static vec<4, int, Q> call(vec<4, int, Q> const& a, vec<4, int, Q> const& b) + { + vec<4, int, Q> Result; + Result.data = vmulq_s32(a.data, b.data); + return Result; + } + }; + + template + struct compute_vec4_div + { + static vec<4, float, Q> call(vec<4, float, Q> const& a, vec<4, float, Q> const& b) + { + vec<4, float, Q> Result; +#if GLM_ARCH & GLM_ARCH_ARMV8_BIT + Result.data = vdivq_f32(a.data, b.data); +#else + /* Arm assembler reference: + * + * The Newton-Raphson iteration: x[n+1] = x[n] * (2 - d * x[n]) + * converges to (1/d) if x0 is the result of VRECPE applied to d. + * + * Note: The precision usually improves with two interactions, but more than two iterations are not helpful. */ + float32x4_t x = vrecpeq_f32(b.data); + x = vmulq_f32(vrecpsq_f32(b.data, x), x); + x = vmulq_f32(vrecpsq_f32(b.data, x), x); + Result.data = vmulq_f32(a.data, x); +#endif + return Result; + } + }; + + template + struct compute_vec4_equal + { + static bool call(vec<4, float, Q> const& v1, vec<4, float, Q> const& v2) + { + uint32x4_t cmp = vceqq_f32(v1.data, v2.data); +#if GLM_ARCH & GLM_ARCH_ARMV8_BIT + cmp = vpminq_u32(cmp, cmp); + cmp = vpminq_u32(cmp, cmp); + uint32_t r = cmp[0]; +#else + uint32x2_t cmpx2 = vpmin_u32(vget_low_u32(cmp), vget_high_u32(cmp)); + cmpx2 = vpmin_u32(cmpx2, cmpx2); + uint32_t r = cmpx2[0]; +#endif + return r == ~0u; + } + }; + + template + struct compute_vec4_equal + { + static bool call(vec<4, uint, Q> const& v1, vec<4, uint, Q> const& v2) + { + uint32x4_t cmp = vceqq_u32(v1.data, v2.data); +#if GLM_ARCH & GLM_ARCH_ARMV8_BIT + cmp = vpminq_u32(cmp, cmp); + cmp = vpminq_u32(cmp, cmp); + uint32_t r = cmp[0]; +#else + uint32x2_t cmpx2 = vpmin_u32(vget_low_u32(cmp), vget_high_u32(cmp)); + cmpx2 = vpmin_u32(cmpx2, cmpx2); + uint32_t r = cmpx2[0]; +#endif + return r == ~0u; + } + }; + + template + struct compute_vec4_equal + { + static bool call(vec<4, int, Q> const& v1, vec<4, int, Q> const& v2) + { + uint32x4_t cmp = vceqq_s32(v1.data, v2.data); +#if GLM_ARCH & GLM_ARCH_ARMV8_BIT + cmp = vpminq_u32(cmp, cmp); + cmp = vpminq_u32(cmp, cmp); + uint32_t r = cmp[0]; +#else + uint32x2_t cmpx2 = vpmin_u32(vget_low_u32(cmp), vget_high_u32(cmp)); + cmpx2 = vpmin_u32(cmpx2, cmpx2); + uint32_t r = cmpx2[0]; +#endif + return r == ~0u; + } + }; + + template + struct compute_vec4_nequal + { + static bool call(vec<4, float, Q> const& v1, vec<4, float, Q> const& v2) + { + return !compute_vec4_equal::call(v1, v2); + } + }; + + template + struct compute_vec4_nequal + { + static bool call(vec<4, uint, Q> const& v1, vec<4, uint, Q> const& v2) + { + return !compute_vec4_equal::call(v1, v2); + } + }; + + template + struct compute_vec4_nequal + { + static bool call(vec<4, int, Q> const& v1, vec<4, int, Q> const& v2) + { + return !compute_vec4_equal::call(v1, v2); + } + }; + +}//namespace detail + +#if !GLM_CONFIG_XYZW_ONLY + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_lowp>::vec(float _s) : + data(vdupq_n_f32(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_mediump>::vec(float _s) : + data(vdupq_n_f32(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(float _s) : + data(vdupq_n_f32(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_lowp>::vec(int _s) : + data(vdupq_n_s32(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_mediump>::vec(int _s) : + data(vdupq_n_s32(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_highp>::vec(int _s) : + data(vdupq_n_s32(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, uint, aligned_lowp>::vec(uint _s) : + data(vdupq_n_u32(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, uint, aligned_mediump>::vec(uint _s) : + data(vdupq_n_u32(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, uint, aligned_highp>::vec(uint _s) : + data(vdupq_n_u32(_s)) + {} + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(const vec<4, float, aligned_highp>& rhs) : + data(rhs.data) + {} + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(const vec<4, int, aligned_highp>& rhs) : + data(vcvtq_f32_s32(rhs.data)) + {} + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(const vec<4, uint, aligned_highp>& rhs) : + data(vcvtq_f32_u32(rhs.data)) + {} + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_lowp>::vec(int _x, int _y, int _z, int _w) : + data(vcvtq_f32_s32(vec<4, int, aligned_lowp>(_x, _y, _z, _w).data)) + {} + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_mediump>::vec(int _x, int _y, int _z, int _w) : + data(vcvtq_f32_s32(vec<4, int, aligned_mediump>(_x, _y, _z, _w).data)) + {} + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(int _x, int _y, int _z, int _w) : + data(vcvtq_f32_s32(vec<4, int, aligned_highp>(_x, _y, _z, _w).data)) + {} + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_lowp>::vec(uint _x, uint _y, uint _z, uint _w) : + data(vcvtq_f32_u32(vec<4, uint, aligned_lowp>(_x, _y, _z, _w).data)) + {} + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_mediump>::vec(uint _x, uint _y, uint _z, uint _w) : + data(vcvtq_f32_u32(vec<4, uint, aligned_mediump>(_x, _y, _z, _w).data)) + {} + + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(uint _x, uint _y, uint _z, uint _w) : + data(vcvtq_f32_u32(vec<4, uint, aligned_highp>(_x, _y, _z, _w).data)) + {} + +#endif +}//namespace glm + +#endif diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/exponential.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/exponential.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1614f7695dbd6f0061914e50650b8f24ff59c3c0 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/exponential.hpp @@ -0,0 +1,110 @@ +/// @ref core +/// @file glm/exponential.hpp +/// +/// @see GLSL 4.20.8 specification, section 8.2 Exponential Functions +/// +/// @defgroup core_func_exponential Exponential functions +/// @ingroup core +/// +/// Provides GLSL exponential functions +/// +/// These all operate component-wise. The description is per component. +/// +/// Include to use these core features. + +#pragma once + +#include "detail/type_vec1.hpp" +#include "detail/type_vec2.hpp" +#include "detail/type_vec3.hpp" +#include "detail/type_vec4.hpp" +#include + +namespace glm +{ + /// @addtogroup core_func_exponential + /// @{ + + /// Returns 'base' raised to the power 'exponent'. + /// + /// @param base Floating point value. pow function is defined for input values of 'base' defined in the range (inf-, inf+) in the limit of the type qualifier. + /// @param exponent Floating point value representing the 'exponent'. + /// + /// @see GLSL pow man page + /// @see GLSL 4.20.8 specification, section 8.2 Exponential Functions + template + GLM_FUNC_DECL vec pow(vec const& base, vec const& exponent); + + /// Returns the natural exponentiation of v, i.e., e^v. + /// + /// @param v exp function is defined for input values of v defined in the range (inf-, inf+) in the limit of the type qualifier. + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL exp man page + /// @see GLSL 4.20.8 specification, section 8.2 Exponential Functions + template + GLM_FUNC_DECL vec exp(vec const& v); + + /// Returns the natural logarithm of v, i.e., + /// returns the value y which satisfies the equation x = e^y. + /// Results are undefined if v <= 0. + /// + /// @param v log function is defined for input values of v defined in the range (0, inf+) in the limit of the type qualifier. + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL log man page + /// @see GLSL 4.20.8 specification, section 8.2 Exponential Functions + template + GLM_FUNC_DECL vec log(vec const& v); + + /// Returns 2 raised to the v power. + /// + /// @param v exp2 function is defined for input values of v defined in the range (inf-, inf+) in the limit of the type qualifier. + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL exp2 man page + /// @see GLSL 4.20.8 specification, section 8.2 Exponential Functions + template + GLM_FUNC_DECL vec exp2(vec const& v); + + /// Returns the base 2 log of x, i.e., returns the value y, + /// which satisfies the equation x = 2 ^ y. + /// + /// @param v log2 function is defined for input values of v defined in the range (0, inf+) in the limit of the type qualifier. + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL log2 man page + /// @see GLSL 4.20.8 specification, section 8.2 Exponential Functions + template + GLM_FUNC_DECL vec log2(vec const& v); + + /// Returns the positive square root of v. + /// + /// @param v sqrt function is defined for input values of v defined in the range [0, inf+) in the limit of the type qualifier. + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL sqrt man page + /// @see GLSL 4.20.8 specification, section 8.2 Exponential Functions + template + GLM_FUNC_DECL vec sqrt(vec const& v); + + /// Returns the reciprocal of the positive square root of v. + /// + /// @param v inversesqrt function is defined for input values of v defined in the range [0, inf+) in the limit of the type qualifier. + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL inversesqrt man page + /// @see GLSL 4.20.8 specification, section 8.2 Exponential Functions + template + GLM_FUNC_DECL vec inversesqrt(vec const& v); + + /// @} +}//namespace glm + +#include "detail/func_exponential.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext.hpp new file mode 100644 index 0000000000000000000000000000000000000000..39cabc3b540492b9aaa07a942ee7178de935a44c --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext.hpp @@ -0,0 +1,255 @@ +/// @file glm/ext.hpp +/// +/// @ref core (Dependence) + +#include "detail/setup.hpp" + +#pragma once + +#include "glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_MESSAGE_EXT_INCLUDED_DISPLAYED) +# define GLM_MESSAGE_EXT_INCLUDED_DISPLAYED +# pragma message("GLM: All extensions included (not recommended)") +#endif//GLM_MESSAGES + +#include "./ext/matrix_clip_space.hpp" +#include "./ext/matrix_common.hpp" + +#include "./ext/matrix_double2x2.hpp" +#include "./ext/matrix_double2x2_precision.hpp" +#include "./ext/matrix_double2x3.hpp" +#include "./ext/matrix_double2x3_precision.hpp" +#include "./ext/matrix_double2x4.hpp" +#include "./ext/matrix_double2x4_precision.hpp" +#include "./ext/matrix_double3x2.hpp" +#include "./ext/matrix_double3x2_precision.hpp" +#include "./ext/matrix_double3x3.hpp" +#include "./ext/matrix_double3x3_precision.hpp" +#include "./ext/matrix_double3x4.hpp" +#include "./ext/matrix_double3x4_precision.hpp" +#include "./ext/matrix_double4x2.hpp" +#include "./ext/matrix_double4x2_precision.hpp" +#include "./ext/matrix_double4x3.hpp" +#include "./ext/matrix_double4x3_precision.hpp" +#include "./ext/matrix_double4x4.hpp" +#include "./ext/matrix_double4x4_precision.hpp" + +#include "./ext/matrix_float2x2.hpp" +#include "./ext/matrix_float2x2_precision.hpp" +#include "./ext/matrix_float2x3.hpp" +#include "./ext/matrix_float2x3_precision.hpp" +#include "./ext/matrix_float2x4.hpp" +#include "./ext/matrix_float2x4_precision.hpp" +#include "./ext/matrix_float3x2.hpp" +#include "./ext/matrix_float3x2_precision.hpp" +#include "./ext/matrix_float3x3.hpp" +#include "./ext/matrix_float3x3_precision.hpp" +#include "./ext/matrix_float3x4.hpp" +#include "./ext/matrix_float3x4_precision.hpp" +#include "./ext/matrix_float4x2.hpp" +#include "./ext/matrix_float4x2_precision.hpp" +#include "./ext/matrix_float4x3.hpp" +#include "./ext/matrix_float4x3_precision.hpp" +#include "./ext/matrix_float4x4.hpp" +#include "./ext/matrix_float4x4_precision.hpp" + +#include "./ext/matrix_int2x2.hpp" +#include "./ext/matrix_int2x2_sized.hpp" +#include "./ext/matrix_int2x3.hpp" +#include "./ext/matrix_int2x3_sized.hpp" +#include "./ext/matrix_int2x4.hpp" +#include "./ext/matrix_int2x4_sized.hpp" +#include "./ext/matrix_int3x2.hpp" +#include "./ext/matrix_int3x2_sized.hpp" +#include "./ext/matrix_int3x3.hpp" +#include "./ext/matrix_int3x3_sized.hpp" +#include "./ext/matrix_int3x4.hpp" +#include "./ext/matrix_int3x4_sized.hpp" +#include "./ext/matrix_int4x2.hpp" +#include "./ext/matrix_int4x2_sized.hpp" +#include "./ext/matrix_int4x3.hpp" +#include "./ext/matrix_int4x3_sized.hpp" +#include "./ext/matrix_int4x4.hpp" +#include "./ext/matrix_int4x4_sized.hpp" + +#include "./ext/matrix_uint2x2.hpp" +#include "./ext/matrix_uint2x2_sized.hpp" +#include "./ext/matrix_uint2x3.hpp" +#include "./ext/matrix_uint2x3_sized.hpp" +#include "./ext/matrix_uint2x4.hpp" +#include "./ext/matrix_uint2x4_sized.hpp" +#include "./ext/matrix_uint3x2.hpp" +#include "./ext/matrix_uint3x2_sized.hpp" +#include "./ext/matrix_uint3x3.hpp" +#include "./ext/matrix_uint3x3_sized.hpp" +#include "./ext/matrix_uint3x4.hpp" +#include "./ext/matrix_uint3x4_sized.hpp" +#include "./ext/matrix_uint4x2.hpp" +#include "./ext/matrix_uint4x2_sized.hpp" +#include "./ext/matrix_uint4x3.hpp" +#include "./ext/matrix_uint4x3_sized.hpp" +#include "./ext/matrix_uint4x4.hpp" +#include "./ext/matrix_uint4x4_sized.hpp" + +#include "./ext/matrix_projection.hpp" +#include "./ext/matrix_relational.hpp" +#include "./ext/matrix_transform.hpp" + +#include "./ext/quaternion_common.hpp" +#include "./ext/quaternion_double.hpp" +#include "./ext/quaternion_double_precision.hpp" +#include "./ext/quaternion_float.hpp" +#include "./ext/quaternion_float_precision.hpp" +#include "./ext/quaternion_exponential.hpp" +#include "./ext/quaternion_geometric.hpp" +#include "./ext/quaternion_relational.hpp" +#include "./ext/quaternion_transform.hpp" +#include "./ext/quaternion_trigonometric.hpp" + +#include "./ext/scalar_common.hpp" +#include "./ext/scalar_constants.hpp" +#include "./ext/scalar_integer.hpp" +#include "./ext/scalar_packing.hpp" +#include "./ext/scalar_reciprocal.hpp" +#include "./ext/scalar_relational.hpp" +#include "./ext/scalar_ulp.hpp" + +#include "./ext/scalar_int_sized.hpp" +#include "./ext/scalar_uint_sized.hpp" + +#include "./ext/vector_common.hpp" +#include "./ext/vector_integer.hpp" +#include "./ext/vector_packing.hpp" +#include "./ext/vector_reciprocal.hpp" +#include "./ext/vector_relational.hpp" +#include "./ext/vector_ulp.hpp" + +#include "./ext/vector_bool1.hpp" +#include "./ext/vector_bool1_precision.hpp" +#include "./ext/vector_bool2.hpp" +#include "./ext/vector_bool2_precision.hpp" +#include "./ext/vector_bool3.hpp" +#include "./ext/vector_bool3_precision.hpp" +#include "./ext/vector_bool4.hpp" +#include "./ext/vector_bool4_precision.hpp" + +#include "./ext/vector_double1.hpp" +#include "./ext/vector_double1_precision.hpp" +#include "./ext/vector_double2.hpp" +#include "./ext/vector_double2_precision.hpp" +#include "./ext/vector_double3.hpp" +#include "./ext/vector_double3_precision.hpp" +#include "./ext/vector_double4.hpp" +#include "./ext/vector_double4_precision.hpp" + +#include "./ext/vector_float1.hpp" +#include "./ext/vector_float1_precision.hpp" +#include "./ext/vector_float2.hpp" +#include "./ext/vector_float2_precision.hpp" +#include "./ext/vector_float3.hpp" +#include "./ext/vector_float3_precision.hpp" +#include "./ext/vector_float4.hpp" +#include "./ext/vector_float4_precision.hpp" + +#include "./ext/vector_int1.hpp" +#include "./ext/vector_int1_sized.hpp" +#include "./ext/vector_int2.hpp" +#include "./ext/vector_int2_sized.hpp" +#include "./ext/vector_int3.hpp" +#include "./ext/vector_int3_sized.hpp" +#include "./ext/vector_int4.hpp" +#include "./ext/vector_int4_sized.hpp" + +#include "./ext/vector_uint1.hpp" +#include "./ext/vector_uint1_sized.hpp" +#include "./ext/vector_uint2.hpp" +#include "./ext/vector_uint2_sized.hpp" +#include "./ext/vector_uint3.hpp" +#include "./ext/vector_uint3_sized.hpp" +#include "./ext/vector_uint4.hpp" +#include "./ext/vector_uint4_sized.hpp" + +#include "./gtc/bitfield.hpp" +#include "./gtc/color_space.hpp" +#include "./gtc/constants.hpp" +#include "./gtc/epsilon.hpp" +#include "./gtc/integer.hpp" +#include "./gtc/matrix_access.hpp" +#include "./gtc/matrix_integer.hpp" +#include "./gtc/matrix_inverse.hpp" +#include "./gtc/matrix_transform.hpp" +#include "./gtc/noise.hpp" +#include "./gtc/packing.hpp" +#include "./gtc/quaternion.hpp" +#include "./gtc/random.hpp" +#include "./gtc/reciprocal.hpp" +#include "./gtc/round.hpp" +#include "./gtc/type_precision.hpp" +#include "./gtc/type_ptr.hpp" +#include "./gtc/ulp.hpp" +#include "./gtc/vec1.hpp" +#if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE +# include "./gtc/type_aligned.hpp" +#endif + +#ifdef GLM_ENABLE_EXPERIMENTAL +#include "./gtx/associated_min_max.hpp" +#include "./gtx/bit.hpp" +#include "./gtx/closest_point.hpp" +#include "./gtx/color_encoding.hpp" +#include "./gtx/color_space.hpp" +#include "./gtx/color_space_YCoCg.hpp" +#include "./gtx/compatibility.hpp" +#include "./gtx/component_wise.hpp" +#include "./gtx/dual_quaternion.hpp" +#include "./gtx/euler_angles.hpp" +#include "./gtx/extend.hpp" +#include "./gtx/extended_min_max.hpp" +#include "./gtx/fast_exponential.hpp" +#include "./gtx/fast_square_root.hpp" +#include "./gtx/fast_trigonometry.hpp" +#include "./gtx/functions.hpp" +#include "./gtx/gradient_paint.hpp" +#include "./gtx/handed_coordinate_space.hpp" +#include "./gtx/integer.hpp" +#include "./gtx/intersect.hpp" +#include "./gtx/log_base.hpp" +#include "./gtx/matrix_cross_product.hpp" +#include "./gtx/matrix_interpolation.hpp" +#include "./gtx/matrix_major_storage.hpp" +#include "./gtx/matrix_operation.hpp" +#include "./gtx/matrix_query.hpp" +#include "./gtx/mixed_product.hpp" +#include "./gtx/norm.hpp" +#include "./gtx/normal.hpp" +#include "./gtx/normalize_dot.hpp" +#include "./gtx/number_precision.hpp" +#include "./gtx/optimum_pow.hpp" +#include "./gtx/orthonormalize.hpp" +#include "./gtx/perpendicular.hpp" +#include "./gtx/polar_coordinates.hpp" +#include "./gtx/projection.hpp" +#include "./gtx/quaternion.hpp" +#include "./gtx/raw_data.hpp" +#include "./gtx/rotate_vector.hpp" +#include "./gtx/spline.hpp" +#include "./gtx/std_based_type.hpp" +#if !((GLM_COMPILER & GLM_COMPILER_CUDA) || (GLM_COMPILER & GLM_COMPILER_HIP)) +# include "./gtx/string_cast.hpp" +#endif +#include "./gtx/transform.hpp" +#include "./gtx/transform2.hpp" +#include "./gtx/vec_swizzle.hpp" +#include "./gtx/vector_angle.hpp" +#include "./gtx/vector_query.hpp" +#include "./gtx/wrap.hpp" + +#if GLM_HAS_TEMPLATE_ALIASES +# include "./gtx/scalar_multiplication.hpp" +#endif + +#if GLM_HAS_RANGE_FOR +# include "./gtx/range.hpp" +#endif +#endif//GLM_ENABLE_EXPERIMENTAL diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/_matrix_vectorize.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/_matrix_vectorize.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0d08117ed1d1c072a05854ce7c2d4650fa4c79c5 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/_matrix_vectorize.hpp @@ -0,0 +1,128 @@ +#pragma once + +namespace glm { + + namespace detail { + + template class mat, length_t C, length_t R, typename Ret, typename T, qualifier Q> + struct matrix_functor_1 { + }; + + template class mat, typename Ret, typename T, qualifier Q> + struct matrix_functor_1 { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static mat<2, 2, T, Q> call(Ret (*Func)(T x), mat<2, 2, T, Q> const &x) { + return mat<2, 2, Ret, Q>( + Func(x[0][0]), Func(x[0][1]), + Func(x[1][0]), Func(x[1][1]) + ); + } + }; + + template class mat, typename Ret, typename T, qualifier Q> + struct matrix_functor_1 { + + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static mat<2, 3, T, Q> call(Ret (*Func)(T x), mat<2, 3, T, Q> const &x) { + return mat<2, 3, Ret, Q>( + Func(x[0][0]), Func(x[0][1]), Func(x[0][2]), + Func(x[1][0]), Func(x[1][1]), Func(x[1][2]) + ); + } + + }; + + template class mat, typename Ret, typename T, qualifier Q> + struct matrix_functor_1 { + + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static mat<2, 4, T, Q> call(Ret (*Func)(T x), mat<2, 4, T, Q> const &x) { + return mat<2, 4, Ret, Q>( + Func(x[0][0]), Func(x[0][1]), Func(x[0][2]), Func(x[0][3]), + Func(x[1][0]), Func(x[1][1]), Func(x[1][2]), Func(x[1][3]) + ); + } + + }; + + template class mat, typename Ret, typename T, qualifier Q> + struct matrix_functor_1 { + + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static mat<3, 2, T, Q> call(Ret (*Func)(T x), mat<3, 2, T, Q> const &x) { + return mat<3, 2, Ret, Q>( + Func(x[0][0]), Func(x[0][1]), + Func(x[1][0]), Func(x[1][1]), + Func(x[2][0]), Func(x[2][1]) + ); + } + + }; + + template class mat, typename Ret, typename T, qualifier Q> + struct matrix_functor_1 { + + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static mat<3, 3, T, Q> call(Ret (*Func)(T x), mat<3, 3, T, Q> const &x) { + return mat<3, 3, Ret, Q>( + Func(x[0][0]), Func(x[0][1]), Func(x[0][2]), + Func(x[1][0]), Func(x[1][1]), Func(x[1][2]), + Func(x[2][0]), Func(x[2][1]), Func(x[2][2]) + ); + } + + }; + + template class mat, typename Ret, typename T, qualifier Q> + struct matrix_functor_1 { + + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static mat<3, 4, T, Q> call(Ret (*Func)(T x), mat<3, 4, T, Q> const &x) { + return mat<3, 4, Ret, Q>( + Func(x[0][0]), Func(x[0][1]), Func(x[0][2]), Func(x[0][3]), + Func(x[1][0]), Func(x[1][1]), Func(x[1][2]), Func(x[1][3]), + Func(x[2][0]), Func(x[2][1]), Func(x[2][2]), Func(x[2][3]) + ); + } + + }; + + template class mat, typename Ret, typename T, qualifier Q> + struct matrix_functor_1 { + + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static mat<4, 2, T, Q> call(Ret (*Func)(T x), mat<4, 2, T, Q> const &x) { + return mat<4, 2, Ret, Q>( + Func(x[0][0]), Func(x[0][1]), + Func(x[1][0]), Func(x[1][1]), + Func(x[2][0]), Func(x[2][1]), + Func(x[3][0]), Func(x[3][1]) + ); + } + + }; + + template class mat, typename Ret, typename T, qualifier Q> + struct matrix_functor_1 { + + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static mat<4, 3, T, Q> call(Ret (*Func)(T x), mat<4, 3, T, Q> const &x) { + return mat<4, 3, Ret, Q>( + Func(x[0][0]), Func(x[0][1]), Func(x[0][2]), + Func(x[1][0]), Func(x[1][1]), Func(x[1][2]), + Func(x[2][0]), Func(x[2][1]), Func(x[2][2]), + Func(x[3][0]), Func(x[3][1]), Func(x[3][2]) + ); + } + + }; + + template class mat, typename Ret, typename T, qualifier Q> + struct matrix_functor_1 { + + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static mat<4, 4, T, Q> call(Ret (*Func)(T x), mat<4, 4, T, Q> const &x) { + return mat<4, 4, Ret, Q>( + Func(x[0][0]), Func(x[0][1]), Func(x[0][2]), Func(x[0][3]), + Func(x[1][0]), Func(x[1][1]), Func(x[1][2]), Func(x[1][3]), + Func(x[2][0]), Func(x[2][1]), Func(x[2][2]), Func(x[2][3]), + Func(x[3][0]), Func(x[3][1]), Func(x[3][2]), Func(x[3][3]) + ); + } + + }; + + } + +}// namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_clip_space.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_clip_space.hpp new file mode 100644 index 0000000000000000000000000000000000000000..43579b8eee6c24614dcba1b86eed451fc5ed08e8 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_clip_space.hpp @@ -0,0 +1,522 @@ +/// @ref ext_matrix_clip_space +/// @file glm/ext/matrix_clip_space.hpp +/// +/// @defgroup ext_matrix_clip_space GLM_EXT_matrix_clip_space +/// @ingroup ext +/// +/// Defines functions that generate clip space transformation matrices. +/// +/// The matrices generated by this extension use standard OpenGL fixed-function +/// conventions. For example, the lookAt function generates a transform from world +/// space into the specific eye space that the projective matrix functions +/// (perspective, ortho, etc) are designed to expect. The OpenGL compatibility +/// specifications defines the particular layout of this eye space. +/// +/// Include to use the features of this extension. +/// +/// @see ext_matrix_transform +/// @see ext_matrix_projection + +#pragma once + +// Dependencies +#include "../ext/scalar_constants.hpp" +#include "../geometric.hpp" +#include "../trigonometric.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_clip_space extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_clip_space + /// @{ + + /// Creates a matrix for projecting two-dimensional coordinates onto the screen. + /// + /// @tparam T A floating-point scalar type + /// + /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top, T const& zNear, T const& zFar) + /// @see gluOrtho2D man page + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> ortho( + T left, T right, T bottom, T top); + + /// Creates a matrix for an orthographic parallel viewing volume, using left-handed coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @tparam T A floating-point scalar type + /// + /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> orthoLH_ZO( + T left, T right, T bottom, T top, T zNear, T zFar); + + /// Creates a matrix for an orthographic parallel viewing volume using left-handed coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @tparam T A floating-point scalar type + /// + /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> orthoLH_NO( + T left, T right, T bottom, T top, T zNear, T zFar); + + /// Creates a matrix for an orthographic parallel viewing volume, using right-handed coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @tparam T A floating-point scalar type + /// + /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> orthoRH_ZO( + T left, T right, T bottom, T top, T zNear, T zFar); + + /// Creates a matrix for an orthographic parallel viewing volume, using right-handed coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @tparam T A floating-point scalar type + /// + /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> orthoRH_NO( + T left, T right, T bottom, T top, T zNear, T zFar); + + /// Creates a matrix for an orthographic parallel viewing volume, using left-handed coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @tparam T A floating-point scalar type + /// + /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> orthoZO( + T left, T right, T bottom, T top, T zNear, T zFar); + + /// Creates a matrix for an orthographic parallel viewing volume, using left-handed coordinates if GLM_FORCE_LEFT_HANDED if defined or right-handed coordinates otherwise. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @tparam T A floating-point scalar type + /// + /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> orthoNO( + T left, T right, T bottom, T top, T zNear, T zFar); + + /// Creates a matrix for an orthographic parallel viewing volume, using left-handed coordinates. + /// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @tparam T A floating-point scalar type + /// + /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> orthoLH( + T left, T right, T bottom, T top, T zNear, T zFar); + + /// Creates a matrix for an orthographic parallel viewing volume, using right-handed coordinates. + /// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @tparam T A floating-point scalar type + /// + /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> orthoRH( + T left, T right, T bottom, T top, T zNear, T zFar); + + /// Creates a matrix for an orthographic parallel viewing volume, using the default handedness and default near and far clip planes definition. + /// To change default handedness use GLM_FORCE_LEFT_HANDED. To change default near and far clip planes definition use GLM_FORCE_DEPTH_ZERO_TO_ONE. + /// + /// @tparam T A floating-point scalar type + /// + /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) + /// @see glOrtho man page + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> ortho( + T left, T right, T bottom, T top, T zNear, T zFar); + + /// Creates a left-handed frustum matrix. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> frustumLH_ZO( + T left, T right, T bottom, T top, T near, T far); + + /// Creates a left-handed frustum matrix. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> frustumLH_NO( + T left, T right, T bottom, T top, T near, T far); + + /// Creates a right-handed frustum matrix. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> frustumRH_ZO( + T left, T right, T bottom, T top, T near, T far); + + /// Creates a right-handed frustum matrix. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> frustumRH_NO( + T left, T right, T bottom, T top, T near, T far); + + /// Creates a frustum matrix using left-handed coordinates if GLM_FORCE_LEFT_HANDED if defined or right-handed coordinates otherwise. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> frustumZO( + T left, T right, T bottom, T top, T near, T far); + + /// Creates a frustum matrix using left-handed coordinates if GLM_FORCE_LEFT_HANDED if defined or right-handed coordinates otherwise. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> frustumNO( + T left, T right, T bottom, T top, T near, T far); + + /// Creates a left-handed frustum matrix. + /// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> frustumLH( + T left, T right, T bottom, T top, T near, T far); + + /// Creates a right-handed frustum matrix. + /// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> frustumRH( + T left, T right, T bottom, T top, T near, T far); + + /// Creates a frustum matrix with default handedness, using the default handedness and default near and far clip planes definition. + /// To change default handedness use GLM_FORCE_LEFT_HANDED. To change default near and far clip planes definition use GLM_FORCE_DEPTH_ZERO_TO_ONE. + /// + /// @tparam T A floating-point scalar type + /// @see glFrustum man page + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> frustum( + T left, T right, T bottom, T top, T near, T far); + + + /// Creates a matrix for a right-handed, symmetric perspective-view frustum. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveRH_ZO( + T fovy, T aspect, T near, T far); + + /// Creates a matrix for a right-handed, symmetric perspective-view frustum. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveRH_NO( + T fovy, T aspect, T near, T far); + + /// Creates a matrix for a left-handed, symmetric perspective-view frustum. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveLH_ZO( + T fovy, T aspect, T near, T far); + + /// Creates a matrix for a left-handed, symmetric perspective-view frustum. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveLH_NO( + T fovy, T aspect, T near, T far); + + /// Creates a matrix for a symmetric perspective-view frustum using left-handed coordinates if GLM_FORCE_LEFT_HANDED if defined or right-handed coordinates otherwise. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveZO( + T fovy, T aspect, T near, T far); + + /// Creates a matrix for a symmetric perspective-view frustum using left-handed coordinates if GLM_FORCE_LEFT_HANDED if defined or right-handed coordinates otherwise. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveNO( + T fovy, T aspect, T near, T far); + + /// Creates a matrix for a right-handed, symmetric perspective-view frustum. + /// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveRH( + T fovy, T aspect, T near, T far); + + /// Creates a matrix for a left-handed, symmetric perspective-view frustum. + /// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveLH( + T fovy, T aspect, T near, T far); + + /// Creates a matrix for a symmetric perspective-view frustum based on the default handedness and default near and far clip planes definition. + /// To change default handedness use GLM_FORCE_LEFT_HANDED. To change default near and far clip planes definition use GLM_FORCE_DEPTH_ZERO_TO_ONE. + /// + /// @param fovy Specifies the field of view angle in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + /// @see gluPerspective man page + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspective( + T fovy, T aspect, T near, T far); + + /// Builds a perspective projection matrix based on a field of view using right-handed coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @param fov Expressed in radians. + /// @param width Width of the viewport + /// @param height Height of the viewport + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovRH_ZO( + T fov, T width, T height, T near, T far); + + /// Builds a perspective projection matrix based on a field of view using right-handed coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param fov Expressed in radians. + /// @param width Width of the viewport + /// @param height Height of the viewport + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovRH_NO( + T fov, T width, T height, T near, T far); + + /// Builds a perspective projection matrix based on a field of view using left-handed coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @param fov Expressed in radians. + /// @param width Width of the viewport + /// @param height Height of the viewport + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovLH_ZO( + T fov, T width, T height, T near, T far); + + /// Builds a perspective projection matrix based on a field of view using left-handed coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param fov Expressed in radians. + /// @param width Width of the viewport + /// @param height Height of the viewport + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovLH_NO( + T fov, T width, T height, T near, T far); + + /// Builds a perspective projection matrix based on a field of view using left-handed coordinates if GLM_FORCE_LEFT_HANDED if defined or right-handed coordinates otherwise. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @param fov Expressed in radians. + /// @param width Width of the viewport + /// @param height Height of the viewport + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovZO( + T fov, T width, T height, T near, T far); + + /// Builds a perspective projection matrix based on a field of view using left-handed coordinates if GLM_FORCE_LEFT_HANDED if defined or right-handed coordinates otherwise. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param fov Expressed in radians. + /// @param width Width of the viewport + /// @param height Height of the viewport + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovNO( + T fov, T width, T height, T near, T far); + + /// Builds a right-handed perspective projection matrix based on a field of view. + /// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param fov Expressed in radians. + /// @param width Width of the viewport + /// @param height Height of the viewport + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovRH( + T fov, T width, T height, T near, T far); + + /// Builds a left-handed perspective projection matrix based on a field of view. + /// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param fov Expressed in radians. + /// @param width Width of the viewport + /// @param height Height of the viewport + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovLH( + T fov, T width, T height, T near, T far); + + /// Builds a perspective projection matrix based on a field of view and the default handedness and default near and far clip planes definition. + /// To change default handedness use GLM_FORCE_LEFT_HANDED. To change default near and far clip planes definition use GLM_FORCE_DEPTH_ZERO_TO_ONE. + /// + /// @param fov Expressed in radians. + /// @param width Width of the viewport + /// @param height Height of the viewport + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFov( + T fov, T width, T height, T near, T far); + + /// Creates a matrix for a left-handed, symmetric perspective-view frustum with far plane at infinite. + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> infinitePerspectiveLH( + T fovy, T aspect, T near); + + /// Creates a matrix for a right-handed, symmetric perspective-view frustum with far plane at infinite. + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> infinitePerspectiveRH( + T fovy, T aspect, T near); + + /// Creates a matrix for a symmetric perspective-view frustum with far plane at infinite with default handedness. + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> infinitePerspective( + T fovy, T aspect, T near); + + /// Creates a matrix for a symmetric perspective-view frustum with far plane at infinite for graphics hardware that doesn't support depth clamping. + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> tweakedInfinitePerspective( + T fovy, T aspect, T near); + + /// Creates a matrix for a symmetric perspective-view frustum with far plane at infinite for graphics hardware that doesn't support depth clamping. + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param ep Epsilon + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> tweakedInfinitePerspective( + T fovy, T aspect, T near, T ep); + + /// @} +}//namespace glm + +#include "matrix_clip_space.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_clip_space.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_clip_space.inl new file mode 100644 index 0000000000000000000000000000000000000000..2a7f612332d4c4859509a29a4e86cbd088c5c17e --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_clip_space.inl @@ -0,0 +1,555 @@ +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> ortho(T left, T right, T bottom, T top) + { + mat<4, 4, T, defaultp> Result(static_cast(1)); + Result[0][0] = static_cast(2) / (right - left); + Result[1][1] = static_cast(2) / (top - bottom); + Result[2][2] = - static_cast(1); + Result[3][0] = - (right + left) / (right - left); + Result[3][1] = - (top + bottom) / (top - bottom); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoLH_ZO(T left, T right, T bottom, T top, T zNear, T zFar) + { + mat<4, 4, T, defaultp> Result(1); + Result[0][0] = static_cast(2) / (right - left); + Result[1][1] = static_cast(2) / (top - bottom); + Result[2][2] = static_cast(1) / (zFar - zNear); + Result[3][0] = - (right + left) / (right - left); + Result[3][1] = - (top + bottom) / (top - bottom); + Result[3][2] = - zNear / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoLH_NO(T left, T right, T bottom, T top, T zNear, T zFar) + { + mat<4, 4, T, defaultp> Result(1); + Result[0][0] = static_cast(2) / (right - left); + Result[1][1] = static_cast(2) / (top - bottom); + Result[2][2] = static_cast(2) / (zFar - zNear); + Result[3][0] = - (right + left) / (right - left); + Result[3][1] = - (top + bottom) / (top - bottom); + Result[3][2] = - (zFar + zNear) / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoRH_ZO(T left, T right, T bottom, T top, T zNear, T zFar) + { + mat<4, 4, T, defaultp> Result(1); + Result[0][0] = static_cast(2) / (right - left); + Result[1][1] = static_cast(2) / (top - bottom); + Result[2][2] = - static_cast(1) / (zFar - zNear); + Result[3][0] = - (right + left) / (right - left); + Result[3][1] = - (top + bottom) / (top - bottom); + Result[3][2] = - zNear / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoRH_NO(T left, T right, T bottom, T top, T zNear, T zFar) + { + mat<4, 4, T, defaultp> Result(1); + Result[0][0] = static_cast(2) / (right - left); + Result[1][1] = static_cast(2) / (top - bottom); + Result[2][2] = - static_cast(2) / (zFar - zNear); + Result[3][0] = - (right + left) / (right - left); + Result[3][1] = - (top + bottom) / (top - bottom); + Result[3][2] = - (zFar + zNear) / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoZO(T left, T right, T bottom, T top, T zNear, T zFar) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT + return orthoLH_ZO(left, right, bottom, top, zNear, zFar); +# else + return orthoRH_ZO(left, right, bottom, top, zNear, zFar); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoNO(T left, T right, T bottom, T top, T zNear, T zFar) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT + return orthoLH_NO(left, right, bottom, top, zNear, zFar); +# else + return orthoRH_NO(left, right, bottom, top, zNear, zFar); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoLH(T left, T right, T bottom, T top, T zNear, T zFar) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT + return orthoLH_ZO(left, right, bottom, top, zNear, zFar); +# else + return orthoLH_NO(left, right, bottom, top, zNear, zFar); +# endif + + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoRH(T left, T right, T bottom, T top, T zNear, T zFar) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT + return orthoRH_ZO(left, right, bottom, top, zNear, zFar); +# else + return orthoRH_NO(left, right, bottom, top, zNear, zFar); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> ortho(T left, T right, T bottom, T top, T zNear, T zFar) + { +# if GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_ZO + return orthoLH_ZO(left, right, bottom, top, zNear, zFar); +# elif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_NO + return orthoLH_NO(left, right, bottom, top, zNear, zFar); +# elif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_ZO + return orthoRH_ZO(left, right, bottom, top, zNear, zFar); +# elif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_NO + return orthoRH_NO(left, right, bottom, top, zNear, zFar); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumLH_ZO(T left, T right, T bottom, T top, T nearVal, T farVal) + { + mat<4, 4, T, defaultp> Result(0); + Result[0][0] = (static_cast(2) * nearVal) / (right - left); + Result[1][1] = (static_cast(2) * nearVal) / (top - bottom); + Result[2][0] = -(right + left) / (right - left); + Result[2][1] = -(top + bottom) / (top - bottom); + Result[2][2] = farVal / (farVal - nearVal); + Result[2][3] = static_cast(1); + Result[3][2] = -(farVal * nearVal) / (farVal - nearVal); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumLH_NO(T left, T right, T bottom, T top, T nearVal, T farVal) + { + mat<4, 4, T, defaultp> Result(0); + Result[0][0] = (static_cast(2) * nearVal) / (right - left); + Result[1][1] = (static_cast(2) * nearVal) / (top - bottom); + Result[2][0] = -(right + left) / (right - left); + Result[2][1] = -(top + bottom) / (top - bottom); + Result[2][2] = (farVal + nearVal) / (farVal - nearVal); + Result[2][3] = static_cast(1); + Result[3][2] = - (static_cast(2) * farVal * nearVal) / (farVal - nearVal); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumRH_ZO(T left, T right, T bottom, T top, T nearVal, T farVal) + { + mat<4, 4, T, defaultp> Result(0); + Result[0][0] = (static_cast(2) * nearVal) / (right - left); + Result[1][1] = (static_cast(2) * nearVal) / (top - bottom); + Result[2][0] = (right + left) / (right - left); + Result[2][1] = (top + bottom) / (top - bottom); + Result[2][2] = farVal / (nearVal - farVal); + Result[2][3] = static_cast(-1); + Result[3][2] = -(farVal * nearVal) / (farVal - nearVal); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumRH_NO(T left, T right, T bottom, T top, T nearVal, T farVal) + { + mat<4, 4, T, defaultp> Result(0); + Result[0][0] = (static_cast(2) * nearVal) / (right - left); + Result[1][1] = (static_cast(2) * nearVal) / (top - bottom); + Result[2][0] = (right + left) / (right - left); + Result[2][1] = (top + bottom) / (top - bottom); + Result[2][2] = - (farVal + nearVal) / (farVal - nearVal); + Result[2][3] = static_cast(-1); + Result[3][2] = - (static_cast(2) * farVal * nearVal) / (farVal - nearVal); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumZO(T left, T right, T bottom, T top, T nearVal, T farVal) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT + return frustumLH_ZO(left, right, bottom, top, nearVal, farVal); +# else + return frustumRH_ZO(left, right, bottom, top, nearVal, farVal); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumNO(T left, T right, T bottom, T top, T nearVal, T farVal) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT + return frustumLH_NO(left, right, bottom, top, nearVal, farVal); +# else + return frustumRH_NO(left, right, bottom, top, nearVal, farVal); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumLH(T left, T right, T bottom, T top, T nearVal, T farVal) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT + return frustumLH_ZO(left, right, bottom, top, nearVal, farVal); +# else + return frustumLH_NO(left, right, bottom, top, nearVal, farVal); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumRH(T left, T right, T bottom, T top, T nearVal, T farVal) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT + return frustumRH_ZO(left, right, bottom, top, nearVal, farVal); +# else + return frustumRH_NO(left, right, bottom, top, nearVal, farVal); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustum(T left, T right, T bottom, T top, T nearVal, T farVal) + { +# if GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_ZO + return frustumLH_ZO(left, right, bottom, top, nearVal, farVal); +# elif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_NO + return frustumLH_NO(left, right, bottom, top, nearVal, farVal); +# elif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_ZO + return frustumRH_ZO(left, right, bottom, top, nearVal, farVal); +# elif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_NO + return frustumRH_NO(left, right, bottom, top, nearVal, farVal); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveRH_ZO(T fovy, T aspect, T zNear, T zFar) + { + assert(abs(aspect - std::numeric_limits::epsilon()) > static_cast(0)); + + T const tanHalfFovy = tan(fovy / static_cast(2)); + + mat<4, 4, T, defaultp> Result(static_cast(0)); + Result[0][0] = static_cast(1) / (aspect * tanHalfFovy); + Result[1][1] = static_cast(1) / (tanHalfFovy); + Result[2][2] = zFar / (zNear - zFar); + Result[2][3] = - static_cast(1); + Result[3][2] = -(zFar * zNear) / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveRH_NO(T fovy, T aspect, T zNear, T zFar) + { + assert(abs(aspect - std::numeric_limits::epsilon()) > static_cast(0)); + + T const tanHalfFovy = tan(fovy / static_cast(2)); + + mat<4, 4, T, defaultp> Result(static_cast(0)); + Result[0][0] = static_cast(1) / (aspect * tanHalfFovy); + Result[1][1] = static_cast(1) / (tanHalfFovy); + Result[2][2] = - (zFar + zNear) / (zFar - zNear); + Result[2][3] = - static_cast(1); + Result[3][2] = - (static_cast(2) * zFar * zNear) / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveLH_ZO(T fovy, T aspect, T zNear, T zFar) + { + assert(abs(aspect - std::numeric_limits::epsilon()) > static_cast(0)); + + T const tanHalfFovy = tan(fovy / static_cast(2)); + + mat<4, 4, T, defaultp> Result(static_cast(0)); + Result[0][0] = static_cast(1) / (aspect * tanHalfFovy); + Result[1][1] = static_cast(1) / (tanHalfFovy); + Result[2][2] = zFar / (zFar - zNear); + Result[2][3] = static_cast(1); + Result[3][2] = -(zFar * zNear) / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveLH_NO(T fovy, T aspect, T zNear, T zFar) + { + assert(abs(aspect - std::numeric_limits::epsilon()) > static_cast(0)); + + T const tanHalfFovy = tan(fovy / static_cast(2)); + + mat<4, 4, T, defaultp> Result(static_cast(0)); + Result[0][0] = static_cast(1) / (aspect * tanHalfFovy); + Result[1][1] = static_cast(1) / (tanHalfFovy); + Result[2][2] = (zFar + zNear) / (zFar - zNear); + Result[2][3] = static_cast(1); + Result[3][2] = - (static_cast(2) * zFar * zNear) / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveZO(T fovy, T aspect, T zNear, T zFar) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT + return perspectiveLH_ZO(fovy, aspect, zNear, zFar); +# else + return perspectiveRH_ZO(fovy, aspect, zNear, zFar); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveNO(T fovy, T aspect, T zNear, T zFar) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT + return perspectiveLH_NO(fovy, aspect, zNear, zFar); +# else + return perspectiveRH_NO(fovy, aspect, zNear, zFar); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveLH(T fovy, T aspect, T zNear, T zFar) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT + return perspectiveLH_ZO(fovy, aspect, zNear, zFar); +# else + return perspectiveLH_NO(fovy, aspect, zNear, zFar); +# endif + + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveRH(T fovy, T aspect, T zNear, T zFar) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT + return perspectiveRH_ZO(fovy, aspect, zNear, zFar); +# else + return perspectiveRH_NO(fovy, aspect, zNear, zFar); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspective(T fovy, T aspect, T zNear, T zFar) + { +# if GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_ZO + return perspectiveLH_ZO(fovy, aspect, zNear, zFar); +# elif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_NO + return perspectiveLH_NO(fovy, aspect, zNear, zFar); +# elif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_ZO + return perspectiveRH_ZO(fovy, aspect, zNear, zFar); +# elif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_NO + return perspectiveRH_NO(fovy, aspect, zNear, zFar); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovRH_ZO(T fov, T width, T height, T zNear, T zFar) + { + assert(width > static_cast(0)); + assert(height > static_cast(0)); + assert(fov > static_cast(0)); + + T const rad = fov; + T const h = glm::cos(static_cast(0.5) * rad) / glm::sin(static_cast(0.5) * rad); + T const w = h * height / width; ///todo max(width , Height) / min(width , Height)? + + mat<4, 4, T, defaultp> Result(static_cast(0)); + Result[0][0] = w; + Result[1][1] = h; + Result[2][2] = zFar / (zNear - zFar); + Result[2][3] = - static_cast(1); + Result[3][2] = -(zFar * zNear) / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovRH_NO(T fov, T width, T height, T zNear, T zFar) + { + assert(width > static_cast(0)); + assert(height > static_cast(0)); + assert(fov > static_cast(0)); + + T const rad = fov; + T const h = glm::cos(static_cast(0.5) * rad) / glm::sin(static_cast(0.5) * rad); + T const w = h * height / width; ///todo max(width , Height) / min(width , Height)? + + mat<4, 4, T, defaultp> Result(static_cast(0)); + Result[0][0] = w; + Result[1][1] = h; + Result[2][2] = - (zFar + zNear) / (zFar - zNear); + Result[2][3] = - static_cast(1); + Result[3][2] = - (static_cast(2) * zFar * zNear) / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovLH_ZO(T fov, T width, T height, T zNear, T zFar) + { + assert(width > static_cast(0)); + assert(height > static_cast(0)); + assert(fov > static_cast(0)); + + T const rad = fov; + T const h = glm::cos(static_cast(0.5) * rad) / glm::sin(static_cast(0.5) * rad); + T const w = h * height / width; ///todo max(width , Height) / min(width , Height)? + + mat<4, 4, T, defaultp> Result(static_cast(0)); + Result[0][0] = w; + Result[1][1] = h; + Result[2][2] = zFar / (zFar - zNear); + Result[2][3] = static_cast(1); + Result[3][2] = -(zFar * zNear) / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovLH_NO(T fov, T width, T height, T zNear, T zFar) + { + assert(width > static_cast(0)); + assert(height > static_cast(0)); + assert(fov > static_cast(0)); + + T const rad = fov; + T const h = glm::cos(static_cast(0.5) * rad) / glm::sin(static_cast(0.5) * rad); + T const w = h * height / width; ///todo max(width , Height) / min(width , Height)? + + mat<4, 4, T, defaultp> Result(static_cast(0)); + Result[0][0] = w; + Result[1][1] = h; + Result[2][2] = (zFar + zNear) / (zFar - zNear); + Result[2][3] = static_cast(1); + Result[3][2] = - (static_cast(2) * zFar * zNear) / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovZO(T fov, T width, T height, T zNear, T zFar) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT + return perspectiveFovLH_ZO(fov, width, height, zNear, zFar); +# else + return perspectiveFovRH_ZO(fov, width, height, zNear, zFar); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovNO(T fov, T width, T height, T zNear, T zFar) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT + return perspectiveFovLH_NO(fov, width, height, zNear, zFar); +# else + return perspectiveFovRH_NO(fov, width, height, zNear, zFar); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovLH(T fov, T width, T height, T zNear, T zFar) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT + return perspectiveFovLH_ZO(fov, width, height, zNear, zFar); +# else + return perspectiveFovLH_NO(fov, width, height, zNear, zFar); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovRH(T fov, T width, T height, T zNear, T zFar) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT + return perspectiveFovRH_ZO(fov, width, height, zNear, zFar); +# else + return perspectiveFovRH_NO(fov, width, height, zNear, zFar); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFov(T fov, T width, T height, T zNear, T zFar) + { +# if GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_ZO + return perspectiveFovLH_ZO(fov, width, height, zNear, zFar); +# elif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_NO + return perspectiveFovLH_NO(fov, width, height, zNear, zFar); +# elif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_ZO + return perspectiveFovRH_ZO(fov, width, height, zNear, zFar); +# elif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_NO + return perspectiveFovRH_NO(fov, width, height, zNear, zFar); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> infinitePerspectiveRH(T fovy, T aspect, T zNear) + { + T const range = tan(fovy / static_cast(2)) * zNear; + T const left = -range * aspect; + T const right = range * aspect; + T const bottom = -range; + T const top = range; + + mat<4, 4, T, defaultp> Result(static_cast(0)); + Result[0][0] = (static_cast(2) * zNear) / (right - left); + Result[1][1] = (static_cast(2) * zNear) / (top - bottom); + Result[2][2] = - static_cast(1); + Result[2][3] = - static_cast(1); + Result[3][2] = - static_cast(2) * zNear; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> infinitePerspectiveLH(T fovy, T aspect, T zNear) + { + T const range = tan(fovy / static_cast(2)) * zNear; + T const left = -range * aspect; + T const right = range * aspect; + T const bottom = -range; + T const top = range; + + mat<4, 4, T, defaultp> Result(T(0)); + Result[0][0] = (static_cast(2) * zNear) / (right - left); + Result[1][1] = (static_cast(2) * zNear) / (top - bottom); + Result[2][2] = static_cast(1); + Result[2][3] = static_cast(1); + Result[3][2] = - static_cast(2) * zNear; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> infinitePerspective(T fovy, T aspect, T zNear) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT + return infinitePerspectiveLH(fovy, aspect, zNear); +# else + return infinitePerspectiveRH(fovy, aspect, zNear); +# endif + } + + // Infinite projection matrix: http://www.terathon.com/gdc07_lengyel.pdf + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> tweakedInfinitePerspective(T fovy, T aspect, T zNear, T ep) + { + T const range = tan(fovy / static_cast(2)) * zNear; + T const left = -range * aspect; + T const right = range * aspect; + T const bottom = -range; + T const top = range; + + mat<4, 4, T, defaultp> Result(static_cast(0)); + Result[0][0] = (static_cast(2) * zNear) / (right - left); + Result[1][1] = (static_cast(2) * zNear) / (top - bottom); + Result[2][2] = ep - static_cast(1); + Result[2][3] = static_cast(-1); + Result[3][2] = (ep - static_cast(2)) * zNear; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> tweakedInfinitePerspective(T fovy, T aspect, T zNear) + { + return tweakedInfinitePerspective(fovy, aspect, zNear, epsilon()); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_common.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_common.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6bb3d06e7ece1caa363db7dc775dd8fd73bd42a8 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_common.hpp @@ -0,0 +1,39 @@ +/// @ref ext_matrix_common +/// @file glm/ext/matrix_common.hpp +/// +/// @defgroup ext_matrix_common GLM_EXT_matrix_common +/// @ingroup ext +/// +/// Defines functions for common matrix operations. +/// +/// Include to use the features of this extension. +/// +/// @see ext_matrix_common + +#pragma once + +#include "../detail/qualifier.hpp" +#include "../detail/_fixes.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_common extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_common + /// @{ + + template + GLM_FUNC_DECL mat mix(mat const& x, mat const& y, mat const& a); + + template + GLM_FUNC_DECL mat mix(mat const& x, mat const& y, U a); + + template + GLM_FUNC_DECL GLM_CONSTEXPR mat abs(mat const& x); + + /// @} +}//namespace glm + +#include "matrix_common.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_common.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_common.inl new file mode 100644 index 0000000000000000000000000000000000000000..1be422202edb65a759478b8dd00b179e6f1bc1fa --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_common.inl @@ -0,0 +1,34 @@ +#include "../matrix.hpp" + +#include "_matrix_vectorize.hpp" + +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat mix(mat const& x, mat const& y, U a) + { + return mat(x) * (static_cast(1) - a) + mat(y) * a; + } + + template + GLM_FUNC_QUALIFIER mat mix(mat const& x, mat const& y, mat const& a) + { + return matrixCompMult(mat(x), static_cast(1) - a) + matrixCompMult(mat(y), a); + } + + template + struct compute_abs_matrix + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static mat call(mat const& x) + { + return detail::matrix_functor_1::call(abs, x); + } + }; + + template + GLM_FUNC_DECL GLM_CONSTEXPR mat abs(mat const& x) + { + return compute_abs_matrix::value>::call(x); + } + +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double2x2.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double2x2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..94dca54b59bd00e36e28a37816525f59c8eb2a56 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double2x2.hpp @@ -0,0 +1,23 @@ +/// @ref core +/// @file glm/ext/matrix_double2x2.hpp + +#pragma once +#include "../detail/type_mat2x2.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 2 columns of 2 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<2, 2, double, defaultp> dmat2x2; + + /// 2 columns of 2 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<2, 2, double, defaultp> dmat2; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double2x2_precision.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double2x2_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9e2c174e43be2dea558bbe45b75c19a4351c12bc --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double2x2_precision.hpp @@ -0,0 +1,49 @@ +/// @ref core +/// @file glm/ext/matrix_double2x2_precision.hpp + +#pragma once +#include "../detail/type_mat2x2.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 2 columns of 2 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, double, lowp> lowp_dmat2; + + /// 2 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, double, mediump> mediump_dmat2; + + /// 2 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, double, highp> highp_dmat2; + + /// 2 columns of 2 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, double, lowp> lowp_dmat2x2; + + /// 2 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, double, mediump> mediump_dmat2x2; + + /// 2 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, double, highp> highp_dmat2x2; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double2x3.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double2x3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..bfef87a666c1346ef7053f44b8e0d862b86e3af0 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double2x3.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_double2x3.hpp + +#pragma once +#include "../detail/type_mat2x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 2 columns of 3 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<2, 3, double, defaultp> dmat2x3; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double2x3_precision.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double2x3_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..098fb6046e889cf7e2b19039c08ffd9a51bf2fda --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double2x3_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_double2x3_precision.hpp + +#pragma once +#include "../detail/type_mat2x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 2 columns of 3 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 3, double, lowp> lowp_dmat2x3; + + /// 2 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 3, double, mediump> mediump_dmat2x3; + + /// 2 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 3, double, highp> highp_dmat2x3; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double2x4.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double2x4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..499284bce161de74be5cb0ab7798d45c69d682e2 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double2x4.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_double2x4.hpp + +#pragma once +#include "../detail/type_mat2x4.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 2 columns of 4 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<2, 4, double, defaultp> dmat2x4; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double2x4_precision.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double2x4_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9b61ebcee1efbb63b0d95b2fe9e88c804ecb631a --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double2x4_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_double2x4_precision.hpp + +#pragma once +#include "../detail/type_mat2x4.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 2 columns of 4 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 4, double, lowp> lowp_dmat2x4; + + /// 2 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 4, double, mediump> mediump_dmat2x4; + + /// 2 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 4, double, highp> highp_dmat2x4; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double3x2.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double3x2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..dd23f36cdbb2530d9305f4e6e037eb2f88ecb544 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double3x2.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_double3x2.hpp + +#pragma once +#include "../detail/type_mat3x2.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 3 columns of 2 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<3, 2, double, defaultp> dmat3x2; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double3x2_precision.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double3x2_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..068d9e911721623bfb7c5d5ac3ac5591581907e2 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double3x2_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_double3x2_precision.hpp + +#pragma once +#include "../detail/type_mat3x2.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 3 columns of 2 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 2, double, lowp> lowp_dmat3x2; + + /// 3 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 2, double, mediump> mediump_dmat3x2; + + /// 3 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 2, double, highp> highp_dmat3x2; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double3x3.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double3x3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..53572b735626e224c52eb386a794353308574b6a --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double3x3.hpp @@ -0,0 +1,23 @@ +/// @ref core +/// @file glm/ext/matrix_double3x3.hpp + +#pragma once +#include "../detail/type_mat3x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 3 columns of 3 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<3, 3, double, defaultp> dmat3x3; + + /// 3 columns of 3 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<3, 3, double, defaultp> dmat3; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double3x3_precision.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double3x3_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8691e7808dc95b7f4466ec9b6c829f54f9416edf --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double3x3_precision.hpp @@ -0,0 +1,49 @@ +/// @ref core +/// @file glm/ext/matrix_double3x3_precision.hpp + +#pragma once +#include "../detail/type_mat3x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 3 columns of 3 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, double, lowp> lowp_dmat3; + + /// 3 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, double, mediump> mediump_dmat3; + + /// 3 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, double, highp> highp_dmat3; + + /// 3 columns of 3 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, double, lowp> lowp_dmat3x3; + + /// 3 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, double, mediump> mediump_dmat3x3; + + /// 3 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, double, highp> highp_dmat3x3; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double3x4.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double3x4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c572d637cd2dce86aa0d8d45c4457498880a95ca --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double3x4.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_double3x4.hpp + +#pragma once +#include "../detail/type_mat3x4.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 3 columns of 4 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<3, 4, double, defaultp> dmat3x4; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double3x4_precision.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double3x4_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f040217e748ab7b56a8a292b4825c5926716b176 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double3x4_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_double3x4_precision.hpp + +#pragma once +#include "../detail/type_mat3x4.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 3 columns of 4 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 4, double, lowp> lowp_dmat3x4; + + /// 3 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 4, double, mediump> mediump_dmat3x4; + + /// 3 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 4, double, highp> highp_dmat3x4; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double4x2.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double4x2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9b229f471e8d4904c7135e7a27719820dfe5225b --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double4x2.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_double4x2.hpp + +#pragma once +#include "../detail/type_mat4x2.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 4 columns of 2 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<4, 2, double, defaultp> dmat4x2; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double4x2_precision.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double4x2_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6ad18ba9e65e108090e8354e5a55a5ac1c5f3b8f --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double4x2_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_double4x2_precision.hpp + +#pragma once +#include "../detail/type_mat4x2.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 4 columns of 2 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 2, double, lowp> lowp_dmat4x2; + + /// 4 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 2, double, mediump> mediump_dmat4x2; + + /// 4 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 2, double, highp> highp_dmat4x2; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double4x3.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double4x3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..dca4cf956f9189b7b74cece7fc3f2af9501ae49f --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double4x3.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_double4x3.hpp + +#pragma once +#include "../detail/type_mat4x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 4 columns of 3 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<4, 3, double, defaultp> dmat4x3; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double4x3_precision.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double4x3_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f7371de84942ac21b33e7eb81e97352c6a4ec449 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double4x3_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_double4x3_precision.hpp + +#pragma once +#include "../detail/type_mat4x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 4 columns of 3 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 3, double, lowp> lowp_dmat4x3; + + /// 4 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 3, double, mediump> mediump_dmat4x3; + + /// 4 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 3, double, highp> highp_dmat4x3; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double4x4.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double4x4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..81e1bf65cb5c4b071a394b6dc1d9d53e04b21500 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double4x4.hpp @@ -0,0 +1,23 @@ +/// @ref core +/// @file glm/ext/matrix_double4x4.hpp + +#pragma once +#include "../detail/type_mat4x4.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 4 columns of 4 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<4, 4, double, defaultp> dmat4x4; + + /// 4 columns of 4 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<4, 4, double, defaultp> dmat4; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double4x4_precision.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double4x4_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4c36a8486c72988f4d0d1f8a822a69c4e477fa95 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_double4x4_precision.hpp @@ -0,0 +1,49 @@ +/// @ref core +/// @file glm/ext/matrix_double4x4_precision.hpp + +#pragma once +#include "../detail/type_mat4x4.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 4 columns of 4 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, double, lowp> lowp_dmat4; + + /// 4 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, double, mediump> mediump_dmat4; + + /// 4 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, double, highp> highp_dmat4; + + /// 4 columns of 4 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, double, lowp> lowp_dmat4x4; + + /// 4 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, double, mediump> mediump_dmat4x4; + + /// 4 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, double, highp> highp_dmat4x4; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float2x2.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float2x2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..53df921fe216b575c92239c478301db803416a14 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float2x2.hpp @@ -0,0 +1,23 @@ +/// @ref core +/// @file glm/ext/matrix_float2x2.hpp + +#pragma once +#include "../detail/type_mat2x2.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 2 columns of 2 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<2, 2, float, defaultp> mat2x2; + + /// 2 columns of 2 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<2, 2, float, defaultp> mat2; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float2x2_precision.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float2x2_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..898b6db7140807bc0d30b676724827d623c64da3 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float2x2_precision.hpp @@ -0,0 +1,49 @@ +/// @ref core +/// @file glm/ext/matrix_float2x2_precision.hpp + +#pragma once +#include "../detail/type_mat2x2.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 2 columns of 2 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, float, lowp> lowp_mat2; + + /// 2 columns of 2 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, float, mediump> mediump_mat2; + + /// 2 columns of 2 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, float, highp> highp_mat2; + + /// 2 columns of 2 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, float, lowp> lowp_mat2x2; + + /// 2 columns of 2 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, float, mediump> mediump_mat2x2; + + /// 2 columns of 2 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, float, highp> highp_mat2x2; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float2x3.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float2x3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6f68822dbf1e742431163115f4bafc35b6896606 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float2x3.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_float2x3.hpp + +#pragma once +#include "../detail/type_mat2x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 2 columns of 3 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<2, 3, float, defaultp> mat2x3; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float2x3_precision.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float2x3_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..50c103245c3a177b958de4df333245d09f4d1e28 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float2x3_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_float2x3_precision.hpp + +#pragma once +#include "../detail/type_mat2x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 2 columns of 3 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 3, float, lowp> lowp_mat2x3; + + /// 2 columns of 3 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 3, float, mediump> mediump_mat2x3; + + /// 2 columns of 3 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 3, float, highp> highp_mat2x3; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float2x4.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float2x4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..30f30de3cbd4c12cc642a6ac211e40876bdca525 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float2x4.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_float2x4.hpp + +#pragma once +#include "../detail/type_mat2x4.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 2 columns of 4 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<2, 4, float, defaultp> mat2x4; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float2x4_precision.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float2x4_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..079d6382863172411ae6a82837bb34ea6e2096c9 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float2x4_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_float2x4_precision.hpp + +#pragma once +#include "../detail/type_mat2x4.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 2 columns of 4 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 4, float, lowp> lowp_mat2x4; + + /// 2 columns of 4 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 4, float, mediump> mediump_mat2x4; + + /// 2 columns of 4 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 4, float, highp> highp_mat2x4; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float3x2.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float3x2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..280d0a3e974b0d2793895388e276a9f82f5f1f50 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float3x2.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_float3x2.hpp + +#pragma once +#include "../detail/type_mat3x2.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 3 columns of 2 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<3, 2, float, defaultp> mat3x2; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float3x2_precision.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float3x2_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8572c2a1b20e5a1e47bedd72ec6d0009fd15d9bf --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float3x2_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_float3x2_precision.hpp + +#pragma once +#include "../detail/type_mat3x2.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 3 columns of 2 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 2, float, lowp> lowp_mat3x2; + + /// 3 columns of 2 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 2, float, mediump> mediump_mat3x2; + + /// 3 columns of 2 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 2, float, highp> highp_mat3x2; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float3x3.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float3x3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..177d809ff9f4c157beda61885ad3994fe3e3d141 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float3x3.hpp @@ -0,0 +1,23 @@ +/// @ref core +/// @file glm/ext/matrix_float3x3.hpp + +#pragma once +#include "../detail/type_mat3x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 3 columns of 3 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<3, 3, float, defaultp> mat3x3; + + /// 3 columns of 3 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<3, 3, float, defaultp> mat3; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float3x3_precision.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float3x3_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8a900c16420006f110c9bfeaf186156d9fc135c3 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float3x3_precision.hpp @@ -0,0 +1,49 @@ +/// @ref core +/// @file glm/ext/matrix_float3x3_precision.hpp + +#pragma once +#include "../detail/type_mat3x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 3 columns of 3 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, float, lowp> lowp_mat3; + + /// 3 columns of 3 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, float, mediump> mediump_mat3; + + /// 3 columns of 3 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, float, highp> highp_mat3; + + /// 3 columns of 3 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, float, lowp> lowp_mat3x3; + + /// 3 columns of 3 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, float, mediump> mediump_mat3x3; + + /// 3 columns of 3 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, float, highp> highp_mat3x3; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float3x4.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float3x4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..64b8459dcdd2d489a7a8fc93c1282f7cf1ec2673 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float3x4.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_float3x4.hpp + +#pragma once +#include "../detail/type_mat3x4.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 3 columns of 4 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<3, 4, float, defaultp> mat3x4; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float3x4_precision.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float3x4_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..bc36bf13a1e957ab625e3162312f311a9d5a287e --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float3x4_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_float3x4_precision.hpp + +#pragma once +#include "../detail/type_mat3x4.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 3 columns of 4 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 4, float, lowp> lowp_mat3x4; + + /// 3 columns of 4 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 4, float, mediump> mediump_mat3x4; + + /// 3 columns of 4 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 4, float, highp> highp_mat3x4; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float4x2.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float4x2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1ed5227bf58000e7c2d822014b29b49d685f6972 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float4x2.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_float4x2.hpp + +#pragma once +#include "../detail/type_mat4x2.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 4 columns of 2 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<4, 2, float, defaultp> mat4x2; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float4x2_precision.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float4x2_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..88fd069630a802ab8c7d80791ae91f98969098a4 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float4x2_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_float2x2_precision.hpp + +#pragma once +#include "../detail/type_mat2x2.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 4 columns of 2 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 2, float, lowp> lowp_mat4x2; + + /// 4 columns of 2 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 2, float, mediump> mediump_mat4x2; + + /// 4 columns of 2 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 2, float, highp> highp_mat4x2; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float4x3.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float4x3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5dbe7657043f704017228a0ebc03ed5a7a0c9e40 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float4x3.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_float4x3.hpp + +#pragma once +#include "../detail/type_mat4x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 4 columns of 3 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<4, 3, float, defaultp> mat4x3; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float4x3_precision.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float4x3_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..846ed4fc8d9ccb0de18374fa039cffb823d3586a --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float4x3_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_float4x3_precision.hpp + +#pragma once +#include "../detail/type_mat4x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 4 columns of 3 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 3, float, lowp> lowp_mat4x3; + + /// 4 columns of 3 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 3, float, mediump> mediump_mat4x3; + + /// 4 columns of 3 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 3, float, highp> highp_mat4x3; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float4x4.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float4x4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5ba111de048171ae0f9849a2c5e375f9351a8bbc --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float4x4.hpp @@ -0,0 +1,23 @@ +/// @ref core +/// @file glm/ext/matrix_float4x4.hpp + +#pragma once +#include "../detail/type_mat4x4.hpp" + +namespace glm +{ + /// @ingroup core_matrix + /// @{ + + /// 4 columns of 4 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<4, 4, float, defaultp> mat4x4; + + /// 4 columns of 4 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<4, 4, float, defaultp> mat4; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float4x4_precision.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float4x4_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..597149bcf90fcd34e1b22e970fbd01cc45742fa5 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_float4x4_precision.hpp @@ -0,0 +1,49 @@ +/// @ref core +/// @file glm/ext/matrix_float4x4_precision.hpp + +#pragma once +#include "../detail/type_mat4x4.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 4 columns of 4 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, float, lowp> lowp_mat4; + + /// 4 columns of 4 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, float, mediump> mediump_mat4; + + /// 4 columns of 4 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, float, highp> highp_mat4; + + /// 4 columns of 4 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, float, lowp> lowp_mat4x4; + + /// 4 columns of 4 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, float, mediump> mediump_mat4x4; + + /// 4 columns of 4 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, float, highp> highp_mat4x4; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int2x2.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int2x2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c6aa0686ae78e5778c087c665ee6ab44384e1aa2 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int2x2.hpp @@ -0,0 +1,38 @@ +/// @ref ext_matrix_int2x2 +/// @file glm/ext/matrix_int2x2.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int2x2 GLM_EXT_matrix_int2x2 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat2x2.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int2x2 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int2x2 + /// @{ + + /// Signed integer 2x2 matrix. + /// + /// @see ext_matrix_int2x2 + typedef mat<2, 2, int, defaultp> imat2x2; + + /// Signed integer 2x2 matrix. + /// + /// @see ext_matrix_int2x2 + typedef mat<2, 2, int, defaultp> imat2; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int2x2_sized.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int2x2_sized.hpp new file mode 100644 index 0000000000000000000000000000000000000000..70c0c2106acdb5bdaf14d74364cb0a8040e3ca8f --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int2x2_sized.hpp @@ -0,0 +1,70 @@ +/// @ref ext_matrix_int2x2_sized +/// @file glm/ext/matrix_int2x2_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int2x2_sized GLM_EXT_matrix_int2x2_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat2x2.hpp" +#include "../ext/scalar_int_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int2x2_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int2x2_sized + /// @{ + + /// 8 bit signed integer 2x2 matrix. + /// + /// @see ext_matrix_int2x2_sized + typedef mat<2, 2, int8, defaultp> i8mat2x2; + + /// 16 bit signed integer 2x2 matrix. + /// + /// @see ext_matrix_int2x2_sized + typedef mat<2, 2, int16, defaultp> i16mat2x2; + + /// 32 bit signed integer 2x2 matrix. + /// + /// @see ext_matrix_int2x2_sized + typedef mat<2, 2, int32, defaultp> i32mat2x2; + + /// 64 bit signed integer 2x2 matrix. + /// + /// @see ext_matrix_int2x2_sized + typedef mat<2, 2, int64, defaultp> i64mat2x2; + + + /// 8 bit signed integer 2x2 matrix. + /// + /// @see ext_matrix_int2x2_sized + typedef mat<2, 2, int8, defaultp> i8mat2; + + /// 16 bit signed integer 2x2 matrix. + /// + /// @see ext_matrix_int2x2_sized + typedef mat<2, 2, int16, defaultp> i16mat2; + + /// 32 bit signed integer 2x2 matrix. + /// + /// @see ext_matrix_int2x2_sized + typedef mat<2, 2, int32, defaultp> i32mat2; + + /// 64 bit signed integer 2x2 matrix. + /// + /// @see ext_matrix_int2x2_sized + typedef mat<2, 2, int64, defaultp> i64mat2; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int2x3.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int2x3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..aee415caa6e1dd9658c12e91c0be07dc858baf70 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int2x3.hpp @@ -0,0 +1,33 @@ +/// @ref ext_matrix_int2x3 +/// @file glm/ext/matrix_int2x3.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int2x3 GLM_EXT_matrix_int2x3 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat2x3.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int2x3 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int2x3 + /// @{ + + /// Signed integer 2x3 matrix. + /// + /// @see ext_matrix_int2x3 + typedef mat<2, 3, int, defaultp> imat2x3; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int2x3_sized.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int2x3_sized.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b5526fe55143cf872978a4c2c13a2bda2b2bcd27 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int2x3_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_matrix_int2x3_sized +/// @file glm/ext/matrix_int2x3_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int2x3_sized GLM_EXT_matrix_int2x3_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat2x3.hpp" +#include "../ext/scalar_int_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int2x3_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int2x3_sized + /// @{ + + /// 8 bit signed integer 2x3 matrix. + /// + /// @see ext_matrix_int2x3_sized + typedef mat<2, 3, int8, defaultp> i8mat2x3; + + /// 16 bit signed integer 2x3 matrix. + /// + /// @see ext_matrix_int2x3_sized + typedef mat<2, 3, int16, defaultp> i16mat2x3; + + /// 32 bit signed integer 2x3 matrix. + /// + /// @see ext_matrix_int2x3_sized + typedef mat<2, 3, int32, defaultp> i32mat2x3; + + /// 64 bit signed integer 2x3 matrix. + /// + /// @see ext_matrix_int2x3_sized + typedef mat<2, 3, int64, defaultp> i64mat2x3; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int2x4.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int2x4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4f36331d66023619a6f296644d243ad61f5411c0 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int2x4.hpp @@ -0,0 +1,33 @@ +/// @ref ext_matrix_int2x4 +/// @file glm/ext/matrix_int2x4.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int2x4 GLM_EXT_matrix_int2x4 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat2x4.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int2x4 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int2x4 + /// @{ + + /// Signed integer 2x4 matrix. + /// + /// @see ext_matrix_int2x4 + typedef mat<2, 4, int, defaultp> imat2x4; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int2x4_sized.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int2x4_sized.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a66a5e72688139b620784c4908c8db9cf7da5024 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int2x4_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_matrix_int2x4_sized +/// @file glm/ext/matrix_int2x4_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int2x4_sized GLM_EXT_matrix_int2x4_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat2x4.hpp" +#include "../ext/scalar_int_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int2x4_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int2x4_sized + /// @{ + + /// 8 bit signed integer 2x4 matrix. + /// + /// @see ext_matrix_int2x4_sized + typedef mat<2, 4, int8, defaultp> i8mat2x4; + + /// 16 bit signed integer 2x4 matrix. + /// + /// @see ext_matrix_int2x4_sized + typedef mat<2, 4, int16, defaultp> i16mat2x4; + + /// 32 bit signed integer 2x4 matrix. + /// + /// @see ext_matrix_int2x4_sized + typedef mat<2, 4, int32, defaultp> i32mat2x4; + + /// 64 bit signed integer 2x4 matrix. + /// + /// @see ext_matrix_int2x4_sized + typedef mat<2, 4, int64, defaultp> i64mat2x4; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int3x2.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int3x2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..3bd563b7de9c7b5487868ae21c4cc885219f4130 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int3x2.hpp @@ -0,0 +1,33 @@ +/// @ref ext_matrix_int3x2 +/// @file glm/ext/matrix_int3x2.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int3x2 GLM_EXT_matrix_int3x2 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat3x2.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int3x2 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int3x2 + /// @{ + + /// Signed integer 3x2 matrix. + /// + /// @see ext_matrix_int3x2 + typedef mat<3, 2, int, defaultp> imat3x2; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int3x2_sized.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int3x2_sized.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7e34c5240f401cae66d5d6536862bc9bc84d8dce --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int3x2_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_matrix_int3x2_sized +/// @file glm/ext/matrix_int3x2_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int3x2_sized GLM_EXT_matrix_int3x2_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat3x2.hpp" +#include "../ext/scalar_int_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int3x2_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int3x2_sized + /// @{ + + /// 8 bit signed integer 3x2 matrix. + /// + /// @see ext_matrix_int3x2_sized + typedef mat<3, 2, int8, defaultp> i8mat3x2; + + /// 16 bit signed integer 3x2 matrix. + /// + /// @see ext_matrix_int3x2_sized + typedef mat<3, 2, int16, defaultp> i16mat3x2; + + /// 32 bit signed integer 3x2 matrix. + /// + /// @see ext_matrix_int3x2_sized + typedef mat<3, 2, int32, defaultp> i32mat3x2; + + /// 64 bit signed integer 3x2 matrix. + /// + /// @see ext_matrix_int3x2_sized + typedef mat<3, 2, int64, defaultp> i64mat3x2; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int3x3.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int3x3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..287488da0343cf12207cea1dbba0bd8727342ef2 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int3x3.hpp @@ -0,0 +1,38 @@ +/// @ref ext_matrix_int3x3 +/// @file glm/ext/matrix_int3x3.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int3x3 GLM_EXT_matrix_int3x3 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat3x3.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int3x3 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int3x3 + /// @{ + + /// Signed integer 3x3 matrix. + /// + /// @see ext_matrix_int3x3 + typedef mat<3, 3, int, defaultp> imat3x3; + + /// Signed integer 3x3 matrix. + /// + /// @see ext_matrix_int3x3 + typedef mat<3, 3, int, defaultp> imat3; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int3x3_sized.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int3x3_sized.hpp new file mode 100644 index 0000000000000000000000000000000000000000..577e305aa7f74ab3418f92e728e740c6a5c437f3 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int3x3_sized.hpp @@ -0,0 +1,70 @@ +/// @ref ext_matrix_int3x3_sized +/// @file glm/ext/matrix_int3x3_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int3x3_sized GLM_EXT_matrix_int3x3_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat3x3.hpp" +#include "../ext/scalar_int_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int3x3_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int3x3_sized + /// @{ + + /// 8 bit signed integer 3x3 matrix. + /// + /// @see ext_matrix_int3x3_sized + typedef mat<3, 3, int8, defaultp> i8mat3x3; + + /// 16 bit signed integer 3x3 matrix. + /// + /// @see ext_matrix_int3x3_sized + typedef mat<3, 3, int16, defaultp> i16mat3x3; + + /// 32 bit signed integer 3x3 matrix. + /// + /// @see ext_matrix_int3x3_sized + typedef mat<3, 3, int32, defaultp> i32mat3x3; + + /// 64 bit signed integer 3x3 matrix. + /// + /// @see ext_matrix_int3x3_sized + typedef mat<3, 3, int64, defaultp> i64mat3x3; + + + /// 8 bit signed integer 3x3 matrix. + /// + /// @see ext_matrix_int3x3_sized + typedef mat<3, 3, int8, defaultp> i8mat3; + + /// 16 bit signed integer 3x3 matrix. + /// + /// @see ext_matrix_int3x3_sized + typedef mat<3, 3, int16, defaultp> i16mat3; + + /// 32 bit signed integer 3x3 matrix. + /// + /// @see ext_matrix_int3x3_sized + typedef mat<3, 3, int32, defaultp> i32mat3; + + /// 64 bit signed integer 3x3 matrix. + /// + /// @see ext_matrix_int3x3_sized + typedef mat<3, 3, int64, defaultp> i64mat3; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int3x4.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int3x4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..08e534d9c4d5b7fbd8c815d0bc4639c7a7f7ae5b --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int3x4.hpp @@ -0,0 +1,33 @@ +/// @ref ext_matrix_int3x4 +/// @file glm/ext/matrix_int3x4.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int3x4 GLM_EXT_matrix_int3x4 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat3x4.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int3x4 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int3x4 + /// @{ + + /// Signed integer 3x4 matrix. + /// + /// @see ext_matrix_int3x4 + typedef mat<3, 4, int, defaultp> imat3x4; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int3x4_sized.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int3x4_sized.hpp new file mode 100644 index 0000000000000000000000000000000000000000..692c48c439e7bfcd1016eb8f871833eda432913b --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int3x4_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_matrix_int3x4_sized +/// @file glm/ext/matrix_int3x2_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int3x4_sized GLM_EXT_matrix_int3x4_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat3x4.hpp" +#include "../ext/scalar_int_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int3x4_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int3x4_sized + /// @{ + + /// 8 bit signed integer 3x4 matrix. + /// + /// @see ext_matrix_int3x4_sized + typedef mat<3, 4, int8, defaultp> i8mat3x4; + + /// 16 bit signed integer 3x4 matrix. + /// + /// @see ext_matrix_int3x4_sized + typedef mat<3, 4, int16, defaultp> i16mat3x4; + + /// 32 bit signed integer 3x4 matrix. + /// + /// @see ext_matrix_int3x4_sized + typedef mat<3, 4, int32, defaultp> i32mat3x4; + + /// 64 bit signed integer 3x4 matrix. + /// + /// @see ext_matrix_int3x4_sized + typedef mat<3, 4, int64, defaultp> i64mat3x4; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int4x2.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int4x2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f756ef2804c81278d2c78aea85ad0e0fe3db468f --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int4x2.hpp @@ -0,0 +1,33 @@ +/// @ref ext_matrix_int4x2 +/// @file glm/ext/matrix_int4x2.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int4x2 GLM_EXT_matrix_int4x2 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat4x2.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int4x2 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int4x2 + /// @{ + + /// Signed integer 4x2 matrix. + /// + /// @see ext_matrix_int4x2 + typedef mat<4, 2, int, defaultp> imat4x2; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int4x2_sized.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int4x2_sized.hpp new file mode 100644 index 0000000000000000000000000000000000000000..63a99d604dc5c02a132b9e61ce120c7dfd7ccd90 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int4x2_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_matrix_int4x2_sized +/// @file glm/ext/matrix_int4x2_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int4x2_sized GLM_EXT_matrix_int4x2_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat4x2.hpp" +#include "../ext/scalar_int_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int4x2_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int4x2_sized + /// @{ + + /// 8 bit signed integer 4x2 matrix. + /// + /// @see ext_matrix_int4x2_sized + typedef mat<4, 2, int8, defaultp> i8mat4x2; + + /// 16 bit signed integer 4x2 matrix. + /// + /// @see ext_matrix_int4x2_sized + typedef mat<4, 2, int16, defaultp> i16mat4x2; + + /// 32 bit signed integer 4x2 matrix. + /// + /// @see ext_matrix_int4x2_sized + typedef mat<4, 2, int32, defaultp> i32mat4x2; + + /// 64 bit signed integer 4x2 matrix. + /// + /// @see ext_matrix_int4x2_sized + typedef mat<4, 2, int64, defaultp> i64mat4x2; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int4x3.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int4x3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d5d97a7a37cf976fbff71ee29dc6953cdd65db90 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int4x3.hpp @@ -0,0 +1,33 @@ +/// @ref ext_matrix_int4x3 +/// @file glm/ext/matrix_int4x3.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int4x3 GLM_EXT_matrix_int4x3 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat4x3.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int4x3 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int4x3 + /// @{ + + /// Signed integer 4x3 matrix. + /// + /// @see ext_matrix_int4x3 + typedef mat<4, 3, int, defaultp> imat4x3; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int4x3_sized.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int4x3_sized.hpp new file mode 100644 index 0000000000000000000000000000000000000000..55078fadc60f8c98be996a74ee62fc407d7fa444 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int4x3_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_matrix_int4x3_sized +/// @file glm/ext/matrix_int4x3_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int4x3_sized GLM_EXT_matrix_int4x3_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat4x3.hpp" +#include "../ext/scalar_int_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int4x3_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int4x3_sized + /// @{ + + /// 8 bit signed integer 4x3 matrix. + /// + /// @see ext_matrix_int4x3_sized + typedef mat<4, 3, int8, defaultp> i8mat4x3; + + /// 16 bit signed integer 4x3 matrix. + /// + /// @see ext_matrix_int4x3_sized + typedef mat<4, 3, int16, defaultp> i16mat4x3; + + /// 32 bit signed integer 4x3 matrix. + /// + /// @see ext_matrix_int4x3_sized + typedef mat<4, 3, int32, defaultp> i32mat4x3; + + /// 64 bit signed integer 4x3 matrix. + /// + /// @see ext_matrix_int4x3_sized + typedef mat<4, 3, int64, defaultp> i64mat4x3; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int4x4.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int4x4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e17cff17f9fb2fb444badc4ca08b9623acaa559c --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int4x4.hpp @@ -0,0 +1,38 @@ +/// @ref ext_matrix_int4x4 +/// @file glm/ext/matrix_int4x4.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int4x4 GLM_EXT_matrix_int4x4 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat4x4.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int4x4 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int4x4 + /// @{ + + /// Signed integer 4x4 matrix. + /// + /// @see ext_matrix_int4x4 + typedef mat<4, 4, int, defaultp> imat4x4; + + /// Signed integer 4x4 matrix. + /// + /// @see ext_matrix_int4x4 + typedef mat<4, 4, int, defaultp> imat4; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int4x4_sized.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int4x4_sized.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4a11203eb25b1fd7adf3311c770aaffd1527e16b --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_int4x4_sized.hpp @@ -0,0 +1,70 @@ +/// @ref ext_matrix_int4x4_sized +/// @file glm/ext/matrix_int4x4_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int4x4_sized GLM_EXT_matrix_int4x4_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat4x4.hpp" +#include "../ext/scalar_int_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int4x4_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int4x4_sized + /// @{ + + /// 8 bit signed integer 4x4 matrix. + /// + /// @see ext_matrix_int4x4_sized + typedef mat<4, 4, int8, defaultp> i8mat4x4; + + /// 16 bit signed integer 4x4 matrix. + /// + /// @see ext_matrix_int4x4_sized + typedef mat<4, 4, int16, defaultp> i16mat4x4; + + /// 32 bit signed integer 4x4 matrix. + /// + /// @see ext_matrix_int4x4_sized + typedef mat<4, 4, int32, defaultp> i32mat4x4; + + /// 64 bit signed integer 4x4 matrix. + /// + /// @see ext_matrix_int4x4_sized + typedef mat<4, 4, int64, defaultp> i64mat4x4; + + + /// 8 bit signed integer 4x4 matrix. + /// + /// @see ext_matrix_int4x4_sized + typedef mat<4, 4, int8, defaultp> i8mat4; + + /// 16 bit signed integer 4x4 matrix. + /// + /// @see ext_matrix_int4x4_sized + typedef mat<4, 4, int16, defaultp> i16mat4; + + /// 32 bit signed integer 4x4 matrix. + /// + /// @see ext_matrix_int4x4_sized + typedef mat<4, 4, int32, defaultp> i32mat4; + + /// 64 bit signed integer 4x4 matrix. + /// + /// @see ext_matrix_int4x4_sized + typedef mat<4, 4, int64, defaultp> i64mat4; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_integer.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_integer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7d7dfc5a5b08e2f8f26515d4ee56a18494b866c6 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_integer.hpp @@ -0,0 +1,91 @@ +/// @ref ext_matrix_integer +/// @file glm/ext/matrix_integer.hpp +/// +/// @defgroup ext_matrix_integer GLM_EXT_matrix_integer +/// @ingroup ext +/// +/// Defines functions that generate common transformation matrices. +/// +/// The matrices generated by this extension use standard OpenGL fixed-function +/// conventions. For example, the lookAt function generates a transform from world +/// space into the specific eye space that the projective matrix functions +/// (perspective, ortho, etc) are designed to expect. The OpenGL compatibility +/// specifications defines the particular layout of this eye space. +/// +/// Include to use the features of this extension. +/// +/// @see ext_matrix_projection +/// @see ext_matrix_clip_space + +#pragma once + +// Dependencies +#include "../gtc/constants.hpp" +#include "../geometric.hpp" +#include "../trigonometric.hpp" +#include "../matrix.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_integer extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_integer + /// @{ + + /// Multiply matrix x by matrix y component-wise, i.e., + /// result[i][j] is the scalar product of x[i][j] and y[i][j]. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number a column + /// @tparam R Integer between 1 and 4 included that qualify the number a row + /// @tparam T Floating-point or signed integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL matrixCompMult man page + /// @see GLSL 4.20.8 specification, section 8.6 Matrix Functions + template + GLM_FUNC_DECL mat matrixCompMult(mat const& x, mat const& y); + + /// Treats the first parameter c as a column vector + /// and the second parameter r as a row vector + /// and does a linear algebraic matrix multiply c * r. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number a column + /// @tparam R Integer between 1 and 4 included that qualify the number a row + /// @tparam T Floating-point or signed integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL outerProduct man page + /// @see GLSL 4.20.8 specification, section 8.6 Matrix Functions + template + GLM_FUNC_DECL typename detail::outerProduct_trait::type outerProduct(vec const& c, vec const& r); + + /// Returns the transposed matrix of x + /// + /// @tparam C Integer between 1 and 4 included that qualify the number a column + /// @tparam R Integer between 1 and 4 included that qualify the number a row + /// @tparam T Floating-point or signed integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL transpose man page + /// @see GLSL 4.20.8 specification, section 8.6 Matrix Functions + template + GLM_FUNC_DECL typename mat::transpose_type transpose(mat const& x); + + /// Return the determinant of a squared matrix. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number a column + /// @tparam R Integer between 1 and 4 included that qualify the number a row + /// @tparam T Floating-point or signed integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL determinant man page + /// @see GLSL 4.20.8 specification, section 8.6 Matrix Functions + template + GLM_FUNC_DECL T determinant(mat const& m); + + /// @} +}//namespace glm + +#include "matrix_integer.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_integer.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_integer.inl new file mode 100644 index 0000000000000000000000000000000000000000..8b377ce2a8e6b426f9a31e1d9e1ffcdb31aba03c --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_integer.inl @@ -0,0 +1,38 @@ +namespace glm{ +namespace detail +{ + template + struct compute_matrixCompMult_type { + GLM_FUNC_QUALIFIER static mat call(mat const& x, mat const& y) + { + return detail::compute_matrixCompMult::value>::call(x, y); + } + }; + + template + struct compute_outerProduct_type { + GLM_FUNC_QUALIFIER static typename detail::outerProduct_trait::type call(vec const& c, vec const& r) + { + return detail::compute_outerProduct::call(c, r); + } + }; + + template + struct compute_transpose_type + { + GLM_FUNC_QUALIFIER static mat call(mat const& m) + { + return detail::compute_transpose::value>::call(m); + } + }; + + template + struct compute_determinant_type{ + + GLM_FUNC_QUALIFIER static T call(mat const& m) + { + return detail::compute_determinant::value>::call(m); + } + }; +}//namespace detail +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_projection.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_projection.hpp new file mode 100644 index 0000000000000000000000000000000000000000..51fd01bd8ee7fb28c992579c31c6200bfff98cf0 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_projection.hpp @@ -0,0 +1,149 @@ +/// @ref ext_matrix_projection +/// @file glm/ext/matrix_projection.hpp +/// +/// @defgroup ext_matrix_projection GLM_EXT_matrix_projection +/// @ingroup ext +/// +/// Functions that generate common projection transformation matrices. +/// +/// The matrices generated by this extension use standard OpenGL fixed-function +/// conventions. For example, the lookAt function generates a transform from world +/// space into the specific eye space that the projective matrix functions +/// (perspective, ortho, etc) are designed to expect. The OpenGL compatibility +/// specifications defines the particular layout of this eye space. +/// +/// Include to use the features of this extension. +/// +/// @see ext_matrix_transform +/// @see ext_matrix_clip_space + +#pragma once + +// Dependencies +#include "../gtc/constants.hpp" +#include "../geometric.hpp" +#include "../trigonometric.hpp" +#include "../matrix.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_projection extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_projection + /// @{ + + /// Map the specified object coordinates (obj.x, obj.y, obj.z) into window coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @param obj Specify the object coordinates. + /// @param model Specifies the current modelview matrix + /// @param proj Specifies the current projection matrix + /// @param viewport Specifies the current viewport + /// @return Return the computed window coordinates. + /// @tparam T Native type used for the computation. Currently supported: half (not recommended), float or double. + /// @tparam U Currently supported: Floating-point types and integer types. + /// + /// @see gluProject man page + template + GLM_FUNC_DECL vec<3, T, Q> projectZO( + vec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport); + + /// Map the specified object coordinates (obj.x, obj.y, obj.z) into window coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param obj Specify the object coordinates. + /// @param model Specifies the current modelview matrix + /// @param proj Specifies the current projection matrix + /// @param viewport Specifies the current viewport + /// @return Return the computed window coordinates. + /// @tparam T Native type used for the computation. Currently supported: half (not recommended), float or double. + /// @tparam U Currently supported: Floating-point types and integer types. + /// + /// @see gluProject man page + template + GLM_FUNC_DECL vec<3, T, Q> projectNO( + vec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport); + + /// Map the specified object coordinates (obj.x, obj.y, obj.z) into window coordinates using default near and far clip planes definition. + /// To change default near and far clip planes definition use GLM_FORCE_DEPTH_ZERO_TO_ONE. + /// + /// @param obj Specify the object coordinates. + /// @param model Specifies the current modelview matrix + /// @param proj Specifies the current projection matrix + /// @param viewport Specifies the current viewport + /// @return Return the computed window coordinates. + /// @tparam T Native type used for the computation. Currently supported: half (not recommended), float or double. + /// @tparam U Currently supported: Floating-point types and integer types. + /// + /// @see gluProject man page + template + GLM_FUNC_DECL vec<3, T, Q> project( + vec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport); + + /// Map the specified window coordinates (win.x, win.y, win.z) into object coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @param win Specify the window coordinates to be mapped. + /// @param model Specifies the modelview matrix + /// @param proj Specifies the projection matrix + /// @param viewport Specifies the viewport + /// @return Returns the computed object coordinates. + /// @tparam T Native type used for the computation. Currently supported: half (not recommended), float or double. + /// @tparam U Currently supported: Floating-point types and integer types. + /// + /// @see gluUnProject man page + template + GLM_FUNC_DECL vec<3, T, Q> unProjectZO( + vec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport); + + /// Map the specified window coordinates (win.x, win.y, win.z) into object coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param win Specify the window coordinates to be mapped. + /// @param model Specifies the modelview matrix + /// @param proj Specifies the projection matrix + /// @param viewport Specifies the viewport + /// @return Returns the computed object coordinates. + /// @tparam T Native type used for the computation. Currently supported: half (not recommended), float or double. + /// @tparam U Currently supported: Floating-point types and integer types. + /// + /// @see gluUnProject man page + template + GLM_FUNC_DECL vec<3, T, Q> unProjectNO( + vec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport); + + /// Map the specified window coordinates (win.x, win.y, win.z) into object coordinates using default near and far clip planes definition. + /// To change default near and far clip planes definition use GLM_FORCE_DEPTH_ZERO_TO_ONE. + /// + /// @param win Specify the window coordinates to be mapped. + /// @param model Specifies the modelview matrix + /// @param proj Specifies the projection matrix + /// @param viewport Specifies the viewport + /// @return Returns the computed object coordinates. + /// @tparam T Native type used for the computation. Currently supported: half (not recommended), float or double. + /// @tparam U Currently supported: Floating-point types and integer types. + /// + /// @see gluUnProject man page + template + GLM_FUNC_DECL vec<3, T, Q> unProject( + vec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport); + + /// Define a picking region + /// + /// @param center Specify the center of a picking region in window coordinates. + /// @param delta Specify the width and height, respectively, of the picking region in window coordinates. + /// @param viewport Rendering viewport + /// @tparam T Native type used for the computation. Currently supported: half (not recommended), float or double. + /// @tparam U Currently supported: Floating-point types and integer types. + /// + /// @see gluPickMatrix man page + template + GLM_FUNC_DECL mat<4, 4, T, Q> pickMatrix( + vec<2, T, Q> const& center, vec<2, T, Q> const& delta, vec<4, U, Q> const& viewport); + + /// @} +}//namespace glm + +#include "matrix_projection.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_projection.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_projection.inl new file mode 100644 index 0000000000000000000000000000000000000000..2f2c196aac5f2018c70ac579cb31c558e9d20139 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_projection.inl @@ -0,0 +1,106 @@ +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec<3, T, Q> projectZO(vec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport) + { + vec<4, T, Q> tmp = vec<4, T, Q>(obj, static_cast(1)); + tmp = model * tmp; + tmp = proj * tmp; + + tmp /= tmp.w; + tmp.x = tmp.x * static_cast(0.5) + static_cast(0.5); + tmp.y = tmp.y * static_cast(0.5) + static_cast(0.5); + + tmp[0] = tmp[0] * T(viewport[2]) + T(viewport[0]); + tmp[1] = tmp[1] * T(viewport[3]) + T(viewport[1]); + + return vec<3, T, Q>(tmp); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> projectNO(vec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport) + { + vec<4, T, Q> tmp = vec<4, T, Q>(obj, static_cast(1)); + tmp = model * tmp; + tmp = proj * tmp; + + tmp /= tmp.w; + tmp = tmp * static_cast(0.5) + static_cast(0.5); + tmp[0] = tmp[0] * T(viewport[2]) + T(viewport[0]); + tmp[1] = tmp[1] * T(viewport[3]) + T(viewport[1]); + + return vec<3, T, Q>(tmp); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> project(vec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT + return projectZO(obj, model, proj, viewport); +# else + return projectNO(obj, model, proj, viewport); +# endif + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> unProjectZO(vec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport) + { + mat<4, 4, T, Q> Inverse = inverse(proj * model); + + vec<4, T, Q> tmp = vec<4, T, Q>(win, T(1)); + tmp.x = (tmp.x - T(viewport[0])) / T(viewport[2]); + tmp.y = (tmp.y - T(viewport[1])) / T(viewport[3]); + tmp.x = tmp.x * static_cast(2) - static_cast(1); + tmp.y = tmp.y * static_cast(2) - static_cast(1); + + vec<4, T, Q> obj = Inverse * tmp; + obj /= obj.w; + + return vec<3, T, Q>(obj); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> unProjectNO(vec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport) + { + mat<4, 4, T, Q> Inverse = inverse(proj * model); + + vec<4, T, Q> tmp = vec<4, T, Q>(win, T(1)); + tmp.x = (tmp.x - T(viewport[0])) / T(viewport[2]); + tmp.y = (tmp.y - T(viewport[1])) / T(viewport[3]); + tmp = tmp * static_cast(2) - static_cast(1); + + vec<4, T, Q> obj = Inverse * tmp; + obj /= obj.w; + + return vec<3, T, Q>(obj); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> unProject(vec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT + return unProjectZO(win, model, proj, viewport); +# else + return unProjectNO(win, model, proj, viewport); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> pickMatrix(vec<2, T, Q> const& center, vec<2, T, Q> const& delta, vec<4, U, Q> const& viewport) + { + assert(delta.x > static_cast(0) && delta.y > static_cast(0)); + mat<4, 4, T, Q> Result(static_cast(1)); + + if(!(delta.x > static_cast(0) && delta.y > static_cast(0))) + return Result; // Error + + vec<3, T, Q> Temp( + (static_cast(viewport[2]) - static_cast(2) * (center.x - static_cast(viewport[0]))) / delta.x, + (static_cast(viewport[3]) - static_cast(2) * (center.y - static_cast(viewport[1]))) / delta.y, + static_cast(0)); + + // Translate and scale the picked region to the entire window + Result = translate(Result, Temp); + return scale(Result, vec<3, T, Q>(static_cast(viewport[2]) / delta.x, static_cast(viewport[3]) / delta.y, static_cast(1))); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_relational.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_relational.hpp new file mode 100644 index 0000000000000000000000000000000000000000..20023ad89a0ce6fa19b1294212ab78d0dff479b3 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_relational.hpp @@ -0,0 +1,132 @@ +/// @ref ext_matrix_relational +/// @file glm/ext/matrix_relational.hpp +/// +/// @defgroup ext_matrix_relational GLM_EXT_matrix_relational +/// @ingroup ext +/// +/// Exposes comparison functions for matrix types that take a user defined epsilon values. +/// +/// Include to use the features of this extension. +/// +/// @see ext_vector_relational +/// @see ext_scalar_relational +/// @see ext_quaternion_relational + +#pragma once + +// Dependencies +#include "../detail/qualifier.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_relational extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_relational + /// @{ + + /// Perform a component-wise equal-to comparison of two matrices. + /// Return a boolean vector which components value is True if this expression is satisfied per column of the matrices. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix + /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec equal(mat const& x, mat const& y); + + /// Perform a component-wise not-equal-to comparison of two matrices. + /// Return a boolean vector which components value is True if this expression is satisfied per column of the matrices. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix + /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(mat const& x, mat const& y); + + /// Returns the component-wise comparison of |x - y| < epsilon. + /// True if this expression is satisfied. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix + /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec equal(mat const& x, mat const& y, T epsilon); + + /// Returns the component-wise comparison of |x - y| < epsilon. + /// True if this expression is satisfied. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix + /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec equal(mat const& x, mat const& y, vec const& epsilon); + + /// Returns the component-wise comparison of |x - y| < epsilon. + /// True if this expression is not satisfied. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix + /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(mat const& x, mat const& y, T epsilon); + + /// Returns the component-wise comparison of |x - y| >= epsilon. + /// True if this expression is not satisfied. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix + /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(mat const& x, mat const& y, vec const& epsilon); + + /// Returns the component-wise comparison between two vectors in term of ULPs. + /// True if this expression is satisfied. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix + /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec equal(mat const& x, mat const& y, int ULPs); + + /// Returns the component-wise comparison between two vectors in term of ULPs. + /// True if this expression is satisfied. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix + /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec equal(mat const& x, mat const& y, vec const& ULPs); + + /// Returns the component-wise comparison between two vectors in term of ULPs. + /// True if this expression is not satisfied. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix + /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(mat const& x, mat const& y, int ULPs); + + /// Returns the component-wise comparison between two vectors in term of ULPs. + /// True if this expression is not satisfied. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix + /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(mat const& x, mat const& y, vec const& ULPs); + + /// @} +}//namespace glm + +#include "matrix_relational.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_relational.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_relational.inl new file mode 100644 index 0000000000000000000000000000000000000000..9cd42b772b325fe83863058368b0411fee21148c --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_relational.inl @@ -0,0 +1,88 @@ +/// @ref ext_vector_relational +/// @file glm/ext/vector_relational.inl + +// Dependency: +#include "../ext/vector_relational.hpp" +#include "../common.hpp" + +namespace glm +{ + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(mat const& a, mat const& b) + { + vec Result(true); + for(length_t i = 0; i < C; ++i) + Result[i] = all(equal(a[i], b[i])); + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(mat const& a, mat const& b, T Epsilon) + { + return equal(a, b, vec(Epsilon)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(mat const& a, mat const& b, vec const& Epsilon) + { + vec Result(true); + for(length_t i = 0; i < C; ++i) + Result[i] = all(equal(a[i], b[i], Epsilon[i])); + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(mat const& a, mat const& b) + { + vec Result(true); + for(length_t i = 0; i < C; ++i) + Result[i] = any(notEqual(a[i], b[i])); + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(mat const& a, mat const& b, T Epsilon) + { + return notEqual(a, b, vec(Epsilon)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(mat const& a, mat const& b, vec const& Epsilon) + { + vec Result(true); + for(length_t i = 0; i < C; ++i) + Result[i] = any(notEqual(a[i], b[i], Epsilon[i])); + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(mat const& a, mat const& b, int MaxULPs) + { + return equal(a, b, vec(MaxULPs)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(mat const& a, mat const& b, vec const& MaxULPs) + { + vec Result(true); + for(length_t i = 0; i < C; ++i) + Result[i] = all(equal(a[i], b[i], MaxULPs[i])); + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(mat const& a, mat const& b, int MaxULPs) + { + return notEqual(a, b, vec(MaxULPs)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(mat const& a, mat const& b, vec const& MaxULPs) + { + vec Result(true); + for(length_t i = 0; i < C; ++i) + Result[i] = any(notEqual(a[i], b[i], MaxULPs[i])); + return Result; + } + +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_transform.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_transform.hpp new file mode 100644 index 0000000000000000000000000000000000000000..3e688b919bfcf601d1c14c85ea5f78a1b37c9ab3 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_transform.hpp @@ -0,0 +1,171 @@ +/// @ref ext_matrix_transform +/// @file glm/ext/matrix_transform.hpp +/// +/// @defgroup ext_matrix_transform GLM_EXT_matrix_transform +/// @ingroup ext +/// +/// Defines functions that generate common transformation matrices. +/// +/// The matrices generated by this extension use standard OpenGL fixed-function +/// conventions. For example, the lookAt function generates a transform from world +/// space into the specific eye space that the projective matrix functions +/// (perspective, ortho, etc) are designed to expect. The OpenGL compatibility +/// specifications defines the particular layout of this eye space. +/// +/// Include to use the features of this extension. +/// +/// @see ext_matrix_projection +/// @see ext_matrix_clip_space + +#pragma once + +// Dependencies +#include "../gtc/constants.hpp" +#include "../geometric.hpp" +#include "../trigonometric.hpp" +#include "../matrix.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_transform extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_transform + /// @{ + + /// Builds an identity matrix. + template + GLM_FUNC_DECL GLM_CONSTEXPR genType identity(); + + /// Builds a translation 4 * 4 matrix created from a vector of 3 components. + /// + /// @param m Input matrix multiplied by this translation matrix. + /// @param v Coordinates of a translation vector. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + /// + /// @code + /// #include + /// #include + /// ... + /// glm::mat4 m = glm::translate(glm::mat4(1.0f), glm::vec3(1.0f)); + /// // m[0][0] == 1.0f, m[0][1] == 0.0f, m[0][2] == 0.0f, m[0][3] == 0.0f + /// // m[1][0] == 0.0f, m[1][1] == 1.0f, m[1][2] == 0.0f, m[1][3] == 0.0f + /// // m[2][0] == 0.0f, m[2][1] == 0.0f, m[2][2] == 1.0f, m[2][3] == 0.0f + /// // m[3][0] == 1.0f, m[3][1] == 1.0f, m[3][2] == 1.0f, m[3][3] == 1.0f + /// @endcode + /// + /// @see - translate(mat<4, 4, T, Q> const& m, T x, T y, T z) + /// @see - translate(vec<3, T, Q> const& v) + /// @see glTranslate man page + template + GLM_FUNC_DECL mat<4, 4, T, Q> translate( + mat<4, 4, T, Q> const& m, vec<3, T, Q> const& v); + + /// Builds a rotation 4 * 4 matrix created from an axis vector and an angle. + /// + /// @param m Input matrix multiplied by this rotation matrix. + /// @param angle Rotation angle expressed in radians. + /// @param axis Rotation axis, recommended to be normalized. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + /// + /// @see - rotate(mat<4, 4, T, Q> const& m, T angle, T x, T y, T z) + /// @see - rotate(T angle, vec<3, T, Q> const& v) + /// @see glRotate man page + template + GLM_FUNC_DECL mat<4, 4, T, Q> rotate( + mat<4, 4, T, Q> const& m, T angle, vec<3, T, Q> const& axis); + + /// Builds a scale 4 * 4 matrix created from 3 scalars. + /// + /// @param m Input matrix multiplied by this scale matrix. + /// @param v Ratio of scaling for each axis. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + /// + /// @see - scale(mat<4, 4, T, Q> const& m, T x, T y, T z) + /// @see - scale(vec<3, T, Q> const& v) + /// @see glScale man page + template + GLM_FUNC_DECL mat<4, 4, T, Q> scale( + mat<4, 4, T, Q> const& m, vec<3, T, Q> const& v); + + /// Builds a scale 4 * 4 matrix created from point referent 3 shearers. + /// + /// @param m Input matrix multiplied by this shear matrix. + /// @param p Point of shearing as reference. + /// @param l_x Ratio of matrix.x projection in YZ plane relative to the y-axis/z-axis. + /// @param l_y Ratio of matrix.y projection in XZ plane relative to the x-axis/z-axis. + /// @param l_z Ratio of matrix.z projection in XY plane relative to the x-axis/y-axis. + /// + /// as example: + /// [1 , l_xy, l_xz, -(l_xy+l_xz) * p_x] [x] T + /// [x`, y`, z`, w`] = [x`, y`, z`, w`] * [l_yx, 1 , l_yz, -(l_yx+l_yz) * p_y] [y] + /// [l_zx, l_zy, 1 , -(l_zx+l_zy) * p_z] [z] + /// [0 , 0 , 0 , 1 ] [w] + /// + /// @tparam T A floating-point shear type + /// @tparam Q A value from qualifier enum + /// + /// @see - shear(mat<4, 4, T, Q> const& m, T x, T y, T z) + /// @see - shear(vec<3, T, Q> const& p) + /// @see - shear(vec<2, T, Q> const& l_x) + /// @see - shear(vec<2, T, Q> const& l_y) + /// @see - shear(vec<2, T, Q> const& l_z) + /// @see no resource... + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> shear( + mat<4, 4, T, Q> const &m, vec<3, T, Q> const& p, vec<2, T, Q> const &l_x, vec<2, T, Q> const &l_y, vec<2, T, Q> const &l_z); + + /// Build a right handed look at view matrix. + /// + /// @param eye Position of the camera + /// @param center Position where the camera is looking at + /// @param up Normalized up vector, how the camera is oriented. Typically (0, 0, 1) + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + /// + /// @see - frustum(T const& left, T const& right, T const& bottom, T const& top, T const& nearVal, T const& farVal) frustum(T const& left, T const& right, T const& bottom, T const& top, T const& nearVal, T const& farVal) + template + GLM_FUNC_DECL mat<4, 4, T, Q> lookAtRH( + vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up); + + /// Build a left handed look at view matrix. + /// + /// @param eye Position of the camera + /// @param center Position where the camera is looking at + /// @param up Normalized up vector, how the camera is oriented. Typically (0, 0, 1) + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + /// + /// @see - frustum(T const& left, T const& right, T const& bottom, T const& top, T const& nearVal, T const& farVal) frustum(T const& left, T const& right, T const& bottom, T const& top, T const& nearVal, T const& farVal) + template + GLM_FUNC_DECL mat<4, 4, T, Q> lookAtLH( + vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up); + + /// Build a look at view matrix based on the default handedness. + /// + /// @param eye Position of the camera + /// @param center Position where the camera is looking at + /// @param up Normalized up vector, how the camera is oriented. Typically (0, 0, 1) + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + /// + /// @see - frustum(T const& left, T const& right, T const& bottom, T const& top, T const& nearVal, T const& farVal) frustum(T const& left, T const& right, T const& bottom, T const& top, T const& nearVal, T const& farVal) + /// @see gluLookAt man page + template + GLM_FUNC_DECL mat<4, 4, T, Q> lookAt( + vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up); + + /// @} +}//namespace glm + +#include "matrix_transform.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_transform.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_transform.inl new file mode 100644 index 0000000000000000000000000000000000000000..ef2e9f348396e2cda4ca2a55ea7bf276a876f976 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_transform.inl @@ -0,0 +1,207 @@ +namespace glm +{ + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType identity() + { + return detail::init_gentype::GENTYPE>::identity(); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> translate(mat<4, 4, T, Q> const& m, vec<3, T, Q> const& v) + { + mat<4, 4, T, Q> Result(m); + Result[3] = m[0] * v[0] + m[1] * v[1] + m[2] * v[2] + m[3]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> rotate(mat<4, 4, T, Q> const& m, T angle, vec<3, T, Q> const& v) + { + T const a = angle; + T const c = cos(a); + T const s = sin(a); + + vec<3, T, Q> axis(normalize(v)); + vec<3, T, Q> temp((T(1) - c) * axis); + + mat<4, 4, T, Q> Rotate; + Rotate[0][0] = c + temp[0] * axis[0]; + Rotate[0][1] = temp[0] * axis[1] + s * axis[2]; + Rotate[0][2] = temp[0] * axis[2] - s * axis[1]; + + Rotate[1][0] = temp[1] * axis[0] - s * axis[2]; + Rotate[1][1] = c + temp[1] * axis[1]; + Rotate[1][2] = temp[1] * axis[2] + s * axis[0]; + + Rotate[2][0] = temp[2] * axis[0] + s * axis[1]; + Rotate[2][1] = temp[2] * axis[1] - s * axis[0]; + Rotate[2][2] = c + temp[2] * axis[2]; + + mat<4, 4, T, Q> Result; + Result[0] = m[0] * Rotate[0][0] + m[1] * Rotate[0][1] + m[2] * Rotate[0][2]; + Result[1] = m[0] * Rotate[1][0] + m[1] * Rotate[1][1] + m[2] * Rotate[1][2]; + Result[2] = m[0] * Rotate[2][0] + m[1] * Rotate[2][1] + m[2] * Rotate[2][2]; + Result[3] = m[3]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> rotate_slow(mat<4, 4, T, Q> const& m, T angle, vec<3, T, Q> const& v) + { + T const a = angle; + T const c = cos(a); + T const s = sin(a); + mat<4, 4, T, Q> Result; + + vec<3, T, Q> axis = normalize(v); + + Result[0][0] = c + (static_cast(1) - c) * axis.x * axis.x; + Result[0][1] = (static_cast(1) - c) * axis.x * axis.y + s * axis.z; + Result[0][2] = (static_cast(1) - c) * axis.x * axis.z - s * axis.y; + Result[0][3] = static_cast(0); + + Result[1][0] = (static_cast(1) - c) * axis.y * axis.x - s * axis.z; + Result[1][1] = c + (static_cast(1) - c) * axis.y * axis.y; + Result[1][2] = (static_cast(1) - c) * axis.y * axis.z + s * axis.x; + Result[1][3] = static_cast(0); + + Result[2][0] = (static_cast(1) - c) * axis.z * axis.x + s * axis.y; + Result[2][1] = (static_cast(1) - c) * axis.z * axis.y - s * axis.x; + Result[2][2] = c + (static_cast(1) - c) * axis.z * axis.z; + Result[2][3] = static_cast(0); + + Result[3] = vec<4, T, Q>(0, 0, 0, 1); + return m * Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> scale(mat<4, 4, T, Q> const& m, vec<3, T, Q> const& v) + { + mat<4, 4, T, Q> Result; + Result[0] = m[0] * v[0]; + Result[1] = m[1] * v[1]; + Result[2] = m[2] * v[2]; + Result[3] = m[3]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> scale_slow(mat<4, 4, T, Q> const& m, vec<3, T, Q> const& v) + { + mat<4, 4, T, Q> Result(T(1)); + Result[0][0] = v.x; + Result[1][1] = v.y; + Result[2][2] = v.z; + return m * Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> shear(mat<4, 4, T, Q> const &m, vec<3, T, Q> const& p, vec<2, T, Q> const &l_x, vec<2, T, Q> const &l_y, vec<2, T, Q> const &l_z) + { + T const lambda_xy = l_x[0]; + T const lambda_xz = l_x[1]; + T const lambda_yx = l_y[0]; + T const lambda_yz = l_y[1]; + T const lambda_zx = l_z[0]; + T const lambda_zy = l_z[1]; + + vec<3, T, Q> point_lambda = vec<3, T, Q>( + (lambda_xy + lambda_xz), (lambda_yx + lambda_yz), (lambda_zx + lambda_zy) + ); + + mat<4, 4, T, Q> Shear = mat<4, 4, T, Q>( + 1 , lambda_yx , lambda_zx , 0, + lambda_xy , 1 , lambda_zy , 0, + lambda_xz , lambda_yz , 1 , 0, + -point_lambda[0] * p[0], -point_lambda[1] * p[1], -point_lambda[2] * p[2], 1 + ); + + mat<4, 4, T, Q> Result; + Result[0] = Shear[0] * m[0][0] + Shear[1] * m[0][1] + Shear[2] * m[0][2] + Shear[3] * m[0][3]; + Result[1] = Shear[0] * m[1][0] + Shear[1] * m[1][1] + Shear[2] * m[1][2] + Shear[3] * m[1][3]; + Result[2] = Shear[0] * m[2][0] + Shear[1] * m[2][1] + Shear[2] * m[2][2] + Shear[3] * m[2][3]; + Result[3] = Shear[0] * m[3][0] + Shear[1] * m[3][1] + Shear[2] * m[3][2] + Shear[3] * m[3][3]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> shear_slow(mat<4, 4, T, Q> const &m, vec<3, T, Q> const& p, vec<2, T, Q> const &l_x, vec<2, T, Q> const &l_y, vec<2, T, Q> const &l_z) + { + T const lambda_xy = static_cast(l_x[0]); + T const lambda_xz = static_cast(l_x[1]); + T const lambda_yx = static_cast(l_y[0]); + T const lambda_yz = static_cast(l_y[1]); + T const lambda_zx = static_cast(l_z[0]); + T const lambda_zy = static_cast(l_z[1]); + + vec<3, T, Q> point_lambda = vec<3, T, Q>( + static_cast(lambda_xy + lambda_xz), + static_cast(lambda_yx + lambda_yz), + static_cast(lambda_zx + lambda_zy) + ); + + mat<4, 4, T, Q> Shear = mat<4, 4, T, Q>( + 1 , lambda_yx , lambda_zx , 0, + lambda_xy , 1 , lambda_zy , 0, + lambda_xz , lambda_yz , 1 , 0, + -point_lambda[0] * p[0], -point_lambda[1] * p[1], -point_lambda[2] * p[2], 1 + ); + return m * Shear; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> lookAtRH(vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up) + { + vec<3, T, Q> const f(normalize(center - eye)); + vec<3, T, Q> const s(normalize(cross(f, up))); + vec<3, T, Q> const u(cross(s, f)); + + mat<4, 4, T, Q> Result(1); + Result[0][0] = s.x; + Result[1][0] = s.y; + Result[2][0] = s.z; + Result[0][1] = u.x; + Result[1][1] = u.y; + Result[2][1] = u.z; + Result[0][2] =-f.x; + Result[1][2] =-f.y; + Result[2][2] =-f.z; + Result[3][0] =-dot(s, eye); + Result[3][1] =-dot(u, eye); + Result[3][2] = dot(f, eye); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> lookAtLH(vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up) + { + vec<3, T, Q> const f(normalize(center - eye)); + vec<3, T, Q> const s(normalize(cross(up, f))); + vec<3, T, Q> const u(cross(f, s)); + + mat<4, 4, T, Q> Result(1); + Result[0][0] = s.x; + Result[1][0] = s.y; + Result[2][0] = s.z; + Result[0][1] = u.x; + Result[1][1] = u.y; + Result[2][1] = u.z; + Result[0][2] = f.x; + Result[1][2] = f.y; + Result[2][2] = f.z; + Result[3][0] = -dot(s, eye); + Result[3][1] = -dot(u, eye); + Result[3][2] = -dot(f, eye); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> lookAt(vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up) + { +# if (GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT) + return lookAtLH(eye, center, up); +# else + return lookAtRH(eye, center, up); +# endif + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint2x2.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint2x2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..034771ae52256fd2d94ce0b7a3dd6eaf4b23a386 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint2x2.hpp @@ -0,0 +1,38 @@ +/// @ref ext_matrix_uint2x2 +/// @file glm/ext/matrix_uint2x2.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_uint2x2 GLM_EXT_matrix_uint2x2 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat2x2.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint2x2 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint2x2 + /// @{ + + /// Unsigned integer 2x2 matrix. + /// + /// @see ext_matrix_uint2x2 + typedef mat<2, 2, uint, defaultp> umat2x2; + + /// Unsigned integer 2x2 matrix. + /// + /// @see ext_matrix_uint2x2 + typedef mat<2, 2, uint, defaultp> umat2; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint2x2_sized.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint2x2_sized.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4555324d2b52e140cc5392487ef123d2f6408e58 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint2x2_sized.hpp @@ -0,0 +1,70 @@ +/// @ref ext_matrix_uint2x2_sized +/// @file glm/ext/matrix_uint2x2_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_uint2x2_sized GLM_EXT_matrix_uint2x2_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat2x2.hpp" +#include "../ext/scalar_uint_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint2x2_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint2x2_sized + /// @{ + + /// 8 bit unsigned integer 2x2 matrix. + /// + /// @see ext_matrix_uint2x2_sized + typedef mat<2, 2, uint8, defaultp> u8mat2x2; + + /// 16 bit unsigned integer 2x2 matrix. + /// + /// @see ext_matrix_uint2x2_sized + typedef mat<2, 2, uint16, defaultp> u16mat2x2; + + /// 32 bit unsigned integer 2x2 matrix. + /// + /// @see ext_matrix_uint2x2_sized + typedef mat<2, 2, uint32, defaultp> u32mat2x2; + + /// 64 bit unsigned integer 2x2 matrix. + /// + /// @see ext_matrix_uint2x2_sized + typedef mat<2, 2, uint64, defaultp> u64mat2x2; + + + /// 8 bit unsigned integer 2x2 matrix. + /// + /// @see ext_matrix_uint2x2_sized + typedef mat<2, 2, uint8, defaultp> u8mat2; + + /// 16 bit unsigned integer 2x2 matrix. + /// + /// @see ext_matrix_uint2x2_sized + typedef mat<2, 2, uint16, defaultp> u16mat2; + + /// 32 bit unsigned integer 2x2 matrix. + /// + /// @see ext_matrix_uint2x2_sized + typedef mat<2, 2, uint32, defaultp> u32mat2; + + /// 64 bit unsigned integer 2x2 matrix. + /// + /// @see ext_matrix_uint2x2_sized + typedef mat<2, 2, uint64, defaultp> u64mat2; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint2x3.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint2x3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f496c531a0b8b68577c5d0f5066d9032fc4b2bc8 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint2x3.hpp @@ -0,0 +1,33 @@ +/// @ref ext_matrix_uint2x3 +/// @file glm/ext/matrix_uint2x3.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_uint2x3 GLM_EXT_matrix_uint2x3 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat2x3.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint2x3 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint2x3 + /// @{ + + /// Unsigned integer 2x3 matrix. + /// + /// @see ext_matrix_uint2x3 + typedef mat<2, 3, uint, defaultp> umat2x3; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint2x3_sized.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint2x3_sized.hpp new file mode 100644 index 0000000000000000000000000000000000000000..db7939c94658de2277b2af422a1ba0642228588c --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint2x3_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_matrix_uint2x3_sized +/// @file glm/ext/matrix_uint2x3_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_uint2x3_sized GLM_EXT_matrix_uint2x3_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat2x3.hpp" +#include "../ext/scalar_uint_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint2x3_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint2x3_sized + /// @{ + + /// 8 bit unsigned integer 2x3 matrix. + /// + /// @see ext_matrix_uint2x3_sized + typedef mat<2, 3, uint8, defaultp> u8mat2x3; + + /// 16 bit unsigned integer 2x3 matrix. + /// + /// @see ext_matrix_uint2x3_sized + typedef mat<2, 3, uint16, defaultp> u16mat2x3; + + /// 32 bit unsigned integer 2x3 matrix. + /// + /// @see ext_matrix_uint2x3_sized + typedef mat<2, 3, uint32, defaultp> u32mat2x3; + + /// 64 bit unsigned integer 2x3 matrix. + /// + /// @see ext_matrix_uint2x3_sized + typedef mat<2, 3, uint64, defaultp> u64mat2x3; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint2x4.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint2x4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0f993509c23b271d2230ef8d7fbd2c007ac1980b --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint2x4.hpp @@ -0,0 +1,33 @@ +/// @ref ext_matrix_uint2x4 +/// @file glm/ext/matrix_uint2x4.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_uint2x4 GLM_EXT_matrix_int2x4 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat2x4.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint2x4 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint2x4 + /// @{ + + /// Unsigned integer 2x4 matrix. + /// + /// @see ext_matrix_uint2x4 + typedef mat<2, 4, uint, defaultp> umat2x4; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint2x4_sized.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint2x4_sized.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5c55547ff76a54d6b8ff63d3bd21163eff4e3eb0 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint2x4_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_matrix_uint2x4_sized +/// @file glm/ext/matrix_uint2x4_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_uint2x4_sized GLM_EXT_matrix_uint2x4_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat2x4.hpp" +#include "../ext/scalar_uint_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint2x4_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint2x4_sized + /// @{ + + /// 8 bit unsigned integer 2x4 matrix. + /// + /// @see ext_matrix_uint2x4_sized + typedef mat<2, 4, uint8, defaultp> u8mat2x4; + + /// 16 bit unsigned integer 2x4 matrix. + /// + /// @see ext_matrix_uint2x4_sized + typedef mat<2, 4, uint16, defaultp> u16mat2x4; + + /// 32 bit unsigned integer 2x4 matrix. + /// + /// @see ext_matrix_uint2x4_sized + typedef mat<2, 4, uint32, defaultp> u32mat2x4; + + /// 64 bit unsigned integer 2x4 matrix. + /// + /// @see ext_matrix_uint2x4_sized + typedef mat<2, 4, uint64, defaultp> u64mat2x4; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint3x2.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint3x2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..55a9bed688e92d0e0815fb12f7c32816e5895a00 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint3x2.hpp @@ -0,0 +1,33 @@ +/// @ref ext_matrix_uint3x2 +/// @file glm/ext/matrix_uint3x2.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_uint3x2 GLM_EXT_matrix_uint3x2 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat3x2.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint3x2 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint3x2 + /// @{ + + /// Unsigned integer 3x2 matrix. + /// + /// @see ext_matrix_uint3x2 + typedef mat<3, 2, uint, defaultp> umat3x2; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint3x2_sized.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint3x2_sized.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c81af8f968d6ee45a13295915a8f6b220f77b9cf --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint3x2_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_matrix_uint3x2_sized +/// @file glm/ext/matrix_uint3x2_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_uint3x2_sized GLM_EXT_matrix_uint3x2_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat3x2.hpp" +#include "../ext/scalar_uint_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint3x2_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint3x2_sized + /// @{ + + /// 8 bit signed integer 3x2 matrix. + /// + /// @see ext_matrix_uint3x2_sized + typedef mat<3, 2, uint8, defaultp> u8mat3x2; + + /// 16 bit signed integer 3x2 matrix. + /// + /// @see ext_matrix_uint3x2_sized + typedef mat<3, 2, uint16, defaultp> u16mat3x2; + + /// 32 bit signed integer 3x2 matrix. + /// + /// @see ext_matrix_uint3x2_sized + typedef mat<3, 2, uint32, defaultp> u32mat3x2; + + /// 64 bit signed integer 3x2 matrix. + /// + /// @see ext_matrix_uint3x2_sized + typedef mat<3, 2, uint64, defaultp> u64mat3x2; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint3x3.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint3x3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1004c0d2d541a9fd796b28a7b9b93054776a4ab1 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint3x3.hpp @@ -0,0 +1,38 @@ +/// @ref ext_matrix_uint3x3 +/// @file glm/ext/matrix_uint3x3.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_uint3x3 GLM_EXT_matrix_uint3x3 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat3x3.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint3x3 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint3x3 + /// @{ + + /// Unsigned integer 3x3 matrix. + /// + /// @see ext_matrix_uint3x3 + typedef mat<3, 3, uint, defaultp> umat3x3; + + /// Unsigned integer 3x3 matrix. + /// + /// @see ext_matrix_uint3x3 + typedef mat<3, 3, uint, defaultp> umat3; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint3x3_sized.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint3x3_sized.hpp new file mode 100644 index 0000000000000000000000000000000000000000..41a8be748660fdf568608baa724bea58c6fe2814 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint3x3_sized.hpp @@ -0,0 +1,70 @@ +/// @ref ext_matrix_uint3x3_sized +/// @file glm/ext/matrix_uint3x3_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_uint3x3_sized GLM_EXT_matrix_uint3x3_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat3x3.hpp" +#include "../ext/scalar_uint_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint3x3_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint3x3_sized + /// @{ + + /// 8 bit unsigned integer 3x3 matrix. + /// + /// @see ext_matrix_uint3x3_sized + typedef mat<3, 3, uint8, defaultp> u8mat3x3; + + /// 16 bit unsigned integer 3x3 matrix. + /// + /// @see ext_matrix_uint3x3_sized + typedef mat<3, 3, uint16, defaultp> u16mat3x3; + + /// 32 bit unsigned integer 3x3 matrix. + /// + /// @see ext_matrix_uint3x3_sized + typedef mat<3, 3, uint32, defaultp> u32mat3x3; + + /// 64 bit unsigned integer 3x3 matrix. + /// + /// @see ext_matrix_uint3x3_sized + typedef mat<3, 3, uint64, defaultp> u64mat3x3; + + + /// 8 bit unsigned integer 3x3 matrix. + /// + /// @see ext_matrix_uint3x3_sized + typedef mat<3, 3, uint8, defaultp> u8mat3; + + /// 16 bit unsigned integer 3x3 matrix. + /// + /// @see ext_matrix_uint3x3_sized + typedef mat<3, 3, uint16, defaultp> u16mat3; + + /// 32 bit unsigned integer 3x3 matrix. + /// + /// @see ext_matrix_uint3x3_sized + typedef mat<3, 3, uint32, defaultp> u32mat3; + + /// 64 bit unsigned integer 3x3 matrix. + /// + /// @see ext_matrix_uint3x3_sized + typedef mat<3, 3, uint64, defaultp> u64mat3; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint3x4.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint3x4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c6dd78c4a0535b21d30aec53ce1e93ec5b05496a --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint3x4.hpp @@ -0,0 +1,33 @@ +/// @ref ext_matrix_uint3x4 +/// @file glm/ext/matrix_uint3x4.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_uint3x4 GLM_EXT_matrix_uint3x4 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat3x4.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint3x4 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint3x4 + /// @{ + + /// Signed integer 3x4 matrix. + /// + /// @see ext_matrix_uint3x4 + typedef mat<3, 4, uint, defaultp> umat3x4; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint3x4_sized.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint3x4_sized.hpp new file mode 100644 index 0000000000000000000000000000000000000000..2ce28ad816fc03f1ba82c80860f2c95d57b83d3c --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint3x4_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_matrix_uint3x4_sized +/// @file glm/ext/matrix_uint3x2_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_uint3x4_sized GLM_EXT_matrix_uint3x4_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat3x4.hpp" +#include "../ext/scalar_uint_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint3x4_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint3x4_sized + /// @{ + + /// 8 bit unsigned integer 3x4 matrix. + /// + /// @see ext_matrix_uint3x4_sized + typedef mat<3, 4, uint8, defaultp> u8mat3x4; + + /// 16 bit unsigned integer 3x4 matrix. + /// + /// @see ext_matrix_uint3x4_sized + typedef mat<3, 4, uint16, defaultp> u16mat3x4; + + /// 32 bit unsigned integer 3x4 matrix. + /// + /// @see ext_matrix_uint3x4_sized + typedef mat<3, 4, uint32, defaultp> u32mat3x4; + + /// 64 bit unsigned integer 3x4 matrix. + /// + /// @see ext_matrix_uint3x4_sized + typedef mat<3, 4, uint64, defaultp> u64mat3x4; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint4x2.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint4x2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0446f5745bdeb7b6999ab7d8c5461b1cc739a61a --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint4x2.hpp @@ -0,0 +1,33 @@ +/// @ref ext_matrix_uint4x2 +/// @file glm/ext/matrix_uint4x2.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_uint4x2 GLM_EXT_matrix_uint4x2 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat4x2.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint4x2 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint4x2 + /// @{ + + /// Unsigned integer 4x2 matrix. + /// + /// @see ext_matrix_uint4x2 + typedef mat<4, 2, uint, defaultp> umat4x2; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint4x2_sized.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint4x2_sized.hpp new file mode 100644 index 0000000000000000000000000000000000000000..57a66bf9b8b0c52b7a7564b7ce47660c08cdfc57 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint4x2_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_matrix_uint4x2_sized +/// @file glm/ext/matrix_uint4x2_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_uint4x2_sized GLM_EXT_matrix_uint4x2_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat4x2.hpp" +#include "../ext/scalar_uint_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint4x2_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint4x2_sized + /// @{ + + /// 8 bit unsigned integer 4x2 matrix. + /// + /// @see ext_matrix_uint4x2_sized + typedef mat<4, 2, uint8, defaultp> u8mat4x2; + + /// 16 bit unsigned integer 4x2 matrix. + /// + /// @see ext_matrix_uint4x2_sized + typedef mat<4, 2, uint16, defaultp> u16mat4x2; + + /// 32 bit unsigned integer 4x2 matrix. + /// + /// @see ext_matrix_uint4x2_sized + typedef mat<4, 2, uint32, defaultp> u32mat4x2; + + /// 64 bit unsigned integer 4x2 matrix. + /// + /// @see ext_matrix_uint4x2_sized + typedef mat<4, 2, uint64, defaultp> u64mat4x2; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint4x3.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint4x3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..54c24e4e50b170328e881753c9d8537ca9630605 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint4x3.hpp @@ -0,0 +1,33 @@ +/// @ref ext_matrix_uint4x3 +/// @file glm/ext/matrix_uint4x3.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_uint4x3 GLM_EXT_matrix_uint4x3 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat4x3.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint4x3 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint4x3 + /// @{ + + /// Unsigned integer 4x3 matrix. + /// + /// @see ext_matrix_uint4x3 + typedef mat<4, 3, uint, defaultp> umat4x3; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint4x3_sized.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint4x3_sized.hpp new file mode 100644 index 0000000000000000000000000000000000000000..2e61124d63b47e6361e47b38249ca48a9070f266 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint4x3_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_matrix_uint4x3_sized +/// @file glm/ext/matrix_uint4x3_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_uint4x3_sized GLM_EXT_matrix_uint4x3_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat4x3.hpp" +#include "../ext/scalar_uint_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint4x3_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint4x3_sized + /// @{ + + /// 8 bit unsigned integer 4x3 matrix. + /// + /// @see ext_matrix_uint4x3_sized + typedef mat<4, 3, uint8, defaultp> u8mat4x3; + + /// 16 bit unsigned integer 4x3 matrix. + /// + /// @see ext_matrix_uint4x3_sized + typedef mat<4, 3, uint16, defaultp> u16mat4x3; + + /// 32 bit unsigned integer 4x3 matrix. + /// + /// @see ext_matrix_uint4x3_sized + typedef mat<4, 3, uint32, defaultp> u32mat4x3; + + /// 64 bit unsigned integer 4x3 matrix. + /// + /// @see ext_matrix_uint4x3_sized + typedef mat<4, 3, uint64, defaultp> u64mat4x3; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint4x4.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint4x4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5cc84553d9366c8a621a9a67a3b28d15ba5e70de --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint4x4.hpp @@ -0,0 +1,38 @@ +/// @ref ext_matrix_uint4x4 +/// @file glm/ext/matrix_uint4x4.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_uint4x4 GLM_EXT_matrix_uint4x4 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat4x4.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint4x4 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint4x4 + /// @{ + + /// Unsigned integer 4x4 matrix. + /// + /// @see ext_matrix_uint4x4 + typedef mat<4, 4, uint, defaultp> umat4x4; + + /// Unsigned integer 4x4 matrix. + /// + /// @see ext_matrix_uint4x4 + typedef mat<4, 4, uint, defaultp> umat4; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint4x4_sized.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint4x4_sized.hpp new file mode 100644 index 0000000000000000000000000000000000000000..bb10bd2b77d1212949e084fa0aae5abc9647c89c --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/matrix_uint4x4_sized.hpp @@ -0,0 +1,70 @@ +/// @ref ext_matrix_uint4x4_sized +/// @file glm/ext/matrix_uint4x4_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_uint4x4_sized GLM_EXT_matrix_uint4x4_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat4x4.hpp" +#include "../ext/scalar_uint_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint4x4_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint4x4_sized + /// @{ + + /// 8 bit unsigned integer 4x4 matrix. + /// + /// @see ext_matrix_uint4x4_sized + typedef mat<4, 4, uint8, defaultp> u8mat4x4; + + /// 16 bit unsigned integer 4x4 matrix. + /// + /// @see ext_matrix_uint4x4_sized + typedef mat<4, 4, uint16, defaultp> u16mat4x4; + + /// 32 bit unsigned integer 4x4 matrix. + /// + /// @see ext_matrix_uint4x4_sized + typedef mat<4, 4, uint32, defaultp> u32mat4x4; + + /// 64 bit unsigned integer 4x4 matrix. + /// + /// @see ext_matrix_uint4x4_sized + typedef mat<4, 4, uint64, defaultp> u64mat4x4; + + + /// 8 bit unsigned integer 4x4 matrix. + /// + /// @see ext_matrix_uint4x4_sized + typedef mat<4, 4, uint8, defaultp> u8mat4; + + /// 16 bit unsigned integer 4x4 matrix. + /// + /// @see ext_matrix_uint4x4_sized + typedef mat<4, 4, uint16, defaultp> u16mat4; + + /// 32 bit unsigned integer 4x4 matrix. + /// + /// @see ext_matrix_uint4x4_sized + typedef mat<4, 4, uint32, defaultp> u32mat4; + + /// 64 bit unsigned integer 4x4 matrix. + /// + /// @see ext_matrix_uint4x4_sized + typedef mat<4, 4, uint64, defaultp> u64mat4; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_common.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_common.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f519d5591852ece21c1dc90bfdd3c26164fad030 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_common.hpp @@ -0,0 +1,135 @@ +/// @ref ext_quaternion_common +/// @file glm/ext/quaternion_common.hpp +/// +/// @defgroup ext_quaternion_common GLM_EXT_quaternion_common +/// @ingroup ext +/// +/// Provides common functions for quaternion types +/// +/// Include to use the features of this extension. +/// +/// @see ext_scalar_common +/// @see ext_vector_common +/// @see ext_quaternion_float +/// @see ext_quaternion_double +/// @see ext_quaternion_exponential +/// @see ext_quaternion_geometric +/// @see ext_quaternion_relational +/// @see ext_quaternion_trigonometric +/// @see ext_quaternion_transform + +#pragma once + +// Dependency: +#include "../ext/scalar_constants.hpp" +#include "../ext/quaternion_geometric.hpp" +#include "../common.hpp" +#include "../trigonometric.hpp" +#include "../exponential.hpp" +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_quaternion_common extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_quaternion_common + /// @{ + + /// Spherical linear interpolation of two quaternions. + /// The interpolation is oriented and the rotation is performed at constant speed. + /// For short path spherical linear interpolation, use the slerp function. + /// + /// @param x A quaternion + /// @param y A quaternion + /// @param a Interpolation factor. The interpolation is defined beyond the range [0, 1]. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + /// + /// @see - slerp(qua const& x, qua const& y, T const& a) + template + GLM_FUNC_DECL qua mix(qua const& x, qua const& y, T a); + + /// Linear interpolation of two quaternions. + /// The interpolation is oriented. + /// + /// @param x A quaternion + /// @param y A quaternion + /// @param a Interpolation factor. The interpolation is defined in the range [0, 1]. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL qua lerp(qua const& x, qua const& y, T a); + + /// Spherical linear interpolation of two quaternions. + /// The interpolation always take the short path and the rotation is performed at constant speed. + /// + /// @param x A quaternion + /// @param y A quaternion + /// @param a Interpolation factor. The interpolation is defined beyond the range [0, 1]. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL qua slerp(qua const& x, qua const& y, T a); + + /// Spherical linear interpolation of two quaternions with multiple spins over rotation axis. + /// The interpolation always take the short path when the spin count is positive and long path + /// when count is negative. Rotation is performed at constant speed. + /// + /// @param x A quaternion + /// @param y A quaternion + /// @param a Interpolation factor. The interpolation is defined beyond the range [0, 1]. + /// @param k Additional spin count. If Value is negative interpolation will be on "long" path. + /// + /// @tparam T A floating-point scalar type + /// @tparam S An integer scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL qua slerp(qua const& x, qua const& y, T a, S k); + + /// Returns the q conjugate. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL qua conjugate(qua const& q); + + /// Returns the q inverse. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL qua inverse(qua const& q); + + /// Returns true if x holds a NaN (not a number) + /// representation in the underlying implementation's set of + /// floating point representations. Returns false otherwise, + /// including for implementations with no NaN + /// representations. + /// + /// /!\ When using compiler fast math, this function may fail. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL vec<4, bool, Q> isnan(qua const& x); + + /// Returns true if x holds a positive infinity or negative + /// infinity representation in the underlying implementation's + /// set of floating point representations. Returns false + /// otherwise, including for implementations with no infinity + /// representations. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL vec<4, bool, Q> isinf(qua const& x); + + /// @} +} //namespace glm + +#include "quaternion_common.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_common.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_common.inl new file mode 100644 index 0000000000000000000000000000000000000000..0e4a3bb2a3ccbdd1fc8faeb809a07fe35ad4c1a3 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_common.inl @@ -0,0 +1,144 @@ +namespace glm +{ + template + GLM_FUNC_QUALIFIER qua mix(qua const& x, qua const& y, T a) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'mix' only accept floating-point inputs"); + + T const cosTheta = dot(x, y); + + // Perform a linear interpolation when cosTheta is close to 1 to avoid side effect of sin(angle) becoming a zero denominator + if(cosTheta > static_cast(1) - epsilon()) + { + // Linear interpolation + return qua( + mix(x.w, y.w, a), + mix(x.x, y.x, a), + mix(x.y, y.y, a), + mix(x.z, y.z, a)); + } + else + { + // Essential Mathematics, page 467 + T angle = acos(cosTheta); + return (sin((static_cast(1) - a) * angle) * x + sin(a * angle) * y) / sin(angle); + } + } + + template + GLM_FUNC_QUALIFIER qua lerp(qua const& x, qua const& y, T a) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'lerp' only accept floating-point inputs"); + + // Lerp is only defined in [0, 1] + assert(a >= static_cast(0)); + assert(a <= static_cast(1)); + + return x * (static_cast(1) - a) + (y * a); + } + + template + GLM_FUNC_QUALIFIER qua slerp(qua const& x, qua const& y, T a) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'slerp' only accept floating-point inputs"); + + qua z = y; + + T cosTheta = dot(x, y); + + // If cosTheta < 0, the interpolation will take the long way around the sphere. + // To fix this, one quat must be negated. + if(cosTheta < static_cast(0)) + { + z = -y; + cosTheta = -cosTheta; + } + + // Perform a linear interpolation when cosTheta is close to 1 to avoid side effect of sin(angle) becoming a zero denominator + if(cosTheta > static_cast(1) - epsilon()) + { + // Linear interpolation + return qua( + mix(x.w, z.w, a), + mix(x.x, z.x, a), + mix(x.y, z.y, a), + mix(x.z, z.z, a)); + } + else + { + // Essential Mathematics, page 467 + T angle = acos(cosTheta); + return (sin((static_cast(1) - a) * angle) * x + sin(a * angle) * z) / sin(angle); + } + } + + template + GLM_FUNC_QUALIFIER qua slerp(qua const& x, qua const& y, T a, S k) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'slerp' only accept floating-point inputs"); + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'slerp' only accept integer for spin count"); + + qua z = y; + + T cosTheta = dot(x, y); + + // If cosTheta < 0, the interpolation will take the long way around the sphere. + // To fix this, one quat must be negated. + if (cosTheta < static_cast(0)) + { + z = -y; + cosTheta = -cosTheta; + } + + // Perform a linear interpolation when cosTheta is close to 1 to avoid side effect of sin(angle) becoming a zero denominator + if (cosTheta > static_cast(1) - epsilon()) + { + // Linear interpolation + return qua( + mix(x.w, z.w, a), + mix(x.x, z.x, a), + mix(x.y, z.y, a), + mix(x.z, z.z, a)); + } + else + { + // Graphics Gems III, page 96 + T angle = acos(cosTheta); + T phi = angle + k * glm::pi(); + return (sin(angle - a * phi)* x + sin(a * phi) * z) / sin(angle); + } + } + + template + GLM_FUNC_QUALIFIER qua conjugate(qua const& q) + { + return qua(q.w, -q.x, -q.y, -q.z); + } + + template + GLM_FUNC_QUALIFIER qua inverse(qua const& q) + { + return conjugate(q) / dot(q, q); + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> isnan(qua const& q) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isnan' only accept floating-point inputs"); + + return vec<4, bool, Q>(isnan(q.x), isnan(q.y), isnan(q.z), isnan(q.w)); + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> isinf(qua const& q) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isinf' only accept floating-point inputs"); + + return vec<4, bool, Q>(isinf(q.x), isinf(q.y), isinf(q.z), isinf(q.w)); + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "quaternion_common_simd.inl" +#endif + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_common_simd.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_common_simd.inl new file mode 100644 index 0000000000000000000000000000000000000000..ddfc8a44f6a32774ff092201bc9ee2fd2a11b80b --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_common_simd.inl @@ -0,0 +1,18 @@ +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +namespace glm{ +namespace detail +{ + template + struct compute_dot, float, true> + { + static GLM_FUNC_QUALIFIER float call(qua const& x, qua const& y) + { + return _mm_cvtss_f32(glm_vec1_dot(x.data, y.data)); + } + }; +}//namespace detail +}//namespace glm + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_double.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_double.hpp new file mode 100644 index 0000000000000000000000000000000000000000..63b24de4d52afb415cdaf8a8077cbb95e5a01d90 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_double.hpp @@ -0,0 +1,39 @@ +/// @ref ext_quaternion_double +/// @file glm/ext/quaternion_double.hpp +/// +/// @defgroup ext_quaternion_double GLM_EXT_quaternion_double +/// @ingroup ext +/// +/// Exposes double-precision floating point quaternion type. +/// +/// Include to use the features of this extension. +/// +/// @see ext_quaternion_float +/// @see ext_quaternion_double_precision +/// @see ext_quaternion_common +/// @see ext_quaternion_exponential +/// @see ext_quaternion_geometric +/// @see ext_quaternion_relational +/// @see ext_quaternion_transform +/// @see ext_quaternion_trigonometric + +#pragma once + +// Dependency: +#include "../detail/type_quat.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_quaternion_double extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_quaternion_double + /// @{ + + /// Quaternion of double-precision floating-point numbers. + typedef qua dquat; + + /// @} +} //namespace glm + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_double_precision.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_double_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8aa24a17752dfd04aa05bc80ff179c0b02d58fbb --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_double_precision.hpp @@ -0,0 +1,42 @@ +/// @ref ext_quaternion_double_precision +/// @file glm/ext/quaternion_double_precision.hpp +/// +/// @defgroup ext_quaternion_double_precision GLM_EXT_quaternion_double_precision +/// @ingroup ext +/// +/// Exposes double-precision floating point quaternion type with various precision in term of ULPs. +/// +/// Include to use the features of this extension. + +#pragma once + +// Dependency: +#include "../detail/type_quat.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_quaternion_double_precision extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_quaternion_double_precision + /// @{ + + /// Quaternion of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see ext_quaternion_double_precision + typedef qua lowp_dquat; + + /// Quaternion of medium double-qualifier floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see ext_quaternion_double_precision + typedef qua mediump_dquat; + + /// Quaternion of high double-qualifier floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see ext_quaternion_double_precision + typedef qua highp_dquat; + + /// @} +} //namespace glm + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_exponential.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_exponential.hpp new file mode 100644 index 0000000000000000000000000000000000000000..affe2979aad5bcc7a475d8293bab6421ae0c7bba --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_exponential.hpp @@ -0,0 +1,63 @@ +/// @ref ext_quaternion_exponential +/// @file glm/ext/quaternion_exponential.hpp +/// +/// @defgroup ext_quaternion_exponential GLM_EXT_quaternion_exponential +/// @ingroup ext +/// +/// Provides exponential functions for quaternion types +/// +/// Include to use the features of this extension. +/// +/// @see core_exponential +/// @see ext_quaternion_float +/// @see ext_quaternion_double + +#pragma once + +// Dependency: +#include "../common.hpp" +#include "../trigonometric.hpp" +#include "../geometric.hpp" +#include "../ext/scalar_constants.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_quaternion_exponential extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_quaternion_transform + /// @{ + + /// Returns a exponential of a quaternion. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL qua exp(qua const& q); + + /// Returns a logarithm of a quaternion + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL qua log(qua const& q); + + /// Returns a quaternion raised to a power. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL qua pow(qua const& q, T y); + + /// Returns the square root of a quaternion + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL qua sqrt(qua const& q); + + /// @} +} //namespace glm + +#include "quaternion_exponential.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_exponential.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_exponential.inl new file mode 100644 index 0000000000000000000000000000000000000000..dd24b6cb18971079cd1d540d9638061383d76e5a --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_exponential.inl @@ -0,0 +1,89 @@ +#include "scalar_constants.hpp" + +namespace glm +{ + template + GLM_FUNC_QUALIFIER qua exp(qua const& q) + { + vec<3, T, Q> u(q.x, q.y, q.z); + T const Angle = glm::length(u); + if (Angle < epsilon()) + return qua(); + + vec<3, T, Q> const v(u / Angle); + return qua(cos(Angle), sin(Angle) * v); + } + + template + GLM_FUNC_QUALIFIER qua log(qua const& q) + { + vec<3, T, Q> u(q.x, q.y, q.z); + T Vec3Len = length(u); + + if (Vec3Len < epsilon()) + { + if(q.w > static_cast(0)) + return qua(log(q.w), static_cast(0), static_cast(0), static_cast(0)); + else if(q.w < static_cast(0)) + return qua(log(-q.w), pi(), static_cast(0), static_cast(0)); + else + return qua(std::numeric_limits::infinity(), std::numeric_limits::infinity(), std::numeric_limits::infinity(), std::numeric_limits::infinity()); + } + else + { + T t = atan(Vec3Len, T(q.w)) / Vec3Len; + T QuatLen2 = Vec3Len * Vec3Len + q.w * q.w; + return qua(static_cast(0.5) * log(QuatLen2), t * q.x, t * q.y, t * q.z); + } + } + + template + GLM_FUNC_QUALIFIER qua pow(qua const& x, T y) + { + //Raising to the power of 0 should yield 1 + //Needed to prevent a division by 0 error later on + if(y > -epsilon() && y < epsilon()) + return qua(1,0,0,0); + + //To deal with non-unit quaternions + T magnitude = sqrt(x.x * x.x + x.y * x.y + x.z * x.z + x.w *x.w); + + T Angle; + if(abs(x.w / magnitude) > cos_one_over_two()) + { + //Scalar component is close to 1; using it to recover angle would lose precision + //Instead, we use the non-scalar components since sin() is accurate around 0 + + //Prevent a division by 0 error later on + T VectorMagnitude = x.x * x.x + x.y * x.y + x.z * x.z; + //Despite the compiler might say, we actually want to compare + //VectorMagnitude to 0. here; we could use denorm_int() compiling a + //project with unsafe maths optimizations might make the comparison + //always false, even when VectorMagnitude is 0. + if (VectorMagnitude < std::numeric_limits::min()) { + //Equivalent to raising a real number to a power + return qua(pow(x.w, y), 0, 0, 0); + } + + Angle = asin(sqrt(VectorMagnitude) / magnitude); + } + else + { + //Scalar component is small, shouldn't cause loss of precision + Angle = acos(x.w / magnitude); + } + + T NewAngle = Angle * y; + T Div = sin(NewAngle) / sin(Angle); + T Mag = pow(magnitude, y - static_cast(1)); + return qua(cos(NewAngle) * magnitude * Mag, x.x * Div * Mag, x.y * Div * Mag, x.z * Div * Mag); + } + + template + GLM_FUNC_QUALIFIER qua sqrt(qua const& x) + { + return pow(x, static_cast(0.5)); + } +}//namespace glm + + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_float.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_float.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ca42a60597f43d241f7e6a82bf6d0b98c2161621 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_float.hpp @@ -0,0 +1,39 @@ +/// @ref ext_quaternion_float +/// @file glm/ext/quaternion_float.hpp +/// +/// @defgroup ext_quaternion_float GLM_EXT_quaternion_float +/// @ingroup ext +/// +/// Exposes single-precision floating point quaternion type. +/// +/// Include to use the features of this extension. +/// +/// @see ext_quaternion_double +/// @see ext_quaternion_float_precision +/// @see ext_quaternion_common +/// @see ext_quaternion_exponential +/// @see ext_quaternion_geometric +/// @see ext_quaternion_relational +/// @see ext_quaternion_transform +/// @see ext_quaternion_trigonometric + +#pragma once + +// Dependency: +#include "../detail/type_quat.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_quaternion_float extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_quaternion_float + /// @{ + + /// Quaternion of single-precision floating-point numbers. + typedef qua quat; + + /// @} +} //namespace glm + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_float_precision.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_float_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f9e4f5c21d9075fbd6cf3d684774a62a39c0d15b --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_float_precision.hpp @@ -0,0 +1,36 @@ +/// @ref ext_quaternion_float_precision +/// @file glm/ext/quaternion_float_precision.hpp +/// +/// @defgroup ext_quaternion_float_precision GLM_EXT_quaternion_float_precision +/// @ingroup ext +/// +/// Exposes single-precision floating point quaternion type with various precision in term of ULPs. +/// +/// Include to use the features of this extension. + +#pragma once + +// Dependency: +#include "../detail/type_quat.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_quaternion_float_precision extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_quaternion_float_precision + /// @{ + + /// Quaternion of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef qua lowp_quat; + + /// Quaternion of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef qua mediump_quat; + + /// Quaternion of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef qua highp_quat; + + /// @} +} //namespace glm + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_geometric.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_geometric.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f4b9d6e69332769bfbc7490bc874b82573c0ab65 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_geometric.hpp @@ -0,0 +1,70 @@ +/// @ref ext_quaternion_geometric +/// @file glm/ext/quaternion_geometric.hpp +/// +/// @defgroup ext_quaternion_geometric GLM_EXT_quaternion_geometric +/// @ingroup ext +/// +/// Provides geometric functions for quaternion types +/// +/// Include to use the features of this extension. +/// +/// @see core_func_geometric +/// @see ext_quaternion_float +/// @see ext_quaternion_double + +#pragma once + +// Dependency: +#include "../geometric.hpp" +#include "../exponential.hpp" +#include "../ext/vector_relational.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_quaternion_geometric extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_quaternion_geometric + /// @{ + + /// Returns the norm of a quaternions + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_quaternion_geometric + template + GLM_FUNC_DECL T length(qua const& q); + + /// Returns the normalized quaternion. + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_quaternion_geometric + template + GLM_FUNC_DECL qua normalize(qua const& q); + + /// Returns dot product of q1 and q2, i.e., q1[0] * q2[0] + q1[1] * q2[1] + ... + /// + /// @tparam T Floating-point scalar types. + /// @tparam Q Value from qualifier enum + /// + /// @see ext_quaternion_geometric + template + GLM_FUNC_DECL T dot(qua const& x, qua const& y); + + /// Compute a cross product. + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_quaternion_geometric + template + GLM_FUNC_QUALIFIER qua cross(qua const& q1, qua const& q2); + + /// @} +} //namespace glm + +#include "quaternion_geometric.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_geometric.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_geometric.inl new file mode 100644 index 0000000000000000000000000000000000000000..e155ac5218075dfc37aa0720ace9b0bce901c071 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_geometric.inl @@ -0,0 +1,36 @@ +namespace glm +{ + template + GLM_FUNC_QUALIFIER T dot(qua const& x, qua const& y) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'dot' accepts only floating-point inputs"); + return detail::compute_dot, T, detail::is_aligned::value>::call(x, y); + } + + template + GLM_FUNC_QUALIFIER T length(qua const& q) + { + return glm::sqrt(dot(q, q)); + } + + template + GLM_FUNC_QUALIFIER qua normalize(qua const& q) + { + T len = length(q); + if(len <= static_cast(0)) // Problem + return qua(static_cast(1), static_cast(0), static_cast(0), static_cast(0)); + T oneOverLen = static_cast(1) / len; + return qua(q.w * oneOverLen, q.x * oneOverLen, q.y * oneOverLen, q.z * oneOverLen); + } + + template + GLM_FUNC_QUALIFIER qua cross(qua const& q1, qua const& q2) + { + return qua( + q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z, + q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y, + q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z, + q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x); + } +}//namespace glm + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_relational.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_relational.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7aa121da0a1570460ecf379cf3d4b3ae7c9941c3 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_relational.hpp @@ -0,0 +1,62 @@ +/// @ref ext_quaternion_relational +/// @file glm/ext/quaternion_relational.hpp +/// +/// @defgroup ext_quaternion_relational GLM_EXT_quaternion_relational +/// @ingroup ext +/// +/// Exposes comparison functions for quaternion types that take a user defined epsilon values. +/// +/// Include to use the features of this extension. +/// +/// @see core_vector_relational +/// @see ext_vector_relational +/// @see ext_matrix_relational +/// @see ext_quaternion_float +/// @see ext_quaternion_double + +#pragma once + +// Dependency: +#include "../vector_relational.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_quaternion_relational extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_quaternion_relational + /// @{ + + /// Returns the component-wise comparison of result x == y. + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL vec<4, bool, Q> equal(qua const& x, qua const& y); + + /// Returns the component-wise comparison of |x - y| < epsilon. + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL vec<4, bool, Q> equal(qua const& x, qua const& y, T epsilon); + + /// Returns the component-wise comparison of result x != y. + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL vec<4, bool, Q> notEqual(qua const& x, qua const& y); + + /// Returns the component-wise comparison of |x - y| >= epsilon. + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL vec<4, bool, Q> notEqual(qua const& x, qua const& y, T epsilon); + + /// @} +} //namespace glm + +#include "quaternion_relational.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_relational.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_relational.inl new file mode 100644 index 0000000000000000000000000000000000000000..b1713e95c6c5b9dffb8f49aeeb659d7e82a7dbc6 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_relational.inl @@ -0,0 +1,35 @@ +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> equal(qua const& x, qua const& y) + { + vec<4, bool, Q> Result; + for(length_t i = 0; i < x.length(); ++i) + Result[i] = x[i] == y[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> equal(qua const& x, qua const& y, T epsilon) + { + vec<4, T, Q> v(x.x - y.x, x.y - y.y, x.z - y.z, x.w - y.w); + return lessThan(abs(v), vec<4, T, Q>(epsilon)); + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> notEqual(qua const& x, qua const& y) + { + vec<4, bool, Q> Result; + for(length_t i = 0; i < x.length(); ++i) + Result[i] = x[i] != y[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> notEqual(qua const& x, qua const& y, T epsilon) + { + vec<4, T, Q> v(x.x - y.x, x.y - y.y, x.z - y.z, x.w - y.w); + return greaterThanEqual(abs(v), vec<4, T, Q>(epsilon)); + } +}//namespace glm + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_transform.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_transform.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a9cc5c2b59ff883d1de1b2bc2a0b57ca57144089 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_transform.hpp @@ -0,0 +1,47 @@ +/// @ref ext_quaternion_transform +/// @file glm/ext/quaternion_transform.hpp +/// +/// @defgroup ext_quaternion_transform GLM_EXT_quaternion_transform +/// @ingroup ext +/// +/// Provides transformation functions for quaternion types +/// +/// Include to use the features of this extension. +/// +/// @see ext_quaternion_float +/// @see ext_quaternion_double +/// @see ext_quaternion_exponential +/// @see ext_quaternion_geometric +/// @see ext_quaternion_relational +/// @see ext_quaternion_trigonometric + +#pragma once + +// Dependency: +#include "../common.hpp" +#include "../trigonometric.hpp" +#include "../geometric.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_quaternion_transform extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_quaternion_transform + /// @{ + + /// Rotates a quaternion from a vector of 3 components axis and an angle. + /// + /// @param q Source orientation + /// @param angle Angle expressed in radians. + /// @param axis Axis of the rotation + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL qua rotate(qua const& q, T const& angle, vec<3, T, Q> const& axis); + /// @} +} //namespace glm + +#include "quaternion_transform.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_transform.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_transform.inl new file mode 100644 index 0000000000000000000000000000000000000000..b87ecb65d9f7ce739f5f3eeb1e57d5b4f4edf9e6 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_transform.inl @@ -0,0 +1,24 @@ +namespace glm +{ + template + GLM_FUNC_QUALIFIER qua rotate(qua const& q, T const& angle, vec<3, T, Q> const& v) + { + vec<3, T, Q> Tmp = v; + + // Axis of rotation must be normalised + T len = glm::length(Tmp); + if(abs(len - static_cast(1)) > static_cast(0.001)) + { + T oneOverLen = static_cast(1) / len; + Tmp.x *= oneOverLen; + Tmp.y *= oneOverLen; + Tmp.z *= oneOverLen; + } + + T const AngleRad(angle); + T const Sin = sin(AngleRad * static_cast(0.5)); + + return q * qua(cos(AngleRad * static_cast(0.5)), Tmp.x * Sin, Tmp.y * Sin, Tmp.z * Sin); + } +}//namespace glm + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_trigonometric.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_trigonometric.hpp new file mode 100644 index 0000000000000000000000000000000000000000..76cea27add64c4d32ec8dd0e164132090e1a43c7 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_trigonometric.hpp @@ -0,0 +1,63 @@ +/// @ref ext_quaternion_trigonometric +/// @file glm/ext/quaternion_trigonometric.hpp +/// +/// @defgroup ext_quaternion_trigonometric GLM_EXT_quaternion_trigonometric +/// @ingroup ext +/// +/// Provides trigonometric functions for quaternion types +/// +/// Include to use the features of this extension. +/// +/// @see ext_quaternion_float +/// @see ext_quaternion_double +/// @see ext_quaternion_exponential +/// @see ext_quaternion_geometric +/// @see ext_quaternion_relational +/// @see ext_quaternion_transform + +#pragma once + +// Dependency: +#include "../trigonometric.hpp" +#include "../exponential.hpp" +#include "scalar_constants.hpp" +#include "vector_relational.hpp" +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_quaternion_trigonometric extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_quaternion_trigonometric + /// @{ + + /// Returns the quaternion rotation angle. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL T angle(qua const& x); + + /// Returns the q rotation axis. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL vec<3, T, Q> axis(qua const& x); + + /// Build a quaternion from an angle and a normalized axis. + /// + /// @param angle Angle expressed in radians. + /// @param axis Axis of the quaternion, must be normalized. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL qua angleAxis(T const& angle, vec<3, T, Q> const& axis); + + /// @} +} //namespace glm + +#include "quaternion_trigonometric.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_trigonometric.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_trigonometric.inl new file mode 100644 index 0000000000000000000000000000000000000000..896449aa6e1f41e2423f7e13b235ac08ab022703 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/quaternion_trigonometric.inl @@ -0,0 +1,37 @@ +#include "scalar_constants.hpp" + +namespace glm +{ + template + GLM_FUNC_QUALIFIER T angle(qua const& x) + { + if (abs(x.w) > cos_one_over_two()) + { + T const a = asin(sqrt(x.x * x.x + x.y * x.y + x.z * x.z)) * static_cast(2); + if(x.w < static_cast(0)) + return pi() * static_cast(2) - a; + return a; + } + + return acos(x.w) * static_cast(2); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> axis(qua const& x) + { + T const tmp1 = static_cast(1) - x.w * x.w; + if(tmp1 <= static_cast(0)) + return vec<3, T, Q>(0, 0, 1); + T const tmp2 = static_cast(1) / sqrt(tmp1); + return vec<3, T, Q>(x.x * tmp2, x.y * tmp2, x.z * tmp2); + } + + template + GLM_FUNC_QUALIFIER qua angleAxis(T const& angle, vec<3, T, Q> const& v) + { + T const a(angle); + T const s = glm::sin(a * static_cast(0.5)); + + return qua(glm::cos(a * static_cast(0.5)), v * s); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_common.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_common.hpp new file mode 100644 index 0000000000000000000000000000000000000000..df04b6b809a94b26aa4de8ee36ede4a6a7bf3460 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_common.hpp @@ -0,0 +1,181 @@ +/// @ref ext_scalar_common +/// @file glm/ext/scalar_common.hpp +/// +/// @defgroup ext_scalar_common GLM_EXT_scalar_common +/// @ingroup ext +/// +/// Exposes min and max functions for 3 to 4 scalar parameters. +/// +/// Include to use the features of this extension. +/// +/// @see core_func_common +/// @see ext_vector_common + +#pragma once + +// Dependency: +#include "../common.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_scalar_common extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_scalar_common + /// @{ + + /// Returns the minimum component-wise values of 3 inputs + /// + /// @tparam T A floating-point scalar type. + /// + /// @see ext_scalar_common + template + GLM_FUNC_DECL T min(T a, T b, T c); + + /// Returns the minimum component-wise values of 4 inputs + /// + /// @tparam T A floating-point scalar type. + /// + /// @see ext_scalar_common + template + GLM_FUNC_DECL T min(T a, T b, T c, T d); + + /// Returns the maximum component-wise values of 3 inputs + /// + /// @tparam T A floating-point scalar type. + /// + /// @see ext_scalar_common + template + GLM_FUNC_DECL T max(T a, T b, T c); + + /// Returns the maximum component-wise values of 4 inputs + /// + /// @tparam T A floating-point scalar type. + /// + /// @see ext_scalar_common + template + GLM_FUNC_DECL T max(T a, T b, T c, T d); + + /// Returns the minimum component-wise values of 2 inputs. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam T A floating-point scalar type. + /// + /// @see std::fmin documentation + /// @see ext_scalar_common + template + GLM_FUNC_DECL T fmin(T a, T b); + + /// Returns the minimum component-wise values of 3 inputs. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam T A floating-point scalar type. + /// + /// @see std::fmin documentation + /// @see ext_scalar_common + template + GLM_FUNC_DECL T fmin(T a, T b, T c); + + /// Returns the minimum component-wise values of 4 inputs. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam T A floating-point scalar type. + /// + /// @see std::fmin documentation + /// @see ext_scalar_common + template + GLM_FUNC_DECL T fmin(T a, T b, T c, T d); + + /// Returns the maximum component-wise values of 2 inputs. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam T A floating-point scalar type. + /// + /// @see std::fmax documentation + /// @see ext_scalar_common + template + GLM_FUNC_DECL T fmax(T a, T b); + + /// Returns the maximum component-wise values of 3 inputs. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam T A floating-point scalar type. + /// + /// @see std::fmax documentation + /// @see ext_scalar_common + template + GLM_FUNC_DECL T fmax(T a, T b, T C); + + /// Returns the maximum component-wise values of 4 inputs. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam T A floating-point scalar type. + /// + /// @see std::fmax documentation + /// @see ext_scalar_common + template + GLM_FUNC_DECL T fmax(T a, T b, T C, T D); + + /// Returns min(max(x, minVal), maxVal) for each component in x. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam genType Floating-point scalar types. + /// + /// @see ext_scalar_common + template + GLM_FUNC_DECL genType fclamp(genType x, genType minVal, genType maxVal); + + /// Simulate GL_CLAMP OpenGL wrap mode + /// + /// @tparam genType Floating-point scalar types. + /// + /// @see ext_scalar_common extension. + template + GLM_FUNC_DECL genType clamp(genType const& Texcoord); + + /// Simulate GL_REPEAT OpenGL wrap mode + /// + /// @tparam genType Floating-point scalar types. + /// + /// @see ext_scalar_common extension. + template + GLM_FUNC_DECL genType repeat(genType const& Texcoord); + + /// Simulate GL_MIRRORED_REPEAT OpenGL wrap mode + /// + /// @tparam genType Floating-point scalar types. + /// + /// @see ext_scalar_common extension. + template + GLM_FUNC_DECL genType mirrorClamp(genType const& Texcoord); + + /// Simulate GL_MIRROR_REPEAT OpenGL wrap mode + /// + /// @tparam genType Floating-point scalar types. + /// + /// @see ext_scalar_common extension. + template + GLM_FUNC_DECL genType mirrorRepeat(genType const& Texcoord); + + /// Returns a value equal to the nearest integer to x. + /// The fraction 0.5 will round in a direction chosen by the + /// implementation, presumably the direction that is fastest. + /// + /// @param x The values of the argument must be greater or equal to zero. + /// @tparam genType floating point scalar types. + /// + /// @see GLSL round man page + /// @see ext_scalar_common extension. + template + GLM_FUNC_DECL int iround(genType const& x); + + /// Returns a value equal to the nearest integer to x. + /// The fraction 0.5 will round in a direction chosen by the + /// implementation, presumably the direction that is fastest. + /// + /// @param x The values of the argument must be greater or equal to zero. + /// @tparam genType floating point scalar types. + /// + /// @see GLSL round man page + /// @see ext_scalar_common extension. + template + GLM_FUNC_DECL uint uround(genType const& x); + + /// @} +}//namespace glm + +#include "scalar_common.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_common.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_common.inl new file mode 100644 index 0000000000000000000000000000000000000000..2807a3725f70af0b345b13288a9e44accd11e2b3 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_common.inl @@ -0,0 +1,170 @@ +namespace glm +{ + template + GLM_FUNC_QUALIFIER T min(T a, T b, T c) + { + return glm::min(glm::min(a, b), c); + } + + template + GLM_FUNC_QUALIFIER T min(T a, T b, T c, T d) + { + return glm::min(glm::min(a, b), glm::min(c, d)); + } + + template + GLM_FUNC_QUALIFIER T max(T a, T b, T c) + { + return glm::max(glm::max(a, b), c); + } + + template + GLM_FUNC_QUALIFIER T max(T a, T b, T c, T d) + { + return glm::max(glm::max(a, b), glm::max(c, d)); + } + +# if GLM_HAS_CXX11_STL + using std::fmin; +# else + template + GLM_FUNC_QUALIFIER T fmin(T a, T b) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmin' only accept floating-point input"); + + if (isnan(a)) + return b; + return min(a, b); + } +# endif + + template + GLM_FUNC_QUALIFIER T fmin(T a, T b, T c) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmin' only accept floating-point input"); + + if (isnan(a)) + return fmin(b, c); + if (isnan(b)) + return fmin(a, c); + if (isnan(c)) + return min(a, b); + return min(a, b, c); + } + + template + GLM_FUNC_QUALIFIER T fmin(T a, T b, T c, T d) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmin' only accept floating-point input"); + + if (isnan(a)) + return fmin(b, c, d); + if (isnan(b)) + return min(a, fmin(c, d)); + if (isnan(c)) + return fmin(min(a, b), d); + if (isnan(d)) + return min(a, b, c); + return min(a, b, c, d); + } + + +# if GLM_HAS_CXX11_STL + using std::fmax; +# else + template + GLM_FUNC_QUALIFIER T fmax(T a, T b) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmax' only accept floating-point input"); + + if (isnan(a)) + return b; + return max(a, b); + } +# endif + + template + GLM_FUNC_QUALIFIER T fmax(T a, T b, T c) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmax' only accept floating-point input"); + + if (isnan(a)) + return fmax(b, c); + if (isnan(b)) + return fmax(a, c); + if (isnan(c)) + return max(a, b); + return max(a, b, c); + } + + template + GLM_FUNC_QUALIFIER T fmax(T a, T b, T c, T d) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmax' only accept floating-point input"); + + if (isnan(a)) + return fmax(b, c, d); + if (isnan(b)) + return max(a, fmax(c, d)); + if (isnan(c)) + return fmax(max(a, b), d); + if (isnan(d)) + return max(a, b, c); + return max(a, b, c, d); + } + + // fclamp + template + GLM_FUNC_QUALIFIER genType fclamp(genType x, genType minVal, genType maxVal) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fclamp' only accept floating-point or integer inputs"); + return fmin(fmax(x, minVal), maxVal); + } + + template + GLM_FUNC_QUALIFIER genType clamp(genType const& Texcoord) + { + return glm::clamp(Texcoord, static_cast(0), static_cast(1)); + } + + template + GLM_FUNC_QUALIFIER genType repeat(genType const& Texcoord) + { + return glm::fract(Texcoord); + } + + template + GLM_FUNC_QUALIFIER genType mirrorClamp(genType const& Texcoord) + { + return glm::fract(glm::abs(Texcoord)); + } + + template + GLM_FUNC_QUALIFIER genType mirrorRepeat(genType const& Texcoord) + { + genType const Abs = glm::abs(Texcoord); + genType const Clamp = glm::mod(glm::floor(Abs), static_cast(2)); + genType const Floor = glm::floor(Abs); + genType const Rest = Abs - Floor; + genType const Mirror = Clamp + Rest; + return mix(Rest, static_cast(1) - Rest, Mirror >= static_cast(1)); + } + + template + GLM_FUNC_QUALIFIER int iround(genType const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'iround' only accept floating-point inputs"); + assert(static_cast(0.0) <= x); + + return static_cast(x + static_cast(0.5)); + } + + template + GLM_FUNC_QUALIFIER uint uround(genType const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'uround' only accept floating-point inputs"); + assert(static_cast(0.0) <= x); + + return static_cast(x + static_cast(0.5)); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_constants.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_constants.hpp new file mode 100644 index 0000000000000000000000000000000000000000..74e210d9c09ec9440ce0dd8b843ba6b294c13ccd --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_constants.hpp @@ -0,0 +1,40 @@ +/// @ref ext_scalar_constants +/// @file glm/ext/scalar_constants.hpp +/// +/// @defgroup ext_scalar_constants GLM_EXT_scalar_constants +/// @ingroup ext +/// +/// Provides a list of constants and precomputed useful values. +/// +/// Include to use the features of this extension. + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_scalar_constants extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_scalar_constants + /// @{ + + /// Return the epsilon constant for floating point types. + template + GLM_FUNC_DECL GLM_CONSTEXPR genType epsilon(); + + /// Return the pi constant for floating point types. + template + GLM_FUNC_DECL GLM_CONSTEXPR genType pi(); + + /// Return the value of cos(1 / 2) for floating point types. + template + GLM_FUNC_DECL GLM_CONSTEXPR genType cos_one_over_two(); + + /// @} +} //namespace glm + +#include "scalar_constants.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_constants.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_constants.inl new file mode 100644 index 0000000000000000000000000000000000000000..b475adf83b6e248e0736e12963aef4c8562272c0 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_constants.inl @@ -0,0 +1,24 @@ +#include + +namespace glm +{ + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType epsilon() + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'epsilon' only accepts floating-point inputs"); + return std::numeric_limits::epsilon(); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType pi() + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'pi' only accepts floating-point inputs"); + return static_cast(3.14159265358979323846264338327950288); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType cos_one_over_two() + { + return genType(0.877582561890372716130286068203503191); + } +} //namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_int_sized.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_int_sized.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8e9c511c9cb51010b4063882e14477d71eb3c7eb --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_int_sized.hpp @@ -0,0 +1,70 @@ +/// @ref ext_scalar_int_sized +/// @file glm/ext/scalar_int_sized.hpp +/// +/// @defgroup ext_scalar_int_sized GLM_EXT_scalar_int_sized +/// @ingroup ext +/// +/// Exposes sized signed integer scalar types. +/// +/// Include to use the features of this extension. +/// +/// @see ext_scalar_uint_sized + +#pragma once + +#include "../detail/setup.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_scalar_int_sized extension included") +#endif + +namespace glm{ +namespace detail +{ +# if GLM_HAS_EXTENDED_INTEGER_TYPE + typedef std::int8_t int8; + typedef std::int16_t int16; + typedef std::int32_t int32; +# else + typedef signed char int8; + typedef signed short int16; + typedef signed int int32; +#endif// + + template<> + struct is_int + { + enum test {value = ~0}; + }; + + template<> + struct is_int + { + enum test {value = ~0}; + }; + + template<> + struct is_int + { + enum test {value = ~0}; + }; +}//namespace detail + + + /// @addtogroup ext_scalar_int_sized + /// @{ + + /// 8 bit signed integer type. + typedef detail::int8 int8; + + /// 16 bit signed integer type. + typedef detail::int16 int16; + + /// 32 bit signed integer type. + typedef detail::int32 int32; + + /// 64 bit signed integer type. + typedef detail::int64 int64; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_integer.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_integer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a2ca8a2ae37c6fe87997e66515ffead64fea23c7 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_integer.hpp @@ -0,0 +1,92 @@ +/// @ref ext_scalar_integer +/// @file glm/ext/scalar_integer.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_scalar_integer GLM_EXT_scalar_integer +/// @ingroup ext +/// +/// Include to use the features of this extension. + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../detail/qualifier.hpp" +#include "../detail/_vectorize.hpp" +#include "../detail/type_float.hpp" +#include "../vector_relational.hpp" +#include "../common.hpp" +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_scalar_integer extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_scalar_integer + /// @{ + + /// Return true if the value is a power of two number. + /// + /// @see ext_scalar_integer + template + GLM_FUNC_DECL bool isPowerOfTwo(genIUType v); + + /// Return the power of two number which value is just higher the input value, + /// round up to a power of two. + /// + /// @see ext_scalar_integer + template + GLM_FUNC_DECL genIUType nextPowerOfTwo(genIUType v); + + /// Return the power of two number which value is just lower the input value, + /// round down to a power of two. + /// + /// @see ext_scalar_integer + template + GLM_FUNC_DECL genIUType prevPowerOfTwo(genIUType v); + + /// Return true if the 'Value' is a multiple of 'Multiple'. + /// + /// @see ext_scalar_integer + template + GLM_FUNC_DECL bool isMultiple(genIUType v, genIUType Multiple); + + /// Higher multiple number of Source. + /// + /// @tparam genIUType Integer scalar or vector types. + /// + /// @param v Source value to which is applied the function + /// @param Multiple Must be a null or positive value + /// + /// @see ext_scalar_integer + template + GLM_FUNC_DECL genIUType nextMultiple(genIUType v, genIUType Multiple); + + /// Lower multiple number of Source. + /// + /// @tparam genIUType Integer scalar or vector types. + /// + /// @param v Source value to which is applied the function + /// @param Multiple Must be a null or positive value + /// + /// @see ext_scalar_integer + template + GLM_FUNC_DECL genIUType prevMultiple(genIUType v, genIUType Multiple); + + /// Returns the bit number of the Nth significant bit set to + /// 1 in the binary representation of value. + /// If value bitcount is less than the Nth significant bit, -1 will be returned. + /// + /// @tparam genIUType Signed or unsigned integer scalar types. + /// + /// @see ext_scalar_integer + template + GLM_FUNC_DECL int findNSB(genIUType x, int significantBitCount); + + /// @} +} //namespace glm + +#include "scalar_integer.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_integer.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_integer.inl new file mode 100644 index 0000000000000000000000000000000000000000..efba960097514ed1b3e4a33f55f49605f0d3d2dd --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_integer.inl @@ -0,0 +1,243 @@ +#include "../integer.hpp" + +namespace glm{ +namespace detail +{ + template + struct compute_ceilShift + { + GLM_FUNC_QUALIFIER static vec call(vec const& v, T) + { + return v; + } + }; + + template + struct compute_ceilShift + { + GLM_FUNC_QUALIFIER static vec call(vec const& v, T Shift) + { + return v | (v >> Shift); + } + }; + + template + struct compute_ceilPowerOfTwo + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + GLM_STATIC_ASSERT(!std::numeric_limits::is_iec559, "'ceilPowerOfTwo' only accept integer scalar or vector inputs"); + + vec const Sign(sign(x)); + + vec v(abs(x)); + + v = v - static_cast(1); + v = v | (v >> static_cast(1)); + v = v | (v >> static_cast(2)); + v = v | (v >> static_cast(4)); + v = compute_ceilShift= 2>::call(v, 8); + v = compute_ceilShift= 4>::call(v, 16); + v = compute_ceilShift= 8>::call(v, 32); + return (v + static_cast(1)) * Sign; + } + }; + + template + struct compute_ceilPowerOfTwo + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + GLM_STATIC_ASSERT(!std::numeric_limits::is_iec559, "'ceilPowerOfTwo' only accept integer scalar or vector inputs"); + + vec v(x); + + v = v - static_cast(1); + v = v | (v >> static_cast(1)); + v = v | (v >> static_cast(2)); + v = v | (v >> static_cast(4)); + v = compute_ceilShift= 2>::call(v, 8); + v = compute_ceilShift= 4>::call(v, 16); + v = compute_ceilShift= 8>::call(v, 32); + return v + static_cast(1); + } + }; + + template + struct compute_ceilMultiple{}; + + template<> + struct compute_ceilMultiple + { + template + GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) + { + if(Source > genType(0)) + return Source + (Multiple - std::fmod(Source, Multiple)); + else + return Source + std::fmod(-Source, Multiple); + } + }; + + template<> + struct compute_ceilMultiple + { + template + GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) + { + genType Tmp = Source - genType(1); + return Tmp + (Multiple - (Tmp % Multiple)); + } + }; + + template<> + struct compute_ceilMultiple + { + template + GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) + { + assert(Multiple > genType(0)); + if(Source > genType(0)) + { + genType Tmp = Source - genType(1); + return Tmp + (Multiple - (Tmp % Multiple)); + } + else + return Source + (-Source % Multiple); + } + }; + + template + struct compute_floorMultiple{}; + + template<> + struct compute_floorMultiple + { + template + GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) + { + if(Source >= genType(0)) + return Source - std::fmod(Source, Multiple); + else + return Source - std::fmod(Source, Multiple) - Multiple; + } + }; + + template<> + struct compute_floorMultiple + { + template + GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) + { + if(Source >= genType(0)) + return Source - Source % Multiple; + else + { + genType Tmp = Source + genType(1); + return Tmp - Tmp % Multiple - Multiple; + } + } + }; + + template<> + struct compute_floorMultiple + { + template + GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) + { + if(Source >= genType(0)) + return Source - Source % Multiple; + else + { + genType Tmp = Source + genType(1); + return Tmp - Tmp % Multiple - Multiple; + } + } + }; +}//namespace detail + + template + GLM_FUNC_QUALIFIER bool isPowerOfTwo(genIUType Value) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'isPowerOfTwo' only accept integer inputs"); + + genIUType const Result = glm::abs(Value); + return !(Result & (Result - 1)); + } + + template + GLM_FUNC_QUALIFIER genIUType nextPowerOfTwo(genIUType value) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'nextPowerOfTwo' only accept integer inputs"); + + return detail::compute_ceilPowerOfTwo<1, genIUType, defaultp, std::numeric_limits::is_signed>::call(vec<1, genIUType, defaultp>(value)).x; + } + + template + GLM_FUNC_QUALIFIER genIUType prevPowerOfTwo(genIUType value) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'prevPowerOfTwo' only accept integer inputs"); + + return isPowerOfTwo(value) ? value : static_cast(static_cast(1) << static_cast(findMSB(value))); + } + + template + GLM_FUNC_QUALIFIER bool isMultiple(genIUType Value, genIUType Multiple) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'isMultiple' only accept integer inputs"); + + return isMultiple(vec<1, genIUType>(Value), vec<1, genIUType>(Multiple)).x; + } + + template + GLM_FUNC_QUALIFIER genIUType nextMultiple(genIUType Source, genIUType Multiple) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'nextMultiple' only accept integer inputs"); + + return detail::compute_ceilMultiple::is_iec559, std::numeric_limits::is_signed>::call(Source, Multiple); + } + + template + GLM_FUNC_QUALIFIER genIUType prevMultiple(genIUType Source, genIUType Multiple) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'prevMultiple' only accept integer inputs"); + + return detail::compute_floorMultiple::is_iec559, std::numeric_limits::is_signed>::call(Source, Multiple); + } + + template + GLM_FUNC_QUALIFIER int findNSB(genIUType x, int significantBitCount) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'findNSB' only accept integer inputs"); + + if(bitCount(x) < significantBitCount) + return -1; + + genIUType const One = static_cast(1); + int bitPos = 0; + + genIUType key = x; + int nBitCount = significantBitCount; + int Step = sizeof(x) * 8 / 2; + while (key > One) + { + genIUType Mask = static_cast((One << Step) - One); + genIUType currentKey = key & Mask; + int currentBitCount = bitCount(currentKey); + if (nBitCount > currentBitCount) + { + nBitCount -= currentBitCount; + bitPos += Step; + key >>= static_cast(Step); + } + else + { + key = key & Mask; + } + + Step >>= 1; + } + + return static_cast(bitPos); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_packing.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_packing.hpp new file mode 100644 index 0000000000000000000000000000000000000000..18b85b72a404b7a9bba50d88812dce114671969a --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_packing.hpp @@ -0,0 +1,32 @@ +/// @ref ext_scalar_packing +/// @file glm/ext/scalar_packing.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_scalar_packing GLM_EXT_scalar_packing +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// This extension provides a set of function to convert scalar values to packed +/// formats. + +#pragma once + +// Dependency: +#include "../detail/qualifier.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_scalar_packing extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_scalar_packing + /// @{ + + + /// @} +}// namespace glm + +#include "scalar_packing.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_packing.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_packing.inl new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_reciprocal.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_reciprocal.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1c7b81dde09a5703fcb914bbe98ec39fee3530b6 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_reciprocal.hpp @@ -0,0 +1,135 @@ +/// @ref ext_scalar_reciprocal +/// @file glm/ext/scalar_reciprocal.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_scalar_reciprocal GLM_EXT_scalar_reciprocal +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Define secant, cosecant and cotangent functions. + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_scalar_reciprocal extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_scalar_reciprocal + /// @{ + + /// Secant function. + /// hypotenuse / adjacent or 1 / cos(x) + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see ext_scalar_reciprocal + template + GLM_FUNC_DECL genType sec(genType angle); + + /// Cosecant function. + /// hypotenuse / opposite or 1 / sin(x) + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see ext_scalar_reciprocal + template + GLM_FUNC_DECL genType csc(genType angle); + + /// Cotangent function. + /// adjacent / opposite or 1 / tan(x) + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see ext_scalar_reciprocal + template + GLM_FUNC_DECL genType cot(genType angle); + + /// Inverse secant function. + /// + /// @return Return an angle expressed in radians. + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see ext_scalar_reciprocal + template + GLM_FUNC_DECL genType asec(genType x); + + /// Inverse cosecant function. + /// + /// @return Return an angle expressed in radians. + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see ext_scalar_reciprocal + template + GLM_FUNC_DECL genType acsc(genType x); + + /// Inverse cotangent function. + /// + /// @return Return an angle expressed in radians. + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see ext_scalar_reciprocal + template + GLM_FUNC_DECL genType acot(genType x); + + /// Secant hyperbolic function. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see ext_scalar_reciprocal + template + GLM_FUNC_DECL genType sech(genType angle); + + /// Cosecant hyperbolic function. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see ext_scalar_reciprocal + template + GLM_FUNC_DECL genType csch(genType angle); + + /// Cotangent hyperbolic function. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see ext_scalar_reciprocal + template + GLM_FUNC_DECL genType coth(genType angle); + + /// Inverse secant hyperbolic function. + /// + /// @return Return an angle expressed in radians. + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see ext_scalar_reciprocal + template + GLM_FUNC_DECL genType asech(genType x); + + /// Inverse cosecant hyperbolic function. + /// + /// @return Return an angle expressed in radians. + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see ext_scalar_reciprocal + template + GLM_FUNC_DECL genType acsch(genType x); + + /// Inverse cotangent hyperbolic function. + /// + /// @return Return an angle expressed in radians. + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see ext_scalar_reciprocal + template + GLM_FUNC_DECL genType acoth(genType x); + + /// @} +}//namespace glm + +#include "scalar_reciprocal.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_reciprocal.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_reciprocal.inl new file mode 100644 index 0000000000000000000000000000000000000000..570a406d3983326eb0d8c8687bb16c453f5ebe88 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_reciprocal.inl @@ -0,0 +1,107 @@ +/// @ref ext_scalar_reciprocal + +#include "../trigonometric.hpp" +#include + +namespace glm +{ + // sec + template + GLM_FUNC_QUALIFIER genType sec(genType angle) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'sec' only accept floating-point values"); + return genType(1) / glm::cos(angle); + } + + // csc + template + GLM_FUNC_QUALIFIER genType csc(genType angle) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'csc' only accept floating-point values"); + return genType(1) / glm::sin(angle); + } + + // cot + template + GLM_FUNC_QUALIFIER genType cot(genType angle) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'cot' only accept floating-point values"); + + genType const pi_over_2 = genType(3.1415926535897932384626433832795 / 2.0); + return glm::tan(pi_over_2 - angle); + } + + // asec + template + GLM_FUNC_QUALIFIER genType asec(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'asec' only accept floating-point values"); + return acos(genType(1) / x); + } + + // acsc + template + GLM_FUNC_QUALIFIER genType acsc(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acsc' only accept floating-point values"); + return asin(genType(1) / x); + } + + // acot + template + GLM_FUNC_QUALIFIER genType acot(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acot' only accept floating-point values"); + + genType const pi_over_2 = genType(3.1415926535897932384626433832795 / 2.0); + return pi_over_2 - atan(x); + } + + // sech + template + GLM_FUNC_QUALIFIER genType sech(genType angle) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'sech' only accept floating-point values"); + return genType(1) / glm::cosh(angle); + } + + // csch + template + GLM_FUNC_QUALIFIER genType csch(genType angle) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'csch' only accept floating-point values"); + return genType(1) / glm::sinh(angle); + } + + // coth + template + GLM_FUNC_QUALIFIER genType coth(genType angle) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'coth' only accept floating-point values"); + return glm::cosh(angle) / glm::sinh(angle); + } + + // asech + template + GLM_FUNC_QUALIFIER genType asech(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'asech' only accept floating-point values"); + return acosh(genType(1) / x); + } + + // acsch + template + GLM_FUNC_QUALIFIER genType acsch(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acsch' only accept floating-point values"); + return asinh(genType(1) / x); + } + + // acoth + template + GLM_FUNC_QUALIFIER genType acoth(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acoth' only accept floating-point values"); + return atanh(genType(1) / x); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_relational.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_relational.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e84df17868249e86376d97d2d02e6bb895b9e7fe --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_relational.hpp @@ -0,0 +1,68 @@ +/// @ref ext_scalar_relational +/// @file glm/ext/scalar_relational.hpp +/// +/// @defgroup ext_scalar_relational GLM_EXT_scalar_relational +/// @ingroup ext +/// +/// Exposes comparison functions for scalar types that take a user defined epsilon values. +/// +/// Include to use the features of this extension. +/// +/// @see core_vector_relational +/// @see ext_vector_relational +/// @see ext_matrix_relational + +#pragma once + +// Dependencies +#include "../detail/qualifier.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_scalar_relational extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_scalar_relational + /// @{ + + /// Returns the component-wise comparison of |x - y| < epsilon. + /// True if this expression is satisfied. + /// + /// @tparam genType Floating-point or integer scalar types + template + GLM_FUNC_DECL GLM_CONSTEXPR bool equal(genType const& x, genType const& y, genType const& epsilon); + + /// Returns the component-wise comparison of |x - y| >= epsilon. + /// True if this expression is not satisfied. + /// + /// @tparam genType Floating-point or integer scalar types + template + GLM_FUNC_DECL GLM_CONSTEXPR bool notEqual(genType const& x, genType const& y, genType const& epsilon); + + /// Returns the component-wise comparison between two scalars in term of ULPs. + /// True if this expression is satisfied. + /// + /// @param x First operand. + /// @param y Second operand. + /// @param ULPs Maximum difference in ULPs between the two operators to consider them equal. + /// + /// @tparam genType Floating-point or integer scalar types + template + GLM_FUNC_DECL GLM_CONSTEXPR bool equal(genType const& x, genType const& y, int ULPs); + + /// Returns the component-wise comparison between two scalars in term of ULPs. + /// True if this expression is not satisfied. + /// + /// @param x First operand. + /// @param y Second operand. + /// @param ULPs Maximum difference in ULPs between the two operators to consider them not equal. + /// + /// @tparam genType Floating-point or integer scalar types + template + GLM_FUNC_DECL GLM_CONSTEXPR bool notEqual(genType const& x, genType const& y, int ULPs); + + /// @} +}//namespace glm + +#include "scalar_relational.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_relational.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_relational.inl new file mode 100644 index 0000000000000000000000000000000000000000..c85583ef5bbd476161be8a5b1d2b1b1e90675b2b --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_relational.inl @@ -0,0 +1,40 @@ +#include "../common.hpp" +#include "../ext/scalar_int_sized.hpp" +#include "../ext/scalar_uint_sized.hpp" +#include "../detail/type_float.hpp" + +namespace glm +{ + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool equal(genType const& x, genType const& y, genType const& epsilon) + { + return abs(x - y) <= epsilon; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool notEqual(genType const& x, genType const& y, genType const& epsilon) + { + return abs(x - y) > epsilon; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool equal(genType const& x, genType const& y, int MaxULPs) + { + detail::float_t const a(x); + detail::float_t const b(y); + + // Different signs means they do not match. + if(a.negative() != b.negative()) + return false; + + // Find the difference in ULPs. + typename detail::float_t::int_type const DiffULPs = abs(a.i - b.i); + return DiffULPs <= MaxULPs; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool notEqual(genType const& x, genType const& y, int ULPs) + { + return !equal(x, y, ULPs); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_uint_sized.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_uint_sized.hpp new file mode 100644 index 0000000000000000000000000000000000000000..fd5267fad7c16dc5670f1622b3328ea5089d5a66 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_uint_sized.hpp @@ -0,0 +1,70 @@ +/// @ref ext_scalar_uint_sized +/// @file glm/ext/scalar_uint_sized.hpp +/// +/// @defgroup ext_scalar_uint_sized GLM_EXT_scalar_uint_sized +/// @ingroup ext +/// +/// Exposes sized unsigned integer scalar types. +/// +/// Include to use the features of this extension. +/// +/// @see ext_scalar_int_sized + +#pragma once + +#include "../detail/setup.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_scalar_uint_sized extension included") +#endif + +namespace glm{ +namespace detail +{ +# if GLM_HAS_EXTENDED_INTEGER_TYPE + typedef std::uint8_t uint8; + typedef std::uint16_t uint16; + typedef std::uint32_t uint32; +# else + typedef unsigned char uint8; + typedef unsigned short uint16; + typedef unsigned int uint32; +#endif + + template<> + struct is_int + { + enum test {value = ~0}; + }; + + template<> + struct is_int + { + enum test {value = ~0}; + }; + + template<> + struct is_int + { + enum test {value = ~0}; + }; +}//namespace detail + + + /// @addtogroup ext_scalar_uint_sized + /// @{ + + /// 8 bit unsigned integer type. + typedef detail::uint8 uint8; + + /// 16 bit unsigned integer type. + typedef detail::uint16 uint16; + + /// 32 bit unsigned integer type. + typedef detail::uint32 uint32; + + /// 64 bit unsigned integer type. + typedef detail::uint64 uint64; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_ulp.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_ulp.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6344d95bf23cb10dc90422594164d424ab32506e --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_ulp.hpp @@ -0,0 +1,77 @@ +/// @ref ext_scalar_ulp +/// @file glm/ext/scalar_ulp.hpp +/// +/// @defgroup ext_scalar_ulp GLM_EXT_scalar_ulp +/// @ingroup ext +/// +/// Allow the measurement of the accuracy of a function against a reference +/// implementation. This extension works on floating-point data and provide results +/// in ULP. +/// +/// Include to use the features of this extension. +/// +/// @see ext_vector_ulp +/// @see ext_scalar_relational + +#pragma once + +// Dependencies +#include "../ext/scalar_int_sized.hpp" +#include "../common.hpp" +#include "../detail/qualifier.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_scalar_ulp extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_scalar_ulp + /// @{ + + /// Return the next ULP value(s) after the input value(s). + /// + /// @tparam genType A floating-point scalar type. + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL genType nextFloat(genType x); + + /// Return the previous ULP value(s) before the input value(s). + /// + /// @tparam genType A floating-point scalar type. + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL genType prevFloat(genType x); + + /// Return the value(s) ULP distance after the input value(s). + /// + /// @tparam genType A floating-point scalar type. + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL genType nextFloat(genType x, int ULPs); + + /// Return the value(s) ULP distance before the input value(s). + /// + /// @tparam genType A floating-point scalar type. + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL genType prevFloat(genType x, int ULPs); + + /// Return the distance in the number of ULP between 2 single-precision floating-point scalars. + /// + /// @see ext_scalar_ulp + GLM_FUNC_DECL int floatDistance(float x, float y); + + /// Return the distance in the number of ULP between 2 double-precision floating-point scalars. + /// + /// @see ext_scalar_ulp + GLM_FUNC_DECL int64 floatDistance(double x, double y); + + /// @} +}//namespace glm + +#include "scalar_ulp.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_ulp.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_ulp.inl new file mode 100644 index 0000000000000000000000000000000000000000..308df150687c033bcd36d3ce5dd0a4e2d841150e --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/scalar_ulp.inl @@ -0,0 +1,284 @@ +/// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +/// +/// Developed at SunPro, a Sun Microsystems, Inc. business. +/// Permission to use, copy, modify, and distribute this +/// software is freely granted, provided that this notice +/// is preserved. + +#include "../detail/type_float.hpp" +#include "../ext/scalar_constants.hpp" +#include +#include + +#if(GLM_COMPILER & GLM_COMPILER_VC) +# pragma warning(push) +# pragma warning(disable : 4127) +#endif + +typedef union +{ + float value; + /* FIXME: Assumes 32 bit int. */ + unsigned int word; +} ieee_float_shape_type; + +typedef union +{ + double value; + struct + { + int lsw; + int msw; + } parts; +} ieee_double_shape_type; + +#define GLM_EXTRACT_WORDS(ix0,ix1,d) \ + do { \ + ieee_double_shape_type ew_u; \ + ew_u.value = (d); \ + (ix0) = ew_u.parts.msw; \ + (ix1) = ew_u.parts.lsw; \ + } while (0) + +#define GLM_GET_FLOAT_WORD(i,d) \ + do { \ + ieee_float_shape_type gf_u; \ + gf_u.value = (d); \ + (i) = gf_u.word; \ + } while (0) + +#define GLM_SET_FLOAT_WORD(d,i) \ + do { \ + ieee_float_shape_type sf_u; \ + sf_u.word = (i); \ + (d) = sf_u.value; \ + } while (0) + +#define GLM_INSERT_WORDS(d,ix0,ix1) \ + do { \ + ieee_double_shape_type iw_u; \ + iw_u.parts.msw = (ix0); \ + iw_u.parts.lsw = (ix1); \ + (d) = iw_u.value; \ + } while (0) + +namespace glm{ +namespace detail +{ + GLM_FUNC_QUALIFIER float nextafterf(float x, float y) + { + volatile float t; + int hx, hy, ix, iy; + + GLM_GET_FLOAT_WORD(hx, x); + GLM_GET_FLOAT_WORD(hy, y); + ix = hx & 0x7fffffff; // |x| + iy = hy & 0x7fffffff; // |y| + + if((ix > 0x7f800000) || // x is nan + (iy > 0x7f800000)) // y is nan + return x + y; + if(abs(y - x) <= epsilon()) + return y; // x=y, return y + if(ix == 0) + { // x == 0 + GLM_SET_FLOAT_WORD(x, (hy & 0x80000000) | 1);// return +-minsubnormal + t = x * x; + if(abs(t - x) <= epsilon()) + return t; + else + return x; // raise underflow flag + } + if(hx >= 0) + { // x > 0 + if(hx > hy) // x > y, x -= ulp + hx -= 1; + else // x < y, x += ulp + hx += 1; + } + else + { // x < 0 + if(hy >= 0 || hx > hy) // x < y, x -= ulp + hx -= 1; + else // x > y, x += ulp + hx += 1; + } + hy = hx & 0x7f800000; + if(hy >= 0x7f800000) + return x + x; // overflow + if(hy < 0x00800000) // underflow + { + t = x * x; + if(abs(t - x) > epsilon()) + { // raise underflow flag + GLM_SET_FLOAT_WORD(y, hx); + return y; + } + } + GLM_SET_FLOAT_WORD(x, hx); + return x; + } + + GLM_FUNC_QUALIFIER double nextafter(double x, double y) + { + volatile double t; + int hx, hy, ix, iy; + unsigned int lx, ly; + + GLM_EXTRACT_WORDS(hx, lx, x); + GLM_EXTRACT_WORDS(hy, ly, y); + ix = hx & 0x7fffffff; // |x| + iy = hy & 0x7fffffff; // |y| + + if(((ix >= 0x7ff00000) && ((ix - 0x7ff00000) | lx) != 0) || // x is nan + ((iy >= 0x7ff00000) && ((iy - 0x7ff00000) | ly) != 0)) // y is nan + return x + y; + if(abs(y - x) <= epsilon()) + return y; // x=y, return y + if((ix | lx) == 0) + { // x == 0 + GLM_INSERT_WORDS(x, hy & 0x80000000, 1); // return +-minsubnormal + t = x * x; + if(abs(t - x) <= epsilon()) + return t; + else + return x; // raise underflow flag + } + if(hx >= 0) { // x > 0 + if(hx > hy || ((hx == hy) && (lx > ly))) { // x > y, x -= ulp + if(lx == 0) hx -= 1; + lx -= 1; + } + else { // x < y, x += ulp + lx += 1; + if(lx == 0) hx += 1; + } + } + else { // x < 0 + if(hy >= 0 || hx > hy || ((hx == hy) && (lx > ly))){// x < y, x -= ulp + if(lx == 0) hx -= 1; + lx -= 1; + } + else { // x > y, x += ulp + lx += 1; + if(lx == 0) hx += 1; + } + } + hy = hx & 0x7ff00000; + if(hy >= 0x7ff00000) + return x + x; // overflow + if(hy < 0x00100000) + { // underflow + t = x * x; + if(abs(t - x) > epsilon()) + { // raise underflow flag + GLM_INSERT_WORDS(y, hx, lx); + return y; + } + } + GLM_INSERT_WORDS(x, hx, lx); + return x; + } +}//namespace detail +}//namespace glm + +#if(GLM_COMPILER & GLM_COMPILER_VC) +# pragma warning(pop) +#endif + +namespace glm +{ + template<> + GLM_FUNC_QUALIFIER float nextFloat(float x) + { +# if GLM_HAS_CXX11_STL + return std::nextafter(x, std::numeric_limits::max()); +# elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS))) + return detail::nextafterf(x, FLT_MAX); +# elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID) + return __builtin_nextafterf(x, FLT_MAX); +# else + return nextafterf(x, FLT_MAX); +# endif + } + + template<> + GLM_FUNC_QUALIFIER double nextFloat(double x) + { +# if GLM_HAS_CXX11_STL + return std::nextafter(x, std::numeric_limits::max()); +# elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS))) + return detail::nextafter(x, std::numeric_limits::max()); +# elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID) + return __builtin_nextafter(x, DBL_MAX); +# else + return nextafter(x, DBL_MAX); +# endif + } + + template + GLM_FUNC_QUALIFIER T nextFloat(T x, int ULPs) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'next_float' only accept floating-point input"); + assert(ULPs >= 0); + + T temp = x; + for(int i = 0; i < ULPs; ++i) + temp = nextFloat(temp); + return temp; + } + + GLM_FUNC_QUALIFIER float prevFloat(float x) + { +# if GLM_HAS_CXX11_STL + return std::nextafter(x, std::numeric_limits::min()); +# elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS))) + return detail::nextafterf(x, FLT_MIN); +# elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID) + return __builtin_nextafterf(x, FLT_MIN); +# else + return nextafterf(x, FLT_MIN); +# endif + } + + GLM_FUNC_QUALIFIER double prevFloat(double x) + { +# if GLM_HAS_CXX11_STL + return std::nextafter(x, std::numeric_limits::min()); +# elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS))) + return _nextafter(x, DBL_MIN); +# elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID) + return __builtin_nextafter(x, DBL_MIN); +# else + return nextafter(x, DBL_MIN); +# endif + } + + template + GLM_FUNC_QUALIFIER T prevFloat(T x, int ULPs) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'prev_float' only accept floating-point input"); + assert(ULPs >= 0); + + T temp = x; + for(int i = 0; i < ULPs; ++i) + temp = prevFloat(temp); + return temp; + } + + GLM_FUNC_QUALIFIER int floatDistance(float x, float y) + { + detail::float_t const a(x); + detail::float_t const b(y); + + return abs(a.i - b.i); + } + + GLM_FUNC_QUALIFIER int64 floatDistance(double x, double y) + { + detail::float_t const a(x); + detail::float_t const b(y); + + return abs(a.i - b.i); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_bool1.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_bool1.hpp new file mode 100644 index 0000000000000000000000000000000000000000..002c3202adf0dfbb2db1eedf23f2f677d343c6f3 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_bool1.hpp @@ -0,0 +1,30 @@ +/// @ref ext_vector_bool1 +/// @file glm/ext/vector_bool1.hpp +/// +/// @defgroup ext_vector_bool1 GLM_EXT_vector_bool1 +/// @ingroup ext +/// +/// Exposes bvec1 vector type. +/// +/// Include to use the features of this extension. +/// +/// @see ext_vector_bool1_precision extension. + +#pragma once + +#include "../detail/type_vec1.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_bool1 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_bool1 + /// @{ + + /// 1 components vector of boolean. + typedef vec<1, bool, defaultp> bvec1; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_bool1_precision.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_bool1_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e62d3cfb5fd4c6f31e9bb22cc4129c7bf7f28e01 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_bool1_precision.hpp @@ -0,0 +1,34 @@ +/// @ref ext_vector_bool1_precision +/// @file glm/ext/vector_bool1_precision.hpp +/// +/// @defgroup ext_vector_bool1_precision GLM_EXT_vector_bool1_precision +/// @ingroup ext +/// +/// Exposes highp_bvec1, mediump_bvec1 and lowp_bvec1 types. +/// +/// Include to use the features of this extension. + +#pragma once + +#include "../detail/type_vec1.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_bool1_precision extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_bool1_precision + /// @{ + + /// 1 component vector of bool values. + typedef vec<1, bool, highp> highp_bvec1; + + /// 1 component vector of bool values. + typedef vec<1, bool, mediump> mediump_bvec1; + + /// 1 component vector of bool values. + typedef vec<1, bool, lowp> lowp_bvec1; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_bool2.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_bool2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..52288b75c6973f49aabb5b8a15ddd1036b172f84 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_bool2.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_bool2.hpp + +#pragma once +#include "../detail/type_vec2.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 2 components vector of boolean. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<2, bool, defaultp> bvec2; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_bool2_precision.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_bool2_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..43709332c6298ff345ab3b061917272aa954f655 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_bool2_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/vector_bool2_precision.hpp + +#pragma once +#include "../detail/type_vec2.hpp" + +namespace glm +{ + /// @addtogroup core_vector_precision + /// @{ + + /// 2 components vector of high qualifier bool numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<2, bool, highp> highp_bvec2; + + /// 2 components vector of medium qualifier bool numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<2, bool, mediump> mediump_bvec2; + + /// 2 components vector of low qualifier bool numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<2, bool, lowp> lowp_bvec2; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_bool3.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_bool3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..90a0b7ea5ac048f264dff79fe8d270993e55d414 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_bool3.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_bool3.hpp + +#pragma once +#include "../detail/type_vec3.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 3 components vector of boolean. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<3, bool, defaultp> bvec3; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_bool3_precision.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_bool3_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..89cd2d3207a168545f98a3d0af69b9c772a7c965 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_bool3_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/vector_bool3_precision.hpp + +#pragma once +#include "../detail/type_vec3.hpp" + +namespace glm +{ + /// @addtogroup core_vector_precision + /// @{ + + /// 3 components vector of high qualifier bool numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<3, bool, highp> highp_bvec3; + + /// 3 components vector of medium qualifier bool numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<3, bool, mediump> mediump_bvec3; + + /// 3 components vector of low qualifier bool numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<3, bool, lowp> lowp_bvec3; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_bool4.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_bool4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..18aa71bd0f49851cac489520c4df893370ddeb6e --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_bool4.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_bool4.hpp + +#pragma once +#include "../detail/type_vec4.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 4 components vector of boolean. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<4, bool, defaultp> bvec4; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_bool4_precision.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_bool4_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..79786e54206b9cb3e92c6ba3d9d69f35200e552b --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_bool4_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/vector_bool4_precision.hpp + +#pragma once +#include "../detail/type_vec4.hpp" + +namespace glm +{ + /// @addtogroup core_vector_precision + /// @{ + + /// 4 components vector of high qualifier bool numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<4, bool, highp> highp_bvec4; + + /// 4 components vector of medium qualifier bool numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<4, bool, mediump> mediump_bvec4; + + /// 4 components vector of low qualifier bool numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<4, bool, lowp> lowp_bvec4; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_common.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_common.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c0a2858cc288e4dd8a3f93830dda2575fb498fc2 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_common.hpp @@ -0,0 +1,228 @@ +/// @ref ext_vector_common +/// @file glm/ext/vector_common.hpp +/// +/// @defgroup ext_vector_common GLM_EXT_vector_common +/// @ingroup ext +/// +/// Exposes min and max functions for 3 to 4 vector parameters. +/// +/// Include to use the features of this extension. +/// +/// @see core_common +/// @see ext_scalar_common + +#pragma once + +// Dependency: +#include "../ext/scalar_common.hpp" +#include "../common.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_common extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_common + /// @{ + + /// Return the minimum component-wise values of 3 inputs + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec min(vec const& a, vec const& b, vec const& c); + + /// Return the minimum component-wise values of 4 inputs + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec min(vec const& a, vec const& b, vec const& c, vec const& d); + + /// Return the maximum component-wise values of 3 inputs + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec max(vec const& x, vec const& y, vec const& z); + + /// Return the maximum component-wise values of 4 inputs + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec max( vec const& x, vec const& y, vec const& z, vec const& w); + + /// Returns y if y < x; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see std::fmin documentation + template + GLM_FUNC_DECL vec fmin(vec const& x, T y); + + /// Returns y if y < x; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see std::fmin documentation + template + GLM_FUNC_DECL vec fmin(vec const& x, vec const& y); + + /// Returns y if y < x; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see std::fmin documentation + template + GLM_FUNC_DECL vec fmin(vec const& a, vec const& b, vec const& c); + + /// Returns y if y < x; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see std::fmin documentation + template + GLM_FUNC_DECL vec fmin(vec const& a, vec const& b, vec const& c, vec const& d); + + /// Returns y if x < y; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see std::fmax documentation + template + GLM_FUNC_DECL vec fmax(vec const& a, T b); + + /// Returns y if x < y; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see std::fmax documentation + template + GLM_FUNC_DECL vec fmax(vec const& a, vec const& b); + + /// Returns y if x < y; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see std::fmax documentation + template + GLM_FUNC_DECL vec fmax(vec const& a, vec const& b, vec const& c); + + /// Returns y if x < y; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see std::fmax documentation + template + GLM_FUNC_DECL vec fmax(vec const& a, vec const& b, vec const& c, vec const& d); + + /// Returns min(max(x, minVal), maxVal) for each component in x. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_vector_common + template + GLM_FUNC_DECL vec fclamp(vec const& x, T minVal, T maxVal); + + /// Returns min(max(x, minVal), maxVal) for each component in x. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_vector_common + template + GLM_FUNC_DECL vec fclamp(vec const& x, vec const& minVal, vec const& maxVal); + + /// Simulate GL_CLAMP OpenGL wrap mode + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_vector_common extension. + template + GLM_FUNC_DECL vec clamp(vec const& Texcoord); + + /// Simulate GL_REPEAT OpenGL wrap mode + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_vector_common extension. + template + GLM_FUNC_DECL vec repeat(vec const& Texcoord); + + /// Simulate GL_MIRRORED_REPEAT OpenGL wrap mode + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_vector_common extension. + template + GLM_FUNC_DECL vec mirrorClamp(vec const& Texcoord); + + /// Simulate GL_MIRROR_REPEAT OpenGL wrap mode + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_vector_common extension. + template + GLM_FUNC_DECL vec mirrorRepeat(vec const& Texcoord); + + /// Returns a value equal to the nearest integer to x. + /// The fraction 0.5 will round in a direction chosen by the + /// implementation, presumably the direction that is fastest. + /// + /// @param x The values of the argument must be greater or equal to zero. + /// @tparam T floating point scalar types. + /// + /// @see GLSL round man page + /// @see ext_vector_common extension. + template + GLM_FUNC_DECL vec iround(vec const& x); + + /// Returns a value equal to the nearest integer to x. + /// The fraction 0.5 will round in a direction chosen by the + /// implementation, presumably the direction that is fastest. + /// + /// @param x The values of the argument must be greater or equal to zero. + /// @tparam T floating point scalar types. + /// + /// @see GLSL round man page + /// @see ext_vector_common extension. + template + GLM_FUNC_DECL vec uround(vec const& x); + + /// @} +}//namespace glm + +#include "vector_common.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_common.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_common.inl new file mode 100644 index 0000000000000000000000000000000000000000..67817fc554b06c69935ca3a51af3a547c95c1c57 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_common.inl @@ -0,0 +1,147 @@ +#include "../detail/_vectorize.hpp" + +namespace glm +{ + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec min(vec const& x, vec const& y, vec const& z) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer, "'min' only accept floating-point or integer inputs"); + return glm::min(glm::min(x, y), z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec min(vec const& x, vec const& y, vec const& z, vec const& w) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer, "'min' only accept floating-point or integer inputs"); + return glm::min(glm::min(x, y), glm::min(z, w)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec max(vec const& x, vec const& y, vec const& z) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer, "'max' only accept floating-point or integer inputs"); + return glm::max(glm::max(x, y), z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec max(vec const& x, vec const& y, vec const& z, vec const& w) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer, "'max' only accept floating-point or integer inputs"); + return glm::max(glm::max(x, y), glm::max(z, w)); + } + + template + GLM_FUNC_QUALIFIER vec fmin(vec const& a, T b) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmin' only accept floating-point inputs"); + return detail::functor2::call(fmin, a, vec(b)); + } + + template + GLM_FUNC_QUALIFIER vec fmin(vec const& a, vec const& b) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmin' only accept floating-point inputs"); + return detail::functor2::call(fmin, a, b); + } + + template + GLM_FUNC_QUALIFIER vec fmin(vec const& a, vec const& b, vec const& c) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmin' only accept floating-point inputs"); + return fmin(fmin(a, b), c); + } + + template + GLM_FUNC_QUALIFIER vec fmin(vec const& a, vec const& b, vec const& c, vec const& d) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmin' only accept floating-point inputs"); + return fmin(fmin(a, b), fmin(c, d)); + } + + template + GLM_FUNC_QUALIFIER vec fmax(vec const& a, T b) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmax' only accept floating-point inputs"); + return detail::functor2::call(fmax, a, vec(b)); + } + + template + GLM_FUNC_QUALIFIER vec fmax(vec const& a, vec const& b) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmax' only accept floating-point inputs"); + return detail::functor2::call(fmax, a, b); + } + + template + GLM_FUNC_QUALIFIER vec fmax(vec const& a, vec const& b, vec const& c) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmax' only accept floating-point inputs"); + return fmax(fmax(a, b), c); + } + + template + GLM_FUNC_QUALIFIER vec fmax(vec const& a, vec const& b, vec const& c, vec const& d) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmax' only accept floating-point inputs"); + return fmax(fmax(a, b), fmax(c, d)); + } + + template + GLM_FUNC_QUALIFIER vec fclamp(vec const& x, T minVal, T maxVal) + { + return fmin(fmax(x, vec(minVal)), vec(maxVal)); + } + + template + GLM_FUNC_QUALIFIER vec fclamp(vec const& x, vec const& minVal, vec const& maxVal) + { + return fmin(fmax(x, minVal), maxVal); + } + + template + GLM_FUNC_QUALIFIER vec clamp(vec const& Texcoord) + { + return glm::clamp(Texcoord, vec(0), vec(1)); + } + + template + GLM_FUNC_QUALIFIER vec repeat(vec const& Texcoord) + { + return glm::fract(Texcoord); + } + + template + GLM_FUNC_QUALIFIER vec mirrorClamp(vec const& Texcoord) + { + return glm::fract(glm::abs(Texcoord)); + } + + template + GLM_FUNC_QUALIFIER vec mirrorRepeat(vec const& Texcoord) + { + vec const Abs = glm::abs(Texcoord); + vec const Clamp = glm::mod(glm::floor(Abs), vec(2)); + vec const Floor = glm::floor(Abs); + vec const Rest = Abs - Floor; + vec const Mirror = Clamp + Rest; + return mix(Rest, vec(1) - Rest, glm::greaterThanEqual(Mirror, vec(1))); + } + + template + GLM_FUNC_QUALIFIER vec iround(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'iround' only accept floating-point inputs"); + assert(all(lessThanEqual(vec(0), x))); + + return vec(x + static_cast(0.5)); + } + + template + GLM_FUNC_QUALIFIER vec uround(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'uround' only accept floating-point inputs"); + assert(all(lessThanEqual(vec(0), x))); + + return vec(x + static_cast(0.5)); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_double1.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_double1.hpp new file mode 100644 index 0000000000000000000000000000000000000000..388266774d8b3371be46da89e13af7b1edde240c --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_double1.hpp @@ -0,0 +1,31 @@ +/// @ref ext_vector_double1 +/// @file glm/ext/vector_double1.hpp +/// +/// @defgroup ext_vector_double1 GLM_EXT_vector_double1 +/// @ingroup ext +/// +/// Exposes double-precision floating point vector type with one component. +/// +/// Include to use the features of this extension. +/// +/// @see ext_vector_double1_precision extension. +/// @see ext_vector_float1 extension. + +#pragma once + +#include "../detail/type_vec1.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_double1 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_double1 + /// @{ + + /// 1 components vector of double-precision floating-point numbers. + typedef vec<1, double, defaultp> dvec1; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_double1_precision.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_double1_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1d4719595481adf57c071e0fbf6df4716447a55a --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_double1_precision.hpp @@ -0,0 +1,36 @@ +/// @ref ext_vector_double1_precision +/// @file glm/ext/vector_double1_precision.hpp +/// +/// @defgroup ext_vector_double1_precision GLM_EXT_vector_double1_precision +/// @ingroup ext +/// +/// Exposes highp_dvec1, mediump_dvec1 and lowp_dvec1 types. +/// +/// Include to use the features of this extension. +/// +/// @see ext_vector_double1 + +#pragma once + +#include "../detail/type_vec1.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_double1_precision extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_double1_precision + /// @{ + + /// 1 component vector of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<1, double, highp> highp_dvec1; + + /// 1 component vector of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<1, double, mediump> mediump_dvec1; + + /// 1 component vector of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<1, double, lowp> lowp_dvec1; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_double2.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_double2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..60e357750b675415da9d8911b92ba702b7aa8390 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_double2.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_double2.hpp + +#pragma once +#include "../detail/type_vec2.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 2 components vector of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<2, double, defaultp> dvec2; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_double2_precision.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_double2_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..fa53940f6bbed061a7f3fc4162877b68b96c9388 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_double2_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/vector_double2_precision.hpp + +#pragma once +#include "../detail/type_vec2.hpp" + +namespace glm +{ + /// @addtogroup core_vector_precision + /// @{ + + /// 2 components vector of high double-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<2, double, highp> highp_dvec2; + + /// 2 components vector of medium double-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<2, double, mediump> mediump_dvec2; + + /// 2 components vector of low double-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<2, double, lowp> lowp_dvec2; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_double3.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_double3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6dfe4c675b5d7af1f3538f5c32203065453b4025 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_double3.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_double3.hpp + +#pragma once +#include "../detail/type_vec3.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 3 components vector of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<3, double, defaultp> dvec3; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_double3_precision.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_double3_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a8cfa37a8c78009bd18ddfbfff7e4a658300e712 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_double3_precision.hpp @@ -0,0 +1,34 @@ +/// @ref core +/// @file glm/ext/vector_double3_precision.hpp + +#pragma once +#include "../detail/type_vec3.hpp" + +namespace glm +{ + /// @addtogroup core_vector_precision + /// @{ + + /// 3 components vector of high double-qualifier floating-point numbers. + /// There is no guarantee on the actual qualifier. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<3, double, highp> highp_dvec3; + + /// 3 components vector of medium double-qualifier floating-point numbers. + /// There is no guarantee on the actual qualifier. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<3, double, mediump> mediump_dvec3; + + /// 3 components vector of low double-qualifier floating-point numbers. + /// There is no guarantee on the actual qualifier. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<3, double, lowp> lowp_dvec3; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_double4.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_double4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..87f225f64d4ab38b0d7212174308e606e2c9ad18 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_double4.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_double4.hpp + +#pragma once +#include "../detail/type_vec4.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 4 components vector of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<4, double, defaultp> dvec4; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_double4_precision.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_double4_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..09cafa1ebafdd72b85c4f01746bf315ddee1c02a --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_double4_precision.hpp @@ -0,0 +1,35 @@ +/// @ref core +/// @file glm/ext/vector_double4_precision.hpp + +#pragma once +#include "../detail/setup.hpp" +#include "../detail/type_vec4.hpp" + +namespace glm +{ + /// @addtogroup core_vector_precision + /// @{ + + /// 4 components vector of high double-qualifier floating-point numbers. + /// There is no guarantee on the actual qualifier. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<4, double, highp> highp_dvec4; + + /// 4 components vector of medium double-qualifier floating-point numbers. + /// There is no guarantee on the actual qualifier. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<4, double, mediump> mediump_dvec4; + + /// 4 components vector of low double-qualifier floating-point numbers. + /// There is no guarantee on the actual qualifier. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<4, double, lowp> lowp_dvec4; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_float1.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_float1.hpp new file mode 100644 index 0000000000000000000000000000000000000000..28acc2c9ca59619ba1401032141ed223d347650f --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_float1.hpp @@ -0,0 +1,31 @@ +/// @ref ext_vector_float1 +/// @file glm/ext/vector_float1.hpp +/// +/// @defgroup ext_vector_float1 GLM_EXT_vector_float1 +/// @ingroup ext +/// +/// Exposes single-precision floating point vector type with one component. +/// +/// Include to use the features of this extension. +/// +/// @see ext_vector_float1_precision extension. +/// @see ext_vector_double1 extension. + +#pragma once + +#include "../detail/type_vec1.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_float1 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_float1 + /// @{ + + /// 1 components vector of single-precision floating-point numbers. + typedef vec<1, float, defaultp> vec1; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_float1_precision.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_float1_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6e8dad8d17c8e0e2765aa53323a1c093c685279e --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_float1_precision.hpp @@ -0,0 +1,36 @@ +/// @ref ext_vector_float1_precision +/// @file glm/ext/vector_float1_precision.hpp +/// +/// @defgroup ext_vector_float1_precision GLM_EXT_vector_float1_precision +/// @ingroup ext +/// +/// Exposes highp_vec1, mediump_vec1 and lowp_vec1 types. +/// +/// Include to use the features of this extension. +/// +/// @see ext_vector_float1 extension. + +#pragma once + +#include "../detail/type_vec1.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_float1_precision extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_float1_precision + /// @{ + + /// 1 component vector of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<1, float, highp> highp_vec1; + + /// 1 component vector of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<1, float, mediump> mediump_vec1; + + /// 1 component vector of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<1, float, lowp> lowp_vec1; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_float2.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_float2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d31545dcc966b37c0c942a9d248bb337c4b178a5 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_float2.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_float2.hpp + +#pragma once +#include "../detail/type_vec2.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 2 components vector of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<2, float, defaultp> vec2; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_float2_precision.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_float2_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..23c0820d0ae8445f4539bf0b7f7c18886eb8ae41 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_float2_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/vector_float2_precision.hpp + +#pragma once +#include "../detail/type_vec2.hpp" + +namespace glm +{ + /// @addtogroup core_vector_precision + /// @{ + + /// 2 components vector of high single-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<2, float, highp> highp_vec2; + + /// 2 components vector of medium single-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<2, float, mediump> mediump_vec2; + + /// 2 components vector of low single-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<2, float, lowp> lowp_vec2; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_float3.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_float3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..cd79a62004e41ebb2798363235b7573496eacf05 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_float3.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_float3.hpp + +#pragma once +#include "../detail/type_vec3.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 3 components vector of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<3, float, defaultp> vec3; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_float3_precision.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_float3_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..be640b53168387c07c3c2f8640794699a8e5953c --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_float3_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/vector_float3_precision.hpp + +#pragma once +#include "../detail/type_vec3.hpp" + +namespace glm +{ + /// @addtogroup core_vector_precision + /// @{ + + /// 3 components vector of high single-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<3, float, highp> highp_vec3; + + /// 3 components vector of medium single-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<3, float, mediump> mediump_vec3; + + /// 3 components vector of low single-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<3, float, lowp> lowp_vec3; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_float4.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_float4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d84adcc22fd2b2e914ab6f56af92d534a00ddbd7 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_float4.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_float4.hpp + +#pragma once +#include "../detail/type_vec4.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 4 components vector of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<4, float, defaultp> vec4; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_float4_precision.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_float4_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..aede83882e55140fa53adde2ea0b72be29c77490 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_float4_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/vector_float4_precision.hpp + +#pragma once +#include "../detail/type_vec4.hpp" + +namespace glm +{ + /// @addtogroup core_vector_precision + /// @{ + + /// 4 components vector of high single-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<4, float, highp> highp_vec4; + + /// 4 components vector of medium single-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<4, float, mediump> mediump_vec4; + + /// 4 components vector of low single-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<4, float, lowp> lowp_vec4; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_int1.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_int1.hpp new file mode 100644 index 0000000000000000000000000000000000000000..dc8603891a9967bace26b4c23f4c5485b22f6ba4 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_int1.hpp @@ -0,0 +1,32 @@ +/// @ref ext_vector_int1 +/// @file glm/ext/vector_int1.hpp +/// +/// @defgroup ext_vector_int1 GLM_EXT_vector_int1 +/// @ingroup ext +/// +/// Exposes ivec1 vector type. +/// +/// Include to use the features of this extension. +/// +/// @see ext_vector_uint1 extension. +/// @see ext_vector_int1_precision extension. + +#pragma once + +#include "../detail/type_vec1.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_int1 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_int1 + /// @{ + + /// 1 component vector of signed integer numbers. + typedef vec<1, int, defaultp> ivec1; + + /// @} +}//namespace glm + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_int1_sized.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_int1_sized.hpp new file mode 100644 index 0000000000000000000000000000000000000000..de0d4cf82e633bc8a1139f770a9f17349462433f --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_int1_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_vector_int1_sized +/// @file glm/ext/vector_int1_sized.hpp +/// +/// @defgroup ext_vector_int1_sized GLM_EXT_vector_int1_sized +/// @ingroup ext +/// +/// Exposes sized signed integer vector types. +/// +/// Include to use the features of this extension. +/// +/// @see ext_scalar_int_sized +/// @see ext_vector_uint1_sized + +#pragma once + +#include "../ext/vector_int1.hpp" +#include "../ext/scalar_int_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_int1_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_int1_sized + /// @{ + + /// 8 bit signed integer vector of 1 component type. + /// + /// @see ext_vector_int1_sized + typedef vec<1, int8, defaultp> i8vec1; + + /// 16 bit signed integer vector of 1 component type. + /// + /// @see ext_vector_int1_sized + typedef vec<1, int16, defaultp> i16vec1; + + /// 32 bit signed integer vector of 1 component type. + /// + /// @see ext_vector_int1_sized + typedef vec<1, int32, defaultp> i32vec1; + + /// 64 bit signed integer vector of 1 component type. + /// + /// @see ext_vector_int1_sized + typedef vec<1, int64, defaultp> i64vec1; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_int2.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_int2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..aef803e91b736a1f2a3a32deefecdebbbc70fe5d --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_int2.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_int2.hpp + +#pragma once +#include "../detail/type_vec2.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 2 components vector of signed integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<2, int, defaultp> ivec2; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_int2_sized.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_int2_sized.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1fd57eef310d7522f0969f2ca3f71857aa40f596 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_int2_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_vector_int2_sized +/// @file glm/ext/vector_int2_sized.hpp +/// +/// @defgroup ext_vector_int2_sized GLM_EXT_vector_int2_sized +/// @ingroup ext +/// +/// Exposes sized signed integer vector of 2 components type. +/// +/// Include to use the features of this extension. +/// +/// @see ext_scalar_int_sized +/// @see ext_vector_uint2_sized + +#pragma once + +#include "../ext/vector_int2.hpp" +#include "../ext/scalar_int_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_int2_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_int2_sized + /// @{ + + /// 8 bit signed integer vector of 2 components type. + /// + /// @see ext_vector_int2_sized + typedef vec<2, int8, defaultp> i8vec2; + + /// 16 bit signed integer vector of 2 components type. + /// + /// @see ext_vector_int2_sized + typedef vec<2, int16, defaultp> i16vec2; + + /// 32 bit signed integer vector of 2 components type. + /// + /// @see ext_vector_int2_sized + typedef vec<2, int32, defaultp> i32vec2; + + /// 64 bit signed integer vector of 2 components type. + /// + /// @see ext_vector_int2_sized + typedef vec<2, int64, defaultp> i64vec2; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_int3.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_int3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4767e61e88c08a38696700ab9d2517bcde346085 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_int3.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_int3.hpp + +#pragma once +#include "../detail/type_vec3.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 3 components vector of signed integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<3, int, defaultp> ivec3; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_int3_sized.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_int3_sized.hpp new file mode 100644 index 0000000000000000000000000000000000000000..085a3febbffdf31a2b35637f403dfb366c0b03de --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_int3_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_vector_int3_sized +/// @file glm/ext/vector_int3_sized.hpp +/// +/// @defgroup ext_vector_int3_sized GLM_EXT_vector_int3_sized +/// @ingroup ext +/// +/// Exposes sized signed integer vector of 3 components type. +/// +/// Include to use the features of this extension. +/// +/// @see ext_scalar_int_sized +/// @see ext_vector_uint3_sized + +#pragma once + +#include "../ext/vector_int3.hpp" +#include "../ext/scalar_int_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_int3_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_int3_sized + /// @{ + + /// 8 bit signed integer vector of 3 components type. + /// + /// @see ext_vector_int3_sized + typedef vec<3, int8, defaultp> i8vec3; + + /// 16 bit signed integer vector of 3 components type. + /// + /// @see ext_vector_int3_sized + typedef vec<3, int16, defaultp> i16vec3; + + /// 32 bit signed integer vector of 3 components type. + /// + /// @see ext_vector_int3_sized + typedef vec<3, int32, defaultp> i32vec3; + + /// 64 bit signed integer vector of 3 components type. + /// + /// @see ext_vector_int3_sized + typedef vec<3, int64, defaultp> i64vec3; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_int4.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_int4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..bb23adf706c226d13cb3291f7ab9ded06c30e945 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_int4.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_int4.hpp + +#pragma once +#include "../detail/type_vec4.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 4 components vector of signed integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<4, int, defaultp> ivec4; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_int4_sized.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_int4_sized.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c63d46540b3e149429c4afa540fac28792b0a00f --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_int4_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_vector_int4_sized +/// @file glm/ext/vector_int4_sized.hpp +/// +/// @defgroup ext_vector_int4_sized GLM_EXT_vector_int4_sized +/// @ingroup ext +/// +/// Exposes sized signed integer vector of 4 components type. +/// +/// Include to use the features of this extension. +/// +/// @see ext_scalar_int_sized +/// @see ext_vector_uint4_sized + +#pragma once + +#include "../ext/vector_int4.hpp" +#include "../ext/scalar_int_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_int4_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_int4_sized + /// @{ + + /// 8 bit signed integer vector of 4 components type. + /// + /// @see ext_vector_int4_sized + typedef vec<4, int8, defaultp> i8vec4; + + /// 16 bit signed integer vector of 4 components type. + /// + /// @see ext_vector_int4_sized + typedef vec<4, int16, defaultp> i16vec4; + + /// 32 bit signed integer vector of 4 components type. + /// + /// @see ext_vector_int4_sized + typedef vec<4, int32, defaultp> i32vec4; + + /// 64 bit signed integer vector of 4 components type. + /// + /// @see ext_vector_int4_sized + typedef vec<4, int64, defaultp> i64vec4; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_integer.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_integer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1304dd8d660f0e051500cd3ff8a905221f94fd12 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_integer.hpp @@ -0,0 +1,149 @@ +/// @ref ext_vector_integer +/// @file glm/ext/vector_integer.hpp +/// +/// @see core (dependence) +/// @see ext_vector_integer (dependence) +/// +/// @defgroup ext_vector_integer GLM_EXT_vector_integer +/// @ingroup ext +/// +/// Include to use the features of this extension. + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../detail/qualifier.hpp" +#include "../detail/_vectorize.hpp" +#include "../vector_relational.hpp" +#include "../common.hpp" +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_integer extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_integer + /// @{ + + /// Return true if the value is a power of two number. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Signed or unsigned integer scalar types. + /// @tparam Q Value from qualifier enum + /// + /// @see ext_vector_integer + template + GLM_FUNC_DECL vec isPowerOfTwo(vec const& v); + + /// Return the power of two number which value is just higher the input value, + /// round up to a power of two. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Signed or unsigned integer scalar types. + /// @tparam Q Value from qualifier enum + /// + /// @see ext_vector_integer + template + GLM_FUNC_DECL vec nextPowerOfTwo(vec const& v); + + /// Return the power of two number which value is just lower the input value, + /// round down to a power of two. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Signed or unsigned integer scalar types. + /// @tparam Q Value from qualifier enum + /// + /// @see ext_vector_integer + template + GLM_FUNC_DECL vec prevPowerOfTwo(vec const& v); + + /// Return true if the 'Value' is a multiple of 'Multiple'. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Signed or unsigned integer scalar types. + /// @tparam Q Value from qualifier enum + /// + /// @see ext_vector_integer + template + GLM_FUNC_DECL vec isMultiple(vec const& v, T Multiple); + + /// Return true if the 'Value' is a multiple of 'Multiple'. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Signed or unsigned integer scalar types. + /// @tparam Q Value from qualifier enum + /// + /// @see ext_vector_integer + template + GLM_FUNC_DECL vec isMultiple(vec const& v, vec const& Multiple); + + /// Higher multiple number of Source. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Signed or unsigned integer scalar types. + /// @tparam Q Value from qualifier enum + /// + /// @param v Source values to which is applied the function + /// @param Multiple Must be a null or positive value + /// + /// @see ext_vector_integer + template + GLM_FUNC_DECL vec nextMultiple(vec const& v, T Multiple); + + /// Higher multiple number of Source. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Signed or unsigned integer scalar types. + /// @tparam Q Value from qualifier enum + /// + /// @param v Source values to which is applied the function + /// @param Multiple Must be a null or positive value + /// + /// @see ext_vector_integer + template + GLM_FUNC_DECL vec nextMultiple(vec const& v, vec const& Multiple); + + /// Lower multiple number of Source. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Signed or unsigned integer scalar types. + /// @tparam Q Value from qualifier enum + /// + /// @param v Source values to which is applied the function + /// @param Multiple Must be a null or positive value + /// + /// @see ext_vector_integer + template + GLM_FUNC_DECL vec prevMultiple(vec const& v, T Multiple); + + /// Lower multiple number of Source. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Signed or unsigned integer scalar types. + /// @tparam Q Value from qualifier enum + /// + /// @param v Source values to which is applied the function + /// @param Multiple Must be a null or positive value + /// + /// @see ext_vector_integer + template + GLM_FUNC_DECL vec prevMultiple(vec const& v, vec const& Multiple); + + /// Returns the bit number of the Nth significant bit set to + /// 1 in the binary representation of value. + /// If value bitcount is less than the Nth significant bit, -1 will be returned. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Signed or unsigned integer scalar types. + /// + /// @see ext_vector_integer + template + GLM_FUNC_DECL vec findNSB(vec const& Source, vec SignificantBitCount); + + /// @} +} //namespace glm + +#include "vector_integer.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_integer.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_integer.inl new file mode 100644 index 0000000000000000000000000000000000000000..cefb132e237af22509626d793b69c0ab08b7ebec --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_integer.inl @@ -0,0 +1,85 @@ +#include "scalar_integer.hpp" + +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec isPowerOfTwo(vec const& Value) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'isPowerOfTwo' only accept integer inputs"); + + vec const Result(abs(Value)); + return equal(Result & (Result - vec(1)), vec(0)); + } + + template + GLM_FUNC_QUALIFIER vec nextPowerOfTwo(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'nextPowerOfTwo' only accept integer inputs"); + + return detail::compute_ceilPowerOfTwo::is_signed>::call(v); + } + + template + GLM_FUNC_QUALIFIER vec prevPowerOfTwo(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'prevPowerOfTwo' only accept integer inputs"); + + return detail::functor1::call(prevPowerOfTwo, v); + } + + template + GLM_FUNC_QUALIFIER vec isMultiple(vec const& Value, T Multiple) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'isMultiple' only accept integer inputs"); + + return equal(Value % Multiple, vec(0)); + } + + template + GLM_FUNC_QUALIFIER vec isMultiple(vec const& Value, vec const& Multiple) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'isMultiple' only accept integer inputs"); + + return equal(Value % Multiple, vec(0)); + } + + template + GLM_FUNC_QUALIFIER vec nextMultiple(vec const& Source, T Multiple) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'nextMultiple' only accept integer inputs"); + + return detail::functor2::call(nextMultiple, Source, vec(Multiple)); + } + + template + GLM_FUNC_QUALIFIER vec nextMultiple(vec const& Source, vec const& Multiple) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'nextMultiple' only accept integer inputs"); + + return detail::functor2::call(nextMultiple, Source, Multiple); + } + + template + GLM_FUNC_QUALIFIER vec prevMultiple(vec const& Source, T Multiple) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'prevMultiple' only accept integer inputs"); + + return detail::functor2::call(prevMultiple, Source, vec(Multiple)); + } + + template + GLM_FUNC_QUALIFIER vec prevMultiple(vec const& Source, vec const& Multiple) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'prevMultiple' only accept integer inputs"); + + return detail::functor2::call(prevMultiple, Source, Multiple); + } + + template + GLM_FUNC_QUALIFIER vec findNSB(vec const& Source, vec SignificantBitCount) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'findNSB' only accept integer inputs"); + + return detail::functor2_vec_int::call(findNSB, Source, SignificantBitCount); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_packing.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_packing.hpp new file mode 100644 index 0000000000000000000000000000000000000000..76e5d0cc6c2f0c8d6a6cbcbc176a1fc7b90b9b32 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_packing.hpp @@ -0,0 +1,32 @@ +/// @ref ext_vector_packing +/// @file glm/ext/vector_packing.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_vector_packing GLM_EXT_vector_packing +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// This extension provides a set of function to convert vectors to packed +/// formats. + +#pragma once + +// Dependency: +#include "../detail/qualifier.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_packing extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_packing + /// @{ + + + /// @} +}// namespace glm + +#include "vector_packing.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_packing.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_packing.inl new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_reciprocal.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_reciprocal.hpp new file mode 100644 index 0000000000000000000000000000000000000000..84d67662f26e0456c5c1caf426ed3b73af54b2ca --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_reciprocal.hpp @@ -0,0 +1,135 @@ +/// @ref ext_vector_reciprocal +/// @file glm/ext/vector_reciprocal.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_vector_reciprocal GLM_EXT_vector_reciprocal +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Define secant, cosecant and cotangent functions. + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_reciprocal extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_reciprocal + /// @{ + + /// Secant function. + /// hypotenuse / adjacent or 1 / cos(x) + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see ext_vector_reciprocal + template + GLM_FUNC_DECL genType sec(genType angle); + + /// Cosecant function. + /// hypotenuse / opposite or 1 / sin(x) + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see ext_vector_reciprocal + template + GLM_FUNC_DECL genType csc(genType angle); + + /// Cotangent function. + /// adjacent / opposite or 1 / tan(x) + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see ext_vector_reciprocal + template + GLM_FUNC_DECL genType cot(genType angle); + + /// Inverse secant function. + /// + /// @return Return an angle expressed in radians. + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see ext_vector_reciprocal + template + GLM_FUNC_DECL genType asec(genType x); + + /// Inverse cosecant function. + /// + /// @return Return an angle expressed in radians. + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see ext_vector_reciprocal + template + GLM_FUNC_DECL genType acsc(genType x); + + /// Inverse cotangent function. + /// + /// @return Return an angle expressed in radians. + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see ext_vector_reciprocal + template + GLM_FUNC_DECL genType acot(genType x); + + /// Secant hyperbolic function. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see ext_vector_reciprocal + template + GLM_FUNC_DECL genType sech(genType angle); + + /// Cosecant hyperbolic function. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see ext_vector_reciprocal + template + GLM_FUNC_DECL genType csch(genType angle); + + /// Cotangent hyperbolic function. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see ext_vector_reciprocal + template + GLM_FUNC_DECL genType coth(genType angle); + + /// Inverse secant hyperbolic function. + /// + /// @return Return an angle expressed in radians. + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see ext_vector_reciprocal + template + GLM_FUNC_DECL genType asech(genType x); + + /// Inverse cosecant hyperbolic function. + /// + /// @return Return an angle expressed in radians. + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see ext_vector_reciprocal + template + GLM_FUNC_DECL genType acsch(genType x); + + /// Inverse cotangent hyperbolic function. + /// + /// @return Return an angle expressed in radians. + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see ext_vector_reciprocal + template + GLM_FUNC_DECL genType acoth(genType x); + + /// @} +}//namespace glm + +#include "vector_reciprocal.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_reciprocal.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_reciprocal.inl new file mode 100644 index 0000000000000000000000000000000000000000..0d3c25fb61aac9e4280a4c11590a75fe3d40a09f --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_reciprocal.inl @@ -0,0 +1,105 @@ +/// @ref ext_vector_reciprocal + +#include "../trigonometric.hpp" +#include + +namespace glm +{ + // sec + template + GLM_FUNC_QUALIFIER vec sec(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'sec' only accept floating-point inputs"); + return static_cast(1) / detail::functor1::call(cos, x); + } + + // csc + template + GLM_FUNC_QUALIFIER vec csc(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'csc' only accept floating-point inputs"); + return static_cast(1) / detail::functor1::call(sin, x); + } + + // cot + template + GLM_FUNC_QUALIFIER vec cot(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'cot' only accept floating-point inputs"); + T const pi_over_2 = static_cast(3.1415926535897932384626433832795 / 2.0); + return detail::functor1::call(tan, pi_over_2 - x); + } + + // asec + template + GLM_FUNC_QUALIFIER vec asec(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'asec' only accept floating-point inputs"); + return detail::functor1::call(acos, static_cast(1) / x); + } + + // acsc + template + GLM_FUNC_QUALIFIER vec acsc(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acsc' only accept floating-point inputs"); + return detail::functor1::call(asin, static_cast(1) / x); + } + + // acot + template + GLM_FUNC_QUALIFIER vec acot(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acot' only accept floating-point inputs"); + T const pi_over_2 = static_cast(3.1415926535897932384626433832795 / 2.0); + return pi_over_2 - detail::functor1::call(atan, x); + } + + // sech + template + GLM_FUNC_QUALIFIER vec sech(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'sech' only accept floating-point inputs"); + return static_cast(1) / detail::functor1::call(cosh, x); + } + + // csch + template + GLM_FUNC_QUALIFIER vec csch(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'csch' only accept floating-point inputs"); + return static_cast(1) / detail::functor1::call(sinh, x); + } + + // coth + template + GLM_FUNC_QUALIFIER vec coth(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'coth' only accept floating-point inputs"); + return glm::cosh(x) / glm::sinh(x); + } + + // asech + template + GLM_FUNC_QUALIFIER vec asech(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'asech' only accept floating-point inputs"); + return detail::functor1::call(acosh, static_cast(1) / x); + } + + // acsch + template + GLM_FUNC_QUALIFIER vec acsch(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acsch' only accept floating-point inputs"); + return detail::functor1::call(asinh, static_cast(1) / x); + } + + // acoth + template + GLM_FUNC_QUALIFIER vec acoth(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acoth' only accept floating-point inputs"); + return detail::functor1::call(atanh, static_cast(1) / x); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_relational.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_relational.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1c2367dc023103160ec68dee0590d32f8be70550 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_relational.hpp @@ -0,0 +1,107 @@ +/// @ref ext_vector_relational +/// @file glm/ext/vector_relational.hpp +/// +/// @see core (dependence) +/// @see ext_scalar_integer (dependence) +/// +/// @defgroup ext_vector_relational GLM_EXT_vector_relational +/// @ingroup ext +/// +/// Exposes comparison functions for vector types that take a user defined epsilon values. +/// +/// Include to use the features of this extension. +/// +/// @see core_vector_relational +/// @see ext_scalar_relational +/// @see ext_matrix_relational + +#pragma once + +// Dependencies +#include "../detail/qualifier.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_relational extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_relational + /// @{ + + /// Returns the component-wise comparison of |x - y| < epsilon. + /// True if this expression is satisfied. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec equal(vec const& x, vec const& y, T epsilon); + + /// Returns the component-wise comparison of |x - y| < epsilon. + /// True if this expression is satisfied. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec equal(vec const& x, vec const& y, vec const& epsilon); + + /// Returns the component-wise comparison of |x - y| >= epsilon. + /// True if this expression is not satisfied. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y, T epsilon); + + /// Returns the component-wise comparison of |x - y| >= epsilon. + /// True if this expression is not satisfied. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y, vec const& epsilon); + + /// Returns the component-wise comparison between two vectors in term of ULPs. + /// True if this expression is satisfied. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec equal(vec const& x, vec const& y, int ULPs); + + /// Returns the component-wise comparison between two vectors in term of ULPs. + /// True if this expression is satisfied. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec equal(vec const& x, vec const& y, vec const& ULPs); + + /// Returns the component-wise comparison between two vectors in term of ULPs. + /// True if this expression is not satisfied. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y, int ULPs); + + /// Returns the component-wise comparison between two vectors in term of ULPs. + /// True if this expression is not satisfied. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y, vec const& ULPs); + + /// @} +}//namespace glm + +#include "vector_relational.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_relational.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_relational.inl new file mode 100644 index 0000000000000000000000000000000000000000..7a39ab50897e35588cf226c741df6e7beb00e884 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_relational.inl @@ -0,0 +1,75 @@ +#include "../vector_relational.hpp" +#include "../common.hpp" +#include "../detail/qualifier.hpp" +#include "../detail/type_float.hpp" + +namespace glm +{ + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(vec const& x, vec const& y, T Epsilon) + { + return equal(x, y, vec(Epsilon)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(vec const& x, vec const& y, vec const& Epsilon) + { + return lessThanEqual(abs(x - y), Epsilon); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y, T Epsilon) + { + return notEqual(x, y, vec(Epsilon)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y, vec const& Epsilon) + { + return greaterThan(abs(x - y), Epsilon); + } + + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(vec const& x, vec const& y, int MaxULPs) + { + return equal(x, y, vec(MaxULPs)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(vec const& x, vec const& y, vec const& MaxULPs) + { + vec Result(false); + for(length_t i = 0; i < L; ++i) + { + detail::float_t const a(x[i]); + detail::float_t const b(y[i]); + + // Different signs means they do not match. + if(a.negative() != b.negative()) + { + // Check for equality to make sure +0==-0 + Result[i] = a.mantissa() == b.mantissa() && a.exponent() == b.exponent(); + } + else + { + // Find the difference in ULPs. + typename detail::float_t::int_type const DiffULPs = abs(a.i - b.i); + Result[i] = DiffULPs <= MaxULPs[i]; + } + } + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y, int MaxULPs) + { + return notEqual(x, y, vec(MaxULPs)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y, vec const& MaxULPs) + { + return not_(equal(x, y, MaxULPs)); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_uint1.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_uint1.hpp new file mode 100644 index 0000000000000000000000000000000000000000..eb8a7049761f0bb7c735ba689faac84ea5eb65d8 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_uint1.hpp @@ -0,0 +1,32 @@ +/// @ref ext_vector_uint1 +/// @file glm/ext/vector_uint1.hpp +/// +/// @defgroup ext_vector_uint1 GLM_EXT_vector_uint1 +/// @ingroup ext +/// +/// Exposes uvec1 vector type. +/// +/// Include to use the features of this extension. +/// +/// @see ext_vector_int1 extension. +/// @see ext_vector_uint1_precision extension. + +#pragma once + +#include "../detail/type_vec1.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_uint1 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_uint1 + /// @{ + + /// 1 component vector of unsigned integer numbers. + typedef vec<1, unsigned int, defaultp> uvec1; + + /// @} +}//namespace glm + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_uint1_sized.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_uint1_sized.hpp new file mode 100644 index 0000000000000000000000000000000000000000..2a938bbaf61662b648c0886565911eff4a51a9ef --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_uint1_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_vector_uint1_sized +/// @file glm/ext/vector_uint1_sized.hpp +/// +/// @defgroup ext_vector_uint1_sized GLM_EXT_vector_uint1_sized +/// @ingroup ext +/// +/// Exposes sized unsigned integer vector types. +/// +/// Include to use the features of this extension. +/// +/// @see ext_scalar_uint_sized +/// @see ext_vector_int1_sized + +#pragma once + +#include "../ext/vector_uint1.hpp" +#include "../ext/scalar_uint_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_uint1_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_uint1_sized + /// @{ + + /// 8 bit unsigned integer vector of 1 component type. + /// + /// @see ext_vector_uint1_sized + typedef vec<1, uint8, defaultp> u8vec1; + + /// 16 bit unsigned integer vector of 1 component type. + /// + /// @see ext_vector_uint1_sized + typedef vec<1, uint16, defaultp> u16vec1; + + /// 32 bit unsigned integer vector of 1 component type. + /// + /// @see ext_vector_uint1_sized + typedef vec<1, uint32, defaultp> u32vec1; + + /// 64 bit unsigned integer vector of 1 component type. + /// + /// @see ext_vector_uint1_sized + typedef vec<1, uint64, defaultp> u64vec1; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_uint2.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_uint2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..03c00f5ff584d48baf6aab0ed8c5a794138f3219 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_uint2.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_uint2.hpp + +#pragma once +#include "../detail/type_vec2.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 2 components vector of unsigned integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<2, unsigned int, defaultp> uvec2; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_uint2_sized.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_uint2_sized.hpp new file mode 100644 index 0000000000000000000000000000000000000000..620fdc6ece39396568745882180d89d4d3391acb --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_uint2_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_vector_uint2_sized +/// @file glm/ext/vector_uint2_sized.hpp +/// +/// @defgroup ext_vector_uint2_sized GLM_EXT_vector_uint2_sized +/// @ingroup ext +/// +/// Exposes sized unsigned integer vector of 2 components type. +/// +/// Include to use the features of this extension. +/// +/// @see ext_scalar_uint_sized +/// @see ext_vector_int2_sized + +#pragma once + +#include "../ext/vector_uint2.hpp" +#include "../ext/scalar_uint_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_uint2_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_uint2_sized + /// @{ + + /// 8 bit unsigned integer vector of 2 components type. + /// + /// @see ext_vector_uint2_sized + typedef vec<2, uint8, defaultp> u8vec2; + + /// 16 bit unsigned integer vector of 2 components type. + /// + /// @see ext_vector_uint2_sized + typedef vec<2, uint16, defaultp> u16vec2; + + /// 32 bit unsigned integer vector of 2 components type. + /// + /// @see ext_vector_uint2_sized + typedef vec<2, uint32, defaultp> u32vec2; + + /// 64 bit unsigned integer vector of 2 components type. + /// + /// @see ext_vector_uint2_sized + typedef vec<2, uint64, defaultp> u64vec2; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_uint3.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_uint3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f5b41c40882ac5fda0c1440956c8bcd8f7c098d4 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_uint3.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_uint3.hpp + +#pragma once +#include "../detail/type_vec3.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 3 components vector of unsigned integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<3, unsigned int, defaultp> uvec3; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_uint3_sized.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_uint3_sized.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6f96b98e276fb10a896ad9ff42e1df0455b07997 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_uint3_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_vector_uint3_sized +/// @file glm/ext/vector_uint3_sized.hpp +/// +/// @defgroup ext_vector_uint3_sized GLM_EXT_vector_uint3_sized +/// @ingroup ext +/// +/// Exposes sized unsigned integer vector of 3 components type. +/// +/// Include to use the features of this extension. +/// +/// @see ext_scalar_uint_sized +/// @see ext_vector_int3_sized + +#pragma once + +#include "../ext/vector_uint3.hpp" +#include "../ext/scalar_uint_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_uint3_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_uint3_sized + /// @{ + + /// 8 bit unsigned integer vector of 3 components type. + /// + /// @see ext_vector_uint3_sized + typedef vec<3, uint8, defaultp> u8vec3; + + /// 16 bit unsigned integer vector of 3 components type. + /// + /// @see ext_vector_uint3_sized + typedef vec<3, uint16, defaultp> u16vec3; + + /// 32 bit unsigned integer vector of 3 components type. + /// + /// @see ext_vector_uint3_sized + typedef vec<3, uint32, defaultp> u32vec3; + + /// 64 bit unsigned integer vector of 3 components type. + /// + /// @see ext_vector_uint3_sized + typedef vec<3, uint64, defaultp> u64vec3; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_uint4.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_uint4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..32ced58a8f03f902acae6e0fd0e79a0efdb0653a --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_uint4.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_uint4.hpp + +#pragma once +#include "../detail/type_vec4.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 4 components vector of unsigned integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<4, unsigned int, defaultp> uvec4; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_uint4_sized.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_uint4_sized.hpp new file mode 100644 index 0000000000000000000000000000000000000000..da992ea2da86ad2c15ab834dd0acf6fa19fd19e3 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_uint4_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_vector_uint4_sized +/// @file glm/ext/vector_uint4_sized.hpp +/// +/// @defgroup ext_vector_uint4_sized GLM_EXT_vector_uint4_sized +/// @ingroup ext +/// +/// Exposes sized unsigned integer vector of 4 components type. +/// +/// Include to use the features of this extension. +/// +/// @see ext_scalar_uint_sized +/// @see ext_vector_int4_sized + +#pragma once + +#include "../ext/vector_uint4.hpp" +#include "../ext/scalar_uint_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_uint4_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_uint4_sized + /// @{ + + /// 8 bit unsigned integer vector of 4 components type. + /// + /// @see ext_vector_uint4_sized + typedef vec<4, uint8, defaultp> u8vec4; + + /// 16 bit unsigned integer vector of 4 components type. + /// + /// @see ext_vector_uint4_sized + typedef vec<4, uint16, defaultp> u16vec4; + + /// 32 bit unsigned integer vector of 4 components type. + /// + /// @see ext_vector_uint4_sized + typedef vec<4, uint32, defaultp> u32vec4; + + /// 64 bit unsigned integer vector of 4 components type. + /// + /// @see ext_vector_uint4_sized + typedef vec<4, uint64, defaultp> u64vec4; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_ulp.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_ulp.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7c539bbf886699645dc93b9c0faa3e815a359d53 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_ulp.hpp @@ -0,0 +1,112 @@ +/// @ref ext_vector_ulp +/// @file glm/ext/vector_ulp.hpp +/// +/// @defgroup ext_vector_ulp GLM_EXT_vector_ulp +/// @ingroup ext +/// +/// Allow the measurement of the accuracy of a function against a reference +/// implementation. This extension works on floating-point data and provide results +/// in ULP. +/// +/// Include to use the features of this extension. +/// +/// @see ext_scalar_ulp +/// @see ext_scalar_relational +/// @see ext_vector_relational + +#pragma once + +// Dependencies +#include "../ext/scalar_ulp.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_ulp extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_ulp + /// @{ + + /// Return the next ULP value(s) after the input value(s). + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL vec nextFloat(vec const& x); + + /// Return the value(s) ULP distance after the input value(s). + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL vec nextFloat(vec const& x, int ULPs); + + /// Return the value(s) ULP distance after the input value(s). + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL vec nextFloat(vec const& x, vec const& ULPs); + + /// Return the previous ULP value(s) before the input value(s). + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL vec prevFloat(vec const& x); + + /// Return the value(s) ULP distance before the input value(s). + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL vec prevFloat(vec const& x, int ULPs); + + /// Return the value(s) ULP distance before the input value(s). + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL vec prevFloat(vec const& x, vec const& ULPs); + + /// Return the distance in the number of ULP between 2 single-precision floating-point scalars. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam Q Value from qualifier enum + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL vec floatDistance(vec const& x, vec const& y); + + /// Return the distance in the number of ULP between 2 double-precision floating-point scalars. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam Q Value from qualifier enum + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL vec floatDistance(vec const& x, vec const& y); + + /// @} +}//namespace glm + +#include "vector_ulp.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_ulp.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_ulp.inl new file mode 100644 index 0000000000000000000000000000000000000000..91565ce510742bfd98b470976fae19d60c3f2947 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/ext/vector_ulp.inl @@ -0,0 +1,74 @@ +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec nextFloat(vec const& x) + { + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = nextFloat(x[i]); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec nextFloat(vec const& x, int ULPs) + { + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = nextFloat(x[i], ULPs); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec nextFloat(vec const& x, vec const& ULPs) + { + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = nextFloat(x[i], ULPs[i]); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec prevFloat(vec const& x) + { + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = prevFloat(x[i]); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec prevFloat(vec const& x, int ULPs) + { + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = prevFloat(x[i], ULPs); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec prevFloat(vec const& x, vec const& ULPs) + { + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = prevFloat(x[i], ULPs[i]); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec floatDistance(vec const& x, vec const& y) + { + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = floatDistance(x[i], y[i]); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec floatDistance(vec const& x, vec const& y) + { + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = floatDistance(x[i], y[i]); + return Result; + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/fwd.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/fwd.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9c2e5eafa4ea07abda138ca3ec9cdcd6936103a9 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/fwd.hpp @@ -0,0 +1,1233 @@ +#pragma once + +#include "detail/qualifier.hpp" + +namespace glm +{ +#if GLM_HAS_EXTENDED_INTEGER_TYPE + typedef std::int8_t int8; + typedef std::int16_t int16; + typedef std::int32_t int32; + typedef std::int64_t int64; + + typedef std::uint8_t uint8; + typedef std::uint16_t uint16; + typedef std::uint32_t uint32; + typedef std::uint64_t uint64; +#else + typedef signed char int8; + typedef signed short int16; + typedef signed int int32; + typedef detail::int64 int64; + + typedef unsigned char uint8; + typedef unsigned short uint16; + typedef unsigned int uint32; + typedef detail::uint64 uint64; +#endif + + // Scalar int + + typedef int8 lowp_i8; + typedef int8 mediump_i8; + typedef int8 highp_i8; + typedef int8 i8; + + typedef int8 lowp_int8; + typedef int8 mediump_int8; + typedef int8 highp_int8; + + typedef int8 lowp_int8_t; + typedef int8 mediump_int8_t; + typedef int8 highp_int8_t; + typedef int8 int8_t; + + typedef int16 lowp_i16; + typedef int16 mediump_i16; + typedef int16 highp_i16; + typedef int16 i16; + + typedef int16 lowp_int16; + typedef int16 mediump_int16; + typedef int16 highp_int16; + + typedef int16 lowp_int16_t; + typedef int16 mediump_int16_t; + typedef int16 highp_int16_t; + typedef int16 int16_t; + + typedef int32 lowp_i32; + typedef int32 mediump_i32; + typedef int32 highp_i32; + typedef int32 i32; + + typedef int32 lowp_int32; + typedef int32 mediump_int32; + typedef int32 highp_int32; + + typedef int32 lowp_int32_t; + typedef int32 mediump_int32_t; + typedef int32 highp_int32_t; + typedef int32 int32_t; + + typedef int64 lowp_i64; + typedef int64 mediump_i64; + typedef int64 highp_i64; + typedef int64 i64; + + typedef int64 lowp_int64; + typedef int64 mediump_int64; + typedef int64 highp_int64; + + typedef int64 lowp_int64_t; + typedef int64 mediump_int64_t; + typedef int64 highp_int64_t; + typedef int64 int64_t; + + // Scalar uint + + typedef unsigned int uint; + + typedef uint8 lowp_u8; + typedef uint8 mediump_u8; + typedef uint8 highp_u8; + typedef uint8 u8; + + typedef uint8 lowp_uint8; + typedef uint8 mediump_uint8; + typedef uint8 highp_uint8; + + typedef uint8 lowp_uint8_t; + typedef uint8 mediump_uint8_t; + typedef uint8 highp_uint8_t; + typedef uint8 uint8_t; + + typedef uint16 lowp_u16; + typedef uint16 mediump_u16; + typedef uint16 highp_u16; + typedef uint16 u16; + + typedef uint16 lowp_uint16; + typedef uint16 mediump_uint16; + typedef uint16 highp_uint16; + + typedef uint16 lowp_uint16_t; + typedef uint16 mediump_uint16_t; + typedef uint16 highp_uint16_t; + typedef uint16 uint16_t; + + typedef uint32 lowp_u32; + typedef uint32 mediump_u32; + typedef uint32 highp_u32; + typedef uint32 u32; + + typedef uint32 lowp_uint32; + typedef uint32 mediump_uint32; + typedef uint32 highp_uint32; + + typedef uint32 lowp_uint32_t; + typedef uint32 mediump_uint32_t; + typedef uint32 highp_uint32_t; + typedef uint32 uint32_t; + + typedef uint64 lowp_u64; + typedef uint64 mediump_u64; + typedef uint64 highp_u64; + typedef uint64 u64; + + typedef uint64 lowp_uint64; + typedef uint64 mediump_uint64; + typedef uint64 highp_uint64; + + typedef uint64 lowp_uint64_t; + typedef uint64 mediump_uint64_t; + typedef uint64 highp_uint64_t; + typedef uint64 uint64_t; + + // Scalar float + + typedef float lowp_f32; + typedef float mediump_f32; + typedef float highp_f32; + typedef float f32; + + typedef float lowp_float32; + typedef float mediump_float32; + typedef float highp_float32; + typedef float float32; + + typedef float lowp_float32_t; + typedef float mediump_float32_t; + typedef float highp_float32_t; + typedef float float32_t; + + + typedef double lowp_f64; + typedef double mediump_f64; + typedef double highp_f64; + typedef double f64; + + typedef double lowp_float64; + typedef double mediump_float64; + typedef double highp_float64; + typedef double float64; + + typedef double lowp_float64_t; + typedef double mediump_float64_t; + typedef double highp_float64_t; + typedef double float64_t; + + // Vector bool + + typedef vec<1, bool, lowp> lowp_bvec1; + typedef vec<2, bool, lowp> lowp_bvec2; + typedef vec<3, bool, lowp> lowp_bvec3; + typedef vec<4, bool, lowp> lowp_bvec4; + + typedef vec<1, bool, mediump> mediump_bvec1; + typedef vec<2, bool, mediump> mediump_bvec2; + typedef vec<3, bool, mediump> mediump_bvec3; + typedef vec<4, bool, mediump> mediump_bvec4; + + typedef vec<1, bool, highp> highp_bvec1; + typedef vec<2, bool, highp> highp_bvec2; + typedef vec<3, bool, highp> highp_bvec3; + typedef vec<4, bool, highp> highp_bvec4; + + typedef vec<1, bool, defaultp> bvec1; + typedef vec<2, bool, defaultp> bvec2; + typedef vec<3, bool, defaultp> bvec3; + typedef vec<4, bool, defaultp> bvec4; + + // Vector int + + typedef vec<1, int, lowp> lowp_ivec1; + typedef vec<2, int, lowp> lowp_ivec2; + typedef vec<3, int, lowp> lowp_ivec3; + typedef vec<4, int, lowp> lowp_ivec4; + + typedef vec<1, int, mediump> mediump_ivec1; + typedef vec<2, int, mediump> mediump_ivec2; + typedef vec<3, int, mediump> mediump_ivec3; + typedef vec<4, int, mediump> mediump_ivec4; + + typedef vec<1, int, highp> highp_ivec1; + typedef vec<2, int, highp> highp_ivec2; + typedef vec<3, int, highp> highp_ivec3; + typedef vec<4, int, highp> highp_ivec4; + + typedef vec<1, int, defaultp> ivec1; + typedef vec<2, int, defaultp> ivec2; + typedef vec<3, int, defaultp> ivec3; + typedef vec<4, int, defaultp> ivec4; + + typedef vec<1, i8, lowp> lowp_i8vec1; + typedef vec<2, i8, lowp> lowp_i8vec2; + typedef vec<3, i8, lowp> lowp_i8vec3; + typedef vec<4, i8, lowp> lowp_i8vec4; + + typedef vec<1, i8, mediump> mediump_i8vec1; + typedef vec<2, i8, mediump> mediump_i8vec2; + typedef vec<3, i8, mediump> mediump_i8vec3; + typedef vec<4, i8, mediump> mediump_i8vec4; + + typedef vec<1, i8, highp> highp_i8vec1; + typedef vec<2, i8, highp> highp_i8vec2; + typedef vec<3, i8, highp> highp_i8vec3; + typedef vec<4, i8, highp> highp_i8vec4; + + typedef vec<1, i8, defaultp> i8vec1; + typedef vec<2, i8, defaultp> i8vec2; + typedef vec<3, i8, defaultp> i8vec3; + typedef vec<4, i8, defaultp> i8vec4; + + typedef vec<1, i16, lowp> lowp_i16vec1; + typedef vec<2, i16, lowp> lowp_i16vec2; + typedef vec<3, i16, lowp> lowp_i16vec3; + typedef vec<4, i16, lowp> lowp_i16vec4; + + typedef vec<1, i16, mediump> mediump_i16vec1; + typedef vec<2, i16, mediump> mediump_i16vec2; + typedef vec<3, i16, mediump> mediump_i16vec3; + typedef vec<4, i16, mediump> mediump_i16vec4; + + typedef vec<1, i16, highp> highp_i16vec1; + typedef vec<2, i16, highp> highp_i16vec2; + typedef vec<3, i16, highp> highp_i16vec3; + typedef vec<4, i16, highp> highp_i16vec4; + + typedef vec<1, i16, defaultp> i16vec1; + typedef vec<2, i16, defaultp> i16vec2; + typedef vec<3, i16, defaultp> i16vec3; + typedef vec<4, i16, defaultp> i16vec4; + + typedef vec<1, i32, lowp> lowp_i32vec1; + typedef vec<2, i32, lowp> lowp_i32vec2; + typedef vec<3, i32, lowp> lowp_i32vec3; + typedef vec<4, i32, lowp> lowp_i32vec4; + + typedef vec<1, i32, mediump> mediump_i32vec1; + typedef vec<2, i32, mediump> mediump_i32vec2; + typedef vec<3, i32, mediump> mediump_i32vec3; + typedef vec<4, i32, mediump> mediump_i32vec4; + + typedef vec<1, i32, highp> highp_i32vec1; + typedef vec<2, i32, highp> highp_i32vec2; + typedef vec<3, i32, highp> highp_i32vec3; + typedef vec<4, i32, highp> highp_i32vec4; + + typedef vec<1, i32, defaultp> i32vec1; + typedef vec<2, i32, defaultp> i32vec2; + typedef vec<3, i32, defaultp> i32vec3; + typedef vec<4, i32, defaultp> i32vec4; + + typedef vec<1, i64, lowp> lowp_i64vec1; + typedef vec<2, i64, lowp> lowp_i64vec2; + typedef vec<3, i64, lowp> lowp_i64vec3; + typedef vec<4, i64, lowp> lowp_i64vec4; + + typedef vec<1, i64, mediump> mediump_i64vec1; + typedef vec<2, i64, mediump> mediump_i64vec2; + typedef vec<3, i64, mediump> mediump_i64vec3; + typedef vec<4, i64, mediump> mediump_i64vec4; + + typedef vec<1, i64, highp> highp_i64vec1; + typedef vec<2, i64, highp> highp_i64vec2; + typedef vec<3, i64, highp> highp_i64vec3; + typedef vec<4, i64, highp> highp_i64vec4; + + typedef vec<1, i64, defaultp> i64vec1; + typedef vec<2, i64, defaultp> i64vec2; + typedef vec<3, i64, defaultp> i64vec3; + typedef vec<4, i64, defaultp> i64vec4; + + // Vector uint + + typedef vec<1, uint, lowp> lowp_uvec1; + typedef vec<2, uint, lowp> lowp_uvec2; + typedef vec<3, uint, lowp> lowp_uvec3; + typedef vec<4, uint, lowp> lowp_uvec4; + + typedef vec<1, uint, mediump> mediump_uvec1; + typedef vec<2, uint, mediump> mediump_uvec2; + typedef vec<3, uint, mediump> mediump_uvec3; + typedef vec<4, uint, mediump> mediump_uvec4; + + typedef vec<1, uint, highp> highp_uvec1; + typedef vec<2, uint, highp> highp_uvec2; + typedef vec<3, uint, highp> highp_uvec3; + typedef vec<4, uint, highp> highp_uvec4; + + typedef vec<1, uint, defaultp> uvec1; + typedef vec<2, uint, defaultp> uvec2; + typedef vec<3, uint, defaultp> uvec3; + typedef vec<4, uint, defaultp> uvec4; + + typedef vec<1, u8, lowp> lowp_u8vec1; + typedef vec<2, u8, lowp> lowp_u8vec2; + typedef vec<3, u8, lowp> lowp_u8vec3; + typedef vec<4, u8, lowp> lowp_u8vec4; + + typedef vec<1, u8, mediump> mediump_u8vec1; + typedef vec<2, u8, mediump> mediump_u8vec2; + typedef vec<3, u8, mediump> mediump_u8vec3; + typedef vec<4, u8, mediump> mediump_u8vec4; + + typedef vec<1, u8, highp> highp_u8vec1; + typedef vec<2, u8, highp> highp_u8vec2; + typedef vec<3, u8, highp> highp_u8vec3; + typedef vec<4, u8, highp> highp_u8vec4; + + typedef vec<1, u8, defaultp> u8vec1; + typedef vec<2, u8, defaultp> u8vec2; + typedef vec<3, u8, defaultp> u8vec3; + typedef vec<4, u8, defaultp> u8vec4; + + typedef vec<1, u16, lowp> lowp_u16vec1; + typedef vec<2, u16, lowp> lowp_u16vec2; + typedef vec<3, u16, lowp> lowp_u16vec3; + typedef vec<4, u16, lowp> lowp_u16vec4; + + typedef vec<1, u16, mediump> mediump_u16vec1; + typedef vec<2, u16, mediump> mediump_u16vec2; + typedef vec<3, u16, mediump> mediump_u16vec3; + typedef vec<4, u16, mediump> mediump_u16vec4; + + typedef vec<1, u16, highp> highp_u16vec1; + typedef vec<2, u16, highp> highp_u16vec2; + typedef vec<3, u16, highp> highp_u16vec3; + typedef vec<4, u16, highp> highp_u16vec4; + + typedef vec<1, u16, defaultp> u16vec1; + typedef vec<2, u16, defaultp> u16vec2; + typedef vec<3, u16, defaultp> u16vec3; + typedef vec<4, u16, defaultp> u16vec4; + + typedef vec<1, u32, lowp> lowp_u32vec1; + typedef vec<2, u32, lowp> lowp_u32vec2; + typedef vec<3, u32, lowp> lowp_u32vec3; + typedef vec<4, u32, lowp> lowp_u32vec4; + + typedef vec<1, u32, mediump> mediump_u32vec1; + typedef vec<2, u32, mediump> mediump_u32vec2; + typedef vec<3, u32, mediump> mediump_u32vec3; + typedef vec<4, u32, mediump> mediump_u32vec4; + + typedef vec<1, u32, highp> highp_u32vec1; + typedef vec<2, u32, highp> highp_u32vec2; + typedef vec<3, u32, highp> highp_u32vec3; + typedef vec<4, u32, highp> highp_u32vec4; + + typedef vec<1, u32, defaultp> u32vec1; + typedef vec<2, u32, defaultp> u32vec2; + typedef vec<3, u32, defaultp> u32vec3; + typedef vec<4, u32, defaultp> u32vec4; + + typedef vec<1, u64, lowp> lowp_u64vec1; + typedef vec<2, u64, lowp> lowp_u64vec2; + typedef vec<3, u64, lowp> lowp_u64vec3; + typedef vec<4, u64, lowp> lowp_u64vec4; + + typedef vec<1, u64, mediump> mediump_u64vec1; + typedef vec<2, u64, mediump> mediump_u64vec2; + typedef vec<3, u64, mediump> mediump_u64vec3; + typedef vec<4, u64, mediump> mediump_u64vec4; + + typedef vec<1, u64, highp> highp_u64vec1; + typedef vec<2, u64, highp> highp_u64vec2; + typedef vec<3, u64, highp> highp_u64vec3; + typedef vec<4, u64, highp> highp_u64vec4; + + typedef vec<1, u64, defaultp> u64vec1; + typedef vec<2, u64, defaultp> u64vec2; + typedef vec<3, u64, defaultp> u64vec3; + typedef vec<4, u64, defaultp> u64vec4; + + // Vector float + + typedef vec<1, float, lowp> lowp_vec1; + typedef vec<2, float, lowp> lowp_vec2; + typedef vec<3, float, lowp> lowp_vec3; + typedef vec<4, float, lowp> lowp_vec4; + + typedef vec<1, float, mediump> mediump_vec1; + typedef vec<2, float, mediump> mediump_vec2; + typedef vec<3, float, mediump> mediump_vec3; + typedef vec<4, float, mediump> mediump_vec4; + + typedef vec<1, float, highp> highp_vec1; + typedef vec<2, float, highp> highp_vec2; + typedef vec<3, float, highp> highp_vec3; + typedef vec<4, float, highp> highp_vec4; + + typedef vec<1, float, defaultp> vec1; + typedef vec<2, float, defaultp> vec2; + typedef vec<3, float, defaultp> vec3; + typedef vec<4, float, defaultp> vec4; + + typedef vec<1, float, lowp> lowp_fvec1; + typedef vec<2, float, lowp> lowp_fvec2; + typedef vec<3, float, lowp> lowp_fvec3; + typedef vec<4, float, lowp> lowp_fvec4; + + typedef vec<1, float, mediump> mediump_fvec1; + typedef vec<2, float, mediump> mediump_fvec2; + typedef vec<3, float, mediump> mediump_fvec3; + typedef vec<4, float, mediump> mediump_fvec4; + + typedef vec<1, float, highp> highp_fvec1; + typedef vec<2, float, highp> highp_fvec2; + typedef vec<3, float, highp> highp_fvec3; + typedef vec<4, float, highp> highp_fvec4; + + typedef vec<1, f32, defaultp> fvec1; + typedef vec<2, f32, defaultp> fvec2; + typedef vec<3, f32, defaultp> fvec3; + typedef vec<4, f32, defaultp> fvec4; + + typedef vec<1, f32, lowp> lowp_f32vec1; + typedef vec<2, f32, lowp> lowp_f32vec2; + typedef vec<3, f32, lowp> lowp_f32vec3; + typedef vec<4, f32, lowp> lowp_f32vec4; + + typedef vec<1, f32, mediump> mediump_f32vec1; + typedef vec<2, f32, mediump> mediump_f32vec2; + typedef vec<3, f32, mediump> mediump_f32vec3; + typedef vec<4, f32, mediump> mediump_f32vec4; + + typedef vec<1, f32, highp> highp_f32vec1; + typedef vec<2, f32, highp> highp_f32vec2; + typedef vec<3, f32, highp> highp_f32vec3; + typedef vec<4, f32, highp> highp_f32vec4; + + typedef vec<1, f32, defaultp> f32vec1; + typedef vec<2, f32, defaultp> f32vec2; + typedef vec<3, f32, defaultp> f32vec3; + typedef vec<4, f32, defaultp> f32vec4; + + typedef vec<1, f64, lowp> lowp_dvec1; + typedef vec<2, f64, lowp> lowp_dvec2; + typedef vec<3, f64, lowp> lowp_dvec3; + typedef vec<4, f64, lowp> lowp_dvec4; + + typedef vec<1, f64, mediump> mediump_dvec1; + typedef vec<2, f64, mediump> mediump_dvec2; + typedef vec<3, f64, mediump> mediump_dvec3; + typedef vec<4, f64, mediump> mediump_dvec4; + + typedef vec<1, f64, highp> highp_dvec1; + typedef vec<2, f64, highp> highp_dvec2; + typedef vec<3, f64, highp> highp_dvec3; + typedef vec<4, f64, highp> highp_dvec4; + + typedef vec<1, f64, defaultp> dvec1; + typedef vec<2, f64, defaultp> dvec2; + typedef vec<3, f64, defaultp> dvec3; + typedef vec<4, f64, defaultp> dvec4; + + typedef vec<1, f64, lowp> lowp_f64vec1; + typedef vec<2, f64, lowp> lowp_f64vec2; + typedef vec<3, f64, lowp> lowp_f64vec3; + typedef vec<4, f64, lowp> lowp_f64vec4; + + typedef vec<1, f64, mediump> mediump_f64vec1; + typedef vec<2, f64, mediump> mediump_f64vec2; + typedef vec<3, f64, mediump> mediump_f64vec3; + typedef vec<4, f64, mediump> mediump_f64vec4; + + typedef vec<1, f64, highp> highp_f64vec1; + typedef vec<2, f64, highp> highp_f64vec2; + typedef vec<3, f64, highp> highp_f64vec3; + typedef vec<4, f64, highp> highp_f64vec4; + + typedef vec<1, f64, defaultp> f64vec1; + typedef vec<2, f64, defaultp> f64vec2; + typedef vec<3, f64, defaultp> f64vec3; + typedef vec<4, f64, defaultp> f64vec4; + + // Matrix NxN + + typedef mat<2, 2, f32, lowp> lowp_mat2; + typedef mat<3, 3, f32, lowp> lowp_mat3; + typedef mat<4, 4, f32, lowp> lowp_mat4; + + typedef mat<2, 2, f32, mediump> mediump_mat2; + typedef mat<3, 3, f32, mediump> mediump_mat3; + typedef mat<4, 4, f32, mediump> mediump_mat4; + + typedef mat<2, 2, f32, highp> highp_mat2; + typedef mat<3, 3, f32, highp> highp_mat3; + typedef mat<4, 4, f32, highp> highp_mat4; + + typedef mat<2, 2, f32, defaultp> mat2; + typedef mat<3, 3, f32, defaultp> mat3; + typedef mat<4, 4, f32, defaultp> mat4; + + typedef mat<2, 2, f32, lowp> lowp_fmat2; + typedef mat<3, 3, f32, lowp> lowp_fmat3; + typedef mat<4, 4, f32, lowp> lowp_fmat4; + + typedef mat<2, 2, f32, mediump> mediump_fmat2; + typedef mat<3, 3, f32, mediump> mediump_fmat3; + typedef mat<4, 4, f32, mediump> mediump_fmat4; + + typedef mat<2, 2, f32, highp> highp_fmat2; + typedef mat<3, 3, f32, highp> highp_fmat3; + typedef mat<4, 4, f32, highp> highp_fmat4; + + typedef mat<2, 2, f32, defaultp> fmat2; + typedef mat<3, 3, f32, defaultp> fmat3; + typedef mat<4, 4, f32, defaultp> fmat4; + + typedef mat<2, 2, f32, lowp> lowp_f32mat2; + typedef mat<3, 3, f32, lowp> lowp_f32mat3; + typedef mat<4, 4, f32, lowp> lowp_f32mat4; + + typedef mat<2, 2, f32, mediump> mediump_f32mat2; + typedef mat<3, 3, f32, mediump> mediump_f32mat3; + typedef mat<4, 4, f32, mediump> mediump_f32mat4; + + typedef mat<2, 2, f32, highp> highp_f32mat2; + typedef mat<3, 3, f32, highp> highp_f32mat3; + typedef mat<4, 4, f32, highp> highp_f32mat4; + + typedef mat<2, 2, f32, defaultp> f32mat2; + typedef mat<3, 3, f32, defaultp> f32mat3; + typedef mat<4, 4, f32, defaultp> f32mat4; + + typedef mat<2, 2, f64, lowp> lowp_dmat2; + typedef mat<3, 3, f64, lowp> lowp_dmat3; + typedef mat<4, 4, f64, lowp> lowp_dmat4; + + typedef mat<2, 2, f64, mediump> mediump_dmat2; + typedef mat<3, 3, f64, mediump> mediump_dmat3; + typedef mat<4, 4, f64, mediump> mediump_dmat4; + + typedef mat<2, 2, f64, highp> highp_dmat2; + typedef mat<3, 3, f64, highp> highp_dmat3; + typedef mat<4, 4, f64, highp> highp_dmat4; + + typedef mat<2, 2, f64, defaultp> dmat2; + typedef mat<3, 3, f64, defaultp> dmat3; + typedef mat<4, 4, f64, defaultp> dmat4; + + typedef mat<2, 2, f64, lowp> lowp_f64mat2; + typedef mat<3, 3, f64, lowp> lowp_f64mat3; + typedef mat<4, 4, f64, lowp> lowp_f64mat4; + + typedef mat<2, 2, f64, mediump> mediump_f64mat2; + typedef mat<3, 3, f64, mediump> mediump_f64mat3; + typedef mat<4, 4, f64, mediump> mediump_f64mat4; + + typedef mat<2, 2, f64, highp> highp_f64mat2; + typedef mat<3, 3, f64, highp> highp_f64mat3; + typedef mat<4, 4, f64, highp> highp_f64mat4; + + typedef mat<2, 2, f64, defaultp> f64mat2; + typedef mat<3, 3, f64, defaultp> f64mat3; + typedef mat<4, 4, f64, defaultp> f64mat4; + + // Matrix MxN + + typedef mat<2, 2, f32, lowp> lowp_mat2x2; + typedef mat<2, 3, f32, lowp> lowp_mat2x3; + typedef mat<2, 4, f32, lowp> lowp_mat2x4; + typedef mat<3, 2, f32, lowp> lowp_mat3x2; + typedef mat<3, 3, f32, lowp> lowp_mat3x3; + typedef mat<3, 4, f32, lowp> lowp_mat3x4; + typedef mat<4, 2, f32, lowp> lowp_mat4x2; + typedef mat<4, 3, f32, lowp> lowp_mat4x3; + typedef mat<4, 4, f32, lowp> lowp_mat4x4; + + typedef mat<2, 2, f32, mediump> mediump_mat2x2; + typedef mat<2, 3, f32, mediump> mediump_mat2x3; + typedef mat<2, 4, f32, mediump> mediump_mat2x4; + typedef mat<3, 2, f32, mediump> mediump_mat3x2; + typedef mat<3, 3, f32, mediump> mediump_mat3x3; + typedef mat<3, 4, f32, mediump> mediump_mat3x4; + typedef mat<4, 2, f32, mediump> mediump_mat4x2; + typedef mat<4, 3, f32, mediump> mediump_mat4x3; + typedef mat<4, 4, f32, mediump> mediump_mat4x4; + + typedef mat<2, 2, f32, highp> highp_mat2x2; + typedef mat<2, 3, f32, highp> highp_mat2x3; + typedef mat<2, 4, f32, highp> highp_mat2x4; + typedef mat<3, 2, f32, highp> highp_mat3x2; + typedef mat<3, 3, f32, highp> highp_mat3x3; + typedef mat<3, 4, f32, highp> highp_mat3x4; + typedef mat<4, 2, f32, highp> highp_mat4x2; + typedef mat<4, 3, f32, highp> highp_mat4x3; + typedef mat<4, 4, f32, highp> highp_mat4x4; + + typedef mat<2, 2, f32, defaultp> mat2x2; + typedef mat<2, 3, f32, defaultp> mat2x3; + typedef mat<2, 4, f32, defaultp> mat2x4; + typedef mat<3, 2, f32, defaultp> mat3x2; + typedef mat<3, 3, f32, defaultp> mat3x3; + typedef mat<3, 4, f32, defaultp> mat3x4; + typedef mat<4, 2, f32, defaultp> mat4x2; + typedef mat<4, 3, f32, defaultp> mat4x3; + typedef mat<4, 4, f32, defaultp> mat4x4; + + typedef mat<2, 2, f32, lowp> lowp_fmat2x2; + typedef mat<2, 3, f32, lowp> lowp_fmat2x3; + typedef mat<2, 4, f32, lowp> lowp_fmat2x4; + typedef mat<3, 2, f32, lowp> lowp_fmat3x2; + typedef mat<3, 3, f32, lowp> lowp_fmat3x3; + typedef mat<3, 4, f32, lowp> lowp_fmat3x4; + typedef mat<4, 2, f32, lowp> lowp_fmat4x2; + typedef mat<4, 3, f32, lowp> lowp_fmat4x3; + typedef mat<4, 4, f32, lowp> lowp_fmat4x4; + + typedef mat<2, 2, f32, mediump> mediump_fmat2x2; + typedef mat<2, 3, f32, mediump> mediump_fmat2x3; + typedef mat<2, 4, f32, mediump> mediump_fmat2x4; + typedef mat<3, 2, f32, mediump> mediump_fmat3x2; + typedef mat<3, 3, f32, mediump> mediump_fmat3x3; + typedef mat<3, 4, f32, mediump> mediump_fmat3x4; + typedef mat<4, 2, f32, mediump> mediump_fmat4x2; + typedef mat<4, 3, f32, mediump> mediump_fmat4x3; + typedef mat<4, 4, f32, mediump> mediump_fmat4x4; + + typedef mat<2, 2, f32, highp> highp_fmat2x2; + typedef mat<2, 3, f32, highp> highp_fmat2x3; + typedef mat<2, 4, f32, highp> highp_fmat2x4; + typedef mat<3, 2, f32, highp> highp_fmat3x2; + typedef mat<3, 3, f32, highp> highp_fmat3x3; + typedef mat<3, 4, f32, highp> highp_fmat3x4; + typedef mat<4, 2, f32, highp> highp_fmat4x2; + typedef mat<4, 3, f32, highp> highp_fmat4x3; + typedef mat<4, 4, f32, highp> highp_fmat4x4; + + typedef mat<2, 2, f32, defaultp> fmat2x2; + typedef mat<2, 3, f32, defaultp> fmat2x3; + typedef mat<2, 4, f32, defaultp> fmat2x4; + typedef mat<3, 2, f32, defaultp> fmat3x2; + typedef mat<3, 3, f32, defaultp> fmat3x3; + typedef mat<3, 4, f32, defaultp> fmat3x4; + typedef mat<4, 2, f32, defaultp> fmat4x2; + typedef mat<4, 3, f32, defaultp> fmat4x3; + typedef mat<4, 4, f32, defaultp> fmat4x4; + + typedef mat<2, 2, f32, lowp> lowp_f32mat2x2; + typedef mat<2, 3, f32, lowp> lowp_f32mat2x3; + typedef mat<2, 4, f32, lowp> lowp_f32mat2x4; + typedef mat<3, 2, f32, lowp> lowp_f32mat3x2; + typedef mat<3, 3, f32, lowp> lowp_f32mat3x3; + typedef mat<3, 4, f32, lowp> lowp_f32mat3x4; + typedef mat<4, 2, f32, lowp> lowp_f32mat4x2; + typedef mat<4, 3, f32, lowp> lowp_f32mat4x3; + typedef mat<4, 4, f32, lowp> lowp_f32mat4x4; + + typedef mat<2, 2, f32, mediump> mediump_f32mat2x2; + typedef mat<2, 3, f32, mediump> mediump_f32mat2x3; + typedef mat<2, 4, f32, mediump> mediump_f32mat2x4; + typedef mat<3, 2, f32, mediump> mediump_f32mat3x2; + typedef mat<3, 3, f32, mediump> mediump_f32mat3x3; + typedef mat<3, 4, f32, mediump> mediump_f32mat3x4; + typedef mat<4, 2, f32, mediump> mediump_f32mat4x2; + typedef mat<4, 3, f32, mediump> mediump_f32mat4x3; + typedef mat<4, 4, f32, mediump> mediump_f32mat4x4; + + typedef mat<2, 2, f32, highp> highp_f32mat2x2; + typedef mat<2, 3, f32, highp> highp_f32mat2x3; + typedef mat<2, 4, f32, highp> highp_f32mat2x4; + typedef mat<3, 2, f32, highp> highp_f32mat3x2; + typedef mat<3, 3, f32, highp> highp_f32mat3x3; + typedef mat<3, 4, f32, highp> highp_f32mat3x4; + typedef mat<4, 2, f32, highp> highp_f32mat4x2; + typedef mat<4, 3, f32, highp> highp_f32mat4x3; + typedef mat<4, 4, f32, highp> highp_f32mat4x4; + + typedef mat<2, 2, f32, defaultp> f32mat2x2; + typedef mat<2, 3, f32, defaultp> f32mat2x3; + typedef mat<2, 4, f32, defaultp> f32mat2x4; + typedef mat<3, 2, f32, defaultp> f32mat3x2; + typedef mat<3, 3, f32, defaultp> f32mat3x3; + typedef mat<3, 4, f32, defaultp> f32mat3x4; + typedef mat<4, 2, f32, defaultp> f32mat4x2; + typedef mat<4, 3, f32, defaultp> f32mat4x3; + typedef mat<4, 4, f32, defaultp> f32mat4x4; + + typedef mat<2, 2, double, lowp> lowp_dmat2x2; + typedef mat<2, 3, double, lowp> lowp_dmat2x3; + typedef mat<2, 4, double, lowp> lowp_dmat2x4; + typedef mat<3, 2, double, lowp> lowp_dmat3x2; + typedef mat<3, 3, double, lowp> lowp_dmat3x3; + typedef mat<3, 4, double, lowp> lowp_dmat3x4; + typedef mat<4, 2, double, lowp> lowp_dmat4x2; + typedef mat<4, 3, double, lowp> lowp_dmat4x3; + typedef mat<4, 4, double, lowp> lowp_dmat4x4; + + typedef mat<2, 2, double, mediump> mediump_dmat2x2; + typedef mat<2, 3, double, mediump> mediump_dmat2x3; + typedef mat<2, 4, double, mediump> mediump_dmat2x4; + typedef mat<3, 2, double, mediump> mediump_dmat3x2; + typedef mat<3, 3, double, mediump> mediump_dmat3x3; + typedef mat<3, 4, double, mediump> mediump_dmat3x4; + typedef mat<4, 2, double, mediump> mediump_dmat4x2; + typedef mat<4, 3, double, mediump> mediump_dmat4x3; + typedef mat<4, 4, double, mediump> mediump_dmat4x4; + + typedef mat<2, 2, double, highp> highp_dmat2x2; + typedef mat<2, 3, double, highp> highp_dmat2x3; + typedef mat<2, 4, double, highp> highp_dmat2x4; + typedef mat<3, 2, double, highp> highp_dmat3x2; + typedef mat<3, 3, double, highp> highp_dmat3x3; + typedef mat<3, 4, double, highp> highp_dmat3x4; + typedef mat<4, 2, double, highp> highp_dmat4x2; + typedef mat<4, 3, double, highp> highp_dmat4x3; + typedef mat<4, 4, double, highp> highp_dmat4x4; + + typedef mat<2, 2, double, defaultp> dmat2x2; + typedef mat<2, 3, double, defaultp> dmat2x3; + typedef mat<2, 4, double, defaultp> dmat2x4; + typedef mat<3, 2, double, defaultp> dmat3x2; + typedef mat<3, 3, double, defaultp> dmat3x3; + typedef mat<3, 4, double, defaultp> dmat3x4; + typedef mat<4, 2, double, defaultp> dmat4x2; + typedef mat<4, 3, double, defaultp> dmat4x3; + typedef mat<4, 4, double, defaultp> dmat4x4; + + typedef mat<2, 2, f64, lowp> lowp_f64mat2x2; + typedef mat<2, 3, f64, lowp> lowp_f64mat2x3; + typedef mat<2, 4, f64, lowp> lowp_f64mat2x4; + typedef mat<3, 2, f64, lowp> lowp_f64mat3x2; + typedef mat<3, 3, f64, lowp> lowp_f64mat3x3; + typedef mat<3, 4, f64, lowp> lowp_f64mat3x4; + typedef mat<4, 2, f64, lowp> lowp_f64mat4x2; + typedef mat<4, 3, f64, lowp> lowp_f64mat4x3; + typedef mat<4, 4, f64, lowp> lowp_f64mat4x4; + + typedef mat<2, 2, f64, mediump> mediump_f64mat2x2; + typedef mat<2, 3, f64, mediump> mediump_f64mat2x3; + typedef mat<2, 4, f64, mediump> mediump_f64mat2x4; + typedef mat<3, 2, f64, mediump> mediump_f64mat3x2; + typedef mat<3, 3, f64, mediump> mediump_f64mat3x3; + typedef mat<3, 4, f64, mediump> mediump_f64mat3x4; + typedef mat<4, 2, f64, mediump> mediump_f64mat4x2; + typedef mat<4, 3, f64, mediump> mediump_f64mat4x3; + typedef mat<4, 4, f64, mediump> mediump_f64mat4x4; + + typedef mat<2, 2, f64, highp> highp_f64mat2x2; + typedef mat<2, 3, f64, highp> highp_f64mat2x3; + typedef mat<2, 4, f64, highp> highp_f64mat2x4; + typedef mat<3, 2, f64, highp> highp_f64mat3x2; + typedef mat<3, 3, f64, highp> highp_f64mat3x3; + typedef mat<3, 4, f64, highp> highp_f64mat3x4; + typedef mat<4, 2, f64, highp> highp_f64mat4x2; + typedef mat<4, 3, f64, highp> highp_f64mat4x3; + typedef mat<4, 4, f64, highp> highp_f64mat4x4; + + typedef mat<2, 2, f64, defaultp> f64mat2x2; + typedef mat<2, 3, f64, defaultp> f64mat2x3; + typedef mat<2, 4, f64, defaultp> f64mat2x4; + typedef mat<3, 2, f64, defaultp> f64mat3x2; + typedef mat<3, 3, f64, defaultp> f64mat3x3; + typedef mat<3, 4, f64, defaultp> f64mat3x4; + typedef mat<4, 2, f64, defaultp> f64mat4x2; + typedef mat<4, 3, f64, defaultp> f64mat4x3; + typedef mat<4, 4, f64, defaultp> f64mat4x4; + + // Signed integer matrix MxN + + typedef mat<2, 2, int, lowp> lowp_imat2x2; + typedef mat<2, 3, int, lowp> lowp_imat2x3; + typedef mat<2, 4, int, lowp> lowp_imat2x4; + typedef mat<3, 2, int, lowp> lowp_imat3x2; + typedef mat<3, 3, int, lowp> lowp_imat3x3; + typedef mat<3, 4, int, lowp> lowp_imat3x4; + typedef mat<4, 2, int, lowp> lowp_imat4x2; + typedef mat<4, 3, int, lowp> lowp_imat4x3; + typedef mat<4, 4, int, lowp> lowp_imat4x4; + + typedef mat<2, 2, int, mediump> mediump_imat2x2; + typedef mat<2, 3, int, mediump> mediump_imat2x3; + typedef mat<2, 4, int, mediump> mediump_imat2x4; + typedef mat<3, 2, int, mediump> mediump_imat3x2; + typedef mat<3, 3, int, mediump> mediump_imat3x3; + typedef mat<3, 4, int, mediump> mediump_imat3x4; + typedef mat<4, 2, int, mediump> mediump_imat4x2; + typedef mat<4, 3, int, mediump> mediump_imat4x3; + typedef mat<4, 4, int, mediump> mediump_imat4x4; + + typedef mat<2, 2, int, highp> highp_imat2x2; + typedef mat<2, 3, int, highp> highp_imat2x3; + typedef mat<2, 4, int, highp> highp_imat2x4; + typedef mat<3, 2, int, highp> highp_imat3x2; + typedef mat<3, 3, int, highp> highp_imat3x3; + typedef mat<3, 4, int, highp> highp_imat3x4; + typedef mat<4, 2, int, highp> highp_imat4x2; + typedef mat<4, 3, int, highp> highp_imat4x3; + typedef mat<4, 4, int, highp> highp_imat4x4; + + typedef mat<2, 2, int, defaultp> imat2x2; + typedef mat<2, 3, int, defaultp> imat2x3; + typedef mat<2, 4, int, defaultp> imat2x4; + typedef mat<3, 2, int, defaultp> imat3x2; + typedef mat<3, 3, int, defaultp> imat3x3; + typedef mat<3, 4, int, defaultp> imat3x4; + typedef mat<4, 2, int, defaultp> imat4x2; + typedef mat<4, 3, int, defaultp> imat4x3; + typedef mat<4, 4, int, defaultp> imat4x4; + + + typedef mat<2, 2, int8, lowp> lowp_i8mat2x2; + typedef mat<2, 3, int8, lowp> lowp_i8mat2x3; + typedef mat<2, 4, int8, lowp> lowp_i8mat2x4; + typedef mat<3, 2, int8, lowp> lowp_i8mat3x2; + typedef mat<3, 3, int8, lowp> lowp_i8mat3x3; + typedef mat<3, 4, int8, lowp> lowp_i8mat3x4; + typedef mat<4, 2, int8, lowp> lowp_i8mat4x2; + typedef mat<4, 3, int8, lowp> lowp_i8mat4x3; + typedef mat<4, 4, int8, lowp> lowp_i8mat4x4; + + typedef mat<2, 2, int8, mediump> mediump_i8mat2x2; + typedef mat<2, 3, int8, mediump> mediump_i8mat2x3; + typedef mat<2, 4, int8, mediump> mediump_i8mat2x4; + typedef mat<3, 2, int8, mediump> mediump_i8mat3x2; + typedef mat<3, 3, int8, mediump> mediump_i8mat3x3; + typedef mat<3, 4, int8, mediump> mediump_i8mat3x4; + typedef mat<4, 2, int8, mediump> mediump_i8mat4x2; + typedef mat<4, 3, int8, mediump> mediump_i8mat4x3; + typedef mat<4, 4, int8, mediump> mediump_i8mat4x4; + + typedef mat<2, 2, int8, highp> highp_i8mat2x2; + typedef mat<2, 3, int8, highp> highp_i8mat2x3; + typedef mat<2, 4, int8, highp> highp_i8mat2x4; + typedef mat<3, 2, int8, highp> highp_i8mat3x2; + typedef mat<3, 3, int8, highp> highp_i8mat3x3; + typedef mat<3, 4, int8, highp> highp_i8mat3x4; + typedef mat<4, 2, int8, highp> highp_i8mat4x2; + typedef mat<4, 3, int8, highp> highp_i8mat4x3; + typedef mat<4, 4, int8, highp> highp_i8mat4x4; + + typedef mat<2, 2, int8, defaultp> i8mat2x2; + typedef mat<2, 3, int8, defaultp> i8mat2x3; + typedef mat<2, 4, int8, defaultp> i8mat2x4; + typedef mat<3, 2, int8, defaultp> i8mat3x2; + typedef mat<3, 3, int8, defaultp> i8mat3x3; + typedef mat<3, 4, int8, defaultp> i8mat3x4; + typedef mat<4, 2, int8, defaultp> i8mat4x2; + typedef mat<4, 3, int8, defaultp> i8mat4x3; + typedef mat<4, 4, int8, defaultp> i8mat4x4; + + + typedef mat<2, 2, int16, lowp> lowp_i16mat2x2; + typedef mat<2, 3, int16, lowp> lowp_i16mat2x3; + typedef mat<2, 4, int16, lowp> lowp_i16mat2x4; + typedef mat<3, 2, int16, lowp> lowp_i16mat3x2; + typedef mat<3, 3, int16, lowp> lowp_i16mat3x3; + typedef mat<3, 4, int16, lowp> lowp_i16mat3x4; + typedef mat<4, 2, int16, lowp> lowp_i16mat4x2; + typedef mat<4, 3, int16, lowp> lowp_i16mat4x3; + typedef mat<4, 4, int16, lowp> lowp_i16mat4x4; + + typedef mat<2, 2, int16, mediump> mediump_i16mat2x2; + typedef mat<2, 3, int16, mediump> mediump_i16mat2x3; + typedef mat<2, 4, int16, mediump> mediump_i16mat2x4; + typedef mat<3, 2, int16, mediump> mediump_i16mat3x2; + typedef mat<3, 3, int16, mediump> mediump_i16mat3x3; + typedef mat<3, 4, int16, mediump> mediump_i16mat3x4; + typedef mat<4, 2, int16, mediump> mediump_i16mat4x2; + typedef mat<4, 3, int16, mediump> mediump_i16mat4x3; + typedef mat<4, 4, int16, mediump> mediump_i16mat4x4; + + typedef mat<2, 2, int16, highp> highp_i16mat2x2; + typedef mat<2, 3, int16, highp> highp_i16mat2x3; + typedef mat<2, 4, int16, highp> highp_i16mat2x4; + typedef mat<3, 2, int16, highp> highp_i16mat3x2; + typedef mat<3, 3, int16, highp> highp_i16mat3x3; + typedef mat<3, 4, int16, highp> highp_i16mat3x4; + typedef mat<4, 2, int16, highp> highp_i16mat4x2; + typedef mat<4, 3, int16, highp> highp_i16mat4x3; + typedef mat<4, 4, int16, highp> highp_i16mat4x4; + + typedef mat<2, 2, int16, defaultp> i16mat2x2; + typedef mat<2, 3, int16, defaultp> i16mat2x3; + typedef mat<2, 4, int16, defaultp> i16mat2x4; + typedef mat<3, 2, int16, defaultp> i16mat3x2; + typedef mat<3, 3, int16, defaultp> i16mat3x3; + typedef mat<3, 4, int16, defaultp> i16mat3x4; + typedef mat<4, 2, int16, defaultp> i16mat4x2; + typedef mat<4, 3, int16, defaultp> i16mat4x3; + typedef mat<4, 4, int16, defaultp> i16mat4x4; + + + typedef mat<2, 2, int32, lowp> lowp_i32mat2x2; + typedef mat<2, 3, int32, lowp> lowp_i32mat2x3; + typedef mat<2, 4, int32, lowp> lowp_i32mat2x4; + typedef mat<3, 2, int32, lowp> lowp_i32mat3x2; + typedef mat<3, 3, int32, lowp> lowp_i32mat3x3; + typedef mat<3, 4, int32, lowp> lowp_i32mat3x4; + typedef mat<4, 2, int32, lowp> lowp_i32mat4x2; + typedef mat<4, 3, int32, lowp> lowp_i32mat4x3; + typedef mat<4, 4, int32, lowp> lowp_i32mat4x4; + + typedef mat<2, 2, int32, mediump> mediump_i32mat2x2; + typedef mat<2, 3, int32, mediump> mediump_i32mat2x3; + typedef mat<2, 4, int32, mediump> mediump_i32mat2x4; + typedef mat<3, 2, int32, mediump> mediump_i32mat3x2; + typedef mat<3, 3, int32, mediump> mediump_i32mat3x3; + typedef mat<3, 4, int32, mediump> mediump_i32mat3x4; + typedef mat<4, 2, int32, mediump> mediump_i32mat4x2; + typedef mat<4, 3, int32, mediump> mediump_i32mat4x3; + typedef mat<4, 4, int32, mediump> mediump_i32mat4x4; + + typedef mat<2, 2, int32, highp> highp_i32mat2x2; + typedef mat<2, 3, int32, highp> highp_i32mat2x3; + typedef mat<2, 4, int32, highp> highp_i32mat2x4; + typedef mat<3, 2, int32, highp> highp_i32mat3x2; + typedef mat<3, 3, int32, highp> highp_i32mat3x3; + typedef mat<3, 4, int32, highp> highp_i32mat3x4; + typedef mat<4, 2, int32, highp> highp_i32mat4x2; + typedef mat<4, 3, int32, highp> highp_i32mat4x3; + typedef mat<4, 4, int32, highp> highp_i32mat4x4; + + typedef mat<2, 2, int32, defaultp> i32mat2x2; + typedef mat<2, 3, int32, defaultp> i32mat2x3; + typedef mat<2, 4, int32, defaultp> i32mat2x4; + typedef mat<3, 2, int32, defaultp> i32mat3x2; + typedef mat<3, 3, int32, defaultp> i32mat3x3; + typedef mat<3, 4, int32, defaultp> i32mat3x4; + typedef mat<4, 2, int32, defaultp> i32mat4x2; + typedef mat<4, 3, int32, defaultp> i32mat4x3; + typedef mat<4, 4, int32, defaultp> i32mat4x4; + + + typedef mat<2, 2, int64, lowp> lowp_i64mat2x2; + typedef mat<2, 3, int64, lowp> lowp_i64mat2x3; + typedef mat<2, 4, int64, lowp> lowp_i64mat2x4; + typedef mat<3, 2, int64, lowp> lowp_i64mat3x2; + typedef mat<3, 3, int64, lowp> lowp_i64mat3x3; + typedef mat<3, 4, int64, lowp> lowp_i64mat3x4; + typedef mat<4, 2, int64, lowp> lowp_i64mat4x2; + typedef mat<4, 3, int64, lowp> lowp_i64mat4x3; + typedef mat<4, 4, int64, lowp> lowp_i64mat4x4; + + typedef mat<2, 2, int64, mediump> mediump_i64mat2x2; + typedef mat<2, 3, int64, mediump> mediump_i64mat2x3; + typedef mat<2, 4, int64, mediump> mediump_i64mat2x4; + typedef mat<3, 2, int64, mediump> mediump_i64mat3x2; + typedef mat<3, 3, int64, mediump> mediump_i64mat3x3; + typedef mat<3, 4, int64, mediump> mediump_i64mat3x4; + typedef mat<4, 2, int64, mediump> mediump_i64mat4x2; + typedef mat<4, 3, int64, mediump> mediump_i64mat4x3; + typedef mat<4, 4, int64, mediump> mediump_i64mat4x4; + + typedef mat<2, 2, int64, highp> highp_i64mat2x2; + typedef mat<2, 3, int64, highp> highp_i64mat2x3; + typedef mat<2, 4, int64, highp> highp_i64mat2x4; + typedef mat<3, 2, int64, highp> highp_i64mat3x2; + typedef mat<3, 3, int64, highp> highp_i64mat3x3; + typedef mat<3, 4, int64, highp> highp_i64mat3x4; + typedef mat<4, 2, int64, highp> highp_i64mat4x2; + typedef mat<4, 3, int64, highp> highp_i64mat4x3; + typedef mat<4, 4, int64, highp> highp_i64mat4x4; + + typedef mat<2, 2, int64, defaultp> i64mat2x2; + typedef mat<2, 3, int64, defaultp> i64mat2x3; + typedef mat<2, 4, int64, defaultp> i64mat2x4; + typedef mat<3, 2, int64, defaultp> i64mat3x2; + typedef mat<3, 3, int64, defaultp> i64mat3x3; + typedef mat<3, 4, int64, defaultp> i64mat3x4; + typedef mat<4, 2, int64, defaultp> i64mat4x2; + typedef mat<4, 3, int64, defaultp> i64mat4x3; + typedef mat<4, 4, int64, defaultp> i64mat4x4; + + + // Unsigned integer matrix MxN + + typedef mat<2, 2, uint, lowp> lowp_umat2x2; + typedef mat<2, 3, uint, lowp> lowp_umat2x3; + typedef mat<2, 4, uint, lowp> lowp_umat2x4; + typedef mat<3, 2, uint, lowp> lowp_umat3x2; + typedef mat<3, 3, uint, lowp> lowp_umat3x3; + typedef mat<3, 4, uint, lowp> lowp_umat3x4; + typedef mat<4, 2, uint, lowp> lowp_umat4x2; + typedef mat<4, 3, uint, lowp> lowp_umat4x3; + typedef mat<4, 4, uint, lowp> lowp_umat4x4; + + typedef mat<2, 2, uint, mediump> mediump_umat2x2; + typedef mat<2, 3, uint, mediump> mediump_umat2x3; + typedef mat<2, 4, uint, mediump> mediump_umat2x4; + typedef mat<3, 2, uint, mediump> mediump_umat3x2; + typedef mat<3, 3, uint, mediump> mediump_umat3x3; + typedef mat<3, 4, uint, mediump> mediump_umat3x4; + typedef mat<4, 2, uint, mediump> mediump_umat4x2; + typedef mat<4, 3, uint, mediump> mediump_umat4x3; + typedef mat<4, 4, uint, mediump> mediump_umat4x4; + + typedef mat<2, 2, uint, highp> highp_umat2x2; + typedef mat<2, 3, uint, highp> highp_umat2x3; + typedef mat<2, 4, uint, highp> highp_umat2x4; + typedef mat<3, 2, uint, highp> highp_umat3x2; + typedef mat<3, 3, uint, highp> highp_umat3x3; + typedef mat<3, 4, uint, highp> highp_umat3x4; + typedef mat<4, 2, uint, highp> highp_umat4x2; + typedef mat<4, 3, uint, highp> highp_umat4x3; + typedef mat<4, 4, uint, highp> highp_umat4x4; + + typedef mat<2, 2, uint, defaultp> umat2x2; + typedef mat<2, 3, uint, defaultp> umat2x3; + typedef mat<2, 4, uint, defaultp> umat2x4; + typedef mat<3, 2, uint, defaultp> umat3x2; + typedef mat<3, 3, uint, defaultp> umat3x3; + typedef mat<3, 4, uint, defaultp> umat3x4; + typedef mat<4, 2, uint, defaultp> umat4x2; + typedef mat<4, 3, uint, defaultp> umat4x3; + typedef mat<4, 4, uint, defaultp> umat4x4; + + + typedef mat<2, 2, uint8, lowp> lowp_u8mat2x2; + typedef mat<2, 3, uint8, lowp> lowp_u8mat2x3; + typedef mat<2, 4, uint8, lowp> lowp_u8mat2x4; + typedef mat<3, 2, uint8, lowp> lowp_u8mat3x2; + typedef mat<3, 3, uint8, lowp> lowp_u8mat3x3; + typedef mat<3, 4, uint8, lowp> lowp_u8mat3x4; + typedef mat<4, 2, uint8, lowp> lowp_u8mat4x2; + typedef mat<4, 3, uint8, lowp> lowp_u8mat4x3; + typedef mat<4, 4, uint8, lowp> lowp_u8mat4x4; + + typedef mat<2, 2, uint8, mediump> mediump_u8mat2x2; + typedef mat<2, 3, uint8, mediump> mediump_u8mat2x3; + typedef mat<2, 4, uint8, mediump> mediump_u8mat2x4; + typedef mat<3, 2, uint8, mediump> mediump_u8mat3x2; + typedef mat<3, 3, uint8, mediump> mediump_u8mat3x3; + typedef mat<3, 4, uint8, mediump> mediump_u8mat3x4; + typedef mat<4, 2, uint8, mediump> mediump_u8mat4x2; + typedef mat<4, 3, uint8, mediump> mediump_u8mat4x3; + typedef mat<4, 4, uint8, mediump> mediump_u8mat4x4; + + typedef mat<2, 2, uint8, highp> highp_u8mat2x2; + typedef mat<2, 3, uint8, highp> highp_u8mat2x3; + typedef mat<2, 4, uint8, highp> highp_u8mat2x4; + typedef mat<3, 2, uint8, highp> highp_u8mat3x2; + typedef mat<3, 3, uint8, highp> highp_u8mat3x3; + typedef mat<3, 4, uint8, highp> highp_u8mat3x4; + typedef mat<4, 2, uint8, highp> highp_u8mat4x2; + typedef mat<4, 3, uint8, highp> highp_u8mat4x3; + typedef mat<4, 4, uint8, highp> highp_u8mat4x4; + + typedef mat<2, 2, uint8, defaultp> u8mat2x2; + typedef mat<2, 3, uint8, defaultp> u8mat2x3; + typedef mat<2, 4, uint8, defaultp> u8mat2x4; + typedef mat<3, 2, uint8, defaultp> u8mat3x2; + typedef mat<3, 3, uint8, defaultp> u8mat3x3; + typedef mat<3, 4, uint8, defaultp> u8mat3x4; + typedef mat<4, 2, uint8, defaultp> u8mat4x2; + typedef mat<4, 3, uint8, defaultp> u8mat4x3; + typedef mat<4, 4, uint8, defaultp> u8mat4x4; + + + typedef mat<2, 2, uint16, lowp> lowp_u16mat2x2; + typedef mat<2, 3, uint16, lowp> lowp_u16mat2x3; + typedef mat<2, 4, uint16, lowp> lowp_u16mat2x4; + typedef mat<3, 2, uint16, lowp> lowp_u16mat3x2; + typedef mat<3, 3, uint16, lowp> lowp_u16mat3x3; + typedef mat<3, 4, uint16, lowp> lowp_u16mat3x4; + typedef mat<4, 2, uint16, lowp> lowp_u16mat4x2; + typedef mat<4, 3, uint16, lowp> lowp_u16mat4x3; + typedef mat<4, 4, uint16, lowp> lowp_u16mat4x4; + + typedef mat<2, 2, uint16, mediump> mediump_u16mat2x2; + typedef mat<2, 3, uint16, mediump> mediump_u16mat2x3; + typedef mat<2, 4, uint16, mediump> mediump_u16mat2x4; + typedef mat<3, 2, uint16, mediump> mediump_u16mat3x2; + typedef mat<3, 3, uint16, mediump> mediump_u16mat3x3; + typedef mat<3, 4, uint16, mediump> mediump_u16mat3x4; + typedef mat<4, 2, uint16, mediump> mediump_u16mat4x2; + typedef mat<4, 3, uint16, mediump> mediump_u16mat4x3; + typedef mat<4, 4, uint16, mediump> mediump_u16mat4x4; + + typedef mat<2, 2, uint16, highp> highp_u16mat2x2; + typedef mat<2, 3, uint16, highp> highp_u16mat2x3; + typedef mat<2, 4, uint16, highp> highp_u16mat2x4; + typedef mat<3, 2, uint16, highp> highp_u16mat3x2; + typedef mat<3, 3, uint16, highp> highp_u16mat3x3; + typedef mat<3, 4, uint16, highp> highp_u16mat3x4; + typedef mat<4, 2, uint16, highp> highp_u16mat4x2; + typedef mat<4, 3, uint16, highp> highp_u16mat4x3; + typedef mat<4, 4, uint16, highp> highp_u16mat4x4; + + typedef mat<2, 2, uint16, defaultp> u16mat2x2; + typedef mat<2, 3, uint16, defaultp> u16mat2x3; + typedef mat<2, 4, uint16, defaultp> u16mat2x4; + typedef mat<3, 2, uint16, defaultp> u16mat3x2; + typedef mat<3, 3, uint16, defaultp> u16mat3x3; + typedef mat<3, 4, uint16, defaultp> u16mat3x4; + typedef mat<4, 2, uint16, defaultp> u16mat4x2; + typedef mat<4, 3, uint16, defaultp> u16mat4x3; + typedef mat<4, 4, uint16, defaultp> u16mat4x4; + + + typedef mat<2, 2, uint32, lowp> lowp_u32mat2x2; + typedef mat<2, 3, uint32, lowp> lowp_u32mat2x3; + typedef mat<2, 4, uint32, lowp> lowp_u32mat2x4; + typedef mat<3, 2, uint32, lowp> lowp_u32mat3x2; + typedef mat<3, 3, uint32, lowp> lowp_u32mat3x3; + typedef mat<3, 4, uint32, lowp> lowp_u32mat3x4; + typedef mat<4, 2, uint32, lowp> lowp_u32mat4x2; + typedef mat<4, 3, uint32, lowp> lowp_u32mat4x3; + typedef mat<4, 4, uint32, lowp> lowp_u32mat4x4; + + typedef mat<2, 2, uint32, mediump> mediump_u32mat2x2; + typedef mat<2, 3, uint32, mediump> mediump_u32mat2x3; + typedef mat<2, 4, uint32, mediump> mediump_u32mat2x4; + typedef mat<3, 2, uint32, mediump> mediump_u32mat3x2; + typedef mat<3, 3, uint32, mediump> mediump_u32mat3x3; + typedef mat<3, 4, uint32, mediump> mediump_u32mat3x4; + typedef mat<4, 2, uint32, mediump> mediump_u32mat4x2; + typedef mat<4, 3, uint32, mediump> mediump_u32mat4x3; + typedef mat<4, 4, uint32, mediump> mediump_u32mat4x4; + + typedef mat<2, 2, uint32, highp> highp_u32mat2x2; + typedef mat<2, 3, uint32, highp> highp_u32mat2x3; + typedef mat<2, 4, uint32, highp> highp_u32mat2x4; + typedef mat<3, 2, uint32, highp> highp_u32mat3x2; + typedef mat<3, 3, uint32, highp> highp_u32mat3x3; + typedef mat<3, 4, uint32, highp> highp_u32mat3x4; + typedef mat<4, 2, uint32, highp> highp_u32mat4x2; + typedef mat<4, 3, uint32, highp> highp_u32mat4x3; + typedef mat<4, 4, uint32, highp> highp_u32mat4x4; + + typedef mat<2, 2, uint32, defaultp> u32mat2x2; + typedef mat<2, 3, uint32, defaultp> u32mat2x3; + typedef mat<2, 4, uint32, defaultp> u32mat2x4; + typedef mat<3, 2, uint32, defaultp> u32mat3x2; + typedef mat<3, 3, uint32, defaultp> u32mat3x3; + typedef mat<3, 4, uint32, defaultp> u32mat3x4; + typedef mat<4, 2, uint32, defaultp> u32mat4x2; + typedef mat<4, 3, uint32, defaultp> u32mat4x3; + typedef mat<4, 4, uint32, defaultp> u32mat4x4; + + + typedef mat<2, 2, uint64, lowp> lowp_u64mat2x2; + typedef mat<2, 3, uint64, lowp> lowp_u64mat2x3; + typedef mat<2, 4, uint64, lowp> lowp_u64mat2x4; + typedef mat<3, 2, uint64, lowp> lowp_u64mat3x2; + typedef mat<3, 3, uint64, lowp> lowp_u64mat3x3; + typedef mat<3, 4, uint64, lowp> lowp_u64mat3x4; + typedef mat<4, 2, uint64, lowp> lowp_u64mat4x2; + typedef mat<4, 3, uint64, lowp> lowp_u64mat4x3; + typedef mat<4, 4, uint64, lowp> lowp_u64mat4x4; + + typedef mat<2, 2, uint64, mediump> mediump_u64mat2x2; + typedef mat<2, 3, uint64, mediump> mediump_u64mat2x3; + typedef mat<2, 4, uint64, mediump> mediump_u64mat2x4; + typedef mat<3, 2, uint64, mediump> mediump_u64mat3x2; + typedef mat<3, 3, uint64, mediump> mediump_u64mat3x3; + typedef mat<3, 4, uint64, mediump> mediump_u64mat3x4; + typedef mat<4, 2, uint64, mediump> mediump_u64mat4x2; + typedef mat<4, 3, uint64, mediump> mediump_u64mat4x3; + typedef mat<4, 4, uint64, mediump> mediump_u64mat4x4; + + typedef mat<2, 2, uint64, highp> highp_u64mat2x2; + typedef mat<2, 3, uint64, highp> highp_u64mat2x3; + typedef mat<2, 4, uint64, highp> highp_u64mat2x4; + typedef mat<3, 2, uint64, highp> highp_u64mat3x2; + typedef mat<3, 3, uint64, highp> highp_u64mat3x3; + typedef mat<3, 4, uint64, highp> highp_u64mat3x4; + typedef mat<4, 2, uint64, highp> highp_u64mat4x2; + typedef mat<4, 3, uint64, highp> highp_u64mat4x3; + typedef mat<4, 4, uint64, highp> highp_u64mat4x4; + + typedef mat<2, 2, uint64, defaultp> u64mat2x2; + typedef mat<2, 3, uint64, defaultp> u64mat2x3; + typedef mat<2, 4, uint64, defaultp> u64mat2x4; + typedef mat<3, 2, uint64, defaultp> u64mat3x2; + typedef mat<3, 3, uint64, defaultp> u64mat3x3; + typedef mat<3, 4, uint64, defaultp> u64mat3x4; + typedef mat<4, 2, uint64, defaultp> u64mat4x2; + typedef mat<4, 3, uint64, defaultp> u64mat4x3; + typedef mat<4, 4, uint64, defaultp> u64mat4x4; + + // Quaternion + + typedef qua lowp_quat; + typedef qua mediump_quat; + typedef qua highp_quat; + typedef qua quat; + + typedef qua lowp_fquat; + typedef qua mediump_fquat; + typedef qua highp_fquat; + typedef qua fquat; + + typedef qua lowp_f32quat; + typedef qua mediump_f32quat; + typedef qua highp_f32quat; + typedef qua f32quat; + + typedef qua lowp_dquat; + typedef qua mediump_dquat; + typedef qua highp_dquat; + typedef qua dquat; + + typedef qua lowp_f64quat; + typedef qua mediump_f64quat; + typedef qua highp_f64quat; + typedef qua f64quat; +}//namespace glm + + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/geometric.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/geometric.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ac857e69d4cf625833d7b8ed9b4f4f34d65304a9 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/geometric.hpp @@ -0,0 +1,116 @@ +/// @ref core +/// @file glm/geometric.hpp +/// +/// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions +/// +/// @defgroup core_func_geometric Geometric functions +/// @ingroup core +/// +/// These operate on vectors as vectors, not component-wise. +/// +/// Include to use these core features. + +#pragma once + +#include "detail/type_vec3.hpp" + +namespace glm +{ + /// @addtogroup core_func_geometric + /// @{ + + /// Returns the length of x, i.e., sqrt(x * x). + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL length man page + /// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions + template + GLM_FUNC_DECL T length(vec const& x); + + /// Returns the distance between p0 and p1, i.e., length(p0 - p1). + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL distance man page + /// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions + template + GLM_FUNC_DECL T distance(vec const& p0, vec const& p1); + + /// Returns the dot product of x and y, i.e., result = x * y. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL dot man page + /// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR T dot(vec const& x, vec const& y); + + /// Returns the cross product of x and y. + /// + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL cross man page + /// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> cross(vec<3, T, Q> const& x, vec<3, T, Q> const& y); + + /// Returns a vector in the same direction as x but with length of 1. + /// According to issue 10 GLSL 1.10 specification, if length(x) == 0 then result is undefined and generate an error. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL normalize man page + /// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions + template + GLM_FUNC_DECL vec normalize(vec const& x); + + /// If dot(Nref, I) < 0.0, return N, otherwise, return -N. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL faceforward man page + /// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions + template + GLM_FUNC_DECL vec faceforward( + vec const& N, + vec const& I, + vec const& Nref); + + /// For the incident vector I and surface orientation N, + /// returns the reflection direction : result = I - 2.0 * dot(N, I) * N. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL reflect man page + /// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions + template + GLM_FUNC_DECL vec reflect( + vec const& I, + vec const& N); + + /// For the incident vector I and surface normal N, + /// and the ratio of indices of refraction eta, + /// return the refraction vector. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL refract man page + /// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions + template + GLM_FUNC_DECL vec refract( + vec const& I, + vec const& N, + T eta); + + /// @} +}//namespace glm + +#include "detail/func_geometric.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/glm.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/glm.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8b375459a78441068e3fbbc2ce35ae6efb3aade9 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/glm.hpp @@ -0,0 +1,137 @@ +/// @ref core +/// @file glm/glm.hpp +/// +/// @mainpage OpenGL Mathematics (GLM) +/// - Website: glm.g-truc.net +/// - GLM API documentation +/// - GLM Manual +/// +/// @defgroup core Core features +/// +/// @brief Features that implement in C++ the GLSL specification as closely as possible. +/// +/// The GLM core consists of C++ types that mirror GLSL types and +/// C++ functions that mirror the GLSL functions. +/// +/// The best documentation for GLM Core is the current GLSL specification, +/// version 4.2 +/// (pdf file). +/// +/// GLM core functionalities require to be included to be used. +/// +/// +/// @defgroup core_vector Vector types +/// +/// Vector types of two to four components with an exhaustive set of operators. +/// +/// @ingroup core +/// +/// +/// @defgroup core_vector_precision Vector types with precision qualifiers +/// +/// @brief Vector types with precision qualifiers which may result in various precision in term of ULPs +/// +/// GLSL allows defining qualifiers for particular variables. +/// With OpenGL's GLSL, these qualifiers have no effect; they are there for compatibility, +/// with OpenGL ES's GLSL, these qualifiers do have an effect. +/// +/// C++ has no language equivalent to qualifier qualifiers. So GLM provides the next-best thing: +/// a number of typedefs that use a particular qualifier. +/// +/// None of these types make any guarantees about the actual qualifier used. +/// +/// @ingroup core +/// +/// +/// @defgroup core_matrix Matrix types +/// +/// Matrix types of with C columns and R rows where C and R are values between 2 to 4 included. +/// These types have exhaustive sets of operators. +/// +/// @ingroup core +/// +/// +/// @defgroup core_matrix_precision Matrix types with precision qualifiers +/// +/// @brief Matrix types with precision qualifiers which may result in various precision in term of ULPs +/// +/// GLSL allows defining qualifiers for particular variables. +/// With OpenGL's GLSL, these qualifiers have no effect; they are there for compatibility, +/// with OpenGL ES's GLSL, these qualifiers do have an effect. +/// +/// C++ has no language equivalent to qualifier qualifiers. So GLM provides the next-best thing: +/// a number of typedefs that use a particular qualifier. +/// +/// None of these types make any guarantees about the actual qualifier used. +/// +/// @ingroup core +/// +/// +/// @defgroup ext Stable extensions +/// +/// @brief Additional features not specified by GLSL specification. +/// +/// EXT extensions are fully tested and documented. +/// +/// Even if it's highly unrecommended, it's possible to include all the extensions at once by +/// including . Otherwise, each extension needs to be included a specific file. +/// +/// +/// @defgroup gtc Recommended extensions +/// +/// @brief Additional features not specified by GLSL specification. +/// +/// GTC extensions aim to be stable with tests and documentation. +/// +/// Even if it's highly unrecommended, it's possible to include all the extensions at once by +/// including . Otherwise, each extension needs to be included a specific file. +/// +/// +/// @defgroup gtx Experimental extensions +/// +/// @brief Experimental features not specified by GLSL specification. +/// +/// Experimental extensions are useful functions and types, but the development of +/// their API and functionality is not necessarily stable. They can change +/// substantially between versions. Backwards compatibility is not much of an issue +/// for them. +/// +/// Even if it's highly unrecommended, it's possible to include all the extensions +/// at once by including . Otherwise, each extension needs to be +/// included a specific file. +/// + +#include "detail/_fixes.hpp" + +#include "detail/setup.hpp" + +#pragma once + +#include +#include +#include +#include +#include +#include "fwd.hpp" + +#include "vec2.hpp" +#include "vec3.hpp" +#include "vec4.hpp" +#include "mat2x2.hpp" +#include "mat2x3.hpp" +#include "mat2x4.hpp" +#include "mat3x2.hpp" +#include "mat3x3.hpp" +#include "mat3x4.hpp" +#include "mat4x2.hpp" +#include "mat4x3.hpp" +#include "mat4x4.hpp" + +#include "trigonometric.hpp" +#include "exponential.hpp" +#include "common.hpp" +#include "packing.hpp" +#include "geometric.hpp" +#include "matrix.hpp" +#include "vector_relational.hpp" +#include "integer.hpp" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/bitfield.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/bitfield.hpp new file mode 100644 index 0000000000000000000000000000000000000000..084fbe75ff144c36e700d9f800fdfba6a0106c30 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/bitfield.hpp @@ -0,0 +1,266 @@ +/// @ref gtc_bitfield +/// @file glm/gtc/bitfield.hpp +/// +/// @see core (dependence) +/// @see gtc_bitfield (dependence) +/// +/// @defgroup gtc_bitfield GLM_GTC_bitfield +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Allow to perform bit operations on integer values + +#include "../detail/setup.hpp" + +#pragma once + +// Dependencies +#include "../ext/scalar_int_sized.hpp" +#include "../ext/scalar_uint_sized.hpp" +#include "../detail/qualifier.hpp" +#include "../detail/_vectorize.hpp" +#include "type_precision.hpp" +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_bitfield extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_bitfield + /// @{ + + /// Build a mask of 'count' bits + /// + /// @see gtc_bitfield + template + GLM_FUNC_DECL genIUType mask(genIUType Bits); + + /// Build a mask of 'count' bits + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Signed and unsigned integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_bitfield + template + GLM_FUNC_DECL vec mask(vec const& v); + + /// Rotate all bits to the right. All the bits dropped in the right side are inserted back on the left side. + /// + /// @see gtc_bitfield + template + GLM_FUNC_DECL genIUType bitfieldRotateRight(genIUType In, int Shift); + + /// Rotate all bits to the right. All the bits dropped in the right side are inserted back on the left side. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Signed and unsigned integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_bitfield + template + GLM_FUNC_DECL vec bitfieldRotateRight(vec const& In, int Shift); + + /// Rotate all bits to the left. All the bits dropped in the left side are inserted back on the right side. + /// + /// @see gtc_bitfield + template + GLM_FUNC_DECL genIUType bitfieldRotateLeft(genIUType In, int Shift); + + /// Rotate all bits to the left. All the bits dropped in the left side are inserted back on the right side. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Signed and unsigned integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_bitfield + template + GLM_FUNC_DECL vec bitfieldRotateLeft(vec const& In, int Shift); + + /// Set to 1 a range of bits. + /// + /// @see gtc_bitfield + template + GLM_FUNC_DECL genIUType bitfieldFillOne(genIUType Value, int FirstBit, int BitCount); + + /// Set to 1 a range of bits. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Signed and unsigned integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_bitfield + template + GLM_FUNC_DECL vec bitfieldFillOne(vec const& Value, int FirstBit, int BitCount); + + /// Set to 0 a range of bits. + /// + /// @see gtc_bitfield + template + GLM_FUNC_DECL genIUType bitfieldFillZero(genIUType Value, int FirstBit, int BitCount); + + /// Set to 0 a range of bits. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Signed and unsigned integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_bitfield + template + GLM_FUNC_DECL vec bitfieldFillZero(vec const& Value, int FirstBit, int BitCount); + + /// Interleaves the bits of x and y. + /// The first bit is the first bit of x followed by the first bit of y. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL int16 bitfieldInterleave(int8 x, int8 y); + + /// Interleaves the bits of x and y. + /// The first bit is the first bit of x followed by the first bit of y. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL uint16 bitfieldInterleave(uint8 x, uint8 y); + + /// Interleaves the bits of x and y. + /// The first bit is the first bit of v.x followed by the first bit of v.y. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL uint16 bitfieldInterleave(u8vec2 const& v); + + /// Deinterleaves the bits of x. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL glm::u8vec2 bitfieldDeinterleave(glm::uint16 x); + + /// Interleaves the bits of x and y. + /// The first bit is the first bit of x followed by the first bit of y. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL int32 bitfieldInterleave(int16 x, int16 y); + + /// Interleaves the bits of x and y. + /// The first bit is the first bit of x followed by the first bit of y. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL uint32 bitfieldInterleave(uint16 x, uint16 y); + + /// Interleaves the bits of x and y. + /// The first bit is the first bit of v.x followed by the first bit of v.y. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL uint32 bitfieldInterleave(u16vec2 const& v); + + /// Deinterleaves the bits of x. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL glm::u16vec2 bitfieldDeinterleave(glm::uint32 x); + + /// Interleaves the bits of x and y. + /// The first bit is the first bit of x followed by the first bit of y. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL int64 bitfieldInterleave(int32 x, int32 y); + + /// Interleaves the bits of x and y. + /// The first bit is the first bit of x followed by the first bit of y. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL uint64 bitfieldInterleave(uint32 x, uint32 y); + + /// Interleaves the bits of x and y. + /// The first bit is the first bit of v.x followed by the first bit of v.y. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL uint64 bitfieldInterleave(u32vec2 const& v); + + /// Deinterleaves the bits of x. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL glm::u32vec2 bitfieldDeinterleave(glm::uint64 x); + + /// Interleaves the bits of x, y and z. + /// The first bit is the first bit of x followed by the first bit of y and the first bit of z. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL int32 bitfieldInterleave(int8 x, int8 y, int8 z); + + /// Interleaves the bits of x, y and z. + /// The first bit is the first bit of x followed by the first bit of y and the first bit of z. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL uint32 bitfieldInterleave(uint8 x, uint8 y, uint8 z); + + /// Interleaves the bits of x, y and z. + /// The first bit is the first bit of x followed by the first bit of y and the first bit of z. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL int64 bitfieldInterleave(int16 x, int16 y, int16 z); + + /// Interleaves the bits of x, y and z. + /// The first bit is the first bit of x followed by the first bit of y and the first bit of z. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL uint64 bitfieldInterleave(uint16 x, uint16 y, uint16 z); + + /// Interleaves the bits of x, y and z. + /// The first bit is the first bit of x followed by the first bit of y and the first bit of z. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL int64 bitfieldInterleave(int32 x, int32 y, int32 z); + + /// Interleaves the bits of x, y and z. + /// The first bit is the first bit of x followed by the first bit of y and the first bit of z. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL uint64 bitfieldInterleave(uint32 x, uint32 y, uint32 z); + + /// Interleaves the bits of x, y, z and w. + /// The first bit is the first bit of x followed by the first bit of y, the first bit of z and finally the first bit of w. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL int32 bitfieldInterleave(int8 x, int8 y, int8 z, int8 w); + + /// Interleaves the bits of x, y, z and w. + /// The first bit is the first bit of x followed by the first bit of y, the first bit of z and finally the first bit of w. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL uint32 bitfieldInterleave(uint8 x, uint8 y, uint8 z, uint8 w); + + /// Interleaves the bits of x, y, z and w. + /// The first bit is the first bit of x followed by the first bit of y, the first bit of z and finally the first bit of w. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL int64 bitfieldInterleave(int16 x, int16 y, int16 z, int16 w); + + /// Interleaves the bits of x, y, z and w. + /// The first bit is the first bit of x followed by the first bit of y, the first bit of z and finally the first bit of w. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL uint64 bitfieldInterleave(uint16 x, uint16 y, uint16 z, uint16 w); + + /// @} +} //namespace glm + +#include "bitfield.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/bitfield.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/bitfield.inl new file mode 100644 index 0000000000000000000000000000000000000000..06cf1889cd40b366882a1f408c8c7ca40da5b680 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/bitfield.inl @@ -0,0 +1,626 @@ +/// @ref gtc_bitfield + +#include "../simd/integer.h" + +namespace glm{ +namespace detail +{ + template + GLM_FUNC_DECL RET bitfieldInterleave(PARAM x, PARAM y); + + template + GLM_FUNC_DECL RET bitfieldInterleave(PARAM x, PARAM y, PARAM z); + + template + GLM_FUNC_DECL RET bitfieldInterleave(PARAM x, PARAM y, PARAM z, PARAM w); + + template<> + GLM_FUNC_QUALIFIER glm::uint16 bitfieldInterleave(glm::uint8 x, glm::uint8 y) + { + glm::uint16 REG1(x); + glm::uint16 REG2(y); + + REG1 = ((REG1 << 4) | REG1) & static_cast(0x0F0F); + REG2 = ((REG2 << 4) | REG2) & static_cast(0x0F0F); + + REG1 = ((REG1 << 2) | REG1) & static_cast(0x3333); + REG2 = ((REG2 << 2) | REG2) & static_cast(0x3333); + + REG1 = ((REG1 << 1) | REG1) & static_cast(0x5555); + REG2 = ((REG2 << 1) | REG2) & static_cast(0x5555); + + return REG1 | static_cast(REG2 << 1); + } + + template<> + GLM_FUNC_QUALIFIER glm::uint32 bitfieldInterleave(glm::uint16 x, glm::uint16 y) + { + glm::uint32 REG1(x); + glm::uint32 REG2(y); + + REG1 = ((REG1 << 8) | REG1) & static_cast(0x00FF00FF); + REG2 = ((REG2 << 8) | REG2) & static_cast(0x00FF00FF); + + REG1 = ((REG1 << 4) | REG1) & static_cast(0x0F0F0F0F); + REG2 = ((REG2 << 4) | REG2) & static_cast(0x0F0F0F0F); + + REG1 = ((REG1 << 2) | REG1) & static_cast(0x33333333); + REG2 = ((REG2 << 2) | REG2) & static_cast(0x33333333); + + REG1 = ((REG1 << 1) | REG1) & static_cast(0x55555555); + REG2 = ((REG2 << 1) | REG2) & static_cast(0x55555555); + + return REG1 | (REG2 << 1); + } + + template<> + GLM_FUNC_QUALIFIER glm::uint64 bitfieldInterleave(glm::uint32 x, glm::uint32 y) + { + glm::uint64 REG1(x); + glm::uint64 REG2(y); + + REG1 = ((REG1 << 16) | REG1) & static_cast(0x0000FFFF0000FFFFull); + REG2 = ((REG2 << 16) | REG2) & static_cast(0x0000FFFF0000FFFFull); + + REG1 = ((REG1 << 8) | REG1) & static_cast(0x00FF00FF00FF00FFull); + REG2 = ((REG2 << 8) | REG2) & static_cast(0x00FF00FF00FF00FFull); + + REG1 = ((REG1 << 4) | REG1) & static_cast(0x0F0F0F0F0F0F0F0Full); + REG2 = ((REG2 << 4) | REG2) & static_cast(0x0F0F0F0F0F0F0F0Full); + + REG1 = ((REG1 << 2) | REG1) & static_cast(0x3333333333333333ull); + REG2 = ((REG2 << 2) | REG2) & static_cast(0x3333333333333333ull); + + REG1 = ((REG1 << 1) | REG1) & static_cast(0x5555555555555555ull); + REG2 = ((REG2 << 1) | REG2) & static_cast(0x5555555555555555ull); + + return REG1 | (REG2 << 1); + } + + template<> + GLM_FUNC_QUALIFIER glm::uint32 bitfieldInterleave(glm::uint8 x, glm::uint8 y, glm::uint8 z) + { + glm::uint32 REG1(x); + glm::uint32 REG2(y); + glm::uint32 REG3(z); + + REG1 = ((REG1 << 16) | REG1) & static_cast(0xFF0000FFu); + REG2 = ((REG2 << 16) | REG2) & static_cast(0xFF0000FFu); + REG3 = ((REG3 << 16) | REG3) & static_cast(0xFF0000FFu); + + REG1 = ((REG1 << 8) | REG1) & static_cast(0x0F00F00Fu); + REG2 = ((REG2 << 8) | REG2) & static_cast(0x0F00F00Fu); + REG3 = ((REG3 << 8) | REG3) & static_cast(0x0F00F00Fu); + + REG1 = ((REG1 << 4) | REG1) & static_cast(0xC30C30C3u); + REG2 = ((REG2 << 4) | REG2) & static_cast(0xC30C30C3u); + REG3 = ((REG3 << 4) | REG3) & static_cast(0xC30C30C3u); + + REG1 = ((REG1 << 2) | REG1) & static_cast(0x49249249u); + REG2 = ((REG2 << 2) | REG2) & static_cast(0x49249249u); + REG3 = ((REG3 << 2) | REG3) & static_cast(0x49249249u); + + return REG1 | (REG2 << 1) | (REG3 << 2); + } + + template<> + GLM_FUNC_QUALIFIER glm::uint64 bitfieldInterleave(glm::uint16 x, glm::uint16 y, glm::uint16 z) + { + glm::uint64 REG1(x); + glm::uint64 REG2(y); + glm::uint64 REG3(z); + + REG1 = ((REG1 << 32) | REG1) & static_cast(0xFFFF00000000FFFFull); + REG2 = ((REG2 << 32) | REG2) & static_cast(0xFFFF00000000FFFFull); + REG3 = ((REG3 << 32) | REG3) & static_cast(0xFFFF00000000FFFFull); + + REG1 = ((REG1 << 16) | REG1) & static_cast(0x00FF0000FF0000FFull); + REG2 = ((REG2 << 16) | REG2) & static_cast(0x00FF0000FF0000FFull); + REG3 = ((REG3 << 16) | REG3) & static_cast(0x00FF0000FF0000FFull); + + REG1 = ((REG1 << 8) | REG1) & static_cast(0xF00F00F00F00F00Full); + REG2 = ((REG2 << 8) | REG2) & static_cast(0xF00F00F00F00F00Full); + REG3 = ((REG3 << 8) | REG3) & static_cast(0xF00F00F00F00F00Full); + + REG1 = ((REG1 << 4) | REG1) & static_cast(0x30C30C30C30C30C3ull); + REG2 = ((REG2 << 4) | REG2) & static_cast(0x30C30C30C30C30C3ull); + REG3 = ((REG3 << 4) | REG3) & static_cast(0x30C30C30C30C30C3ull); + + REG1 = ((REG1 << 2) | REG1) & static_cast(0x9249249249249249ull); + REG2 = ((REG2 << 2) | REG2) & static_cast(0x9249249249249249ull); + REG3 = ((REG3 << 2) | REG3) & static_cast(0x9249249249249249ull); + + return REG1 | (REG2 << 1) | (REG3 << 2); + } + + template<> + GLM_FUNC_QUALIFIER glm::uint64 bitfieldInterleave(glm::uint32 x, glm::uint32 y, glm::uint32 z) + { + glm::uint64 REG1(x); + glm::uint64 REG2(y); + glm::uint64 REG3(z); + + REG1 = ((REG1 << 32) | REG1) & static_cast(0xFFFF00000000FFFFull); + REG2 = ((REG2 << 32) | REG2) & static_cast(0xFFFF00000000FFFFull); + REG3 = ((REG3 << 32) | REG3) & static_cast(0xFFFF00000000FFFFull); + + REG1 = ((REG1 << 16) | REG1) & static_cast(0x00FF0000FF0000FFull); + REG2 = ((REG2 << 16) | REG2) & static_cast(0x00FF0000FF0000FFull); + REG3 = ((REG3 << 16) | REG3) & static_cast(0x00FF0000FF0000FFull); + + REG1 = ((REG1 << 8) | REG1) & static_cast(0xF00F00F00F00F00Full); + REG2 = ((REG2 << 8) | REG2) & static_cast(0xF00F00F00F00F00Full); + REG3 = ((REG3 << 8) | REG3) & static_cast(0xF00F00F00F00F00Full); + + REG1 = ((REG1 << 4) | REG1) & static_cast(0x30C30C30C30C30C3ull); + REG2 = ((REG2 << 4) | REG2) & static_cast(0x30C30C30C30C30C3ull); + REG3 = ((REG3 << 4) | REG3) & static_cast(0x30C30C30C30C30C3ull); + + REG1 = ((REG1 << 2) | REG1) & static_cast(0x9249249249249249ull); + REG2 = ((REG2 << 2) | REG2) & static_cast(0x9249249249249249ull); + REG3 = ((REG3 << 2) | REG3) & static_cast(0x9249249249249249ull); + + return REG1 | (REG2 << 1) | (REG3 << 2); + } + + template<> + GLM_FUNC_QUALIFIER glm::uint32 bitfieldInterleave(glm::uint8 x, glm::uint8 y, glm::uint8 z, glm::uint8 w) + { + glm::uint32 REG1(x); + glm::uint32 REG2(y); + glm::uint32 REG3(z); + glm::uint32 REG4(w); + + REG1 = ((REG1 << 12) | REG1) & static_cast(0x000F000Fu); + REG2 = ((REG2 << 12) | REG2) & static_cast(0x000F000Fu); + REG3 = ((REG3 << 12) | REG3) & static_cast(0x000F000Fu); + REG4 = ((REG4 << 12) | REG4) & static_cast(0x000F000Fu); + + REG1 = ((REG1 << 6) | REG1) & static_cast(0x03030303u); + REG2 = ((REG2 << 6) | REG2) & static_cast(0x03030303u); + REG3 = ((REG3 << 6) | REG3) & static_cast(0x03030303u); + REG4 = ((REG4 << 6) | REG4) & static_cast(0x03030303u); + + REG1 = ((REG1 << 3) | REG1) & static_cast(0x11111111u); + REG2 = ((REG2 << 3) | REG2) & static_cast(0x11111111u); + REG3 = ((REG3 << 3) | REG3) & static_cast(0x11111111u); + REG4 = ((REG4 << 3) | REG4) & static_cast(0x11111111u); + + return REG1 | (REG2 << 1) | (REG3 << 2) | (REG4 << 3); + } + + template<> + GLM_FUNC_QUALIFIER glm::uint64 bitfieldInterleave(glm::uint16 x, glm::uint16 y, glm::uint16 z, glm::uint16 w) + { + glm::uint64 REG1(x); + glm::uint64 REG2(y); + glm::uint64 REG3(z); + glm::uint64 REG4(w); + + REG1 = ((REG1 << 24) | REG1) & static_cast(0x000000FF000000FFull); + REG2 = ((REG2 << 24) | REG2) & static_cast(0x000000FF000000FFull); + REG3 = ((REG3 << 24) | REG3) & static_cast(0x000000FF000000FFull); + REG4 = ((REG4 << 24) | REG4) & static_cast(0x000000FF000000FFull); + + REG1 = ((REG1 << 12) | REG1) & static_cast(0x000F000F000F000Full); + REG2 = ((REG2 << 12) | REG2) & static_cast(0x000F000F000F000Full); + REG3 = ((REG3 << 12) | REG3) & static_cast(0x000F000F000F000Full); + REG4 = ((REG4 << 12) | REG4) & static_cast(0x000F000F000F000Full); + + REG1 = ((REG1 << 6) | REG1) & static_cast(0x0303030303030303ull); + REG2 = ((REG2 << 6) | REG2) & static_cast(0x0303030303030303ull); + REG3 = ((REG3 << 6) | REG3) & static_cast(0x0303030303030303ull); + REG4 = ((REG4 << 6) | REG4) & static_cast(0x0303030303030303ull); + + REG1 = ((REG1 << 3) | REG1) & static_cast(0x1111111111111111ull); + REG2 = ((REG2 << 3) | REG2) & static_cast(0x1111111111111111ull); + REG3 = ((REG3 << 3) | REG3) & static_cast(0x1111111111111111ull); + REG4 = ((REG4 << 3) | REG4) & static_cast(0x1111111111111111ull); + + return REG1 | (REG2 << 1) | (REG3 << 2) | (REG4 << 3); + } +}//namespace detail + + template + GLM_FUNC_QUALIFIER genIUType mask(genIUType Bits) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'mask' accepts only integer values"); + + return Bits >= sizeof(genIUType) * 8 ? ~static_cast(0) : (static_cast(1) << Bits) - static_cast(1); + } + + template + GLM_FUNC_QUALIFIER vec mask(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'mask' accepts only integer values"); + + return detail::functor1::call(mask, v); + } + + template + GLM_FUNC_QUALIFIER genIType bitfieldRotateRight(genIType In, int Shift) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldRotateRight' accepts only integer values"); + + int const BitSize = static_cast(sizeof(genIType) * 8); + return (In << static_cast(Shift)) | (In >> static_cast(BitSize - Shift)); + } + + template + GLM_FUNC_QUALIFIER vec bitfieldRotateRight(vec const& In, int Shift) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldRotateRight' accepts only integer values"); + + int const BitSize = static_cast(sizeof(T) * 8); + return (In << static_cast(Shift)) | (In >> static_cast(BitSize - Shift)); + } + + template + GLM_FUNC_QUALIFIER genIType bitfieldRotateLeft(genIType In, int Shift) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldRotateLeft' accepts only integer values"); + + int const BitSize = static_cast(sizeof(genIType) * 8); + return (In >> static_cast(Shift)) | (In << static_cast(BitSize - Shift)); + } + + template + GLM_FUNC_QUALIFIER vec bitfieldRotateLeft(vec const& In, int Shift) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldRotateLeft' accepts only integer values"); + + int const BitSize = static_cast(sizeof(T) * 8); + return (In >> static_cast(Shift)) | (In << static_cast(BitSize - Shift)); + } + + template + GLM_FUNC_QUALIFIER genIUType bitfieldFillOne(genIUType Value, int FirstBit, int BitCount) + { + return Value | static_cast(mask(BitCount) << FirstBit); + } + + template + GLM_FUNC_QUALIFIER vec bitfieldFillOne(vec const& Value, int FirstBit, int BitCount) + { + return Value | static_cast(mask(BitCount) << FirstBit); + } + + template + GLM_FUNC_QUALIFIER genIUType bitfieldFillZero(genIUType Value, int FirstBit, int BitCount) + { + return Value & static_cast(~(mask(BitCount) << FirstBit)); + } + + template + GLM_FUNC_QUALIFIER vec bitfieldFillZero(vec const& Value, int FirstBit, int BitCount) + { + return Value & static_cast(~(mask(BitCount) << FirstBit)); + } + + GLM_FUNC_QUALIFIER int16 bitfieldInterleave(int8 x, int8 y) + { + union sign8 + { + int8 i; + uint8 u; + } sign_x, sign_y; + + union sign16 + { + int16 i; + uint16 u; + } result; + + sign_x.i = x; + sign_y.i = y; + result.u = bitfieldInterleave(sign_x.u, sign_y.u); + + return result.i; + } + + GLM_FUNC_QUALIFIER uint16 bitfieldInterleave(uint8 x, uint8 y) + { + return detail::bitfieldInterleave(x, y); + } + + GLM_FUNC_QUALIFIER uint16 bitfieldInterleave(u8vec2 const& v) + { + return detail::bitfieldInterleave(v.x, v.y); + } + + GLM_FUNC_QUALIFIER u8vec2 bitfieldDeinterleave(glm::uint16 x) + { + uint16 REG1(x); + uint16 REG2(x >>= 1); + + REG1 = REG1 & static_cast(0x5555); + REG2 = REG2 & static_cast(0x5555); + + REG1 = ((REG1 >> 1) | REG1) & static_cast(0x3333); + REG2 = ((REG2 >> 1) | REG2) & static_cast(0x3333); + + REG1 = ((REG1 >> 2) | REG1) & static_cast(0x0F0F); + REG2 = ((REG2 >> 2) | REG2) & static_cast(0x0F0F); + + REG1 = ((REG1 >> 4) | REG1) & static_cast(0x00FF); + REG2 = ((REG2 >> 4) | REG2) & static_cast(0x00FF); + + REG1 = ((REG1 >> 8) | REG1) & static_cast(0xFFFF); + REG2 = ((REG2 >> 8) | REG2) & static_cast(0xFFFF); + + return glm::u8vec2(REG1, REG2); + } + + GLM_FUNC_QUALIFIER int32 bitfieldInterleave(int16 x, int16 y) + { + union sign16 + { + int16 i; + uint16 u; + } sign_x, sign_y; + + union sign32 + { + int32 i; + uint32 u; + } result; + + sign_x.i = x; + sign_y.i = y; + result.u = bitfieldInterleave(sign_x.u, sign_y.u); + + return result.i; + } + + GLM_FUNC_QUALIFIER uint32 bitfieldInterleave(uint16 x, uint16 y) + { + return detail::bitfieldInterleave(x, y); + } + + GLM_FUNC_QUALIFIER glm::uint32 bitfieldInterleave(u16vec2 const& v) + { + return detail::bitfieldInterleave(v.x, v.y); + } + + GLM_FUNC_QUALIFIER glm::u16vec2 bitfieldDeinterleave(glm::uint32 x) + { + glm::uint32 REG1(x); + glm::uint32 REG2(x >>= 1); + + REG1 = REG1 & static_cast(0x55555555); + REG2 = REG2 & static_cast(0x55555555); + + REG1 = ((REG1 >> 1) | REG1) & static_cast(0x33333333); + REG2 = ((REG2 >> 1) | REG2) & static_cast(0x33333333); + + REG1 = ((REG1 >> 2) | REG1) & static_cast(0x0F0F0F0F); + REG2 = ((REG2 >> 2) | REG2) & static_cast(0x0F0F0F0F); + + REG1 = ((REG1 >> 4) | REG1) & static_cast(0x00FF00FF); + REG2 = ((REG2 >> 4) | REG2) & static_cast(0x00FF00FF); + + REG1 = ((REG1 >> 8) | REG1) & static_cast(0x0000FFFF); + REG2 = ((REG2 >> 8) | REG2) & static_cast(0x0000FFFF); + + return glm::u16vec2(REG1, REG2); + } + + GLM_FUNC_QUALIFIER int64 bitfieldInterleave(int32 x, int32 y) + { + union sign32 + { + int32 i; + uint32 u; + } sign_x, sign_y; + + union sign64 + { + int64 i; + uint64 u; + } result; + + sign_x.i = x; + sign_y.i = y; + result.u = bitfieldInterleave(sign_x.u, sign_y.u); + + return result.i; + } + + GLM_FUNC_QUALIFIER uint64 bitfieldInterleave(uint32 x, uint32 y) + { + return detail::bitfieldInterleave(x, y); + } + + GLM_FUNC_QUALIFIER glm::uint64 bitfieldInterleave(u32vec2 const& v) + { + return detail::bitfieldInterleave(v.x, v.y); + } + + GLM_FUNC_QUALIFIER glm::u32vec2 bitfieldDeinterleave(glm::uint64 x) + { + glm::uint64 REG1(x); + glm::uint64 REG2(x >>= 1); + + REG1 = REG1 & static_cast(0x5555555555555555ull); + REG2 = REG2 & static_cast(0x5555555555555555ull); + + REG1 = ((REG1 >> 1) | REG1) & static_cast(0x3333333333333333ull); + REG2 = ((REG2 >> 1) | REG2) & static_cast(0x3333333333333333ull); + + REG1 = ((REG1 >> 2) | REG1) & static_cast(0x0F0F0F0F0F0F0F0Full); + REG2 = ((REG2 >> 2) | REG2) & static_cast(0x0F0F0F0F0F0F0F0Full); + + REG1 = ((REG1 >> 4) | REG1) & static_cast(0x00FF00FF00FF00FFull); + REG2 = ((REG2 >> 4) | REG2) & static_cast(0x00FF00FF00FF00FFull); + + REG1 = ((REG1 >> 8) | REG1) & static_cast(0x0000FFFF0000FFFFull); + REG2 = ((REG2 >> 8) | REG2) & static_cast(0x0000FFFF0000FFFFull); + + REG1 = ((REG1 >> 16) | REG1) & static_cast(0x00000000FFFFFFFFull); + REG2 = ((REG2 >> 16) | REG2) & static_cast(0x00000000FFFFFFFFull); + + return glm::u32vec2(REG1, REG2); + } + + GLM_FUNC_QUALIFIER int32 bitfieldInterleave(int8 x, int8 y, int8 z) + { + union sign8 + { + int8 i; + uint8 u; + } sign_x, sign_y, sign_z; + + union sign32 + { + int32 i; + uint32 u; + } result; + + sign_x.i = x; + sign_y.i = y; + sign_z.i = z; + result.u = bitfieldInterleave(sign_x.u, sign_y.u, sign_z.u); + + return result.i; + } + + GLM_FUNC_QUALIFIER uint32 bitfieldInterleave(uint8 x, uint8 y, uint8 z) + { + return detail::bitfieldInterleave(x, y, z); + } + + GLM_FUNC_QUALIFIER uint32 bitfieldInterleave(u8vec3 const& v) + { + return detail::bitfieldInterleave(v.x, v.y, v.z); + } + + GLM_FUNC_QUALIFIER int64 bitfieldInterleave(int16 x, int16 y, int16 z) + { + union sign16 + { + int16 i; + uint16 u; + } sign_x, sign_y, sign_z; + + union sign64 + { + int64 i; + uint64 u; + } result; + + sign_x.i = x; + sign_y.i = y; + sign_z.i = z; + result.u = bitfieldInterleave(sign_x.u, sign_y.u, sign_z.u); + + return result.i; + } + + GLM_FUNC_QUALIFIER uint64 bitfieldInterleave(uint16 x, uint16 y, uint16 z) + { + return detail::bitfieldInterleave(x, y, z); + } + + GLM_FUNC_QUALIFIER uint64 bitfieldInterleave(u16vec3 const& v) + { + return detail::bitfieldInterleave(v.x, v.y, v.z); + } + + GLM_FUNC_QUALIFIER int64 bitfieldInterleave(int32 x, int32 y, int32 z) + { + union sign16 + { + int32 i; + uint32 u; + } sign_x, sign_y, sign_z; + + union sign64 + { + int64 i; + uint64 u; + } result; + + sign_x.i = x; + sign_y.i = y; + sign_z.i = z; + result.u = bitfieldInterleave(sign_x.u, sign_y.u, sign_z.u); + + return result.i; + } + + GLM_FUNC_QUALIFIER uint64 bitfieldInterleave(uint32 x, uint32 y, uint32 z) + { + return detail::bitfieldInterleave(x, y, z); + } + + GLM_FUNC_QUALIFIER uint64 bitfieldInterleave(u32vec3 const& v) + { + return detail::bitfieldInterleave(v.x, v.y, v.z); + } + + GLM_FUNC_QUALIFIER int32 bitfieldInterleave(int8 x, int8 y, int8 z, int8 w) + { + union sign8 + { + int8 i; + uint8 u; + } sign_x, sign_y, sign_z, sign_w; + + union sign32 + { + int32 i; + uint32 u; + } result; + + sign_x.i = x; + sign_y.i = y; + sign_z.i = z; + sign_w.i = w; + result.u = bitfieldInterleave(sign_x.u, sign_y.u, sign_z.u, sign_w.u); + + return result.i; + } + + GLM_FUNC_QUALIFIER uint32 bitfieldInterleave(uint8 x, uint8 y, uint8 z, uint8 w) + { + return detail::bitfieldInterleave(x, y, z, w); + } + + GLM_FUNC_QUALIFIER uint32 bitfieldInterleave(u8vec4 const& v) + { + return detail::bitfieldInterleave(v.x, v.y, v.z, v.w); + } + + GLM_FUNC_QUALIFIER int64 bitfieldInterleave(int16 x, int16 y, int16 z, int16 w) + { + union sign16 + { + int16 i; + uint16 u; + } sign_x, sign_y, sign_z, sign_w; + + union sign64 + { + int64 i; + uint64 u; + } result; + + sign_x.i = x; + sign_y.i = y; + sign_z.i = z; + sign_w.i = w; + result.u = bitfieldInterleave(sign_x.u, sign_y.u, sign_z.u, sign_w.u); + + return result.i; + } + + GLM_FUNC_QUALIFIER uint64 bitfieldInterleave(uint16 x, uint16 y, uint16 z, uint16 w) + { + return detail::bitfieldInterleave(x, y, z, w); + } + + GLM_FUNC_QUALIFIER uint64 bitfieldInterleave(u16vec4 const& v) + { + return detail::bitfieldInterleave(v.x, v.y, v.z, v.w); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/color_space.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/color_space.hpp new file mode 100644 index 0000000000000000000000000000000000000000..cffd9f093fb953ed2f52ef5a427c8b889072d899 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/color_space.hpp @@ -0,0 +1,56 @@ +/// @ref gtc_color_space +/// @file glm/gtc/color_space.hpp +/// +/// @see core (dependence) +/// @see gtc_color_space (dependence) +/// +/// @defgroup gtc_color_space GLM_GTC_color_space +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Allow to perform bit operations on integer values + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../detail/qualifier.hpp" +#include "../exponential.hpp" +#include "../vec3.hpp" +#include "../vec4.hpp" +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_color_space extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_color_space + /// @{ + + /// Convert a linear color to sRGB color using a standard gamma correction. + /// IEC 61966-2-1:1999 / Rec. 709 specification https://www.w3.org/Graphics/Color/srgb + template + GLM_FUNC_DECL vec convertLinearToSRGB(vec const& ColorLinear); + + /// Convert a linear color to sRGB color using a custom gamma correction. + /// IEC 61966-2-1:1999 / Rec. 709 specification https://www.w3.org/Graphics/Color/srgb + template + GLM_FUNC_DECL vec convertLinearToSRGB(vec const& ColorLinear, T Gamma); + + /// Convert a sRGB color to linear color using a standard gamma correction. + /// IEC 61966-2-1:1999 / Rec. 709 specification https://www.w3.org/Graphics/Color/srgb + template + GLM_FUNC_DECL vec convertSRGBToLinear(vec const& ColorSRGB); + + /// Convert a sRGB color to linear color using a custom gamma correction. + // IEC 61966-2-1:1999 / Rec. 709 specification https://www.w3.org/Graphics/Color/srgb + template + GLM_FUNC_DECL vec convertSRGBToLinear(vec const& ColorSRGB, T Gamma); + + /// @} +} //namespace glm + +#include "color_space.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/color_space.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/color_space.inl new file mode 100644 index 0000000000000000000000000000000000000000..2a900044e99b7507e9921782684461acfbd6ab1f --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/color_space.inl @@ -0,0 +1,84 @@ +/// @ref gtc_color_space + +namespace glm{ +namespace detail +{ + template + struct compute_rgbToSrgb + { + GLM_FUNC_QUALIFIER static vec call(vec const& ColorRGB, T GammaCorrection) + { + vec const ClampedColor(clamp(ColorRGB, static_cast(0), static_cast(1))); + + return mix( + pow(ClampedColor, vec(GammaCorrection)) * static_cast(1.055) - static_cast(0.055), + ClampedColor * static_cast(12.92), + lessThan(ClampedColor, vec(static_cast(0.0031308)))); + } + }; + + template + struct compute_rgbToSrgb<4, T, Q> + { + GLM_FUNC_QUALIFIER static vec<4, T, Q> call(vec<4, T, Q> const& ColorRGB, T GammaCorrection) + { + return vec<4, T, Q>(compute_rgbToSrgb<3, T, Q>::call(vec<3, T, Q>(ColorRGB), GammaCorrection), ColorRGB.w); + } + }; + + template + struct compute_srgbToRgb + { + GLM_FUNC_QUALIFIER static vec call(vec const& ColorSRGB, T Gamma) + { + return mix( + pow((ColorSRGB + static_cast(0.055)) * static_cast(0.94786729857819905213270142180095), vec(Gamma)), + ColorSRGB * static_cast(0.07739938080495356037151702786378), + lessThanEqual(ColorSRGB, vec(static_cast(0.04045)))); + } + }; + + template + struct compute_srgbToRgb<4, T, Q> + { + GLM_FUNC_QUALIFIER static vec<4, T, Q> call(vec<4, T, Q> const& ColorSRGB, T Gamma) + { + return vec<4, T, Q>(compute_srgbToRgb<3, T, Q>::call(vec<3, T, Q>(ColorSRGB), Gamma), ColorSRGB.w); + } + }; +}//namespace detail + + template + GLM_FUNC_QUALIFIER vec convertLinearToSRGB(vec const& ColorLinear) + { + return detail::compute_rgbToSrgb::call(ColorLinear, static_cast(0.41666)); + } + + // Based on Ian Taylor http://chilliant.blogspot.fr/2012/08/srgb-approximations-for-hlsl.html + template<> + GLM_FUNC_QUALIFIER vec<3, float, lowp> convertLinearToSRGB(vec<3, float, lowp> const& ColorLinear) + { + vec<3, float, lowp> S1 = sqrt(ColorLinear); + vec<3, float, lowp> S2 = sqrt(S1); + vec<3, float, lowp> S3 = sqrt(S2); + return 0.662002687f * S1 + 0.684122060f * S2 - 0.323583601f * S3 - 0.0225411470f * ColorLinear; + } + + template + GLM_FUNC_QUALIFIER vec convertLinearToSRGB(vec const& ColorLinear, T Gamma) + { + return detail::compute_rgbToSrgb::call(ColorLinear, static_cast(1) / Gamma); + } + + template + GLM_FUNC_QUALIFIER vec convertSRGBToLinear(vec const& ColorSRGB) + { + return detail::compute_srgbToRgb::call(ColorSRGB, static_cast(2.4)); + } + + template + GLM_FUNC_QUALIFIER vec convertSRGBToLinear(vec const& ColorSRGB, T Gamma) + { + return detail::compute_srgbToRgb::call(ColorSRGB, Gamma); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/constants.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/constants.hpp new file mode 100644 index 0000000000000000000000000000000000000000..99f212869e0d753d10e0ccaebd51f681de1cce05 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/constants.hpp @@ -0,0 +1,165 @@ +/// @ref gtc_constants +/// @file glm/gtc/constants.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtc_constants GLM_GTC_constants +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Provide a list of constants and precomputed useful values. + +#pragma once + +// Dependencies +#include "../ext/scalar_constants.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_constants extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_constants + /// @{ + + /// Return 0. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType zero(); + + /// Return 1. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType one(); + + /// Return pi * 2. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType two_pi(); + + /// Return square root of pi. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType root_pi(); + + /// Return pi / 2. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType half_pi(); + + /// Return pi / 2 * 3. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType three_over_two_pi(); + + /// Return pi / 4. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType quarter_pi(); + + /// Return 1 / pi. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType one_over_pi(); + + /// Return 1 / (pi * 2). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType one_over_two_pi(); + + /// Return 2 / pi. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType two_over_pi(); + + /// Return 4 / pi. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType four_over_pi(); + + /// Return 2 / sqrt(pi). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType two_over_root_pi(); + + /// Return 1 / sqrt(2). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType one_over_root_two(); + + /// Return sqrt(pi / 2). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType root_half_pi(); + + /// Return sqrt(2 * pi). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType root_two_pi(); + + /// Return sqrt(ln(4)). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType root_ln_four(); + + /// Return e constant. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType e(); + + /// Return Euler's constant. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType euler(); + + /// Return sqrt(2). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType root_two(); + + /// Return sqrt(3). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType root_three(); + + /// Return sqrt(5). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType root_five(); + + /// Return ln(2). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType ln_two(); + + /// Return ln(10). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType ln_ten(); + + /// Return ln(ln(2)). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType ln_ln_two(); + + /// Return 1 / 3. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType third(); + + /// Return 2 / 3. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType two_thirds(); + + /// Return the golden ratio constant. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType golden_ratio(); + + /// @} +} //namespace glm + +#include "constants.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/constants.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/constants.inl new file mode 100644 index 0000000000000000000000000000000000000000..bb98c6bff9d11281f151dfbe7513c8c7f3f26be4 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/constants.inl @@ -0,0 +1,167 @@ +/// @ref gtc_constants + +namespace glm +{ + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType zero() + { + return genType(0); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType one() + { + return genType(1); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType two_pi() + { + return genType(6.28318530717958647692528676655900576); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_pi() + { + return genType(1.772453850905516027); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType half_pi() + { + return genType(1.57079632679489661923132169163975144); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType three_over_two_pi() + { + return genType(4.71238898038468985769396507491925432); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType quarter_pi() + { + return genType(0.785398163397448309615660845819875721); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType one_over_pi() + { + return genType(0.318309886183790671537767526745028724); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType one_over_two_pi() + { + return genType(0.159154943091895335768883763372514362); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType two_over_pi() + { + return genType(0.636619772367581343075535053490057448); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType four_over_pi() + { + return genType(1.273239544735162686151070106980114898); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType two_over_root_pi() + { + return genType(1.12837916709551257389615890312154517); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType one_over_root_two() + { + return genType(0.707106781186547524400844362104849039); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_half_pi() + { + return genType(1.253314137315500251); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_two_pi() + { + return genType(2.506628274631000502); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_ln_four() + { + return genType(1.17741002251547469); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType e() + { + return genType(2.71828182845904523536); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType euler() + { + return genType(0.577215664901532860606); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_two() + { + return genType(1.41421356237309504880168872420969808); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_three() + { + return genType(1.73205080756887729352744634150587236); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_five() + { + return genType(2.23606797749978969640917366873127623); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType ln_two() + { + return genType(0.693147180559945309417232121458176568); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType ln_ten() + { + return genType(2.30258509299404568401799145468436421); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType ln_ln_two() + { + return genType(-0.3665129205816643); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType third() + { + return genType(0.3333333333333333333333333333333333333333); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType two_thirds() + { + return genType(0.666666666666666666666666666666666666667); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType golden_ratio() + { + return genType(1.61803398874989484820458683436563811); + } + +} //namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/epsilon.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/epsilon.hpp new file mode 100644 index 0000000000000000000000000000000000000000..640439b11c36cd5df5261bc0e7a62c280700a252 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/epsilon.hpp @@ -0,0 +1,60 @@ +/// @ref gtc_epsilon +/// @file glm/gtc/epsilon.hpp +/// +/// @see core (dependence) +/// @see gtc_quaternion (dependence) +/// +/// @defgroup gtc_epsilon GLM_GTC_epsilon +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Comparison functions for a user defined epsilon values. + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../detail/qualifier.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_epsilon extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_epsilon + /// @{ + + /// Returns the component-wise comparison of |x - y| < epsilon. + /// True if this expression is satisfied. + /// + /// @see gtc_epsilon + template + GLM_FUNC_DECL vec epsilonEqual(vec const& x, vec const& y, T const& epsilon); + + /// Returns the component-wise comparison of |x - y| < epsilon. + /// True if this expression is satisfied. + /// + /// @see gtc_epsilon + template + GLM_FUNC_DECL bool epsilonEqual(genType const& x, genType const& y, genType const& epsilon); + + /// Returns the component-wise comparison of |x - y| < epsilon. + /// True if this expression is not satisfied. + /// + /// @see gtc_epsilon + template + GLM_FUNC_DECL vec epsilonNotEqual(vec const& x, vec const& y, T const& epsilon); + + /// Returns the component-wise comparison of |x - y| >= epsilon. + /// True if this expression is not satisfied. + /// + /// @see gtc_epsilon + template + GLM_FUNC_DECL bool epsilonNotEqual(genType const& x, genType const& y, genType const& epsilon); + + /// @} +}//namespace glm + +#include "epsilon.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/epsilon.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/epsilon.inl new file mode 100644 index 0000000000000000000000000000000000000000..508b9f8966feff92b269182a24e03b67358a4a91 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/epsilon.inl @@ -0,0 +1,80 @@ +/// @ref gtc_epsilon + +// Dependency: +#include "../vector_relational.hpp" +#include "../common.hpp" + +namespace glm +{ + template<> + GLM_FUNC_QUALIFIER bool epsilonEqual + ( + float const& x, + float const& y, + float const& epsilon + ) + { + return abs(x - y) < epsilon; + } + + template<> + GLM_FUNC_QUALIFIER bool epsilonEqual + ( + double const& x, + double const& y, + double const& epsilon + ) + { + return abs(x - y) < epsilon; + } + + template + GLM_FUNC_QUALIFIER vec epsilonEqual(vec const& x, vec const& y, T const& epsilon) + { + return lessThan(abs(x - y), vec(epsilon)); + } + + template + GLM_FUNC_QUALIFIER vec epsilonEqual(vec const& x, vec const& y, vec const& epsilon) + { + return lessThan(abs(x - y), vec(epsilon)); + } + + template<> + GLM_FUNC_QUALIFIER bool epsilonNotEqual(float const& x, float const& y, float const& epsilon) + { + return abs(x - y) >= epsilon; + } + + template<> + GLM_FUNC_QUALIFIER bool epsilonNotEqual(double const& x, double const& y, double const& epsilon) + { + return abs(x - y) >= epsilon; + } + + template + GLM_FUNC_QUALIFIER vec epsilonNotEqual(vec const& x, vec const& y, T const& epsilon) + { + return greaterThanEqual(abs(x - y), vec(epsilon)); + } + + template + GLM_FUNC_QUALIFIER vec epsilonNotEqual(vec const& x, vec const& y, vec const& epsilon) + { + return greaterThanEqual(abs(x - y), vec(epsilon)); + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> epsilonEqual(qua const& x, qua const& y, T const& epsilon) + { + vec<4, T, Q> v(x.x - y.x, x.y - y.y, x.z - y.z, x.w - y.w); + return lessThan(abs(v), vec<4, T, Q>(epsilon)); + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> epsilonNotEqual(qua const& x, qua const& y, T const& epsilon) + { + vec<4, T, Q> v(x.x - y.x, x.y - y.y, x.z - y.z, x.w - y.w); + return greaterThanEqual(abs(v), vec<4, T, Q>(epsilon)); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/integer.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/integer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ee52e0e0c154ce438b8f8485c596ff5cd0d3cc92 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/integer.hpp @@ -0,0 +1,43 @@ +/// @ref gtc_integer +/// @file glm/gtc/integer.hpp +/// +/// @see core (dependence) +/// @see gtc_integer (dependence) +/// +/// @defgroup gtc_integer GLM_GTC_integer +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// @brief Allow to perform bit operations on integer values + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../detail/qualifier.hpp" +#include "../common.hpp" +#include "../integer.hpp" +#include "../exponential.hpp" +#include "../ext/scalar_common.hpp" +#include "../ext/vector_common.hpp" +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_integer extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_integer + /// @{ + + /// Returns the log2 of x for integer values. Useful to compute mipmap count from the texture size. + /// @see gtc_integer + template + GLM_FUNC_DECL genIUType log2(genIUType x); + + /// @} +} //namespace glm + +#include "integer.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/integer.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/integer.inl new file mode 100644 index 0000000000000000000000000000000000000000..5f66dfe2c096b035880af20a30bc96ed66b5a786 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/integer.inl @@ -0,0 +1,33 @@ +/// @ref gtc_integer + +namespace glm{ +namespace detail +{ + template + struct compute_log2 + { + GLM_FUNC_QUALIFIER static vec call(vec const& v) + { + //Equivalent to return findMSB(vec); but save one function call in ASM with VC + //return findMSB(vec); + return vec(detail::compute_findMSB_vec::call(v)); + } + }; + +# if GLM_HAS_BITSCAN_WINDOWS + template + struct compute_log2<4, int, Q, false, Aligned> + { + GLM_FUNC_QUALIFIER static vec<4, int, Q> call(vec<4, int, Q> const& v) + { + vec<4, int, Q> Result; + _BitScanReverse(reinterpret_cast(&Result.x), v.x); + _BitScanReverse(reinterpret_cast(&Result.y), v.y); + _BitScanReverse(reinterpret_cast(&Result.z), v.z); + _BitScanReverse(reinterpret_cast(&Result.w), v.w); + return Result; + } + }; +# endif//GLM_HAS_BITSCAN_WINDOWS +}//namespace detail +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/matrix_access.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/matrix_access.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4935ba755dd502af46a80bfc30a49b39e188a8bc --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/matrix_access.hpp @@ -0,0 +1,60 @@ +/// @ref gtc_matrix_access +/// @file glm/gtc/matrix_access.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtc_matrix_access GLM_GTC_matrix_access +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Defines functions to access rows or columns of a matrix easily. + +#pragma once + +// Dependency: +#include "../detail/setup.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_matrix_access extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_matrix_access + /// @{ + + /// Get a specific row of a matrix. + /// @see gtc_matrix_access + template + GLM_FUNC_DECL typename genType::row_type row( + genType const& m, + length_t index); + + /// Set a specific row to a matrix. + /// @see gtc_matrix_access + template + GLM_FUNC_DECL genType row( + genType const& m, + length_t index, + typename genType::row_type const& x); + + /// Get a specific column of a matrix. + /// @see gtc_matrix_access + template + GLM_FUNC_DECL typename genType::col_type column( + genType const& m, + length_t index); + + /// Set a specific column to a matrix. + /// @see gtc_matrix_access + template + GLM_FUNC_DECL genType column( + genType const& m, + length_t index, + typename genType::col_type const& x); + + /// @} +}//namespace glm + +#include "matrix_access.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/matrix_access.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/matrix_access.inl new file mode 100644 index 0000000000000000000000000000000000000000..09fcc10d3d7e4c2c1d70de38b4d02628e09477fc --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/matrix_access.inl @@ -0,0 +1,62 @@ +/// @ref gtc_matrix_access + +namespace glm +{ + template + GLM_FUNC_QUALIFIER genType row + ( + genType const& m, + length_t index, + typename genType::row_type const& x + ) + { + assert(index >= 0 && index < m[0].length()); + + genType Result = m; + for(length_t i = 0; i < m.length(); ++i) + Result[i][index] = x[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER typename genType::row_type row + ( + genType const& m, + length_t index + ) + { + assert(index >= 0 && index < m[0].length()); + + typename genType::row_type Result(0); + for(length_t i = 0; i < m.length(); ++i) + Result[i] = m[i][index]; + return Result; + } + + template + GLM_FUNC_QUALIFIER genType column + ( + genType const& m, + length_t index, + typename genType::col_type const& x + ) + { + assert(index >= 0 && index < m.length()); + + genType Result = m; + Result[index] = x; + return Result; + } + + template + GLM_FUNC_QUALIFIER typename genType::col_type column + ( + genType const& m, + length_t index + ) + { + assert(index >= 0 && index < m.length()); + + return m[index]; + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/matrix_integer.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/matrix_integer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d7ebdc719221c06f9b2d975ea987da7809533156 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/matrix_integer.hpp @@ -0,0 +1,433 @@ +/// @ref gtc_matrix_integer +/// @file glm/gtc/matrix_integer.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtc_matrix_integer GLM_GTC_matrix_integer +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat2x2.hpp" +#include "../mat2x3.hpp" +#include "../mat2x4.hpp" +#include "../mat3x2.hpp" +#include "../mat3x3.hpp" +#include "../mat3x4.hpp" +#include "../mat4x2.hpp" +#include "../mat4x3.hpp" +#include "../mat4x4.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_matrix_integer extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_matrix_integer + /// @{ + + /// High-qualifier signed integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, int, highp> highp_imat2; + + /// High-qualifier signed integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, int, highp> highp_imat3; + + /// High-qualifier signed integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, int, highp> highp_imat4; + + /// High-qualifier signed integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, int, highp> highp_imat2x2; + + /// High-qualifier signed integer 2x3 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 3, int, highp> highp_imat2x3; + + /// High-qualifier signed integer 2x4 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 4, int, highp> highp_imat2x4; + + /// High-qualifier signed integer 3x2 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 2, int, highp> highp_imat3x2; + + /// High-qualifier signed integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, int, highp> highp_imat3x3; + + /// High-qualifier signed integer 3x4 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 4, int, highp> highp_imat3x4; + + /// High-qualifier signed integer 4x2 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 2, int, highp> highp_imat4x2; + + /// High-qualifier signed integer 4x3 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 3, int, highp> highp_imat4x3; + + /// High-qualifier signed integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, int, highp> highp_imat4x4; + + + /// Medium-qualifier signed integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, int, mediump> mediump_imat2; + + /// Medium-qualifier signed integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, int, mediump> mediump_imat3; + + /// Medium-qualifier signed integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, int, mediump> mediump_imat4; + + + /// Medium-qualifier signed integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, int, mediump> mediump_imat2x2; + + /// Medium-qualifier signed integer 2x3 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 3, int, mediump> mediump_imat2x3; + + /// Medium-qualifier signed integer 2x4 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 4, int, mediump> mediump_imat2x4; + + /// Medium-qualifier signed integer 3x2 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 2, int, mediump> mediump_imat3x2; + + /// Medium-qualifier signed integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, int, mediump> mediump_imat3x3; + + /// Medium-qualifier signed integer 3x4 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 4, int, mediump> mediump_imat3x4; + + /// Medium-qualifier signed integer 4x2 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 2, int, mediump> mediump_imat4x2; + + /// Medium-qualifier signed integer 4x3 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 3, int, mediump> mediump_imat4x3; + + /// Medium-qualifier signed integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, int, mediump> mediump_imat4x4; + + + /// Low-qualifier signed integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, int, lowp> lowp_imat2; + + /// Low-qualifier signed integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, int, lowp> lowp_imat3; + + /// Low-qualifier signed integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, int, lowp> lowp_imat4; + + + /// Low-qualifier signed integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, int, lowp> lowp_imat2x2; + + /// Low-qualifier signed integer 2x3 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 3, int, lowp> lowp_imat2x3; + + /// Low-qualifier signed integer 2x4 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 4, int, lowp> lowp_imat2x4; + + /// Low-qualifier signed integer 3x2 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 2, int, lowp> lowp_imat3x2; + + /// Low-qualifier signed integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, int, lowp> lowp_imat3x3; + + /// Low-qualifier signed integer 3x4 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 4, int, lowp> lowp_imat3x4; + + /// Low-qualifier signed integer 4x2 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 2, int, lowp> lowp_imat4x2; + + /// Low-qualifier signed integer 4x3 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 3, int, lowp> lowp_imat4x3; + + /// Low-qualifier signed integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, int, lowp> lowp_imat4x4; + + + /// High-qualifier unsigned integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, uint, highp> highp_umat2; + + /// High-qualifier unsigned integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, uint, highp> highp_umat3; + + /// High-qualifier unsigned integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, uint, highp> highp_umat4; + + /// High-qualifier unsigned integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, uint, highp> highp_umat2x2; + + /// High-qualifier unsigned integer 2x3 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 3, uint, highp> highp_umat2x3; + + /// High-qualifier unsigned integer 2x4 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 4, uint, highp> highp_umat2x4; + + /// High-qualifier unsigned integer 3x2 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 2, uint, highp> highp_umat3x2; + + /// High-qualifier unsigned integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, uint, highp> highp_umat3x3; + + /// High-qualifier unsigned integer 3x4 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 4, uint, highp> highp_umat3x4; + + /// High-qualifier unsigned integer 4x2 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 2, uint, highp> highp_umat4x2; + + /// High-qualifier unsigned integer 4x3 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 3, uint, highp> highp_umat4x3; + + /// High-qualifier unsigned integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, uint, highp> highp_umat4x4; + + + /// Medium-qualifier unsigned integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, uint, mediump> mediump_umat2; + + /// Medium-qualifier unsigned integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, uint, mediump> mediump_umat3; + + /// Medium-qualifier unsigned integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, uint, mediump> mediump_umat4; + + + /// Medium-qualifier unsigned integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, uint, mediump> mediump_umat2x2; + + /// Medium-qualifier unsigned integer 2x3 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 3, uint, mediump> mediump_umat2x3; + + /// Medium-qualifier unsigned integer 2x4 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 4, uint, mediump> mediump_umat2x4; + + /// Medium-qualifier unsigned integer 3x2 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 2, uint, mediump> mediump_umat3x2; + + /// Medium-qualifier unsigned integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, uint, mediump> mediump_umat3x3; + + /// Medium-qualifier unsigned integer 3x4 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 4, uint, mediump> mediump_umat3x4; + + /// Medium-qualifier unsigned integer 4x2 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 2, uint, mediump> mediump_umat4x2; + + /// Medium-qualifier unsigned integer 4x3 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 3, uint, mediump> mediump_umat4x3; + + /// Medium-qualifier unsigned integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, uint, mediump> mediump_umat4x4; + + + /// Low-qualifier unsigned integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, uint, lowp> lowp_umat2; + + /// Low-qualifier unsigned integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, uint, lowp> lowp_umat3; + + /// Low-qualifier unsigned integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, uint, lowp> lowp_umat4; + + + /// Low-qualifier unsigned integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, uint, lowp> lowp_umat2x2; + + /// Low-qualifier unsigned integer 2x3 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 3, uint, lowp> lowp_umat2x3; + + /// Low-qualifier unsigned integer 2x4 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 4, uint, lowp> lowp_umat2x4; + + /// Low-qualifier unsigned integer 3x2 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 2, uint, lowp> lowp_umat3x2; + + /// Low-qualifier unsigned integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, uint, lowp> lowp_umat3x3; + + /// Low-qualifier unsigned integer 3x4 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 4, uint, lowp> lowp_umat3x4; + + /// Low-qualifier unsigned integer 4x2 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 2, uint, lowp> lowp_umat4x2; + + /// Low-qualifier unsigned integer 4x3 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 3, uint, lowp> lowp_umat4x3; + + /// Low-qualifier unsigned integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, uint, lowp> lowp_umat4x4; + + + + /// Signed integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, int, defaultp> imat2; + + /// Signed integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, int, defaultp> imat3; + + /// Signed integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, int, defaultp> imat4; + + /// Signed integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, int, defaultp> imat2x2; + + /// Signed integer 2x3 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 3, int, defaultp> imat2x3; + + /// Signed integer 2x4 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 4, int, defaultp> imat2x4; + + /// Signed integer 3x2 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 2, int, defaultp> imat3x2; + + /// Signed integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, int, defaultp> imat3x3; + + /// Signed integer 3x4 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 4, int, defaultp> imat3x4; + + /// Signed integer 4x2 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 2, int, defaultp> imat4x2; + + /// Signed integer 4x3 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 3, int, defaultp> imat4x3; + + /// Signed integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, int, defaultp> imat4x4; + + + + /// Unsigned integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, uint, defaultp> umat2; + + /// Unsigned integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, uint, defaultp> umat3; + + /// Unsigned integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, uint, defaultp> umat4; + + /// Unsigned integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, uint, defaultp> umat2x2; + + /// Unsigned integer 2x3 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 3, uint, defaultp> umat2x3; + + /// Unsigned integer 2x4 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 4, uint, defaultp> umat2x4; + + /// Unsigned integer 3x2 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 2, uint, defaultp> umat3x2; + + /// Unsigned integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, uint, defaultp> umat3x3; + + /// Unsigned integer 3x4 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 4, uint, defaultp> umat3x4; + + /// Unsigned integer 4x2 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 2, uint, defaultp> umat4x2; + + /// Unsigned integer 4x3 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 3, uint, defaultp> umat4x3; + + /// Unsigned integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, uint, defaultp> umat4x4; + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/matrix_inverse.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/matrix_inverse.hpp new file mode 100644 index 0000000000000000000000000000000000000000..75d53f20234d45e6a9d9a0dcc85d731259b70540 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/matrix_inverse.hpp @@ -0,0 +1,50 @@ +/// @ref gtc_matrix_inverse +/// @file glm/gtc/matrix_inverse.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtc_matrix_inverse GLM_GTC_matrix_inverse +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Defines additional matrix inverting functions. + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../matrix.hpp" +#include "../mat2x2.hpp" +#include "../mat3x3.hpp" +#include "../mat4x4.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_matrix_inverse extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_matrix_inverse + /// @{ + + /// Fast matrix inverse for affine matrix. + /// + /// @param m Input matrix to invert. + /// @tparam genType Squared floating-point matrix: half, float or double. Inverse of matrix based of half-qualifier floating point value is highly inaccurate. + /// @see gtc_matrix_inverse + template + GLM_FUNC_DECL genType affineInverse(genType const& m); + + /// Compute the inverse transpose of a matrix. + /// + /// @param m Input matrix to invert transpose. + /// @tparam genType Squared floating-point matrix: half, float or double. Inverse of matrix based of half-qualifier floating point value is highly inaccurate. + /// @see gtc_matrix_inverse + template + GLM_FUNC_DECL genType inverseTranspose(genType const& m); + + /// @} +}//namespace glm + +#include "matrix_inverse.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/matrix_inverse.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/matrix_inverse.inl new file mode 100644 index 0000000000000000000000000000000000000000..c004b9e146706b64fb9e73ba95e7bc3401b8c42a --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/matrix_inverse.inl @@ -0,0 +1,118 @@ +/// @ref gtc_matrix_inverse + +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> affineInverse(mat<3, 3, T, Q> const& m) + { + mat<2, 2, T, Q> const Inv(inverse(mat<2, 2, T, Q>(m))); + + return mat<3, 3, T, Q>( + vec<3, T, Q>(Inv[0], static_cast(0)), + vec<3, T, Q>(Inv[1], static_cast(0)), + vec<3, T, Q>(-Inv * vec<2, T, Q>(m[2]), static_cast(1))); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> affineInverse(mat<4, 4, T, Q> const& m) + { + mat<3, 3, T, Q> const Inv(inverse(mat<3, 3, T, Q>(m))); + + return mat<4, 4, T, Q>( + vec<4, T, Q>(Inv[0], static_cast(0)), + vec<4, T, Q>(Inv[1], static_cast(0)), + vec<4, T, Q>(Inv[2], static_cast(0)), + vec<4, T, Q>(-Inv * vec<3, T, Q>(m[3]), static_cast(1))); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> inverseTranspose(mat<2, 2, T, Q> const& m) + { + T Determinant = m[0][0] * m[1][1] - m[1][0] * m[0][1]; + + mat<2, 2, T, Q> Inverse( + + m[1][1] / Determinant, + - m[0][1] / Determinant, + - m[1][0] / Determinant, + + m[0][0] / Determinant); + + return Inverse; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> inverseTranspose(mat<3, 3, T, Q> const& m) + { + T Determinant = + + m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]) + - m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0]) + + m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0]); + + mat<3, 3, T, Q> Inverse; + Inverse[0][0] = + (m[1][1] * m[2][2] - m[2][1] * m[1][2]); + Inverse[0][1] = - (m[1][0] * m[2][2] - m[2][0] * m[1][2]); + Inverse[0][2] = + (m[1][0] * m[2][1] - m[2][0] * m[1][1]); + Inverse[1][0] = - (m[0][1] * m[2][2] - m[2][1] * m[0][2]); + Inverse[1][1] = + (m[0][0] * m[2][2] - m[2][0] * m[0][2]); + Inverse[1][2] = - (m[0][0] * m[2][1] - m[2][0] * m[0][1]); + Inverse[2][0] = + (m[0][1] * m[1][2] - m[1][1] * m[0][2]); + Inverse[2][1] = - (m[0][0] * m[1][2] - m[1][0] * m[0][2]); + Inverse[2][2] = + (m[0][0] * m[1][1] - m[1][0] * m[0][1]); + Inverse /= Determinant; + + return Inverse; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> inverseTranspose(mat<4, 4, T, Q> const& m) + { + T SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + T SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + T SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + T SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + T SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + T SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + T SubFactor06 = m[1][2] * m[3][3] - m[3][2] * m[1][3]; + T SubFactor07 = m[1][1] * m[3][3] - m[3][1] * m[1][3]; + T SubFactor08 = m[1][1] * m[3][2] - m[3][1] * m[1][2]; + T SubFactor09 = m[1][0] * m[3][3] - m[3][0] * m[1][3]; + T SubFactor10 = m[1][0] * m[3][2] - m[3][0] * m[1][2]; + T SubFactor11 = m[1][0] * m[3][1] - m[3][0] * m[1][1]; + T SubFactor12 = m[1][2] * m[2][3] - m[2][2] * m[1][3]; + T SubFactor13 = m[1][1] * m[2][3] - m[2][1] * m[1][3]; + T SubFactor14 = m[1][1] * m[2][2] - m[2][1] * m[1][2]; + T SubFactor15 = m[1][0] * m[2][3] - m[2][0] * m[1][3]; + T SubFactor16 = m[1][0] * m[2][2] - m[2][0] * m[1][2]; + T SubFactor17 = m[1][0] * m[2][1] - m[2][0] * m[1][1]; + + mat<4, 4, T, Q> Inverse; + Inverse[0][0] = + (m[1][1] * SubFactor00 - m[1][2] * SubFactor01 + m[1][3] * SubFactor02); + Inverse[0][1] = - (m[1][0] * SubFactor00 - m[1][2] * SubFactor03 + m[1][3] * SubFactor04); + Inverse[0][2] = + (m[1][0] * SubFactor01 - m[1][1] * SubFactor03 + m[1][3] * SubFactor05); + Inverse[0][3] = - (m[1][0] * SubFactor02 - m[1][1] * SubFactor04 + m[1][2] * SubFactor05); + + Inverse[1][0] = - (m[0][1] * SubFactor00 - m[0][2] * SubFactor01 + m[0][3] * SubFactor02); + Inverse[1][1] = + (m[0][0] * SubFactor00 - m[0][2] * SubFactor03 + m[0][3] * SubFactor04); + Inverse[1][2] = - (m[0][0] * SubFactor01 - m[0][1] * SubFactor03 + m[0][3] * SubFactor05); + Inverse[1][3] = + (m[0][0] * SubFactor02 - m[0][1] * SubFactor04 + m[0][2] * SubFactor05); + + Inverse[2][0] = + (m[0][1] * SubFactor06 - m[0][2] * SubFactor07 + m[0][3] * SubFactor08); + Inverse[2][1] = - (m[0][0] * SubFactor06 - m[0][2] * SubFactor09 + m[0][3] * SubFactor10); + Inverse[2][2] = + (m[0][0] * SubFactor07 - m[0][1] * SubFactor09 + m[0][3] * SubFactor11); + Inverse[2][3] = - (m[0][0] * SubFactor08 - m[0][1] * SubFactor10 + m[0][2] * SubFactor11); + + Inverse[3][0] = - (m[0][1] * SubFactor12 - m[0][2] * SubFactor13 + m[0][3] * SubFactor14); + Inverse[3][1] = + (m[0][0] * SubFactor12 - m[0][2] * SubFactor15 + m[0][3] * SubFactor16); + Inverse[3][2] = - (m[0][0] * SubFactor13 - m[0][1] * SubFactor15 + m[0][3] * SubFactor17); + Inverse[3][3] = + (m[0][0] * SubFactor14 - m[0][1] * SubFactor16 + m[0][2] * SubFactor17); + + T Determinant = + + m[0][0] * Inverse[0][0] + + m[0][1] * Inverse[0][1] + + m[0][2] * Inverse[0][2] + + m[0][3] * Inverse[0][3]; + + Inverse /= Determinant; + + return Inverse; + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/matrix_transform.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/matrix_transform.hpp new file mode 100644 index 0000000000000000000000000000000000000000..612418fa51c49d91c4e4e4a315083044a3db0b4c --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/matrix_transform.hpp @@ -0,0 +1,36 @@ +/// @ref gtc_matrix_transform +/// @file glm/gtc/matrix_transform.hpp +/// +/// @see core (dependence) +/// @see gtx_transform +/// @see gtx_transform2 +/// +/// @defgroup gtc_matrix_transform GLM_GTC_matrix_transform +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Defines functions that generate common transformation matrices. +/// +/// The matrices generated by this extension use standard OpenGL fixed-function +/// conventions. For example, the lookAt function generates a transform from world +/// space into the specific eye space that the projective matrix functions +/// (perspective, ortho, etc) are designed to expect. The OpenGL compatibility +/// specifications defines the particular layout of this eye space. + +#pragma once + +// Dependencies +#include "../mat4x4.hpp" +#include "../vec2.hpp" +#include "../vec3.hpp" +#include "../vec4.hpp" +#include "../ext/matrix_projection.hpp" +#include "../ext/matrix_clip_space.hpp" +#include "../ext/matrix_transform.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_matrix_transform extension included") +#endif + +#include "matrix_transform.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/matrix_transform.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/matrix_transform.inl new file mode 100644 index 0000000000000000000000000000000000000000..15b46bc9db617b238d8a60d382f584372e9d0855 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/matrix_transform.inl @@ -0,0 +1,3 @@ +#include "../geometric.hpp" +#include "../trigonometric.hpp" +#include "../matrix.hpp" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/noise.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/noise.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ab1772e78125da6c280f4b1a676d7ff2c8fae082 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/noise.hpp @@ -0,0 +1,61 @@ +/// @ref gtc_noise +/// @file glm/gtc/noise.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtc_noise GLM_GTC_noise +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Defines 2D, 3D and 4D procedural noise functions +/// Based on the work of Stefan Gustavson and Ashima Arts on "webgl-noise": +/// https://github.com/ashima/webgl-noise +/// Following Stefan Gustavson's paper "Simplex noise demystified": +/// http://www.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../detail/qualifier.hpp" +#include "../detail/_noise.hpp" +#include "../geometric.hpp" +#include "../common.hpp" +#include "../vector_relational.hpp" +#include "../vec2.hpp" +#include "../vec3.hpp" +#include "../vec4.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_noise extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_noise + /// @{ + + /// Classic perlin noise. + /// @see gtc_noise + template + GLM_FUNC_DECL T perlin( + vec const& p); + + /// Periodic perlin noise. + /// @see gtc_noise + template + GLM_FUNC_DECL T perlin( + vec const& p, + vec const& rep); + + /// Simplex noise. + /// @see gtc_noise + template + GLM_FUNC_DECL T simplex( + vec const& p); + + /// @} +}//namespace glm + +#include "noise.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/noise.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/noise.inl new file mode 100644 index 0000000000000000000000000000000000000000..30d0b274d337a8e990fe0e264130e0e42c0321cb --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/noise.inl @@ -0,0 +1,807 @@ +/// @ref gtc_noise +/// +// Based on the work of Stefan Gustavson and Ashima Arts on "webgl-noise": +// https://github.com/ashima/webgl-noise +// Following Stefan Gustavson's paper "Simplex noise demystified": +// http://www.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf + +namespace glm{ +namespace gtc +{ + template + GLM_FUNC_QUALIFIER vec<4, T, Q> grad4(T const& j, vec<4, T, Q> const& ip) + { + vec<3, T, Q> pXYZ = floor(fract(vec<3, T, Q>(j) * vec<3, T, Q>(ip)) * T(7)) * ip[2] - T(1); + T pW = static_cast(1.5) - dot(abs(pXYZ), vec<3, T, Q>(1)); + vec<4, T, Q> s = vec<4, T, Q>(lessThan(vec<4, T, Q>(pXYZ, pW), vec<4, T, Q>(0.0))); + pXYZ = pXYZ + (vec<3, T, Q>(s) * T(2) - T(1)) * s.w; + return vec<4, T, Q>(pXYZ, pW); + } +}//namespace gtc + + // Classic Perlin noise + template + GLM_FUNC_QUALIFIER T perlin(vec<2, T, Q> const& Position) + { + vec<4, T, Q> Pi = glm::floor(vec<4, T, Q>(Position.x, Position.y, Position.x, Position.y)) + vec<4, T, Q>(0.0, 0.0, 1.0, 1.0); + vec<4, T, Q> Pf = glm::fract(vec<4, T, Q>(Position.x, Position.y, Position.x, Position.y)) - vec<4, T, Q>(0.0, 0.0, 1.0, 1.0); + Pi = mod(Pi, vec<4, T, Q>(289)); // To avoid truncation effects in permutation + vec<4, T, Q> ix(Pi.x, Pi.z, Pi.x, Pi.z); + vec<4, T, Q> iy(Pi.y, Pi.y, Pi.w, Pi.w); + vec<4, T, Q> fx(Pf.x, Pf.z, Pf.x, Pf.z); + vec<4, T, Q> fy(Pf.y, Pf.y, Pf.w, Pf.w); + + vec<4, T, Q> i = detail::permute(detail::permute(ix) + iy); + + vec<4, T, Q> gx = static_cast(2) * glm::fract(i / T(41)) - T(1); + vec<4, T, Q> gy = glm::abs(gx) - T(0.5); + vec<4, T, Q> tx = glm::floor(gx + T(0.5)); + gx = gx - tx; + + vec<2, T, Q> g00(gx.x, gy.x); + vec<2, T, Q> g10(gx.y, gy.y); + vec<2, T, Q> g01(gx.z, gy.z); + vec<2, T, Q> g11(gx.w, gy.w); + + vec<4, T, Q> norm = detail::taylorInvSqrt(vec<4, T, Q>(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11))); + g00 *= norm.x; + g01 *= norm.y; + g10 *= norm.z; + g11 *= norm.w; + + T n00 = dot(g00, vec<2, T, Q>(fx.x, fy.x)); + T n10 = dot(g10, vec<2, T, Q>(fx.y, fy.y)); + T n01 = dot(g01, vec<2, T, Q>(fx.z, fy.z)); + T n11 = dot(g11, vec<2, T, Q>(fx.w, fy.w)); + + vec<2, T, Q> fade_xy = detail::fade(vec<2, T, Q>(Pf.x, Pf.y)); + vec<2, T, Q> n_x = mix(vec<2, T, Q>(n00, n01), vec<2, T, Q>(n10, n11), fade_xy.x); + T n_xy = mix(n_x.x, n_x.y, fade_xy.y); + return T(2.3) * n_xy; + } + + // Classic Perlin noise + template + GLM_FUNC_QUALIFIER T perlin(vec<3, T, Q> const& Position) + { + vec<3, T, Q> Pi0 = floor(Position); // Integer part for indexing + vec<3, T, Q> Pi1 = Pi0 + T(1); // Integer part + 1 + Pi0 = detail::mod289(Pi0); + Pi1 = detail::mod289(Pi1); + vec<3, T, Q> Pf0 = fract(Position); // Fractional part for interpolation + vec<3, T, Q> Pf1 = Pf0 - T(1); // Fractional part - 1.0 + vec<4, T, Q> ix(Pi0.x, Pi1.x, Pi0.x, Pi1.x); + vec<4, T, Q> iy = vec<4, T, Q>(vec<2, T, Q>(Pi0.y), vec<2, T, Q>(Pi1.y)); + vec<4, T, Q> iz0(Pi0.z); + vec<4, T, Q> iz1(Pi1.z); + + vec<4, T, Q> ixy = detail::permute(detail::permute(ix) + iy); + vec<4, T, Q> ixy0 = detail::permute(ixy + iz0); + vec<4, T, Q> ixy1 = detail::permute(ixy + iz1); + + vec<4, T, Q> gx0 = ixy0 * T(1.0 / 7.0); + vec<4, T, Q> gy0 = fract(floor(gx0) * T(1.0 / 7.0)) - T(0.5); + gx0 = fract(gx0); + vec<4, T, Q> gz0 = vec<4, T, Q>(0.5) - abs(gx0) - abs(gy0); + vec<4, T, Q> sz0 = step(gz0, vec<4, T, Q>(0.0)); + gx0 -= sz0 * (step(T(0), gx0) - T(0.5)); + gy0 -= sz0 * (step(T(0), gy0) - T(0.5)); + + vec<4, T, Q> gx1 = ixy1 * T(1.0 / 7.0); + vec<4, T, Q> gy1 = fract(floor(gx1) * T(1.0 / 7.0)) - T(0.5); + gx1 = fract(gx1); + vec<4, T, Q> gz1 = vec<4, T, Q>(0.5) - abs(gx1) - abs(gy1); + vec<4, T, Q> sz1 = step(gz1, vec<4, T, Q>(0.0)); + gx1 -= sz1 * (step(T(0), gx1) - T(0.5)); + gy1 -= sz1 * (step(T(0), gy1) - T(0.5)); + + vec<3, T, Q> g000(gx0.x, gy0.x, gz0.x); + vec<3, T, Q> g100(gx0.y, gy0.y, gz0.y); + vec<3, T, Q> g010(gx0.z, gy0.z, gz0.z); + vec<3, T, Q> g110(gx0.w, gy0.w, gz0.w); + vec<3, T, Q> g001(gx1.x, gy1.x, gz1.x); + vec<3, T, Q> g101(gx1.y, gy1.y, gz1.y); + vec<3, T, Q> g011(gx1.z, gy1.z, gz1.z); + vec<3, T, Q> g111(gx1.w, gy1.w, gz1.w); + + vec<4, T, Q> norm0 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110))); + g000 *= norm0.x; + g010 *= norm0.y; + g100 *= norm0.z; + g110 *= norm0.w; + vec<4, T, Q> norm1 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111))); + g001 *= norm1.x; + g011 *= norm1.y; + g101 *= norm1.z; + g111 *= norm1.w; + + T n000 = dot(g000, Pf0); + T n100 = dot(g100, vec<3, T, Q>(Pf1.x, Pf0.y, Pf0.z)); + T n010 = dot(g010, vec<3, T, Q>(Pf0.x, Pf1.y, Pf0.z)); + T n110 = dot(g110, vec<3, T, Q>(Pf1.x, Pf1.y, Pf0.z)); + T n001 = dot(g001, vec<3, T, Q>(Pf0.x, Pf0.y, Pf1.z)); + T n101 = dot(g101, vec<3, T, Q>(Pf1.x, Pf0.y, Pf1.z)); + T n011 = dot(g011, vec<3, T, Q>(Pf0.x, Pf1.y, Pf1.z)); + T n111 = dot(g111, Pf1); + + vec<3, T, Q> fade_xyz = detail::fade(Pf0); + vec<4, T, Q> n_z = mix(vec<4, T, Q>(n000, n100, n010, n110), vec<4, T, Q>(n001, n101, n011, n111), fade_xyz.z); + vec<2, T, Q> n_yz = mix(vec<2, T, Q>(n_z.x, n_z.y), vec<2, T, Q>(n_z.z, n_z.w), fade_xyz.y); + T n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x); + return T(2.2) * n_xyz; + } + /* + // Classic Perlin noise + template + GLM_FUNC_QUALIFIER T perlin(vec<3, T, Q> const& P) + { + vec<3, T, Q> Pi0 = floor(P); // Integer part for indexing + vec<3, T, Q> Pi1 = Pi0 + T(1); // Integer part + 1 + Pi0 = mod(Pi0, T(289)); + Pi1 = mod(Pi1, T(289)); + vec<3, T, Q> Pf0 = fract(P); // Fractional part for interpolation + vec<3, T, Q> Pf1 = Pf0 - T(1); // Fractional part - 1.0 + vec<4, T, Q> ix(Pi0.x, Pi1.x, Pi0.x, Pi1.x); + vec<4, T, Q> iy(Pi0.y, Pi0.y, Pi1.y, Pi1.y); + vec<4, T, Q> iz0(Pi0.z); + vec<4, T, Q> iz1(Pi1.z); + + vec<4, T, Q> ixy = permute(permute(ix) + iy); + vec<4, T, Q> ixy0 = permute(ixy + iz0); + vec<4, T, Q> ixy1 = permute(ixy + iz1); + + vec<4, T, Q> gx0 = ixy0 / T(7); + vec<4, T, Q> gy0 = fract(floor(gx0) / T(7)) - T(0.5); + gx0 = fract(gx0); + vec<4, T, Q> gz0 = vec<4, T, Q>(0.5) - abs(gx0) - abs(gy0); + vec<4, T, Q> sz0 = step(gz0, vec<4, T, Q>(0.0)); + gx0 -= sz0 * (step(0.0, gx0) - T(0.5)); + gy0 -= sz0 * (step(0.0, gy0) - T(0.5)); + + vec<4, T, Q> gx1 = ixy1 / T(7); + vec<4, T, Q> gy1 = fract(floor(gx1) / T(7)) - T(0.5); + gx1 = fract(gx1); + vec<4, T, Q> gz1 = vec<4, T, Q>(0.5) - abs(gx1) - abs(gy1); + vec<4, T, Q> sz1 = step(gz1, vec<4, T, Q>(0.0)); + gx1 -= sz1 * (step(T(0), gx1) - T(0.5)); + gy1 -= sz1 * (step(T(0), gy1) - T(0.5)); + + vec<3, T, Q> g000(gx0.x, gy0.x, gz0.x); + vec<3, T, Q> g100(gx0.y, gy0.y, gz0.y); + vec<3, T, Q> g010(gx0.z, gy0.z, gz0.z); + vec<3, T, Q> g110(gx0.w, gy0.w, gz0.w); + vec<3, T, Q> g001(gx1.x, gy1.x, gz1.x); + vec<3, T, Q> g101(gx1.y, gy1.y, gz1.y); + vec<3, T, Q> g011(gx1.z, gy1.z, gz1.z); + vec<3, T, Q> g111(gx1.w, gy1.w, gz1.w); + + vec<4, T, Q> norm0 = taylorInvSqrt(vec<4, T, Q>(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110))); + g000 *= norm0.x; + g010 *= norm0.y; + g100 *= norm0.z; + g110 *= norm0.w; + vec<4, T, Q> norm1 = taylorInvSqrt(vec<4, T, Q>(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111))); + g001 *= norm1.x; + g011 *= norm1.y; + g101 *= norm1.z; + g111 *= norm1.w; + + T n000 = dot(g000, Pf0); + T n100 = dot(g100, vec<3, T, Q>(Pf1.x, Pf0.y, Pf0.z)); + T n010 = dot(g010, vec<3, T, Q>(Pf0.x, Pf1.y, Pf0.z)); + T n110 = dot(g110, vec<3, T, Q>(Pf1.x, Pf1.y, Pf0.z)); + T n001 = dot(g001, vec<3, T, Q>(Pf0.x, Pf0.y, Pf1.z)); + T n101 = dot(g101, vec<3, T, Q>(Pf1.x, Pf0.y, Pf1.z)); + T n011 = dot(g011, vec<3, T, Q>(Pf0.x, Pf1.y, Pf1.z)); + T n111 = dot(g111, Pf1); + + vec<3, T, Q> fade_xyz = fade(Pf0); + vec<4, T, Q> n_z = mix(vec<4, T, Q>(n000, n100, n010, n110), vec<4, T, Q>(n001, n101, n011, n111), fade_xyz.z); + vec<2, T, Q> n_yz = mix( + vec<2, T, Q>(n_z.x, n_z.y), + vec<2, T, Q>(n_z.z, n_z.w), fade_xyz.y); + T n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x); + return T(2.2) * n_xyz; + } + */ + // Classic Perlin noise + template + GLM_FUNC_QUALIFIER T perlin(vec<4, T, Q> const& Position) + { + vec<4, T, Q> Pi0 = floor(Position); // Integer part for indexing + vec<4, T, Q> Pi1 = Pi0 + T(1); // Integer part + 1 + Pi0 = mod(Pi0, vec<4, T, Q>(289)); + Pi1 = mod(Pi1, vec<4, T, Q>(289)); + vec<4, T, Q> Pf0 = fract(Position); // Fractional part for interpolation + vec<4, T, Q> Pf1 = Pf0 - T(1); // Fractional part - 1.0 + vec<4, T, Q> ix(Pi0.x, Pi1.x, Pi0.x, Pi1.x); + vec<4, T, Q> iy(Pi0.y, Pi0.y, Pi1.y, Pi1.y); + vec<4, T, Q> iz0(Pi0.z); + vec<4, T, Q> iz1(Pi1.z); + vec<4, T, Q> iw0(Pi0.w); + vec<4, T, Q> iw1(Pi1.w); + + vec<4, T, Q> ixy = detail::permute(detail::permute(ix) + iy); + vec<4, T, Q> ixy0 = detail::permute(ixy + iz0); + vec<4, T, Q> ixy1 = detail::permute(ixy + iz1); + vec<4, T, Q> ixy00 = detail::permute(ixy0 + iw0); + vec<4, T, Q> ixy01 = detail::permute(ixy0 + iw1); + vec<4, T, Q> ixy10 = detail::permute(ixy1 + iw0); + vec<4, T, Q> ixy11 = detail::permute(ixy1 + iw1); + + vec<4, T, Q> gx00 = ixy00 / T(7); + vec<4, T, Q> gy00 = floor(gx00) / T(7); + vec<4, T, Q> gz00 = floor(gy00) / T(6); + gx00 = fract(gx00) - T(0.5); + gy00 = fract(gy00) - T(0.5); + gz00 = fract(gz00) - T(0.5); + vec<4, T, Q> gw00 = vec<4, T, Q>(0.75) - abs(gx00) - abs(gy00) - abs(gz00); + vec<4, T, Q> sw00 = step(gw00, vec<4, T, Q>(0.0)); + gx00 -= sw00 * (step(T(0), gx00) - T(0.5)); + gy00 -= sw00 * (step(T(0), gy00) - T(0.5)); + + vec<4, T, Q> gx01 = ixy01 / T(7); + vec<4, T, Q> gy01 = floor(gx01) / T(7); + vec<4, T, Q> gz01 = floor(gy01) / T(6); + gx01 = fract(gx01) - T(0.5); + gy01 = fract(gy01) - T(0.5); + gz01 = fract(gz01) - T(0.5); + vec<4, T, Q> gw01 = vec<4, T, Q>(0.75) - abs(gx01) - abs(gy01) - abs(gz01); + vec<4, T, Q> sw01 = step(gw01, vec<4, T, Q>(0.0)); + gx01 -= sw01 * (step(T(0), gx01) - T(0.5)); + gy01 -= sw01 * (step(T(0), gy01) - T(0.5)); + + vec<4, T, Q> gx10 = ixy10 / T(7); + vec<4, T, Q> gy10 = floor(gx10) / T(7); + vec<4, T, Q> gz10 = floor(gy10) / T(6); + gx10 = fract(gx10) - T(0.5); + gy10 = fract(gy10) - T(0.5); + gz10 = fract(gz10) - T(0.5); + vec<4, T, Q> gw10 = vec<4, T, Q>(0.75) - abs(gx10) - abs(gy10) - abs(gz10); + vec<4, T, Q> sw10 = step(gw10, vec<4, T, Q>(0)); + gx10 -= sw10 * (step(T(0), gx10) - T(0.5)); + gy10 -= sw10 * (step(T(0), gy10) - T(0.5)); + + vec<4, T, Q> gx11 = ixy11 / T(7); + vec<4, T, Q> gy11 = floor(gx11) / T(7); + vec<4, T, Q> gz11 = floor(gy11) / T(6); + gx11 = fract(gx11) - T(0.5); + gy11 = fract(gy11) - T(0.5); + gz11 = fract(gz11) - T(0.5); + vec<4, T, Q> gw11 = vec<4, T, Q>(0.75) - abs(gx11) - abs(gy11) - abs(gz11); + vec<4, T, Q> sw11 = step(gw11, vec<4, T, Q>(0.0)); + gx11 -= sw11 * (step(T(0), gx11) - T(0.5)); + gy11 -= sw11 * (step(T(0), gy11) - T(0.5)); + + vec<4, T, Q> g0000(gx00.x, gy00.x, gz00.x, gw00.x); + vec<4, T, Q> g1000(gx00.y, gy00.y, gz00.y, gw00.y); + vec<4, T, Q> g0100(gx00.z, gy00.z, gz00.z, gw00.z); + vec<4, T, Q> g1100(gx00.w, gy00.w, gz00.w, gw00.w); + vec<4, T, Q> g0010(gx10.x, gy10.x, gz10.x, gw10.x); + vec<4, T, Q> g1010(gx10.y, gy10.y, gz10.y, gw10.y); + vec<4, T, Q> g0110(gx10.z, gy10.z, gz10.z, gw10.z); + vec<4, T, Q> g1110(gx10.w, gy10.w, gz10.w, gw10.w); + vec<4, T, Q> g0001(gx01.x, gy01.x, gz01.x, gw01.x); + vec<4, T, Q> g1001(gx01.y, gy01.y, gz01.y, gw01.y); + vec<4, T, Q> g0101(gx01.z, gy01.z, gz01.z, gw01.z); + vec<4, T, Q> g1101(gx01.w, gy01.w, gz01.w, gw01.w); + vec<4, T, Q> g0011(gx11.x, gy11.x, gz11.x, gw11.x); + vec<4, T, Q> g1011(gx11.y, gy11.y, gz11.y, gw11.y); + vec<4, T, Q> g0111(gx11.z, gy11.z, gz11.z, gw11.z); + vec<4, T, Q> g1111(gx11.w, gy11.w, gz11.w, gw11.w); + + vec<4, T, Q> norm00 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0000, g0000), dot(g0100, g0100), dot(g1000, g1000), dot(g1100, g1100))); + g0000 *= norm00.x; + g0100 *= norm00.y; + g1000 *= norm00.z; + g1100 *= norm00.w; + + vec<4, T, Q> norm01 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0001, g0001), dot(g0101, g0101), dot(g1001, g1001), dot(g1101, g1101))); + g0001 *= norm01.x; + g0101 *= norm01.y; + g1001 *= norm01.z; + g1101 *= norm01.w; + + vec<4, T, Q> norm10 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0010, g0010), dot(g0110, g0110), dot(g1010, g1010), dot(g1110, g1110))); + g0010 *= norm10.x; + g0110 *= norm10.y; + g1010 *= norm10.z; + g1110 *= norm10.w; + + vec<4, T, Q> norm11 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0011, g0011), dot(g0111, g0111), dot(g1011, g1011), dot(g1111, g1111))); + g0011 *= norm11.x; + g0111 *= norm11.y; + g1011 *= norm11.z; + g1111 *= norm11.w; + + T n0000 = dot(g0000, Pf0); + T n1000 = dot(g1000, vec<4, T, Q>(Pf1.x, Pf0.y, Pf0.z, Pf0.w)); + T n0100 = dot(g0100, vec<4, T, Q>(Pf0.x, Pf1.y, Pf0.z, Pf0.w)); + T n1100 = dot(g1100, vec<4, T, Q>(Pf1.x, Pf1.y, Pf0.z, Pf0.w)); + T n0010 = dot(g0010, vec<4, T, Q>(Pf0.x, Pf0.y, Pf1.z, Pf0.w)); + T n1010 = dot(g1010, vec<4, T, Q>(Pf1.x, Pf0.y, Pf1.z, Pf0.w)); + T n0110 = dot(g0110, vec<4, T, Q>(Pf0.x, Pf1.y, Pf1.z, Pf0.w)); + T n1110 = dot(g1110, vec<4, T, Q>(Pf1.x, Pf1.y, Pf1.z, Pf0.w)); + T n0001 = dot(g0001, vec<4, T, Q>(Pf0.x, Pf0.y, Pf0.z, Pf1.w)); + T n1001 = dot(g1001, vec<4, T, Q>(Pf1.x, Pf0.y, Pf0.z, Pf1.w)); + T n0101 = dot(g0101, vec<4, T, Q>(Pf0.x, Pf1.y, Pf0.z, Pf1.w)); + T n1101 = dot(g1101, vec<4, T, Q>(Pf1.x, Pf1.y, Pf0.z, Pf1.w)); + T n0011 = dot(g0011, vec<4, T, Q>(Pf0.x, Pf0.y, Pf1.z, Pf1.w)); + T n1011 = dot(g1011, vec<4, T, Q>(Pf1.x, Pf0.y, Pf1.z, Pf1.w)); + T n0111 = dot(g0111, vec<4, T, Q>(Pf0.x, Pf1.y, Pf1.z, Pf1.w)); + T n1111 = dot(g1111, Pf1); + + vec<4, T, Q> fade_xyzw = detail::fade(Pf0); + vec<4, T, Q> n_0w = mix(vec<4, T, Q>(n0000, n1000, n0100, n1100), vec<4, T, Q>(n0001, n1001, n0101, n1101), fade_xyzw.w); + vec<4, T, Q> n_1w = mix(vec<4, T, Q>(n0010, n1010, n0110, n1110), vec<4, T, Q>(n0011, n1011, n0111, n1111), fade_xyzw.w); + vec<4, T, Q> n_zw = mix(n_0w, n_1w, fade_xyzw.z); + vec<2, T, Q> n_yzw = mix(vec<2, T, Q>(n_zw.x, n_zw.y), vec<2, T, Q>(n_zw.z, n_zw.w), fade_xyzw.y); + T n_xyzw = mix(n_yzw.x, n_yzw.y, fade_xyzw.x); + return T(2.2) * n_xyzw; + } + + // Classic Perlin noise, periodic variant + template + GLM_FUNC_QUALIFIER T perlin(vec<2, T, Q> const& Position, vec<2, T, Q> const& rep) + { + vec<4, T, Q> Pi = floor(vec<4, T, Q>(Position.x, Position.y, Position.x, Position.y)) + vec<4, T, Q>(0.0, 0.0, 1.0, 1.0); + vec<4, T, Q> Pf = fract(vec<4, T, Q>(Position.x, Position.y, Position.x, Position.y)) - vec<4, T, Q>(0.0, 0.0, 1.0, 1.0); + Pi = mod(Pi, vec<4, T, Q>(rep.x, rep.y, rep.x, rep.y)); // To create noise with explicit period + Pi = mod(Pi, vec<4, T, Q>(289)); // To avoid truncation effects in permutation + vec<4, T, Q> ix(Pi.x, Pi.z, Pi.x, Pi.z); + vec<4, T, Q> iy(Pi.y, Pi.y, Pi.w, Pi.w); + vec<4, T, Q> fx(Pf.x, Pf.z, Pf.x, Pf.z); + vec<4, T, Q> fy(Pf.y, Pf.y, Pf.w, Pf.w); + + vec<4, T, Q> i = detail::permute(detail::permute(ix) + iy); + + vec<4, T, Q> gx = static_cast(2) * fract(i / T(41)) - T(1); + vec<4, T, Q> gy = abs(gx) - T(0.5); + vec<4, T, Q> tx = floor(gx + T(0.5)); + gx = gx - tx; + + vec<2, T, Q> g00(gx.x, gy.x); + vec<2, T, Q> g10(gx.y, gy.y); + vec<2, T, Q> g01(gx.z, gy.z); + vec<2, T, Q> g11(gx.w, gy.w); + + vec<4, T, Q> norm = detail::taylorInvSqrt(vec<4, T, Q>(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11))); + g00 *= norm.x; + g01 *= norm.y; + g10 *= norm.z; + g11 *= norm.w; + + T n00 = dot(g00, vec<2, T, Q>(fx.x, fy.x)); + T n10 = dot(g10, vec<2, T, Q>(fx.y, fy.y)); + T n01 = dot(g01, vec<2, T, Q>(fx.z, fy.z)); + T n11 = dot(g11, vec<2, T, Q>(fx.w, fy.w)); + + vec<2, T, Q> fade_xy = detail::fade(vec<2, T, Q>(Pf.x, Pf.y)); + vec<2, T, Q> n_x = mix(vec<2, T, Q>(n00, n01), vec<2, T, Q>(n10, n11), fade_xy.x); + T n_xy = mix(n_x.x, n_x.y, fade_xy.y); + return T(2.3) * n_xy; + } + + // Classic Perlin noise, periodic variant + template + GLM_FUNC_QUALIFIER T perlin(vec<3, T, Q> const& Position, vec<3, T, Q> const& rep) + { + vec<3, T, Q> Pi0 = mod(floor(Position), rep); // Integer part, modulo period + vec<3, T, Q> Pi1 = mod(Pi0 + vec<3, T, Q>(T(1)), rep); // Integer part + 1, mod period + Pi0 = mod(Pi0, vec<3, T, Q>(289)); + Pi1 = mod(Pi1, vec<3, T, Q>(289)); + vec<3, T, Q> Pf0 = fract(Position); // Fractional part for interpolation + vec<3, T, Q> Pf1 = Pf0 - vec<3, T, Q>(T(1)); // Fractional part - 1.0 + vec<4, T, Q> ix = vec<4, T, Q>(Pi0.x, Pi1.x, Pi0.x, Pi1.x); + vec<4, T, Q> iy = vec<4, T, Q>(Pi0.y, Pi0.y, Pi1.y, Pi1.y); + vec<4, T, Q> iz0(Pi0.z); + vec<4, T, Q> iz1(Pi1.z); + + vec<4, T, Q> ixy = detail::permute(detail::permute(ix) + iy); + vec<4, T, Q> ixy0 = detail::permute(ixy + iz0); + vec<4, T, Q> ixy1 = detail::permute(ixy + iz1); + + vec<4, T, Q> gx0 = ixy0 / T(7); + vec<4, T, Q> gy0 = fract(floor(gx0) / T(7)) - T(0.5); + gx0 = fract(gx0); + vec<4, T, Q> gz0 = vec<4, T, Q>(0.5) - abs(gx0) - abs(gy0); + vec<4, T, Q> sz0 = step(gz0, vec<4, T, Q>(0)); + gx0 -= sz0 * (step(T(0), gx0) - T(0.5)); + gy0 -= sz0 * (step(T(0), gy0) - T(0.5)); + + vec<4, T, Q> gx1 = ixy1 / T(7); + vec<4, T, Q> gy1 = fract(floor(gx1) / T(7)) - T(0.5); + gx1 = fract(gx1); + vec<4, T, Q> gz1 = vec<4, T, Q>(0.5) - abs(gx1) - abs(gy1); + vec<4, T, Q> sz1 = step(gz1, vec<4, T, Q>(T(0))); + gx1 -= sz1 * (step(T(0), gx1) - T(0.5)); + gy1 -= sz1 * (step(T(0), gy1) - T(0.5)); + + vec<3, T, Q> g000 = vec<3, T, Q>(gx0.x, gy0.x, gz0.x); + vec<3, T, Q> g100 = vec<3, T, Q>(gx0.y, gy0.y, gz0.y); + vec<3, T, Q> g010 = vec<3, T, Q>(gx0.z, gy0.z, gz0.z); + vec<3, T, Q> g110 = vec<3, T, Q>(gx0.w, gy0.w, gz0.w); + vec<3, T, Q> g001 = vec<3, T, Q>(gx1.x, gy1.x, gz1.x); + vec<3, T, Q> g101 = vec<3, T, Q>(gx1.y, gy1.y, gz1.y); + vec<3, T, Q> g011 = vec<3, T, Q>(gx1.z, gy1.z, gz1.z); + vec<3, T, Q> g111 = vec<3, T, Q>(gx1.w, gy1.w, gz1.w); + + vec<4, T, Q> norm0 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110))); + g000 *= norm0.x; + g010 *= norm0.y; + g100 *= norm0.z; + g110 *= norm0.w; + vec<4, T, Q> norm1 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111))); + g001 *= norm1.x; + g011 *= norm1.y; + g101 *= norm1.z; + g111 *= norm1.w; + + T n000 = dot(g000, Pf0); + T n100 = dot(g100, vec<3, T, Q>(Pf1.x, Pf0.y, Pf0.z)); + T n010 = dot(g010, vec<3, T, Q>(Pf0.x, Pf1.y, Pf0.z)); + T n110 = dot(g110, vec<3, T, Q>(Pf1.x, Pf1.y, Pf0.z)); + T n001 = dot(g001, vec<3, T, Q>(Pf0.x, Pf0.y, Pf1.z)); + T n101 = dot(g101, vec<3, T, Q>(Pf1.x, Pf0.y, Pf1.z)); + T n011 = dot(g011, vec<3, T, Q>(Pf0.x, Pf1.y, Pf1.z)); + T n111 = dot(g111, Pf1); + + vec<3, T, Q> fade_xyz = detail::fade(Pf0); + vec<4, T, Q> n_z = mix(vec<4, T, Q>(n000, n100, n010, n110), vec<4, T, Q>(n001, n101, n011, n111), fade_xyz.z); + vec<2, T, Q> n_yz = mix(vec<2, T, Q>(n_z.x, n_z.y), vec<2, T, Q>(n_z.z, n_z.w), fade_xyz.y); + T n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x); + return T(2.2) * n_xyz; + } + + // Classic Perlin noise, periodic version + template + GLM_FUNC_QUALIFIER T perlin(vec<4, T, Q> const& Position, vec<4, T, Q> const& rep) + { + vec<4, T, Q> Pi0 = mod(floor(Position), rep); // Integer part modulo rep + vec<4, T, Q> Pi1 = mod(Pi0 + T(1), rep); // Integer part + 1 mod rep + vec<4, T, Q> Pf0 = fract(Position); // Fractional part for interpolation + vec<4, T, Q> Pf1 = Pf0 - T(1); // Fractional part - 1.0 + vec<4, T, Q> ix = vec<4, T, Q>(Pi0.x, Pi1.x, Pi0.x, Pi1.x); + vec<4, T, Q> iy = vec<4, T, Q>(Pi0.y, Pi0.y, Pi1.y, Pi1.y); + vec<4, T, Q> iz0(Pi0.z); + vec<4, T, Q> iz1(Pi1.z); + vec<4, T, Q> iw0(Pi0.w); + vec<4, T, Q> iw1(Pi1.w); + + vec<4, T, Q> ixy = detail::permute(detail::permute(ix) + iy); + vec<4, T, Q> ixy0 = detail::permute(ixy + iz0); + vec<4, T, Q> ixy1 = detail::permute(ixy + iz1); + vec<4, T, Q> ixy00 = detail::permute(ixy0 + iw0); + vec<4, T, Q> ixy01 = detail::permute(ixy0 + iw1); + vec<4, T, Q> ixy10 = detail::permute(ixy1 + iw0); + vec<4, T, Q> ixy11 = detail::permute(ixy1 + iw1); + + vec<4, T, Q> gx00 = ixy00 / T(7); + vec<4, T, Q> gy00 = floor(gx00) / T(7); + vec<4, T, Q> gz00 = floor(gy00) / T(6); + gx00 = fract(gx00) - T(0.5); + gy00 = fract(gy00) - T(0.5); + gz00 = fract(gz00) - T(0.5); + vec<4, T, Q> gw00 = vec<4, T, Q>(0.75) - abs(gx00) - abs(gy00) - abs(gz00); + vec<4, T, Q> sw00 = step(gw00, vec<4, T, Q>(0)); + gx00 -= sw00 * (step(T(0), gx00) - T(0.5)); + gy00 -= sw00 * (step(T(0), gy00) - T(0.5)); + + vec<4, T, Q> gx01 = ixy01 / T(7); + vec<4, T, Q> gy01 = floor(gx01) / T(7); + vec<4, T, Q> gz01 = floor(gy01) / T(6); + gx01 = fract(gx01) - T(0.5); + gy01 = fract(gy01) - T(0.5); + gz01 = fract(gz01) - T(0.5); + vec<4, T, Q> gw01 = vec<4, T, Q>(0.75) - abs(gx01) - abs(gy01) - abs(gz01); + vec<4, T, Q> sw01 = step(gw01, vec<4, T, Q>(0.0)); + gx01 -= sw01 * (step(T(0), gx01) - T(0.5)); + gy01 -= sw01 * (step(T(0), gy01) - T(0.5)); + + vec<4, T, Q> gx10 = ixy10 / T(7); + vec<4, T, Q> gy10 = floor(gx10) / T(7); + vec<4, T, Q> gz10 = floor(gy10) / T(6); + gx10 = fract(gx10) - T(0.5); + gy10 = fract(gy10) - T(0.5); + gz10 = fract(gz10) - T(0.5); + vec<4, T, Q> gw10 = vec<4, T, Q>(0.75) - abs(gx10) - abs(gy10) - abs(gz10); + vec<4, T, Q> sw10 = step(gw10, vec<4, T, Q>(0.0)); + gx10 -= sw10 * (step(T(0), gx10) - T(0.5)); + gy10 -= sw10 * (step(T(0), gy10) - T(0.5)); + + vec<4, T, Q> gx11 = ixy11 / T(7); + vec<4, T, Q> gy11 = floor(gx11) / T(7); + vec<4, T, Q> gz11 = floor(gy11) / T(6); + gx11 = fract(gx11) - T(0.5); + gy11 = fract(gy11) - T(0.5); + gz11 = fract(gz11) - T(0.5); + vec<4, T, Q> gw11 = vec<4, T, Q>(0.75) - abs(gx11) - abs(gy11) - abs(gz11); + vec<4, T, Q> sw11 = step(gw11, vec<4, T, Q>(T(0))); + gx11 -= sw11 * (step(T(0), gx11) - T(0.5)); + gy11 -= sw11 * (step(T(0), gy11) - T(0.5)); + + vec<4, T, Q> g0000(gx00.x, gy00.x, gz00.x, gw00.x); + vec<4, T, Q> g1000(gx00.y, gy00.y, gz00.y, gw00.y); + vec<4, T, Q> g0100(gx00.z, gy00.z, gz00.z, gw00.z); + vec<4, T, Q> g1100(gx00.w, gy00.w, gz00.w, gw00.w); + vec<4, T, Q> g0010(gx10.x, gy10.x, gz10.x, gw10.x); + vec<4, T, Q> g1010(gx10.y, gy10.y, gz10.y, gw10.y); + vec<4, T, Q> g0110(gx10.z, gy10.z, gz10.z, gw10.z); + vec<4, T, Q> g1110(gx10.w, gy10.w, gz10.w, gw10.w); + vec<4, T, Q> g0001(gx01.x, gy01.x, gz01.x, gw01.x); + vec<4, T, Q> g1001(gx01.y, gy01.y, gz01.y, gw01.y); + vec<4, T, Q> g0101(gx01.z, gy01.z, gz01.z, gw01.z); + vec<4, T, Q> g1101(gx01.w, gy01.w, gz01.w, gw01.w); + vec<4, T, Q> g0011(gx11.x, gy11.x, gz11.x, gw11.x); + vec<4, T, Q> g1011(gx11.y, gy11.y, gz11.y, gw11.y); + vec<4, T, Q> g0111(gx11.z, gy11.z, gz11.z, gw11.z); + vec<4, T, Q> g1111(gx11.w, gy11.w, gz11.w, gw11.w); + + vec<4, T, Q> norm00 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0000, g0000), dot(g0100, g0100), dot(g1000, g1000), dot(g1100, g1100))); + g0000 *= norm00.x; + g0100 *= norm00.y; + g1000 *= norm00.z; + g1100 *= norm00.w; + + vec<4, T, Q> norm01 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0001, g0001), dot(g0101, g0101), dot(g1001, g1001), dot(g1101, g1101))); + g0001 *= norm01.x; + g0101 *= norm01.y; + g1001 *= norm01.z; + g1101 *= norm01.w; + + vec<4, T, Q> norm10 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0010, g0010), dot(g0110, g0110), dot(g1010, g1010), dot(g1110, g1110))); + g0010 *= norm10.x; + g0110 *= norm10.y; + g1010 *= norm10.z; + g1110 *= norm10.w; + + vec<4, T, Q> norm11 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0011, g0011), dot(g0111, g0111), dot(g1011, g1011), dot(g1111, g1111))); + g0011 *= norm11.x; + g0111 *= norm11.y; + g1011 *= norm11.z; + g1111 *= norm11.w; + + T n0000 = dot(g0000, Pf0); + T n1000 = dot(g1000, vec<4, T, Q>(Pf1.x, Pf0.y, Pf0.z, Pf0.w)); + T n0100 = dot(g0100, vec<4, T, Q>(Pf0.x, Pf1.y, Pf0.z, Pf0.w)); + T n1100 = dot(g1100, vec<4, T, Q>(Pf1.x, Pf1.y, Pf0.z, Pf0.w)); + T n0010 = dot(g0010, vec<4, T, Q>(Pf0.x, Pf0.y, Pf1.z, Pf0.w)); + T n1010 = dot(g1010, vec<4, T, Q>(Pf1.x, Pf0.y, Pf1.z, Pf0.w)); + T n0110 = dot(g0110, vec<4, T, Q>(Pf0.x, Pf1.y, Pf1.z, Pf0.w)); + T n1110 = dot(g1110, vec<4, T, Q>(Pf1.x, Pf1.y, Pf1.z, Pf0.w)); + T n0001 = dot(g0001, vec<4, T, Q>(Pf0.x, Pf0.y, Pf0.z, Pf1.w)); + T n1001 = dot(g1001, vec<4, T, Q>(Pf1.x, Pf0.y, Pf0.z, Pf1.w)); + T n0101 = dot(g0101, vec<4, T, Q>(Pf0.x, Pf1.y, Pf0.z, Pf1.w)); + T n1101 = dot(g1101, vec<4, T, Q>(Pf1.x, Pf1.y, Pf0.z, Pf1.w)); + T n0011 = dot(g0011, vec<4, T, Q>(Pf0.x, Pf0.y, Pf1.z, Pf1.w)); + T n1011 = dot(g1011, vec<4, T, Q>(Pf1.x, Pf0.y, Pf1.z, Pf1.w)); + T n0111 = dot(g0111, vec<4, T, Q>(Pf0.x, Pf1.y, Pf1.z, Pf1.w)); + T n1111 = dot(g1111, Pf1); + + vec<4, T, Q> fade_xyzw = detail::fade(Pf0); + vec<4, T, Q> n_0w = mix(vec<4, T, Q>(n0000, n1000, n0100, n1100), vec<4, T, Q>(n0001, n1001, n0101, n1101), fade_xyzw.w); + vec<4, T, Q> n_1w = mix(vec<4, T, Q>(n0010, n1010, n0110, n1110), vec<4, T, Q>(n0011, n1011, n0111, n1111), fade_xyzw.w); + vec<4, T, Q> n_zw = mix(n_0w, n_1w, fade_xyzw.z); + vec<2, T, Q> n_yzw = mix(vec<2, T, Q>(n_zw.x, n_zw.y), vec<2, T, Q>(n_zw.z, n_zw.w), fade_xyzw.y); + T n_xyzw = mix(n_yzw.x, n_yzw.y, fade_xyzw.x); + return T(2.2) * n_xyzw; + } + + template + GLM_FUNC_QUALIFIER T simplex(glm::vec<2, T, Q> const& v) + { + vec<4, T, Q> const C = vec<4, T, Q>( + T( 0.211324865405187), // (3.0 - sqrt(3.0)) / 6.0 + T( 0.366025403784439), // 0.5 * (sqrt(3.0) - 1.0) + T(-0.577350269189626), // -1.0 + 2.0 * C.x + T( 0.024390243902439)); // 1.0 / 41.0 + + // First corner + vec<2, T, Q> i = floor(v + dot(v, vec<2, T, Q>(C[1]))); + vec<2, T, Q> x0 = v - i + dot(i, vec<2, T, Q>(C[0])); + + // Other corners + //i1.x = step( x0.y, x0.x ); // x0.x > x0.y ? 1.0 : 0.0 + //i1.y = 1.0 - i1.x; + vec<2, T, Q> i1 = (x0.x > x0.y) ? vec<2, T, Q>(1, 0) : vec<2, T, Q>(0, 1); + // x0 = x0 - 0.0 + 0.0 * C.xx ; + // x1 = x0 - i1 + 1.0 * C.xx ; + // x2 = x0 - 1.0 + 2.0 * C.xx ; + vec<4, T, Q> x12 = vec<4, T, Q>(x0.x, x0.y, x0.x, x0.y) + vec<4, T, Q>(C.x, C.x, C.z, C.z); + x12 = vec<4, T, Q>(vec<2, T, Q>(x12) - i1, x12.z, x12.w); + + // Permutations + i = mod(i, vec<2, T, Q>(289)); // Avoid truncation effects in permutation + vec<3, T, Q> p = detail::permute( + detail::permute(i.y + vec<3, T, Q>(T(0), i1.y, T(1))) + + i.x + vec<3, T, Q>(T(0), i1.x, T(1))); + + vec<3, T, Q> m = max(vec<3, T, Q>(0.5) - vec<3, T, Q>( + dot(x0, x0), + dot(vec<2, T, Q>(x12.x, x12.y), vec<2, T, Q>(x12.x, x12.y)), + dot(vec<2, T, Q>(x12.z, x12.w), vec<2, T, Q>(x12.z, x12.w))), vec<3, T, Q>(0)); + m = m * m ; + m = m * m ; + + // Gradients: 41 points uniformly over a line, mapped onto a diamond. + // The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287) + + vec<3, T, Q> x = static_cast(2) * fract(p * C.w) - T(1); + vec<3, T, Q> h = abs(x) - T(0.5); + vec<3, T, Q> ox = floor(x + T(0.5)); + vec<3, T, Q> a0 = x - ox; + + // Normalise gradients implicitly by scaling m + // Inlined for speed: m *= taylorInvSqrt( a0*a0 + h*h ); + m *= static_cast(1.79284291400159) - T(0.85373472095314) * (a0 * a0 + h * h); + + // Compute final noise value at P + vec<3, T, Q> g; + g.x = a0.x * x0.x + h.x * x0.y; + //g.yz = a0.yz * x12.xz + h.yz * x12.yw; + g.y = a0.y * x12.x + h.y * x12.y; + g.z = a0.z * x12.z + h.z * x12.w; + return T(130) * dot(m, g); + } + + template + GLM_FUNC_QUALIFIER T simplex(vec<3, T, Q> const& v) + { + vec<2, T, Q> const C(1.0 / 6.0, 1.0 / 3.0); + vec<4, T, Q> const D(0.0, 0.5, 1.0, 2.0); + + // First corner + vec<3, T, Q> i(floor(v + dot(v, vec<3, T, Q>(C.y)))); + vec<3, T, Q> x0(v - i + dot(i, vec<3, T, Q>(C.x))); + + // Other corners + vec<3, T, Q> g(step(vec<3, T, Q>(x0.y, x0.z, x0.x), x0)); + vec<3, T, Q> l(T(1) - g); + vec<3, T, Q> i1(min(g, vec<3, T, Q>(l.z, l.x, l.y))); + vec<3, T, Q> i2(max(g, vec<3, T, Q>(l.z, l.x, l.y))); + + // x0 = x0 - 0.0 + 0.0 * C.xxx; + // x1 = x0 - i1 + 1.0 * C.xxx; + // x2 = x0 - i2 + 2.0 * C.xxx; + // x3 = x0 - 1.0 + 3.0 * C.xxx; + vec<3, T, Q> x1(x0 - i1 + C.x); + vec<3, T, Q> x2(x0 - i2 + C.y); // 2.0*C.x = 1/3 = C.y + vec<3, T, Q> x3(x0 - D.y); // -1.0+3.0*C.x = -0.5 = -D.y + + // Permutations + i = detail::mod289(i); + vec<4, T, Q> p(detail::permute(detail::permute(detail::permute( + i.z + vec<4, T, Q>(T(0), i1.z, i2.z, T(1))) + + i.y + vec<4, T, Q>(T(0), i1.y, i2.y, T(1))) + + i.x + vec<4, T, Q>(T(0), i1.x, i2.x, T(1)))); + + // Gradients: 7x7 points over a square, mapped onto an octahedron. + // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) + T n_ = static_cast(0.142857142857); // 1.0/7.0 + vec<3, T, Q> ns(n_ * vec<3, T, Q>(D.w, D.y, D.z) - vec<3, T, Q>(D.x, D.z, D.x)); + + vec<4, T, Q> j(p - T(49) * floor(p * ns.z * ns.z)); // mod(p,7*7) + + vec<4, T, Q> x_(floor(j * ns.z)); + vec<4, T, Q> y_(floor(j - T(7) * x_)); // mod(j,N) + + vec<4, T, Q> x(x_ * ns.x + ns.y); + vec<4, T, Q> y(y_ * ns.x + ns.y); + vec<4, T, Q> h(T(1) - abs(x) - abs(y)); + + vec<4, T, Q> b0(x.x, x.y, y.x, y.y); + vec<4, T, Q> b1(x.z, x.w, y.z, y.w); + + // vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0; + // vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0; + vec<4, T, Q> s0(floor(b0) * T(2) + T(1)); + vec<4, T, Q> s1(floor(b1) * T(2) + T(1)); + vec<4, T, Q> sh(-step(h, vec<4, T, Q>(0.0))); + + vec<4, T, Q> a0 = vec<4, T, Q>(b0.x, b0.z, b0.y, b0.w) + vec<4, T, Q>(s0.x, s0.z, s0.y, s0.w) * vec<4, T, Q>(sh.x, sh.x, sh.y, sh.y); + vec<4, T, Q> a1 = vec<4, T, Q>(b1.x, b1.z, b1.y, b1.w) + vec<4, T, Q>(s1.x, s1.z, s1.y, s1.w) * vec<4, T, Q>(sh.z, sh.z, sh.w, sh.w); + + vec<3, T, Q> p0(a0.x, a0.y, h.x); + vec<3, T, Q> p1(a0.z, a0.w, h.y); + vec<3, T, Q> p2(a1.x, a1.y, h.z); + vec<3, T, Q> p3(a1.z, a1.w, h.w); + + // Normalise gradients + vec<4, T, Q> norm = detail::taylorInvSqrt(vec<4, T, Q>(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3))); + p0 *= norm.x; + p1 *= norm.y; + p2 *= norm.z; + p3 *= norm.w; + + // Mix final noise value + vec<4, T, Q> m = max(T(0.6) - vec<4, T, Q>(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), vec<4, T, Q>(0)); + m = m * m; + return T(42) * dot(m * m, vec<4, T, Q>(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3))); + } + + template + GLM_FUNC_QUALIFIER T simplex(vec<4, T, Q> const& v) + { + vec<4, T, Q> const C( + 0.138196601125011, // (5 - sqrt(5))/20 G4 + 0.276393202250021, // 2 * G4 + 0.414589803375032, // 3 * G4 + -0.447213595499958); // -1 + 4 * G4 + + // (sqrt(5) - 1)/4 = F4, used once below + T const F4 = static_cast(0.309016994374947451); + + // First corner + vec<4, T, Q> i = floor(v + dot(v, vec<4, T, Q>(F4))); + vec<4, T, Q> x0 = v - i + dot(i, vec<4, T, Q>(C.x)); + + // Other corners + + // Rank sorting originally contributed by Bill Licea-Kane, AMD (formerly ATI) + vec<4, T, Q> i0; + vec<3, T, Q> isX = step(vec<3, T, Q>(x0.y, x0.z, x0.w), vec<3, T, Q>(x0.x)); + vec<3, T, Q> isYZ = step(vec<3, T, Q>(x0.z, x0.w, x0.w), vec<3, T, Q>(x0.y, x0.y, x0.z)); + // i0.x = dot(isX, vec3(1.0)); + //i0.x = isX.x + isX.y + isX.z; + //i0.yzw = static_cast(1) - isX; + i0 = vec<4, T, Q>(isX.x + isX.y + isX.z, T(1) - isX); + // i0.y += dot(isYZ.xy, vec2(1.0)); + i0.y += isYZ.x + isYZ.y; + //i0.zw += 1.0 - vec<2, T, Q>(isYZ.x, isYZ.y); + i0.z += static_cast(1) - isYZ.x; + i0.w += static_cast(1) - isYZ.y; + i0.z += isYZ.z; + i0.w += static_cast(1) - isYZ.z; + + // i0 now contains the unique values 0,1,2,3 in each channel + vec<4, T, Q> i3 = clamp(i0, T(0), T(1)); + vec<4, T, Q> i2 = clamp(i0 - T(1), T(0), T(1)); + vec<4, T, Q> i1 = clamp(i0 - T(2), T(0), T(1)); + + // x0 = x0 - 0.0 + 0.0 * C.xxxx + // x1 = x0 - i1 + 0.0 * C.xxxx + // x2 = x0 - i2 + 0.0 * C.xxxx + // x3 = x0 - i3 + 0.0 * C.xxxx + // x4 = x0 - 1.0 + 4.0 * C.xxxx + vec<4, T, Q> x1 = x0 - i1 + C.x; + vec<4, T, Q> x2 = x0 - i2 + C.y; + vec<4, T, Q> x3 = x0 - i3 + C.z; + vec<4, T, Q> x4 = x0 + C.w; + + // Permutations + i = mod(i, vec<4, T, Q>(289)); + T j0 = detail::permute(detail::permute(detail::permute(detail::permute(i.w) + i.z) + i.y) + i.x); + vec<4, T, Q> j1 = detail::permute(detail::permute(detail::permute(detail::permute( + i.w + vec<4, T, Q>(i1.w, i2.w, i3.w, T(1))) + + i.z + vec<4, T, Q>(i1.z, i2.z, i3.z, T(1))) + + i.y + vec<4, T, Q>(i1.y, i2.y, i3.y, T(1))) + + i.x + vec<4, T, Q>(i1.x, i2.x, i3.x, T(1))); + + // Gradients: 7x7x6 points over a cube, mapped onto a 4-cross polytope + // 7*7*6 = 294, which is close to the ring size 17*17 = 289. + vec<4, T, Q> ip = vec<4, T, Q>(T(1) / T(294), T(1) / T(49), T(1) / T(7), T(0)); + + vec<4, T, Q> p0 = gtc::grad4(j0, ip); + vec<4, T, Q> p1 = gtc::grad4(j1.x, ip); + vec<4, T, Q> p2 = gtc::grad4(j1.y, ip); + vec<4, T, Q> p3 = gtc::grad4(j1.z, ip); + vec<4, T, Q> p4 = gtc::grad4(j1.w, ip); + + // Normalise gradients + vec<4, T, Q> norm = detail::taylorInvSqrt(vec<4, T, Q>(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3))); + p0 *= norm.x; + p1 *= norm.y; + p2 *= norm.z; + p3 *= norm.w; + p4 *= detail::taylorInvSqrt(dot(p4, p4)); + + // Mix contributions from the five corners + vec<3, T, Q> m0 = max(T(0.6) - vec<3, T, Q>(dot(x0, x0), dot(x1, x1), dot(x2, x2)), vec<3, T, Q>(0)); + vec<2, T, Q> m1 = max(T(0.6) - vec<2, T, Q>(dot(x3, x3), dot(x4, x4) ), vec<2, T, Q>(0)); + m0 = m0 * m0; + m1 = m1 * m1; + return T(49) * + (dot(m0 * m0, vec<3, T, Q>(dot(p0, x0), dot(p1, x1), dot(p2, x2))) + + dot(m1 * m1, vec<2, T, Q>(dot(p3, x3), dot(p4, x4)))); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/packing.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/packing.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8e416b3fe1b582eb540bd7d425220cd289756921 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/packing.hpp @@ -0,0 +1,728 @@ +/// @ref gtc_packing +/// @file glm/gtc/packing.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtc_packing GLM_GTC_packing +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// This extension provides a set of function to convert vertors to packed +/// formats. + +#pragma once + +// Dependency: +#include "type_precision.hpp" +#include "../ext/vector_packing.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_packing extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_packing + /// @{ + + /// First, converts the normalized floating-point value v into a 8-bit integer value. + /// Then, the results are packed into the returned 8-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packUnorm1x8: round(clamp(c, 0, +1) * 255.0) + /// + /// @see gtc_packing + /// @see uint16 packUnorm2x8(vec2 const& v) + /// @see uint32 packUnorm4x8(vec4 const& v) + /// @see GLSL packUnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint8 packUnorm1x8(float v); + + /// Convert a single 8-bit integer to a normalized floating-point value. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackUnorm4x8: f / 255.0 + /// + /// @see gtc_packing + /// @see vec2 unpackUnorm2x8(uint16 p) + /// @see vec4 unpackUnorm4x8(uint32 p) + /// @see GLSL unpackUnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL float unpackUnorm1x8(uint8 p); + + /// First, converts each component of the normalized floating-point value v into 8-bit integer values. + /// Then, the results are packed into the returned 16-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packUnorm2x8: round(clamp(c, 0, +1) * 255.0) + /// + /// The first component of the vector will be written to the least significant bits of the output; + /// the last component will be written to the most significant bits. + /// + /// @see gtc_packing + /// @see uint8 packUnorm1x8(float const& v) + /// @see uint32 packUnorm4x8(vec4 const& v) + /// @see GLSL packUnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint16 packUnorm2x8(vec2 const& v); + + /// First, unpacks a single 16-bit unsigned integer p into a pair of 8-bit unsigned integers. + /// Then, each component is converted to a normalized floating-point value to generate the returned two-component vector. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackUnorm4x8: f / 255.0 + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see gtc_packing + /// @see float unpackUnorm1x8(uint8 v) + /// @see vec4 unpackUnorm4x8(uint32 p) + /// @see GLSL unpackUnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL vec2 unpackUnorm2x8(uint16 p); + + /// First, converts the normalized floating-point value v into 8-bit integer value. + /// Then, the results are packed into the returned 8-bit unsigned integer. + /// + /// The conversion to fixed point is done as follows: + /// packSnorm1x8: round(clamp(s, -1, +1) * 127.0) + /// + /// @see gtc_packing + /// @see uint16 packSnorm2x8(vec2 const& v) + /// @see uint32 packSnorm4x8(vec4 const& v) + /// @see GLSL packSnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint8 packSnorm1x8(float s); + + /// First, unpacks a single 8-bit unsigned integer p into a single 8-bit signed integers. + /// Then, the value is converted to a normalized floating-point value to generate the returned scalar. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackSnorm1x8: clamp(f / 127.0, -1, +1) + /// + /// @see gtc_packing + /// @see vec2 unpackSnorm2x8(uint16 p) + /// @see vec4 unpackSnorm4x8(uint32 p) + /// @see GLSL unpackSnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL float unpackSnorm1x8(uint8 p); + + /// First, converts each component of the normalized floating-point value v into 8-bit integer values. + /// Then, the results are packed into the returned 16-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packSnorm2x8: round(clamp(c, -1, +1) * 127.0) + /// + /// The first component of the vector will be written to the least significant bits of the output; + /// the last component will be written to the most significant bits. + /// + /// @see gtc_packing + /// @see uint8 packSnorm1x8(float const& v) + /// @see uint32 packSnorm4x8(vec4 const& v) + /// @see GLSL packSnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint16 packSnorm2x8(vec2 const& v); + + /// First, unpacks a single 16-bit unsigned integer p into a pair of 8-bit signed integers. + /// Then, each component is converted to a normalized floating-point value to generate the returned two-component vector. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackSnorm2x8: clamp(f / 127.0, -1, +1) + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see gtc_packing + /// @see float unpackSnorm1x8(uint8 p) + /// @see vec4 unpackSnorm4x8(uint32 p) + /// @see GLSL unpackSnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL vec2 unpackSnorm2x8(uint16 p); + + /// First, converts the normalized floating-point value v into a 16-bit integer value. + /// Then, the results are packed into the returned 16-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packUnorm1x16: round(clamp(c, 0, +1) * 65535.0) + /// + /// @see gtc_packing + /// @see uint16 packSnorm1x16(float const& v) + /// @see uint64 packSnorm4x16(vec4 const& v) + /// @see GLSL packUnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint16 packUnorm1x16(float v); + + /// First, unpacks a single 16-bit unsigned integer p into a of 16-bit unsigned integers. + /// Then, the value is converted to a normalized floating-point value to generate the returned scalar. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackUnorm1x16: f / 65535.0 + /// + /// @see gtc_packing + /// @see vec2 unpackUnorm2x16(uint32 p) + /// @see vec4 unpackUnorm4x16(uint64 p) + /// @see GLSL unpackUnorm2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL float unpackUnorm1x16(uint16 p); + + /// First, converts each component of the normalized floating-point value v into 16-bit integer values. + /// Then, the results are packed into the returned 64-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packUnorm4x16: round(clamp(c, 0, +1) * 65535.0) + /// + /// The first component of the vector will be written to the least significant bits of the output; + /// the last component will be written to the most significant bits. + /// + /// @see gtc_packing + /// @see uint16 packUnorm1x16(float const& v) + /// @see uint32 packUnorm2x16(vec2 const& v) + /// @see GLSL packUnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint64 packUnorm4x16(vec4 const& v); + + /// First, unpacks a single 64-bit unsigned integer p into four 16-bit unsigned integers. + /// Then, each component is converted to a normalized floating-point value to generate the returned four-component vector. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackUnormx4x16: f / 65535.0 + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see gtc_packing + /// @see float unpackUnorm1x16(uint16 p) + /// @see vec2 unpackUnorm2x16(uint32 p) + /// @see GLSL unpackUnorm2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL vec4 unpackUnorm4x16(uint64 p); + + /// First, converts the normalized floating-point value v into 16-bit integer value. + /// Then, the results are packed into the returned 16-bit unsigned integer. + /// + /// The conversion to fixed point is done as follows: + /// packSnorm1x8: round(clamp(s, -1, +1) * 32767.0) + /// + /// @see gtc_packing + /// @see uint32 packSnorm2x16(vec2 const& v) + /// @see uint64 packSnorm4x16(vec4 const& v) + /// @see GLSL packSnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint16 packSnorm1x16(float v); + + /// First, unpacks a single 16-bit unsigned integer p into a single 16-bit signed integers. + /// Then, each component is converted to a normalized floating-point value to generate the returned scalar. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackSnorm1x16: clamp(f / 32767.0, -1, +1) + /// + /// @see gtc_packing + /// @see vec2 unpackSnorm2x16(uint32 p) + /// @see vec4 unpackSnorm4x16(uint64 p) + /// @see GLSL unpackSnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL float unpackSnorm1x16(uint16 p); + + /// First, converts each component of the normalized floating-point value v into 16-bit integer values. + /// Then, the results are packed into the returned 64-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packSnorm2x8: round(clamp(c, -1, +1) * 32767.0) + /// + /// The first component of the vector will be written to the least significant bits of the output; + /// the last component will be written to the most significant bits. + /// + /// @see gtc_packing + /// @see uint16 packSnorm1x16(float const& v) + /// @see uint32 packSnorm2x16(vec2 const& v) + /// @see GLSL packSnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint64 packSnorm4x16(vec4 const& v); + + /// First, unpacks a single 64-bit unsigned integer p into four 16-bit signed integers. + /// Then, each component is converted to a normalized floating-point value to generate the returned four-component vector. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackSnorm4x16: clamp(f / 32767.0, -1, +1) + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see gtc_packing + /// @see float unpackSnorm1x16(uint16 p) + /// @see vec2 unpackSnorm2x16(uint32 p) + /// @see GLSL unpackSnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL vec4 unpackSnorm4x16(uint64 p); + + /// Returns an unsigned integer obtained by converting the components of a floating-point scalar + /// to the 16-bit floating-point representation found in the OpenGL Specification, + /// and then packing this 16-bit value into a 16-bit unsigned integer. + /// + /// @see gtc_packing + /// @see uint32 packHalf2x16(vec2 const& v) + /// @see uint64 packHalf4x16(vec4 const& v) + /// @see GLSL packHalf2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint16 packHalf1x16(float v); + + /// Returns a floating-point scalar with components obtained by unpacking a 16-bit unsigned integer into a 16-bit value, + /// interpreted as a 16-bit floating-point number according to the OpenGL Specification, + /// and converting it to 32-bit floating-point values. + /// + /// @see gtc_packing + /// @see vec2 unpackHalf2x16(uint32 const& v) + /// @see vec4 unpackHalf4x16(uint64 const& v) + /// @see GLSL unpackHalf2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL float unpackHalf1x16(uint16 v); + + /// Returns an unsigned integer obtained by converting the components of a four-component floating-point vector + /// to the 16-bit floating-point representation found in the OpenGL Specification, + /// and then packing these four 16-bit values into a 64-bit unsigned integer. + /// The first vector component specifies the 16 least-significant bits of the result; + /// the forth component specifies the 16 most-significant bits. + /// + /// @see gtc_packing + /// @see uint16 packHalf1x16(float const& v) + /// @see uint32 packHalf2x16(vec2 const& v) + /// @see GLSL packHalf2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint64 packHalf4x16(vec4 const& v); + + /// Returns a four-component floating-point vector with components obtained by unpacking a 64-bit unsigned integer into four 16-bit values, + /// interpreting those values as 16-bit floating-point numbers according to the OpenGL Specification, + /// and converting them to 32-bit floating-point values. + /// The first component of the vector is obtained from the 16 least-significant bits of v; + /// the forth component is obtained from the 16 most-significant bits of v. + /// + /// @see gtc_packing + /// @see float unpackHalf1x16(uint16 const& v) + /// @see vec2 unpackHalf2x16(uint32 const& v) + /// @see GLSL unpackHalf2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL vec4 unpackHalf4x16(uint64 p); + + /// Returns an unsigned integer obtained by converting the components of a four-component signed integer vector + /// to the 10-10-10-2-bit signed integer representation found in the OpenGL Specification, + /// and then packing these four values into a 32-bit unsigned integer. + /// The first vector component specifies the 10 least-significant bits of the result; + /// the forth component specifies the 2 most-significant bits. + /// + /// @see gtc_packing + /// @see uint32 packI3x10_1x2(uvec4 const& v) + /// @see uint32 packSnorm3x10_1x2(vec4 const& v) + /// @see uint32 packUnorm3x10_1x2(vec4 const& v) + /// @see ivec4 unpackI3x10_1x2(uint32 const& p) + GLM_FUNC_DECL uint32 packI3x10_1x2(ivec4 const& v); + + /// Unpacks a single 32-bit unsigned integer p into three 10-bit and one 2-bit signed integers. + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see gtc_packing + /// @see uint32 packU3x10_1x2(uvec4 const& v) + /// @see vec4 unpackSnorm3x10_1x2(uint32 const& p); + /// @see uvec4 unpackI3x10_1x2(uint32 const& p); + GLM_FUNC_DECL ivec4 unpackI3x10_1x2(uint32 p); + + /// Returns an unsigned integer obtained by converting the components of a four-component unsigned integer vector + /// to the 10-10-10-2-bit unsigned integer representation found in the OpenGL Specification, + /// and then packing these four values into a 32-bit unsigned integer. + /// The first vector component specifies the 10 least-significant bits of the result; + /// the forth component specifies the 2 most-significant bits. + /// + /// @see gtc_packing + /// @see uint32 packI3x10_1x2(ivec4 const& v) + /// @see uint32 packSnorm3x10_1x2(vec4 const& v) + /// @see uint32 packUnorm3x10_1x2(vec4 const& v) + /// @see ivec4 unpackU3x10_1x2(uint32 const& p) + GLM_FUNC_DECL uint32 packU3x10_1x2(uvec4 const& v); + + /// Unpacks a single 32-bit unsigned integer p into three 10-bit and one 2-bit unsigned integers. + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see gtc_packing + /// @see uint32 packU3x10_1x2(uvec4 const& v) + /// @see vec4 unpackSnorm3x10_1x2(uint32 const& p); + /// @see uvec4 unpackI3x10_1x2(uint32 const& p); + GLM_FUNC_DECL uvec4 unpackU3x10_1x2(uint32 p); + + /// First, converts the first three components of the normalized floating-point value v into 10-bit signed integer values. + /// Then, converts the forth component of the normalized floating-point value v into 2-bit signed integer values. + /// Then, the results are packed into the returned 32-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packSnorm3x10_1x2(xyz): round(clamp(c, -1, +1) * 511.0) + /// packSnorm3x10_1x2(w): round(clamp(c, -1, +1) * 1.0) + /// + /// The first vector component specifies the 10 least-significant bits of the result; + /// the forth component specifies the 2 most-significant bits. + /// + /// @see gtc_packing + /// @see vec4 unpackSnorm3x10_1x2(uint32 const& p) + /// @see uint32 packUnorm3x10_1x2(vec4 const& v) + /// @see uint32 packU3x10_1x2(uvec4 const& v) + /// @see uint32 packI3x10_1x2(ivec4 const& v) + GLM_FUNC_DECL uint32 packSnorm3x10_1x2(vec4 const& v); + + /// First, unpacks a single 32-bit unsigned integer p into four 16-bit signed integers. + /// Then, each component is converted to a normalized floating-point value to generate the returned four-component vector. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackSnorm3x10_1x2(xyz): clamp(f / 511.0, -1, +1) + /// unpackSnorm3x10_1x2(w): clamp(f / 511.0, -1, +1) + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see gtc_packing + /// @see uint32 packSnorm3x10_1x2(vec4 const& v) + /// @see vec4 unpackUnorm3x10_1x2(uint32 const& p)) + /// @see uvec4 unpackI3x10_1x2(uint32 const& p) + /// @see uvec4 unpackU3x10_1x2(uint32 const& p) + GLM_FUNC_DECL vec4 unpackSnorm3x10_1x2(uint32 p); + + /// First, converts the first three components of the normalized floating-point value v into 10-bit unsigned integer values. + /// Then, converts the forth component of the normalized floating-point value v into 2-bit signed uninteger values. + /// Then, the results are packed into the returned 32-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packUnorm3x10_1x2(xyz): round(clamp(c, 0, +1) * 1023.0) + /// packUnorm3x10_1x2(w): round(clamp(c, 0, +1) * 3.0) + /// + /// The first vector component specifies the 10 least-significant bits of the result; + /// the forth component specifies the 2 most-significant bits. + /// + /// @see gtc_packing + /// @see vec4 unpackUnorm3x10_1x2(uint32 const& p) + /// @see uint32 packUnorm3x10_1x2(vec4 const& v) + /// @see uint32 packU3x10_1x2(uvec4 const& v) + /// @see uint32 packI3x10_1x2(ivec4 const& v) + GLM_FUNC_DECL uint32 packUnorm3x10_1x2(vec4 const& v); + + /// First, unpacks a single 32-bit unsigned integer p into four 16-bit signed integers. + /// Then, each component is converted to a normalized floating-point value to generate the returned four-component vector. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackSnorm3x10_1x2(xyz): clamp(f / 1023.0, 0, +1) + /// unpackSnorm3x10_1x2(w): clamp(f / 3.0, 0, +1) + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see gtc_packing + /// @see uint32 packSnorm3x10_1x2(vec4 const& v) + /// @see vec4 unpackInorm3x10_1x2(uint32 const& p)) + /// @see uvec4 unpackI3x10_1x2(uint32 const& p) + /// @see uvec4 unpackU3x10_1x2(uint32 const& p) + GLM_FUNC_DECL vec4 unpackUnorm3x10_1x2(uint32 p); + + /// First, converts the first two components of the normalized floating-point value v into 11-bit signless floating-point values. + /// Then, converts the third component of the normalized floating-point value v into a 10-bit signless floating-point value. + /// Then, the results are packed into the returned 32-bit unsigned integer. + /// + /// The first vector component specifies the 11 least-significant bits of the result; + /// the last component specifies the 10 most-significant bits. + /// + /// @see gtc_packing + /// @see vec3 unpackF2x11_1x10(uint32 const& p) + GLM_FUNC_DECL uint32 packF2x11_1x10(vec3 const& v); + + /// First, unpacks a single 32-bit unsigned integer p into two 11-bit signless floating-point values and one 10-bit signless floating-point value . + /// Then, each component is converted to a normalized floating-point value to generate the returned three-component vector. + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see gtc_packing + /// @see uint32 packF2x11_1x10(vec3 const& v) + GLM_FUNC_DECL vec3 unpackF2x11_1x10(uint32 p); + + + /// First, converts the first two components of the normalized floating-point value v into 11-bit signless floating-point values. + /// Then, converts the third component of the normalized floating-point value v into a 10-bit signless floating-point value. + /// Then, the results are packed into the returned 32-bit unsigned integer. + /// + /// The first vector component specifies the 11 least-significant bits of the result; + /// the last component specifies the 10 most-significant bits. + /// + /// packF3x9_E1x5 allows encoding into RGBE / RGB9E5 format + /// + /// @see gtc_packing + /// @see vec3 unpackF3x9_E1x5(uint32 const& p) + GLM_FUNC_DECL uint32 packF3x9_E1x5(vec3 const& v); + + /// First, unpacks a single 32-bit unsigned integer p into two 11-bit signless floating-point values and one 10-bit signless floating-point value . + /// Then, each component is converted to a normalized floating-point value to generate the returned three-component vector. + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// unpackF3x9_E1x5 allows decoding RGBE / RGB9E5 data + /// + /// @see gtc_packing + /// @see uint32 packF3x9_E1x5(vec3 const& v) + GLM_FUNC_DECL vec3 unpackF3x9_E1x5(uint32 p); + + /// Returns an unsigned integer vector obtained by converting the components of a floating-point vector + /// to the 16-bit floating-point representation found in the OpenGL Specification. + /// The first vector component specifies the 16 least-significant bits of the result; + /// the forth component specifies the 16 most-significant bits. + /// + /// @see gtc_packing + /// @see vec<3, T, Q> unpackRGBM(vec<4, T, Q> const& p) + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + template + GLM_FUNC_DECL vec<4, T, Q> packRGBM(vec<3, T, Q> const& rgb); + + /// Returns a floating-point vector with components obtained by reinterpreting an integer vector as 16-bit floating-point numbers and converting them to 32-bit floating-point values. + /// The first component of the vector is obtained from the 16 least-significant bits of v; + /// the forth component is obtained from the 16 most-significant bits of v. + /// + /// @see gtc_packing + /// @see vec<4, T, Q> packRGBM(vec<3, float, Q> const& v) + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + template + GLM_FUNC_DECL vec<3, T, Q> unpackRGBM(vec<4, T, Q> const& rgbm); + + /// Returns an unsigned integer vector obtained by converting the components of a floating-point vector + /// to the 16-bit floating-point representation found in the OpenGL Specification. + /// The first vector component specifies the 16 least-significant bits of the result; + /// the forth component specifies the 16 most-significant bits. + /// + /// @see gtc_packing + /// @see vec unpackHalf(vec const& p) + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + template + GLM_FUNC_DECL vec packHalf(vec const& v); + + /// Returns a floating-point vector with components obtained by reinterpreting an integer vector as 16-bit floating-point numbers and converting them to 32-bit floating-point values. + /// The first component of the vector is obtained from the 16 least-significant bits of v; + /// the forth component is obtained from the 16 most-significant bits of v. + /// + /// @see gtc_packing + /// @see vec packHalf(vec const& v) + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + template + GLM_FUNC_DECL vec unpackHalf(vec const& p); + + /// Convert each component of the normalized floating-point vector into unsigned integer values. + /// + /// @see gtc_packing + /// @see vec unpackUnorm(vec const& p); + template + GLM_FUNC_DECL vec packUnorm(vec const& v); + + /// Convert a packed integer to a normalized floating-point vector. + /// + /// @see gtc_packing + /// @see vec packUnorm(vec const& v) + template + GLM_FUNC_DECL vec unpackUnorm(vec const& v); + + /// Convert each component of the normalized floating-point vector into signed integer values. + /// + /// @see gtc_packing + /// @see vec unpackSnorm(vec const& p); + template + GLM_FUNC_DECL vec packSnorm(vec const& v); + + /// Convert a packed integer to a normalized floating-point vector. + /// + /// @see gtc_packing + /// @see vec packSnorm(vec const& v) + template + GLM_FUNC_DECL vec unpackSnorm(vec const& v); + + /// Convert each component of the normalized floating-point vector into unsigned integer values. + /// + /// @see gtc_packing + /// @see vec2 unpackUnorm2x4(uint8 p) + GLM_FUNC_DECL uint8 packUnorm2x4(vec2 const& v); + + /// Convert a packed integer to a normalized floating-point vector. + /// + /// @see gtc_packing + /// @see uint8 packUnorm2x4(vec2 const& v) + GLM_FUNC_DECL vec2 unpackUnorm2x4(uint8 p); + + /// Convert each component of the normalized floating-point vector into unsigned integer values. + /// + /// @see gtc_packing + /// @see vec4 unpackUnorm4x4(uint16 p) + GLM_FUNC_DECL uint16 packUnorm4x4(vec4 const& v); + + /// Convert a packed integer to a normalized floating-point vector. + /// + /// @see gtc_packing + /// @see uint16 packUnorm4x4(vec4 const& v) + GLM_FUNC_DECL vec4 unpackUnorm4x4(uint16 p); + + /// Convert each component of the normalized floating-point vector into unsigned integer values. + /// + /// @see gtc_packing + /// @see vec3 unpackUnorm1x5_1x6_1x5(uint16 p) + GLM_FUNC_DECL uint16 packUnorm1x5_1x6_1x5(vec3 const& v); + + /// Convert a packed integer to a normalized floating-point vector. + /// + /// @see gtc_packing + /// @see uint16 packUnorm1x5_1x6_1x5(vec3 const& v) + GLM_FUNC_DECL vec3 unpackUnorm1x5_1x6_1x5(uint16 p); + + /// Convert each component of the normalized floating-point vector into unsigned integer values. + /// + /// @see gtc_packing + /// @see vec4 unpackUnorm3x5_1x1(uint16 p) + GLM_FUNC_DECL uint16 packUnorm3x5_1x1(vec4 const& v); + + /// Convert a packed integer to a normalized floating-point vector. + /// + /// @see gtc_packing + /// @see uint16 packUnorm3x5_1x1(vec4 const& v) + GLM_FUNC_DECL vec4 unpackUnorm3x5_1x1(uint16 p); + + /// Convert each component of the normalized floating-point vector into unsigned integer values. + /// + /// @see gtc_packing + /// @see vec3 unpackUnorm2x3_1x2(uint8 p) + GLM_FUNC_DECL uint8 packUnorm2x3_1x2(vec3 const& v); + + /// Convert a packed integer to a normalized floating-point vector. + /// + /// @see gtc_packing + /// @see uint8 packUnorm2x3_1x2(vec3 const& v) + GLM_FUNC_DECL vec3 unpackUnorm2x3_1x2(uint8 p); + + + + /// Convert each component from an integer vector into a packed integer. + /// + /// @see gtc_packing + /// @see i8vec2 unpackInt2x8(int16 p) + GLM_FUNC_DECL int16 packInt2x8(i8vec2 const& v); + + /// Convert a packed integer into an integer vector. + /// + /// @see gtc_packing + /// @see int16 packInt2x8(i8vec2 const& v) + GLM_FUNC_DECL i8vec2 unpackInt2x8(int16 p); + + /// Convert each component from an integer vector into a packed unsigned integer. + /// + /// @see gtc_packing + /// @see u8vec2 unpackInt2x8(uint16 p) + GLM_FUNC_DECL uint16 packUint2x8(u8vec2 const& v); + + /// Convert a packed integer into an integer vector. + /// + /// @see gtc_packing + /// @see uint16 packInt2x8(u8vec2 const& v) + GLM_FUNC_DECL u8vec2 unpackUint2x8(uint16 p); + + /// Convert each component from an integer vector into a packed integer. + /// + /// @see gtc_packing + /// @see i8vec4 unpackInt4x8(int32 p) + GLM_FUNC_DECL int32 packInt4x8(i8vec4 const& v); + + /// Convert a packed integer into an integer vector. + /// + /// @see gtc_packing + /// @see int32 packInt2x8(i8vec4 const& v) + GLM_FUNC_DECL i8vec4 unpackInt4x8(int32 p); + + /// Convert each component from an integer vector into a packed unsigned integer. + /// + /// @see gtc_packing + /// @see u8vec4 unpackUint4x8(uint32 p) + GLM_FUNC_DECL uint32 packUint4x8(u8vec4 const& v); + + /// Convert a packed integer into an integer vector. + /// + /// @see gtc_packing + /// @see uint32 packUint4x8(u8vec2 const& v) + GLM_FUNC_DECL u8vec4 unpackUint4x8(uint32 p); + + /// Convert each component from an integer vector into a packed integer. + /// + /// @see gtc_packing + /// @see i16vec2 unpackInt2x16(int p) + GLM_FUNC_DECL int packInt2x16(i16vec2 const& v); + + /// Convert a packed integer into an integer vector. + /// + /// @see gtc_packing + /// @see int packInt2x16(i16vec2 const& v) + GLM_FUNC_DECL i16vec2 unpackInt2x16(int p); + + /// Convert each component from an integer vector into a packed integer. + /// + /// @see gtc_packing + /// @see i16vec4 unpackInt4x16(int64 p) + GLM_FUNC_DECL int64 packInt4x16(i16vec4 const& v); + + /// Convert a packed integer into an integer vector. + /// + /// @see gtc_packing + /// @see int64 packInt4x16(i16vec4 const& v) + GLM_FUNC_DECL i16vec4 unpackInt4x16(int64 p); + + /// Convert each component from an integer vector into a packed unsigned integer. + /// + /// @see gtc_packing + /// @see u16vec2 unpackUint2x16(uint p) + GLM_FUNC_DECL uint packUint2x16(u16vec2 const& v); + + /// Convert a packed integer into an integer vector. + /// + /// @see gtc_packing + /// @see uint packUint2x16(u16vec2 const& v) + GLM_FUNC_DECL u16vec2 unpackUint2x16(uint p); + + /// Convert each component from an integer vector into a packed unsigned integer. + /// + /// @see gtc_packing + /// @see u16vec4 unpackUint4x16(uint64 p) + GLM_FUNC_DECL uint64 packUint4x16(u16vec4 const& v); + + /// Convert a packed integer into an integer vector. + /// + /// @see gtc_packing + /// @see uint64 packUint4x16(u16vec4 const& v) + GLM_FUNC_DECL u16vec4 unpackUint4x16(uint64 p); + + /// Convert each component from an integer vector into a packed integer. + /// + /// @see gtc_packing + /// @see i32vec2 unpackInt2x32(int p) + GLM_FUNC_DECL int64 packInt2x32(i32vec2 const& v); + + /// Convert a packed integer into an integer vector. + /// + /// @see gtc_packing + /// @see int packInt2x16(i32vec2 const& v) + GLM_FUNC_DECL i32vec2 unpackInt2x32(int64 p); + + /// Convert each component from an integer vector into a packed unsigned integer. + /// + /// @see gtc_packing + /// @see u32vec2 unpackUint2x32(int p) + GLM_FUNC_DECL uint64 packUint2x32(u32vec2 const& v); + + /// Convert a packed integer into an integer vector. + /// + /// @see gtc_packing + /// @see int packUint2x16(u32vec2 const& v) + GLM_FUNC_DECL u32vec2 unpackUint2x32(uint64 p); + + /// @} +}// namespace glm + +#include "packing.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/packing.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/packing.inl new file mode 100644 index 0000000000000000000000000000000000000000..84ad60c70f8584640631fd95a2a9d8f53d4fcb98 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/packing.inl @@ -0,0 +1,938 @@ +/// @ref gtc_packing + +#include "../ext/scalar_relational.hpp" +#include "../ext/vector_relational.hpp" +#include "../common.hpp" +#include "../vec2.hpp" +#include "../vec3.hpp" +#include "../vec4.hpp" +#include "../detail/type_half.hpp" +#include +#include + +namespace glm{ +namespace detail +{ + GLM_FUNC_QUALIFIER glm::uint16 float2half(glm::uint32 f) + { + // 10 bits => EE EEEFFFFF + // 11 bits => EEE EEFFFFFF + // Half bits => SEEEEEFF FFFFFFFF + // Float bits => SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF + + // 0x00007c00 => 00000000 00000000 01111100 00000000 + // 0x000003ff => 00000000 00000000 00000011 11111111 + // 0x38000000 => 00111000 00000000 00000000 00000000 + // 0x7f800000 => 01111111 10000000 00000000 00000000 + // 0x00008000 => 00000000 00000000 10000000 00000000 + return + ((f >> 16) & 0x8000) | // sign + ((((f & 0x7f800000) - 0x38000000) >> 13) & 0x7c00) | // exponential + ((f >> 13) & 0x03ff); // Mantissa + } + + GLM_FUNC_QUALIFIER glm::uint32 float2packed11(glm::uint32 f) + { + // 10 bits => EE EEEFFFFF + // 11 bits => EEE EEFFFFFF + // Half bits => SEEEEEFF FFFFFFFF + // Float bits => SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF + + // 0x000007c0 => 00000000 00000000 00000111 11000000 + // 0x00007c00 => 00000000 00000000 01111100 00000000 + // 0x000003ff => 00000000 00000000 00000011 11111111 + // 0x38000000 => 00111000 00000000 00000000 00000000 + // 0x7f800000 => 01111111 10000000 00000000 00000000 + // 0x00008000 => 00000000 00000000 10000000 00000000 + return + ((((f & 0x7f800000) - 0x38000000) >> 17) & 0x07c0) | // exponential + ((f >> 17) & 0x003f); // Mantissa + } + + GLM_FUNC_QUALIFIER glm::uint32 packed11ToFloat(glm::uint32 p) + { + // 10 bits => EE EEEFFFFF + // 11 bits => EEE EEFFFFFF + // Half bits => SEEEEEFF FFFFFFFF + // Float bits => SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF + + // 0x000007c0 => 00000000 00000000 00000111 11000000 + // 0x00007c00 => 00000000 00000000 01111100 00000000 + // 0x000003ff => 00000000 00000000 00000011 11111111 + // 0x38000000 => 00111000 00000000 00000000 00000000 + // 0x7f800000 => 01111111 10000000 00000000 00000000 + // 0x00008000 => 00000000 00000000 10000000 00000000 + return + ((((p & 0x07c0) << 17) + 0x38000000) & 0x7f800000) | // exponential + ((p & 0x003f) << 17); // Mantissa + } + + GLM_FUNC_QUALIFIER glm::uint32 float2packed10(glm::uint32 f) + { + // 10 bits => EE EEEFFFFF + // 11 bits => EEE EEFFFFFF + // Half bits => SEEEEEFF FFFFFFFF + // Float bits => SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF + + // 0x0000001F => 00000000 00000000 00000000 00011111 + // 0x0000003F => 00000000 00000000 00000000 00111111 + // 0x000003E0 => 00000000 00000000 00000011 11100000 + // 0x000007C0 => 00000000 00000000 00000111 11000000 + // 0x00007C00 => 00000000 00000000 01111100 00000000 + // 0x000003FF => 00000000 00000000 00000011 11111111 + // 0x38000000 => 00111000 00000000 00000000 00000000 + // 0x7f800000 => 01111111 10000000 00000000 00000000 + // 0x00008000 => 00000000 00000000 10000000 00000000 + return + ((((f & 0x7f800000) - 0x38000000) >> 18) & 0x03E0) | // exponential + ((f >> 18) & 0x001f); // Mantissa + } + + GLM_FUNC_QUALIFIER glm::uint32 packed10ToFloat(glm::uint32 p) + { + // 10 bits => EE EEEFFFFF + // 11 bits => EEE EEFFFFFF + // Half bits => SEEEEEFF FFFFFFFF + // Float bits => SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF + + // 0x0000001F => 00000000 00000000 00000000 00011111 + // 0x0000003F => 00000000 00000000 00000000 00111111 + // 0x000003E0 => 00000000 00000000 00000011 11100000 + // 0x000007C0 => 00000000 00000000 00000111 11000000 + // 0x00007C00 => 00000000 00000000 01111100 00000000 + // 0x000003FF => 00000000 00000000 00000011 11111111 + // 0x38000000 => 00111000 00000000 00000000 00000000 + // 0x7f800000 => 01111111 10000000 00000000 00000000 + // 0x00008000 => 00000000 00000000 10000000 00000000 + return + ((((p & 0x03E0) << 18) + 0x38000000) & 0x7f800000) | // exponential + ((p & 0x001f) << 18); // Mantissa + } + + GLM_FUNC_QUALIFIER glm::uint half2float(glm::uint h) + { + return ((h & 0x8000) << 16) | ((( h & 0x7c00) + 0x1C000) << 13) | ((h & 0x03FF) << 13); + } + + GLM_FUNC_QUALIFIER glm::uint floatTo11bit(float x) + { + if(x == 0.0f) + return 0u; + else if(glm::isnan(x)) + return ~0u; + else if(glm::isinf(x)) + return 0x1Fu << 6u; + + uint Pack = 0u; + memcpy(&Pack, &x, sizeof(Pack)); + return float2packed11(Pack); + } + + GLM_FUNC_QUALIFIER float packed11bitToFloat(glm::uint x) + { + if(x == 0) + return 0.0f; + else if(x == ((1 << 11) - 1)) + return ~0;//NaN + else if(x == (0x1f << 6)) + return ~0;//Inf + + uint Result = packed11ToFloat(x); + + float Temp = 0; + memcpy(&Temp, &Result, sizeof(Temp)); + return Temp; + } + + GLM_FUNC_QUALIFIER glm::uint floatTo10bit(float x) + { + if(x == 0.0f) + return 0u; + else if(glm::isnan(x)) + return ~0u; + else if(glm::isinf(x)) + return 0x1Fu << 5u; + + uint Pack = 0; + memcpy(&Pack, &x, sizeof(Pack)); + return float2packed10(Pack); + } + + GLM_FUNC_QUALIFIER float packed10bitToFloat(glm::uint x) + { + if(x == 0) + return 0.0f; + else if(x == ((1 << 10) - 1)) + return ~0;//NaN + else if(x == (0x1f << 5)) + return ~0;//Inf + + uint Result = packed10ToFloat(x); + + float Temp = 0; + memcpy(&Temp, &Result, sizeof(Temp)); + return Temp; + } + +// GLM_FUNC_QUALIFIER glm::uint f11_f11_f10(float x, float y, float z) +// { +// return ((floatTo11bit(x) & ((1 << 11) - 1)) << 0) | ((floatTo11bit(y) & ((1 << 11) - 1)) << 11) | ((floatTo10bit(z) & ((1 << 10) - 1)) << 22); +// } + + union u3u3u2 + { + struct + { + uint x : 3; + uint y : 3; + uint z : 2; + } data; + uint8 pack; + }; + + union u4u4 + { + struct + { + uint x : 4; + uint y : 4; + } data; + uint8 pack; + }; + + union u4u4u4u4 + { + struct + { + uint x : 4; + uint y : 4; + uint z : 4; + uint w : 4; + } data; + uint16 pack; + }; + + union u5u6u5 + { + struct + { + uint x : 5; + uint y : 6; + uint z : 5; + } data; + uint16 pack; + }; + + union u5u5u5u1 + { + struct + { + uint x : 5; + uint y : 5; + uint z : 5; + uint w : 1; + } data; + uint16 pack; + }; + + union u10u10u10u2 + { + struct + { + uint x : 10; + uint y : 10; + uint z : 10; + uint w : 2; + } data; + uint32 pack; + }; + + union i10i10i10i2 + { + struct + { + int x : 10; + int y : 10; + int z : 10; + int w : 2; + } data; + uint32 pack; + }; + + union u9u9u9e5 + { + struct + { + uint x : 9; + uint y : 9; + uint z : 9; + uint w : 5; + } data; + uint32 pack; + }; + + template + struct compute_half + {}; + + template + struct compute_half<1, Q> + { + GLM_FUNC_QUALIFIER static vec<1, uint16, Q> pack(vec<1, float, Q> const& v) + { + int16 const Unpack(detail::toFloat16(v.x)); + u16vec1 Packed; + memcpy(&Packed, &Unpack, sizeof(Packed)); + return Packed; + } + + GLM_FUNC_QUALIFIER static vec<1, float, Q> unpack(vec<1, uint16, Q> const& v) + { + i16vec1 Unpack; + memcpy(&Unpack, &v, sizeof(Unpack)); + return vec<1, float, Q>(detail::toFloat32(v.x)); + } + }; + + template + struct compute_half<2, Q> + { + GLM_FUNC_QUALIFIER static vec<2, uint16, Q> pack(vec<2, float, Q> const& v) + { + vec<2, int16, Q> const Unpack(detail::toFloat16(v.x), detail::toFloat16(v.y)); + u16vec2 Packed; + memcpy(&Packed, &Unpack, sizeof(Packed)); + return Packed; + } + + GLM_FUNC_QUALIFIER static vec<2, float, Q> unpack(vec<2, uint16, Q> const& v) + { + i16vec2 Unpack; + memcpy(&Unpack, &v, sizeof(Unpack)); + return vec<2, float, Q>(detail::toFloat32(v.x), detail::toFloat32(v.y)); + } + }; + + template + struct compute_half<3, Q> + { + GLM_FUNC_QUALIFIER static vec<3, uint16, Q> pack(vec<3, float, Q> const& v) + { + vec<3, int16, Q> const Unpack(detail::toFloat16(v.x), detail::toFloat16(v.y), detail::toFloat16(v.z)); + u16vec3 Packed; + memcpy(&Packed, &Unpack, sizeof(Packed)); + return Packed; + } + + GLM_FUNC_QUALIFIER static vec<3, float, Q> unpack(vec<3, uint16, Q> const& v) + { + i16vec3 Unpack; + memcpy(&Unpack, &v, sizeof(Unpack)); + return vec<3, float, Q>(detail::toFloat32(v.x), detail::toFloat32(v.y), detail::toFloat32(v.z)); + } + }; + + template + struct compute_half<4, Q> + { + GLM_FUNC_QUALIFIER static vec<4, uint16, Q> pack(vec<4, float, Q> const& v) + { + vec<4, int16, Q> const Unpack(detail::toFloat16(v.x), detail::toFloat16(v.y), detail::toFloat16(v.z), detail::toFloat16(v.w)); + u16vec4 Packed; + memcpy(&Packed, &Unpack, sizeof(Packed)); + return Packed; + } + + GLM_FUNC_QUALIFIER static vec<4, float, Q> unpack(vec<4, uint16, Q> const& v) + { + i16vec4 Unpack; + memcpy(&Unpack, &v, sizeof(Unpack)); + return vec<4, float, Q>(detail::toFloat32(v.x), detail::toFloat32(v.y), detail::toFloat32(v.z), detail::toFloat32(v.w)); + } + }; +}//namespace detail + + GLM_FUNC_QUALIFIER uint8 packUnorm1x8(float v) + { + return static_cast(round(clamp(v, 0.0f, 1.0f) * 255.0f)); + } + + GLM_FUNC_QUALIFIER float unpackUnorm1x8(uint8 p) + { + float const Unpack(p); + return Unpack * static_cast(0.0039215686274509803921568627451); // 1 / 255 + } + + GLM_FUNC_QUALIFIER uint16 packUnorm2x8(vec2 const& v) + { + u8vec2 const Topack(round(clamp(v, 0.0f, 1.0f) * 255.0f)); + + uint16 Unpack = 0; + memcpy(&Unpack, &Topack, sizeof(Unpack)); + return Unpack; + } + + GLM_FUNC_QUALIFIER vec2 unpackUnorm2x8(uint16 p) + { + u8vec2 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return vec2(Unpack) * float(0.0039215686274509803921568627451); // 1 / 255 + } + + GLM_FUNC_QUALIFIER uint8 packSnorm1x8(float v) + { + int8 const Topack(static_cast(round(clamp(v ,-1.0f, 1.0f) * 127.0f))); + uint8 Packed = 0; + memcpy(&Packed, &Topack, sizeof(Packed)); + return Packed; + } + + GLM_FUNC_QUALIFIER float unpackSnorm1x8(uint8 p) + { + int8 Unpack = 0; + memcpy(&Unpack, &p, sizeof(Unpack)); + return clamp( + static_cast(Unpack) * 0.00787401574803149606299212598425f, // 1.0f / 127.0f + -1.0f, 1.0f); + } + + GLM_FUNC_QUALIFIER uint16 packSnorm2x8(vec2 const& v) + { + i8vec2 const Topack(round(clamp(v, -1.0f, 1.0f) * 127.0f)); + uint16 Packed = 0; + memcpy(&Packed, &Topack, sizeof(Packed)); + return Packed; + } + + GLM_FUNC_QUALIFIER vec2 unpackSnorm2x8(uint16 p) + { + i8vec2 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return clamp( + vec2(Unpack) * 0.00787401574803149606299212598425f, // 1.0f / 127.0f + -1.0f, 1.0f); + } + + GLM_FUNC_QUALIFIER uint16 packUnorm1x16(float s) + { + return static_cast(round(clamp(s, 0.0f, 1.0f) * 65535.0f)); + } + + GLM_FUNC_QUALIFIER float unpackUnorm1x16(uint16 p) + { + float const Unpack(p); + return Unpack * 1.5259021896696421759365224689097e-5f; // 1.0 / 65535.0 + } + + GLM_FUNC_QUALIFIER uint64 packUnorm4x16(vec4 const& v) + { + u16vec4 const Topack(round(clamp(v , 0.0f, 1.0f) * 65535.0f)); + uint64 Packed = 0; + memcpy(&Packed, &Topack, sizeof(Packed)); + return Packed; + } + + GLM_FUNC_QUALIFIER vec4 unpackUnorm4x16(uint64 p) + { + u16vec4 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return vec4(Unpack) * 1.5259021896696421759365224689097e-5f; // 1.0 / 65535.0 + } + + GLM_FUNC_QUALIFIER uint16 packSnorm1x16(float v) + { + int16 const Topack = static_cast(round(clamp(v ,-1.0f, 1.0f) * 32767.0f)); + uint16 Packed = 0; + memcpy(&Packed, &Topack, sizeof(Packed)); + return Packed; + } + + GLM_FUNC_QUALIFIER float unpackSnorm1x16(uint16 p) + { + int16 Unpack = 0; + memcpy(&Unpack, &p, sizeof(Unpack)); + return clamp( + static_cast(Unpack) * 3.0518509475997192297128208258309e-5f, //1.0f / 32767.0f, + -1.0f, 1.0f); + } + + GLM_FUNC_QUALIFIER uint64 packSnorm4x16(vec4 const& v) + { + i16vec4 const Topack(round(clamp(v ,-1.0f, 1.0f) * 32767.0f)); + uint64 Packed = 0; + memcpy(&Packed, &Topack, sizeof(Packed)); + return Packed; + } + + GLM_FUNC_QUALIFIER vec4 unpackSnorm4x16(uint64 p) + { + i16vec4 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return clamp( + vec4(Unpack) * 3.0518509475997192297128208258309e-5f, //1.0f / 32767.0f, + -1.0f, 1.0f); + } + + GLM_FUNC_QUALIFIER uint16 packHalf1x16(float v) + { + int16 const Topack(detail::toFloat16(v)); + uint16 Packed = 0; + memcpy(&Packed, &Topack, sizeof(Packed)); + return Packed; + } + + GLM_FUNC_QUALIFIER float unpackHalf1x16(uint16 v) + { + int16 Unpack = 0; + memcpy(&Unpack, &v, sizeof(Unpack)); + return detail::toFloat32(Unpack); + } + + GLM_FUNC_QUALIFIER uint64 packHalf4x16(glm::vec4 const& v) + { + i16vec4 const Unpack( + detail::toFloat16(v.x), + detail::toFloat16(v.y), + detail::toFloat16(v.z), + detail::toFloat16(v.w)); + uint64 Packed = 0; + memcpy(&Packed, &Unpack, sizeof(Packed)); + return Packed; + } + + GLM_FUNC_QUALIFIER glm::vec4 unpackHalf4x16(uint64 v) + { + i16vec4 Unpack; + memcpy(&Unpack, &v, sizeof(Unpack)); + return vec4( + detail::toFloat32(Unpack.x), + detail::toFloat32(Unpack.y), + detail::toFloat32(Unpack.z), + detail::toFloat32(Unpack.w)); + } + + GLM_FUNC_QUALIFIER uint32 packI3x10_1x2(ivec4 const& v) + { + detail::i10i10i10i2 Result; + Result.data.x = v.x; + Result.data.y = v.y; + Result.data.z = v.z; + Result.data.w = v.w; + return Result.pack; + } + + GLM_FUNC_QUALIFIER ivec4 unpackI3x10_1x2(uint32 v) + { + detail::i10i10i10i2 Unpack; + Unpack.pack = v; + return ivec4( + Unpack.data.x, + Unpack.data.y, + Unpack.data.z, + Unpack.data.w); + } + + GLM_FUNC_QUALIFIER uint32 packU3x10_1x2(uvec4 const& v) + { + detail::u10u10u10u2 Result; + Result.data.x = v.x; + Result.data.y = v.y; + Result.data.z = v.z; + Result.data.w = v.w; + return Result.pack; + } + + GLM_FUNC_QUALIFIER uvec4 unpackU3x10_1x2(uint32 v) + { + detail::u10u10u10u2 Unpack; + Unpack.pack = v; + return uvec4( + Unpack.data.x, + Unpack.data.y, + Unpack.data.z, + Unpack.data.w); + } + + GLM_FUNC_QUALIFIER uint32 packSnorm3x10_1x2(vec4 const& v) + { + ivec4 const Pack(round(clamp(v,-1.0f, 1.0f) * vec4(511.f, 511.f, 511.f, 1.f))); + + detail::i10i10i10i2 Result; + Result.data.x = Pack.x; + Result.data.y = Pack.y; + Result.data.z = Pack.z; + Result.data.w = Pack.w; + return Result.pack; + } + + GLM_FUNC_QUALIFIER vec4 unpackSnorm3x10_1x2(uint32 v) + { + detail::i10i10i10i2 Unpack; + Unpack.pack = v; + + vec4 const Result(Unpack.data.x, Unpack.data.y, Unpack.data.z, Unpack.data.w); + + return clamp(Result * vec4(1.f / 511.f, 1.f / 511.f, 1.f / 511.f, 1.f), -1.0f, 1.0f); + } + + GLM_FUNC_QUALIFIER uint32 packUnorm3x10_1x2(vec4 const& v) + { + uvec4 const Unpack(round(clamp(v, 0.0f, 1.0f) * vec4(1023.f, 1023.f, 1023.f, 3.f))); + + detail::u10u10u10u2 Result; + Result.data.x = Unpack.x; + Result.data.y = Unpack.y; + Result.data.z = Unpack.z; + Result.data.w = Unpack.w; + return Result.pack; + } + + GLM_FUNC_QUALIFIER vec4 unpackUnorm3x10_1x2(uint32 v) + { + vec4 const ScaleFactors(1.0f / 1023.f, 1.0f / 1023.f, 1.0f / 1023.f, 1.0f / 3.f); + + detail::u10u10u10u2 Unpack; + Unpack.pack = v; + return vec4(Unpack.data.x, Unpack.data.y, Unpack.data.z, Unpack.data.w) * ScaleFactors; + } + + GLM_FUNC_QUALIFIER uint32 packF2x11_1x10(vec3 const& v) + { + return + ((detail::floatTo11bit(v.x) & ((1 << 11) - 1)) << 0) | + ((detail::floatTo11bit(v.y) & ((1 << 11) - 1)) << 11) | + ((detail::floatTo10bit(v.z) & ((1 << 10) - 1)) << 22); + } + + GLM_FUNC_QUALIFIER vec3 unpackF2x11_1x10(uint32 v) + { + return vec3( + detail::packed11bitToFloat(v >> 0), + detail::packed11bitToFloat(v >> 11), + detail::packed10bitToFloat(v >> 22)); + } + + GLM_FUNC_QUALIFIER uint32 packF3x9_E1x5(vec3 const& v) + { + float const SharedExpMax = (pow(2.0f, 9.0f - 1.0f) / pow(2.0f, 9.0f)) * pow(2.0f, 31.f - 15.f); + vec3 const Color = clamp(v, 0.0f, SharedExpMax); + float const MaxColor = max(Color.x, max(Color.y, Color.z)); + + float const ExpSharedP = max(-15.f - 1.f, floor(log2(MaxColor))) + 1.0f + 15.f; + float const MaxShared = floor(MaxColor / pow(2.0f, (ExpSharedP - 15.f - 9.f)) + 0.5f); + float const ExpShared = equal(MaxShared, pow(2.0f, 9.0f), epsilon()) ? ExpSharedP + 1.0f : ExpSharedP; + + uvec3 const ColorComp(floor(Color / pow(2.f, (ExpShared - 15.f - 9.f)) + 0.5f)); + + detail::u9u9u9e5 Unpack; + Unpack.data.x = ColorComp.x; + Unpack.data.y = ColorComp.y; + Unpack.data.z = ColorComp.z; + Unpack.data.w = uint(ExpShared); + return Unpack.pack; + } + + GLM_FUNC_QUALIFIER vec3 unpackF3x9_E1x5(uint32 v) + { + detail::u9u9u9e5 Unpack; + Unpack.pack = v; + + return vec3(Unpack.data.x, Unpack.data.y, Unpack.data.z) * pow(2.0f, Unpack.data.w - 15.f - 9.f); + } + + // Based on Brian Karis http://graphicrants.blogspot.fr/2009/04/rgbm-color-encoding.html + template + GLM_FUNC_QUALIFIER vec<4, T, Q> packRGBM(vec<3, T, Q> const& rgb) + { + vec<3, T, Q> const Color(rgb * static_cast(1.0 / 6.0)); + T Alpha = clamp(max(max(Color.x, Color.y), max(Color.z, static_cast(1e-6))), static_cast(0), static_cast(1)); + Alpha = ceil(Alpha * static_cast(255.0)) / static_cast(255.0); + return vec<4, T, Q>(Color / Alpha, Alpha); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> unpackRGBM(vec<4, T, Q> const& rgbm) + { + return vec<3, T, Q>(rgbm.x, rgbm.y, rgbm.z) * rgbm.w * static_cast(6); + } + + template + GLM_FUNC_QUALIFIER vec packHalf(vec const& v) + { + return detail::compute_half::pack(v); + } + + template + GLM_FUNC_QUALIFIER vec unpackHalf(vec const& v) + { + return detail::compute_half::unpack(v); + } + + template + GLM_FUNC_QUALIFIER vec packUnorm(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "uintType must be an integer type"); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "floatType must be a floating point type"); + + return vec(round(clamp(v, static_cast(0), static_cast(1)) * static_cast(std::numeric_limits::max()))); + } + + template + GLM_FUNC_QUALIFIER vec unpackUnorm(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "uintType must be an integer type"); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "floatType must be a floating point type"); + + return vec(v) * (static_cast(1) / static_cast(std::numeric_limits::max())); + } + + template + GLM_FUNC_QUALIFIER vec packSnorm(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "uintType must be an integer type"); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "floatType must be a floating point type"); + + return vec(round(clamp(v , static_cast(-1), static_cast(1)) * static_cast(std::numeric_limits::max()))); + } + + template + GLM_FUNC_QUALIFIER vec unpackSnorm(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "uintType must be an integer type"); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "floatType must be a floating point type"); + + return clamp(vec(v) * (static_cast(1) / static_cast(std::numeric_limits::max())), static_cast(-1), static_cast(1)); + } + + GLM_FUNC_QUALIFIER uint8 packUnorm2x4(vec2 const& v) + { + u32vec2 const Unpack(round(clamp(v, 0.0f, 1.0f) * 15.0f)); + detail::u4u4 Result; + Result.data.x = Unpack.x; + Result.data.y = Unpack.y; + return Result.pack; + } + + GLM_FUNC_QUALIFIER vec2 unpackUnorm2x4(uint8 v) + { + float const ScaleFactor(1.f / 15.f); + detail::u4u4 Unpack; + Unpack.pack = v; + return vec2(Unpack.data.x, Unpack.data.y) * ScaleFactor; + } + + GLM_FUNC_QUALIFIER uint16 packUnorm4x4(vec4 const& v) + { + u32vec4 const Unpack(round(clamp(v, 0.0f, 1.0f) * 15.0f)); + detail::u4u4u4u4 Result; + Result.data.x = Unpack.x; + Result.data.y = Unpack.y; + Result.data.z = Unpack.z; + Result.data.w = Unpack.w; + return Result.pack; + } + + GLM_FUNC_QUALIFIER vec4 unpackUnorm4x4(uint16 v) + { + float const ScaleFactor(1.f / 15.f); + detail::u4u4u4u4 Unpack; + Unpack.pack = v; + return vec4(Unpack.data.x, Unpack.data.y, Unpack.data.z, Unpack.data.w) * ScaleFactor; + } + + GLM_FUNC_QUALIFIER uint16 packUnorm1x5_1x6_1x5(vec3 const& v) + { + u32vec3 const Unpack(round(clamp(v, 0.0f, 1.0f) * vec3(31.f, 63.f, 31.f))); + detail::u5u6u5 Result; + Result.data.x = Unpack.x; + Result.data.y = Unpack.y; + Result.data.z = Unpack.z; + return Result.pack; + } + + GLM_FUNC_QUALIFIER vec3 unpackUnorm1x5_1x6_1x5(uint16 v) + { + vec3 const ScaleFactor(1.f / 31.f, 1.f / 63.f, 1.f / 31.f); + detail::u5u6u5 Unpack; + Unpack.pack = v; + return vec3(Unpack.data.x, Unpack.data.y, Unpack.data.z) * ScaleFactor; + } + + GLM_FUNC_QUALIFIER uint16 packUnorm3x5_1x1(vec4 const& v) + { + u32vec4 const Unpack(round(clamp(v, 0.0f, 1.0f) * vec4(31.f, 31.f, 31.f, 1.f))); + detail::u5u5u5u1 Result; + Result.data.x = Unpack.x; + Result.data.y = Unpack.y; + Result.data.z = Unpack.z; + Result.data.w = Unpack.w; + return Result.pack; + } + + GLM_FUNC_QUALIFIER vec4 unpackUnorm3x5_1x1(uint16 v) + { + vec4 const ScaleFactor(1.f / 31.f, 1.f / 31.f, 1.f / 31.f, 1.f); + detail::u5u5u5u1 Unpack; + Unpack.pack = v; + return vec4(Unpack.data.x, Unpack.data.y, Unpack.data.z, Unpack.data.w) * ScaleFactor; + } + + GLM_FUNC_QUALIFIER uint8 packUnorm2x3_1x2(vec3 const& v) + { + u32vec3 const Unpack(round(clamp(v, 0.0f, 1.0f) * vec3(7.f, 7.f, 3.f))); + detail::u3u3u2 Result; + Result.data.x = Unpack.x; + Result.data.y = Unpack.y; + Result.data.z = Unpack.z; + return Result.pack; + } + + GLM_FUNC_QUALIFIER vec3 unpackUnorm2x3_1x2(uint8 v) + { + vec3 const ScaleFactor(1.f / 7.f, 1.f / 7.f, 1.f / 3.f); + detail::u3u3u2 Unpack; + Unpack.pack = v; + return vec3(Unpack.data.x, Unpack.data.y, Unpack.data.z) * ScaleFactor; + } + + GLM_FUNC_QUALIFIER int16 packInt2x8(i8vec2 const& v) + { + int16 Pack = 0; + memcpy(&Pack, &v, sizeof(Pack)); + return Pack; + } + + GLM_FUNC_QUALIFIER i8vec2 unpackInt2x8(int16 p) + { + i8vec2 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return Unpack; + } + + GLM_FUNC_QUALIFIER uint16 packUint2x8(u8vec2 const& v) + { + uint16 Pack = 0; + memcpy(&Pack, &v, sizeof(Pack)); + return Pack; + } + + GLM_FUNC_QUALIFIER u8vec2 unpackUint2x8(uint16 p) + { + u8vec2 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return Unpack; + } + + GLM_FUNC_QUALIFIER int32 packInt4x8(i8vec4 const& v) + { + int32 Pack = 0; + memcpy(&Pack, &v, sizeof(Pack)); + return Pack; + } + + GLM_FUNC_QUALIFIER i8vec4 unpackInt4x8(int32 p) + { + i8vec4 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return Unpack; + } + + GLM_FUNC_QUALIFIER uint32 packUint4x8(u8vec4 const& v) + { + uint32 Pack = 0; + memcpy(&Pack, &v, sizeof(Pack)); + return Pack; + } + + GLM_FUNC_QUALIFIER u8vec4 unpackUint4x8(uint32 p) + { + u8vec4 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return Unpack; + } + + GLM_FUNC_QUALIFIER int packInt2x16(i16vec2 const& v) + { + int Pack = 0; + memcpy(&Pack, &v, sizeof(Pack)); + return Pack; + } + + GLM_FUNC_QUALIFIER i16vec2 unpackInt2x16(int p) + { + i16vec2 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return Unpack; + } + + GLM_FUNC_QUALIFIER int64 packInt4x16(i16vec4 const& v) + { + int64 Pack = 0; + memcpy(&Pack, &v, sizeof(Pack)); + return Pack; + } + + GLM_FUNC_QUALIFIER i16vec4 unpackInt4x16(int64 p) + { + i16vec4 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return Unpack; + } + + GLM_FUNC_QUALIFIER uint packUint2x16(u16vec2 const& v) + { + uint Pack = 0; + memcpy(&Pack, &v, sizeof(Pack)); + return Pack; + } + + GLM_FUNC_QUALIFIER u16vec2 unpackUint2x16(uint p) + { + u16vec2 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return Unpack; + } + + GLM_FUNC_QUALIFIER uint64 packUint4x16(u16vec4 const& v) + { + uint64 Pack = 0; + memcpy(&Pack, &v, sizeof(Pack)); + return Pack; + } + + GLM_FUNC_QUALIFIER u16vec4 unpackUint4x16(uint64 p) + { + u16vec4 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return Unpack; + } + + GLM_FUNC_QUALIFIER int64 packInt2x32(i32vec2 const& v) + { + int64 Pack = 0; + memcpy(&Pack, &v, sizeof(Pack)); + return Pack; + } + + GLM_FUNC_QUALIFIER i32vec2 unpackInt2x32(int64 p) + { + i32vec2 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return Unpack; + } + + GLM_FUNC_QUALIFIER uint64 packUint2x32(u32vec2 const& v) + { + uint64 Pack = 0; + memcpy(&Pack, &v, sizeof(Pack)); + return Pack; + } + + GLM_FUNC_QUALIFIER u32vec2 unpackUint2x32(uint64 p) + { + u32vec2 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return Unpack; + } +}//namespace glm + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/quaternion.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/quaternion.hpp new file mode 100644 index 0000000000000000000000000000000000000000..359e072b9fa8d7667d54f3afc8ba63ec23563ddf --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/quaternion.hpp @@ -0,0 +1,173 @@ +/// @ref gtc_quaternion +/// @file glm/gtc/quaternion.hpp +/// +/// @see core (dependence) +/// @see gtc_constants (dependence) +/// +/// @defgroup gtc_quaternion GLM_GTC_quaternion +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Defines a templated quaternion type and several quaternion operations. + +#pragma once + +// Dependency: +#include "../gtc/constants.hpp" +#include "../gtc/matrix_transform.hpp" +#include "../ext/vector_relational.hpp" +#include "../ext/quaternion_common.hpp" +#include "../ext/quaternion_float.hpp" +#include "../ext/quaternion_float_precision.hpp" +#include "../ext/quaternion_double.hpp" +#include "../ext/quaternion_double_precision.hpp" +#include "../ext/quaternion_relational.hpp" +#include "../ext/quaternion_geometric.hpp" +#include "../ext/quaternion_trigonometric.hpp" +#include "../ext/quaternion_transform.hpp" +#include "../detail/type_mat3x3.hpp" +#include "../detail/type_mat4x4.hpp" +#include "../detail/type_vec3.hpp" +#include "../detail/type_vec4.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_quaternion extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_quaternion + /// @{ + + /// Returns euler angles, pitch as x, yaw as y, roll as z. + /// The result is expressed in radians. + /// + /// @tparam T Floating-point scalar types. + /// + /// @see gtc_quaternion + template + GLM_FUNC_DECL vec<3, T, Q> eulerAngles(qua const& x); + + /// Returns roll value of euler angles expressed in radians. + /// + /// @tparam T Floating-point scalar types. + /// + /// @see gtc_quaternion + template + GLM_FUNC_DECL T roll(qua const& x); + + /// Returns pitch value of euler angles expressed in radians. + /// + /// @tparam T Floating-point scalar types. + /// + /// @see gtc_quaternion + template + GLM_FUNC_DECL T pitch(qua const& x); + + /// Returns yaw value of euler angles expressed in radians. + /// + /// @tparam T Floating-point scalar types. + /// + /// @see gtc_quaternion + template + GLM_FUNC_DECL T yaw(qua const& x); + + /// Converts a quaternion to a 3 * 3 matrix. + /// + /// @tparam T Floating-point scalar types. + /// + /// @see gtc_quaternion + template + GLM_FUNC_DECL mat<3, 3, T, Q> mat3_cast(qua const& x); + + /// Converts a quaternion to a 4 * 4 matrix. + /// + /// @tparam T Floating-point scalar types. + /// + /// @see gtc_quaternion + template + GLM_FUNC_DECL mat<4, 4, T, Q> mat4_cast(qua const& x); + + /// Converts a pure rotation 3 * 3 matrix to a quaternion. + /// + /// @tparam T Floating-point scalar types. + /// + /// @see gtc_quaternion + template + GLM_FUNC_DECL qua quat_cast(mat<3, 3, T, Q> const& x); + + /// Converts a pure rotation 4 * 4 matrix to a quaternion. + /// + /// @tparam T Floating-point scalar types. + /// + /// @see gtc_quaternion + template + GLM_FUNC_DECL qua quat_cast(mat<4, 4, T, Q> const& x); + + /// Returns the component-wise comparison result of x < y. + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_quaternion_relational + template + GLM_FUNC_DECL vec<4, bool, Q> lessThan(qua const& x, qua const& y); + + /// Returns the component-wise comparison of result x <= y. + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_quaternion_relational + template + GLM_FUNC_DECL vec<4, bool, Q> lessThanEqual(qua const& x, qua const& y); + + /// Returns the component-wise comparison of result x > y. + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_quaternion_relational + template + GLM_FUNC_DECL vec<4, bool, Q> greaterThan(qua const& x, qua const& y); + + /// Returns the component-wise comparison of result x >= y. + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_quaternion_relational + template + GLM_FUNC_DECL vec<4, bool, Q> greaterThanEqual(qua const& x, qua const& y); + + /// Build a look at quaternion based on the default handedness. + /// + /// @param direction Desired forward direction. Needs to be normalized. + /// @param up Up vector, how the camera is oriented. Typically (0, 1, 0). + template + GLM_FUNC_DECL qua quatLookAt( + vec<3, T, Q> const& direction, + vec<3, T, Q> const& up); + + /// Build a right-handed look at quaternion. + /// + /// @param direction Desired forward direction onto which the -z-axis gets mapped. Needs to be normalized. + /// @param up Up vector, how the camera is oriented. Typically (0, 1, 0). + template + GLM_FUNC_DECL qua quatLookAtRH( + vec<3, T, Q> const& direction, + vec<3, T, Q> const& up); + + /// Build a left-handed look at quaternion. + /// + /// @param direction Desired forward direction onto which the +z-axis gets mapped. Needs to be normalized. + /// @param up Up vector, how the camera is oriented. Typically (0, 1, 0). + template + GLM_FUNC_DECL qua quatLookAtLH( + vec<3, T, Q> const& direction, + vec<3, T, Q> const& up); + /// @} +} //namespace glm + +#include "quaternion.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/quaternion.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/quaternion.inl new file mode 100644 index 0000000000000000000000000000000000000000..e1ef0321c7284e797dee9e9713ede066a263e847 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/quaternion.inl @@ -0,0 +1,208 @@ +#include "../trigonometric.hpp" +#include "../geometric.hpp" +#include "../exponential.hpp" +#include "epsilon.hpp" +#include + +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec<3, T, Q> eulerAngles(qua const& x) + { + return vec<3, T, Q>(pitch(x), yaw(x), roll(x)); + } + + template + GLM_FUNC_QUALIFIER T roll(qua const& q) + { + T const y = static_cast(2) * (q.x * q.y + q.w * q.z); + T const x = q.w * q.w + q.x * q.x - q.y * q.y - q.z * q.z; + + if(all(equal(vec<2, T, Q>(x, y), vec<2, T, Q>(0), epsilon()))) //avoid atan2(0,0) - handle singularity - Matiis + return static_cast(0); + + return static_cast(atan(y, x)); + } + + template + GLM_FUNC_QUALIFIER T pitch(qua const& q) + { + //return T(atan(T(2) * (q.y * q.z + q.w * q.x), q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z)); + T const y = static_cast(2) * (q.y * q.z + q.w * q.x); + T const x = q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z; + + if(all(equal(vec<2, T, Q>(x, y), vec<2, T, Q>(0), epsilon()))) //avoid atan2(0,0) - handle singularity - Matiis + return static_cast(static_cast(2) * atan(q.x, q.w)); + + return static_cast(atan(y, x)); + } + + template + GLM_FUNC_QUALIFIER T yaw(qua const& q) + { + return asin(clamp(static_cast(-2) * (q.x * q.z - q.w * q.y), static_cast(-1), static_cast(1))); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> mat3_cast(qua const& q) + { + mat<3, 3, T, Q> Result(T(1)); + T qxx(q.x * q.x); + T qyy(q.y * q.y); + T qzz(q.z * q.z); + T qxz(q.x * q.z); + T qxy(q.x * q.y); + T qyz(q.y * q.z); + T qwx(q.w * q.x); + T qwy(q.w * q.y); + T qwz(q.w * q.z); + + Result[0][0] = T(1) - T(2) * (qyy + qzz); + Result[0][1] = T(2) * (qxy + qwz); + Result[0][2] = T(2) * (qxz - qwy); + + Result[1][0] = T(2) * (qxy - qwz); + Result[1][1] = T(1) - T(2) * (qxx + qzz); + Result[1][2] = T(2) * (qyz + qwx); + + Result[2][0] = T(2) * (qxz + qwy); + Result[2][1] = T(2) * (qyz - qwx); + Result[2][2] = T(1) - T(2) * (qxx + qyy); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> mat4_cast(qua const& q) + { + return mat<4, 4, T, Q>(mat3_cast(q)); + } + + template + GLM_FUNC_QUALIFIER qua quat_cast(mat<3, 3, T, Q> const& m) + { + T fourXSquaredMinus1 = m[0][0] - m[1][1] - m[2][2]; + T fourYSquaredMinus1 = m[1][1] - m[0][0] - m[2][2]; + T fourZSquaredMinus1 = m[2][2] - m[0][0] - m[1][1]; + T fourWSquaredMinus1 = m[0][0] + m[1][1] + m[2][2]; + + int biggestIndex = 0; + T fourBiggestSquaredMinus1 = fourWSquaredMinus1; + if(fourXSquaredMinus1 > fourBiggestSquaredMinus1) + { + fourBiggestSquaredMinus1 = fourXSquaredMinus1; + biggestIndex = 1; + } + if(fourYSquaredMinus1 > fourBiggestSquaredMinus1) + { + fourBiggestSquaredMinus1 = fourYSquaredMinus1; + biggestIndex = 2; + } + if(fourZSquaredMinus1 > fourBiggestSquaredMinus1) + { + fourBiggestSquaredMinus1 = fourZSquaredMinus1; + biggestIndex = 3; + } + + T biggestVal = sqrt(fourBiggestSquaredMinus1 + static_cast(1)) * static_cast(0.5); + T mult = static_cast(0.25) / biggestVal; + + switch(biggestIndex) + { + case 0: + return qua(biggestVal, (m[1][2] - m[2][1]) * mult, (m[2][0] - m[0][2]) * mult, (m[0][1] - m[1][0]) * mult); + case 1: + return qua((m[1][2] - m[2][1]) * mult, biggestVal, (m[0][1] + m[1][0]) * mult, (m[2][0] + m[0][2]) * mult); + case 2: + return qua((m[2][0] - m[0][2]) * mult, (m[0][1] + m[1][0]) * mult, biggestVal, (m[1][2] + m[2][1]) * mult); + case 3: + return qua((m[0][1] - m[1][0]) * mult, (m[2][0] + m[0][2]) * mult, (m[1][2] + m[2][1]) * mult, biggestVal); + default: // Silence a -Wswitch-default warning in GCC. Should never actually get here. Assert is just for sanity. + assert(false); + return qua(1, 0, 0, 0); + } + } + + template + GLM_FUNC_QUALIFIER qua quat_cast(mat<4, 4, T, Q> const& m4) + { + return quat_cast(mat<3, 3, T, Q>(m4)); + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> lessThan(qua const& x, qua const& y) + { + vec<4, bool, Q> Result; + for(length_t i = 0; i < x.length(); ++i) + Result[i] = x[i] < y[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> lessThanEqual(qua const& x, qua const& y) + { + vec<4, bool, Q> Result; + for(length_t i = 0; i < x.length(); ++i) + Result[i] = x[i] <= y[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> greaterThan(qua const& x, qua const& y) + { + vec<4, bool, Q> Result; + for(length_t i = 0; i < x.length(); ++i) + Result[i] = x[i] > y[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> greaterThanEqual(qua const& x, qua const& y) + { + vec<4, bool, Q> Result; + for(length_t i = 0; i < x.length(); ++i) + Result[i] = x[i] >= y[i]; + return Result; + } + + + template + GLM_FUNC_QUALIFIER qua quatLookAt(vec<3, T, Q> const& direction, vec<3, T, Q> const& up) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT + return quatLookAtLH(direction, up); +# else + return quatLookAtRH(direction, up); +# endif + } + + template + GLM_FUNC_QUALIFIER qua quatLookAtRH(vec<3, T, Q> const& direction, vec<3, T, Q> const& up) + { + mat<3, 3, T, Q> Result; + + Result[2] = -direction; + vec<3, T, Q> const& Right = cross(up, Result[2]); + Result[0] = Right * inversesqrt(max(static_cast(0.00001), dot(Right, Right))); + Result[1] = cross(Result[2], Result[0]); + + return quat_cast(Result); + } + + template + GLM_FUNC_QUALIFIER qua quatLookAtLH(vec<3, T, Q> const& direction, vec<3, T, Q> const& up) + { + mat<3, 3, T, Q> Result; + + Result[2] = direction; + vec<3, T, Q> const& Right = cross(up, Result[2]); + Result[0] = Right * inversesqrt(max(static_cast(0.00001), dot(Right, Right))); + Result[1] = cross(Result[2], Result[0]); + + return quat_cast(Result); + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "quaternion_simd.inl" +#endif + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/quaternion_simd.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/quaternion_simd.inl new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/random.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/random.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c6485bf1da38a65aecc61fd4bf6386f32536716e --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/random.hpp @@ -0,0 +1,82 @@ +/// @ref gtc_random +/// @file glm/gtc/random.hpp +/// +/// @see core (dependence) +/// @see gtx_random (extended) +/// +/// @defgroup gtc_random GLM_GTC_random +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Generate random number from various distribution methods. + +#pragma once + +// Dependency: +#include "../ext/scalar_int_sized.hpp" +#include "../ext/scalar_uint_sized.hpp" +#include "../detail/qualifier.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_random extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_random + /// @{ + + /// Generate random numbers in the interval [Min, Max], according a linear distribution + /// + /// @param Min Minimum value included in the sampling + /// @param Max Maximum value included in the sampling + /// @tparam genType Value type. Currently supported: float or double scalars. + /// @see gtc_random + template + GLM_FUNC_DECL genType linearRand(genType Min, genType Max); + + /// Generate random numbers in the interval [Min, Max], according a linear distribution + /// + /// @param Min Minimum value included in the sampling + /// @param Max Maximum value included in the sampling + /// @tparam T Value type. Currently supported: float or double. + /// + /// @see gtc_random + template + GLM_FUNC_DECL vec linearRand(vec const& Min, vec const& Max); + + /// Generate random numbers in the interval [Min, Max], according a gaussian distribution + /// + /// @see gtc_random + template + GLM_FUNC_DECL genType gaussRand(genType Mean, genType Deviation); + + /// Generate a random 2D vector which coordinates are regularly distributed on a circle of a given radius + /// + /// @see gtc_random + template + GLM_FUNC_DECL vec<2, T, defaultp> circularRand(T Radius); + + /// Generate a random 3D vector which coordinates are regularly distributed on a sphere of a given radius + /// + /// @see gtc_random + template + GLM_FUNC_DECL vec<3, T, defaultp> sphericalRand(T Radius); + + /// Generate a random 2D vector which coordinates are regularly distributed within the area of a disk of a given radius + /// + /// @see gtc_random + template + GLM_FUNC_DECL vec<2, T, defaultp> diskRand(T Radius); + + /// Generate a random 3D vector which coordinates are regularly distributed within the volume of a ball of a given radius + /// + /// @see gtc_random + template + GLM_FUNC_DECL vec<3, T, defaultp> ballRand(T Radius); + + /// @} +}//namespace glm + +#include "random.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/random.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/random.inl new file mode 100644 index 0000000000000000000000000000000000000000..249ec9f92b487d8babe4525a0c803305d4a1d09a --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/random.inl @@ -0,0 +1,303 @@ +#include "../geometric.hpp" +#include "../exponential.hpp" +#include "../trigonometric.hpp" +#include "../detail/type_vec1.hpp" +#include +#include +#include +#include + +namespace glm{ +namespace detail +{ + template + struct compute_rand + { + GLM_FUNC_QUALIFIER static vec call(); + }; + + template + struct compute_rand<1, uint8, P> + { + GLM_FUNC_QUALIFIER static vec<1, uint8, P> call() + { + return vec<1, uint8, P>( + static_cast(std::rand() % std::numeric_limits::max())); + } + }; + + template + struct compute_rand<2, uint8, P> + { + GLM_FUNC_QUALIFIER static vec<2, uint8, P> call() + { + return vec<2, uint8, P>( + std::rand() % std::numeric_limits::max(), + std::rand() % std::numeric_limits::max()); + } + }; + + template + struct compute_rand<3, uint8, P> + { + GLM_FUNC_QUALIFIER static vec<3, uint8, P> call() + { + return vec<3, uint8, P>( + std::rand() % std::numeric_limits::max(), + std::rand() % std::numeric_limits::max(), + std::rand() % std::numeric_limits::max()); + } + }; + + template + struct compute_rand<4, uint8, P> + { + GLM_FUNC_QUALIFIER static vec<4, uint8, P> call() + { + return vec<4, uint8, P>( + std::rand() % std::numeric_limits::max(), + std::rand() % std::numeric_limits::max(), + std::rand() % std::numeric_limits::max(), + std::rand() % std::numeric_limits::max()); + } + }; + + template + struct compute_rand + { + GLM_FUNC_QUALIFIER static vec call() + { + return + (vec(compute_rand::call()) << static_cast(8)) | + (vec(compute_rand::call()) << static_cast(0)); + } + }; + + template + struct compute_rand + { + GLM_FUNC_QUALIFIER static vec call() + { + return + (vec(compute_rand::call()) << static_cast(16)) | + (vec(compute_rand::call()) << static_cast(0)); + } + }; + + template + struct compute_rand + { + GLM_FUNC_QUALIFIER static vec call() + { + return + (vec(compute_rand::call()) << static_cast(32)) | + (vec(compute_rand::call()) << static_cast(0)); + } + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max); + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) + { + return (vec(compute_rand::call() % vec(Max + static_cast(1) - Min))) + Min; + } + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) + { + return (compute_rand::call() % (Max + static_cast(1) - Min)) + Min; + } + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) + { + return (vec(compute_rand::call() % vec(Max + static_cast(1) - Min))) + Min; + } + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) + { + return (compute_rand::call() % (Max + static_cast(1) - Min)) + Min; + } + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) + { + return (vec(compute_rand::call() % vec(Max + static_cast(1) - Min))) + Min; + } + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) + { + return (compute_rand::call() % (Max + static_cast(1) - Min)) + Min; + } + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) + { + return (vec(compute_rand::call() % vec(Max + static_cast(1) - Min))) + Min; + } + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) + { + return (compute_rand::call() % (Max + static_cast(1) - Min)) + Min; + } + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) + { + return vec(compute_rand::call()) / static_cast(std::numeric_limits::max()) * (Max - Min) + Min; + } + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) + { + return vec(compute_rand::call()) / static_cast(std::numeric_limits::max()) * (Max - Min) + Min; + } + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) + { + return vec(compute_rand::call()) / static_cast(std::numeric_limits::max()) * (Max - Min) + Min; + } + }; +}//namespace detail + + template + GLM_FUNC_QUALIFIER genType linearRand(genType Min, genType Max) + { + return detail::compute_linearRand<1, genType, highp>::call( + vec<1, genType, highp>(Min), + vec<1, genType, highp>(Max)).x; + } + + template + GLM_FUNC_QUALIFIER vec linearRand(vec const& Min, vec const& Max) + { + return detail::compute_linearRand::call(Min, Max); + } + + template + GLM_FUNC_QUALIFIER genType gaussRand(genType Mean, genType Deviation) + { + genType w, x1, x2; + + do + { + x1 = linearRand(genType(-1), genType(1)); + x2 = linearRand(genType(-1), genType(1)); + + w = x1 * x1 + x2 * x2; + } while(w > genType(1)); + + return static_cast(x2 * Deviation * Deviation * sqrt((genType(-2) * log(w)) / w) + Mean); + } + + template + GLM_FUNC_QUALIFIER vec gaussRand(vec const& Mean, vec const& Deviation) + { + return detail::functor2::call(gaussRand, Mean, Deviation); + } + + template + GLM_FUNC_QUALIFIER vec<2, T, defaultp> diskRand(T Radius) + { + assert(Radius > static_cast(0)); + + vec<2, T, defaultp> Result(T(0)); + T LenRadius(T(0)); + + do + { + Result = linearRand( + vec<2, T, defaultp>(-Radius), + vec<2, T, defaultp>(Radius)); + LenRadius = length(Result); + } + while(LenRadius > Radius); + + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, defaultp> ballRand(T Radius) + { + assert(Radius > static_cast(0)); + + vec<3, T, defaultp> Result(T(0)); + T LenRadius(T(0)); + + do + { + Result = linearRand( + vec<3, T, defaultp>(-Radius), + vec<3, T, defaultp>(Radius)); + LenRadius = length(Result); + } + while(LenRadius > Radius); + + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<2, T, defaultp> circularRand(T Radius) + { + assert(Radius > static_cast(0)); + + T a = linearRand(T(0), static_cast(6.283185307179586476925286766559)); + return vec<2, T, defaultp>(glm::cos(a), glm::sin(a)) * Radius; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, defaultp> sphericalRand(T Radius) + { + assert(Radius > static_cast(0)); + + T theta = linearRand(T(0), T(6.283185307179586476925286766559f)); + T phi = std::acos(linearRand(T(-1.0f), T(1.0f))); + + T x = std::sin(phi) * std::cos(theta); + T y = std::sin(phi) * std::sin(theta); + T z = std::cos(phi); + + return vec<3, T, defaultp>(x, y, z) * Radius; + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/reciprocal.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/reciprocal.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4d0fc91ca657b58e5015c079c3a14fe7d1260346 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/reciprocal.hpp @@ -0,0 +1,24 @@ +/// @ref gtc_reciprocal +/// @file glm/gtc/reciprocal.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtc_reciprocal GLM_GTC_reciprocal +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Define secant, cosecant and cotangent functions. + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_reciprocal extension included") +#endif + +#include "../ext/scalar_reciprocal.hpp" +#include "../ext/vector_reciprocal.hpp" + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/round.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/round.hpp new file mode 100644 index 0000000000000000000000000000000000000000..56edbbca30b502abad5b82a70822453a475e4be2 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/round.hpp @@ -0,0 +1,160 @@ +/// @ref gtc_round +/// @file glm/gtc/round.hpp +/// +/// @see core (dependence) +/// @see gtc_round (dependence) +/// +/// @defgroup gtc_round GLM_GTC_round +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Rounding value to specific boundings + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../detail/qualifier.hpp" +#include "../detail/_vectorize.hpp" +#include "../vector_relational.hpp" +#include "../common.hpp" +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_round extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_round + /// @{ + + /// Return the power of two number which value is just higher the input value, + /// round up to a power of two. + /// + /// @see gtc_round + template + GLM_FUNC_DECL genIUType ceilPowerOfTwo(genIUType v); + + /// Return the power of two number which value is just higher the input value, + /// round up to a power of two. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_round + template + GLM_FUNC_DECL vec ceilPowerOfTwo(vec const& v); + + /// Return the power of two number which value is just lower the input value, + /// round down to a power of two. + /// + /// @see gtc_round + template + GLM_FUNC_DECL genIUType floorPowerOfTwo(genIUType v); + + /// Return the power of two number which value is just lower the input value, + /// round down to a power of two. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_round + template + GLM_FUNC_DECL vec floorPowerOfTwo(vec const& v); + + /// Return the power of two number which value is the closet to the input value. + /// + /// @see gtc_round + template + GLM_FUNC_DECL genIUType roundPowerOfTwo(genIUType v); + + /// Return the power of two number which value is the closet to the input value. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_round + template + GLM_FUNC_DECL vec roundPowerOfTwo(vec const& v); + + /// Higher multiple number of Source. + /// + /// @tparam genType Floating-point or integer scalar or vector types. + /// + /// @param v Source value to which is applied the function + /// @param Multiple Must be a null or positive value + /// + /// @see gtc_round + template + GLM_FUNC_DECL genType ceilMultiple(genType v, genType Multiple); + + /// Higher multiple number of Source. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @param v Source values to which is applied the function + /// @param Multiple Must be a null or positive value + /// + /// @see gtc_round + template + GLM_FUNC_DECL vec ceilMultiple(vec const& v, vec const& Multiple); + + /// Lower multiple number of Source. + /// + /// @tparam genType Floating-point or integer scalar or vector types. + /// + /// @param v Source value to which is applied the function + /// @param Multiple Must be a null or positive value + /// + /// @see gtc_round + template + GLM_FUNC_DECL genType floorMultiple(genType v, genType Multiple); + + /// Lower multiple number of Source. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @param v Source values to which is applied the function + /// @param Multiple Must be a null or positive value + /// + /// @see gtc_round + template + GLM_FUNC_DECL vec floorMultiple(vec const& v, vec const& Multiple); + + /// Lower multiple number of Source. + /// + /// @tparam genType Floating-point or integer scalar or vector types. + /// + /// @param v Source value to which is applied the function + /// @param Multiple Must be a null or positive value + /// + /// @see gtc_round + template + GLM_FUNC_DECL genType roundMultiple(genType v, genType Multiple); + + /// Lower multiple number of Source. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @param v Source values to which is applied the function + /// @param Multiple Must be a null or positive value + /// + /// @see gtc_round + template + GLM_FUNC_DECL vec roundMultiple(vec const& v, vec const& Multiple); + + /// @} +} //namespace glm + +#include "round.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/round.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/round.inl new file mode 100644 index 0000000000000000000000000000000000000000..48411e41dc3442ec38a0dc88d9aa97d7dad20986 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/round.inl @@ -0,0 +1,155 @@ +/// @ref gtc_round + +#include "../integer.hpp" +#include "../ext/vector_integer.hpp" + +namespace glm{ +namespace detail +{ + template + struct compute_roundMultiple {}; + + template<> + struct compute_roundMultiple + { + template + GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) + { + if (Source >= genType(0)) + return Source - std::fmod(Source, Multiple); + else + { + genType Tmp = Source + genType(1); + return Tmp - std::fmod(Tmp, Multiple) - Multiple; + } + } + }; + + template<> + struct compute_roundMultiple + { + template + GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) + { + if (Source >= genType(0)) + return Source - Source % Multiple; + else + { + genType Tmp = Source + genType(1); + return Tmp - Tmp % Multiple - Multiple; + } + } + }; + + template<> + struct compute_roundMultiple + { + template + GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) + { + if (Source >= genType(0)) + return Source - Source % Multiple; + else + { + genType Tmp = Source + genType(1); + return Tmp - Tmp % Multiple - Multiple; + } + } + }; +}//namespace detail + + ////////////////// + // ceilPowerOfTwo + + template + GLM_FUNC_QUALIFIER genType ceilPowerOfTwo(genType value) + { + return detail::compute_ceilPowerOfTwo<1, genType, defaultp, std::numeric_limits::is_signed>::call(vec<1, genType, defaultp>(value)).x; + } + + template + GLM_FUNC_QUALIFIER vec ceilPowerOfTwo(vec const& v) + { + return detail::compute_ceilPowerOfTwo::is_signed>::call(v); + } + + /////////////////// + // floorPowerOfTwo + + template + GLM_FUNC_QUALIFIER genType floorPowerOfTwo(genType value) + { + return isPowerOfTwo(value) ? value : static_cast(1) << findMSB(value); + } + + template + GLM_FUNC_QUALIFIER vec floorPowerOfTwo(vec const& v) + { + return detail::functor1::call(floorPowerOfTwo, v); + } + + /////////////////// + // roundPowerOfTwo + + template + GLM_FUNC_QUALIFIER genIUType roundPowerOfTwo(genIUType value) + { + if(isPowerOfTwo(value)) + return value; + + genIUType const prev = static_cast(1) << findMSB(value); + genIUType const next = prev << static_cast(1); + return (next - value) < (value - prev) ? next : prev; + } + + template + GLM_FUNC_QUALIFIER vec roundPowerOfTwo(vec const& v) + { + return detail::functor1::call(roundPowerOfTwo, v); + } + + ////////////////////// + // ceilMultiple + + template + GLM_FUNC_QUALIFIER genType ceilMultiple(genType Source, genType Multiple) + { + return detail::compute_ceilMultiple::is_iec559, std::numeric_limits::is_signed>::call(Source, Multiple); + } + + template + GLM_FUNC_QUALIFIER vec ceilMultiple(vec const& Source, vec const& Multiple) + { + return detail::functor2::call(ceilMultiple, Source, Multiple); + } + + ////////////////////// + // floorMultiple + + template + GLM_FUNC_QUALIFIER genType floorMultiple(genType Source, genType Multiple) + { + return detail::compute_floorMultiple::is_iec559, std::numeric_limits::is_signed>::call(Source, Multiple); + } + + template + GLM_FUNC_QUALIFIER vec floorMultiple(vec const& Source, vec const& Multiple) + { + return detail::functor2::call(floorMultiple, Source, Multiple); + } + + ////////////////////// + // roundMultiple + + template + GLM_FUNC_QUALIFIER genType roundMultiple(genType Source, genType Multiple) + { + return detail::compute_roundMultiple::is_iec559, std::numeric_limits::is_signed>::call(Source, Multiple); + } + + template + GLM_FUNC_QUALIFIER vec roundMultiple(vec const& Source, vec const& Multiple) + { + return detail::functor2::call(roundMultiple, Source, Multiple); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/type_aligned.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/type_aligned.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5403abf675256b1dcb53bcd7eb553336daed29f6 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/type_aligned.hpp @@ -0,0 +1,1315 @@ +/// @ref gtc_type_aligned +/// @file glm/gtc/type_aligned.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtc_type_aligned GLM_GTC_type_aligned +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Aligned types allowing SIMD optimizations of vectors and matrices types + +#pragma once + +#if (GLM_CONFIG_ALIGNED_GENTYPES == GLM_DISABLE) +# error "GLM: Aligned gentypes require to enable C++ language extensions. Define GLM_FORCE_ALIGNED_GENTYPES before including GLM headers to use aligned types." +#endif + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_type_aligned extension included") +#endif + +#include "../mat4x4.hpp" +#include "../mat4x3.hpp" +#include "../mat4x2.hpp" +#include "../mat3x4.hpp" +#include "../mat3x3.hpp" +#include "../mat3x2.hpp" +#include "../mat2x4.hpp" +#include "../mat2x3.hpp" +#include "../mat2x2.hpp" +#include "../gtc/vec1.hpp" +#include "../vec2.hpp" +#include "../vec3.hpp" +#include "../vec4.hpp" + +namespace glm +{ + /// @addtogroup gtc_type_aligned + /// @{ + + // -- *vec1 -- + + /// 1 component vector aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<1, float, aligned_highp> aligned_highp_vec1; + + /// 1 component vector aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<1, float, aligned_mediump> aligned_mediump_vec1; + + /// 1 component vector aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<1, float, aligned_lowp> aligned_lowp_vec1; + + /// 1 component vector aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<1, double, aligned_highp> aligned_highp_dvec1; + + /// 1 component vector aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<1, double, aligned_mediump> aligned_mediump_dvec1; + + /// 1 component vector aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<1, double, aligned_lowp> aligned_lowp_dvec1; + + /// 1 component vector aligned in memory of signed integer numbers. + typedef vec<1, int, aligned_highp> aligned_highp_ivec1; + + /// 1 component vector aligned in memory of signed integer numbers. + typedef vec<1, int, aligned_mediump> aligned_mediump_ivec1; + + /// 1 component vector aligned in memory of signed integer numbers. + typedef vec<1, int, aligned_lowp> aligned_lowp_ivec1; + + /// 1 component vector aligned in memory of unsigned integer numbers. + typedef vec<1, uint, aligned_highp> aligned_highp_uvec1; + + /// 1 component vector aligned in memory of unsigned integer numbers. + typedef vec<1, uint, aligned_mediump> aligned_mediump_uvec1; + + /// 1 component vector aligned in memory of unsigned integer numbers. + typedef vec<1, uint, aligned_lowp> aligned_lowp_uvec1; + + /// 1 component vector aligned in memory of bool values. + typedef vec<1, bool, aligned_highp> aligned_highp_bvec1; + + /// 1 component vector aligned in memory of bool values. + typedef vec<1, bool, aligned_mediump> aligned_mediump_bvec1; + + /// 1 component vector aligned in memory of bool values. + typedef vec<1, bool, aligned_lowp> aligned_lowp_bvec1; + + /// 1 component vector tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<1, float, packed_highp> packed_highp_vec1; + + /// 1 component vector tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<1, float, packed_mediump> packed_mediump_vec1; + + /// 1 component vector tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<1, float, packed_lowp> packed_lowp_vec1; + + /// 1 component vector tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<1, double, packed_highp> packed_highp_dvec1; + + /// 1 component vector tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<1, double, packed_mediump> packed_mediump_dvec1; + + /// 1 component vector tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<1, double, packed_lowp> packed_lowp_dvec1; + + /// 1 component vector tightly packed in memory of signed integer numbers. + typedef vec<1, int, packed_highp> packed_highp_ivec1; + + /// 1 component vector tightly packed in memory of signed integer numbers. + typedef vec<1, int, packed_mediump> packed_mediump_ivec1; + + /// 1 component vector tightly packed in memory of signed integer numbers. + typedef vec<1, int, packed_lowp> packed_lowp_ivec1; + + /// 1 component vector tightly packed in memory of unsigned integer numbers. + typedef vec<1, uint, packed_highp> packed_highp_uvec1; + + /// 1 component vector tightly packed in memory of unsigned integer numbers. + typedef vec<1, uint, packed_mediump> packed_mediump_uvec1; + + /// 1 component vector tightly packed in memory of unsigned integer numbers. + typedef vec<1, uint, packed_lowp> packed_lowp_uvec1; + + /// 1 component vector tightly packed in memory of bool values. + typedef vec<1, bool, packed_highp> packed_highp_bvec1; + + /// 1 component vector tightly packed in memory of bool values. + typedef vec<1, bool, packed_mediump> packed_mediump_bvec1; + + /// 1 component vector tightly packed in memory of bool values. + typedef vec<1, bool, packed_lowp> packed_lowp_bvec1; + + // -- *vec2 -- + + /// 2 components vector aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<2, float, aligned_highp> aligned_highp_vec2; + + /// 2 components vector aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<2, float, aligned_mediump> aligned_mediump_vec2; + + /// 2 components vector aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<2, float, aligned_lowp> aligned_lowp_vec2; + + /// 2 components vector aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<2, double, aligned_highp> aligned_highp_dvec2; + + /// 2 components vector aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<2, double, aligned_mediump> aligned_mediump_dvec2; + + /// 2 components vector aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<2, double, aligned_lowp> aligned_lowp_dvec2; + + /// 2 components vector aligned in memory of signed integer numbers. + typedef vec<2, int, aligned_highp> aligned_highp_ivec2; + + /// 2 components vector aligned in memory of signed integer numbers. + typedef vec<2, int, aligned_mediump> aligned_mediump_ivec2; + + /// 2 components vector aligned in memory of signed integer numbers. + typedef vec<2, int, aligned_lowp> aligned_lowp_ivec2; + + /// 2 components vector aligned in memory of unsigned integer numbers. + typedef vec<2, uint, aligned_highp> aligned_highp_uvec2; + + /// 2 components vector aligned in memory of unsigned integer numbers. + typedef vec<2, uint, aligned_mediump> aligned_mediump_uvec2; + + /// 2 components vector aligned in memory of unsigned integer numbers. + typedef vec<2, uint, aligned_lowp> aligned_lowp_uvec2; + + /// 2 components vector aligned in memory of bool values. + typedef vec<2, bool, aligned_highp> aligned_highp_bvec2; + + /// 2 components vector aligned in memory of bool values. + typedef vec<2, bool, aligned_mediump> aligned_mediump_bvec2; + + /// 2 components vector aligned in memory of bool values. + typedef vec<2, bool, aligned_lowp> aligned_lowp_bvec2; + + /// 2 components vector tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<2, float, packed_highp> packed_highp_vec2; + + /// 2 components vector tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<2, float, packed_mediump> packed_mediump_vec2; + + /// 2 components vector tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<2, float, packed_lowp> packed_lowp_vec2; + + /// 2 components vector tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<2, double, packed_highp> packed_highp_dvec2; + + /// 2 components vector tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<2, double, packed_mediump> packed_mediump_dvec2; + + /// 2 components vector tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<2, double, packed_lowp> packed_lowp_dvec2; + + /// 2 components vector tightly packed in memory of signed integer numbers. + typedef vec<2, int, packed_highp> packed_highp_ivec2; + + /// 2 components vector tightly packed in memory of signed integer numbers. + typedef vec<2, int, packed_mediump> packed_mediump_ivec2; + + /// 2 components vector tightly packed in memory of signed integer numbers. + typedef vec<2, int, packed_lowp> packed_lowp_ivec2; + + /// 2 components vector tightly packed in memory of unsigned integer numbers. + typedef vec<2, uint, packed_highp> packed_highp_uvec2; + + /// 2 components vector tightly packed in memory of unsigned integer numbers. + typedef vec<2, uint, packed_mediump> packed_mediump_uvec2; + + /// 2 components vector tightly packed in memory of unsigned integer numbers. + typedef vec<2, uint, packed_lowp> packed_lowp_uvec2; + + /// 2 components vector tightly packed in memory of bool values. + typedef vec<2, bool, packed_highp> packed_highp_bvec2; + + /// 2 components vector tightly packed in memory of bool values. + typedef vec<2, bool, packed_mediump> packed_mediump_bvec2; + + /// 2 components vector tightly packed in memory of bool values. + typedef vec<2, bool, packed_lowp> packed_lowp_bvec2; + + // -- *vec3 -- + + /// 3 components vector aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<3, float, aligned_highp> aligned_highp_vec3; + + /// 3 components vector aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<3, float, aligned_mediump> aligned_mediump_vec3; + + /// 3 components vector aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<3, float, aligned_lowp> aligned_lowp_vec3; + + /// 3 components vector aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<3, double, aligned_highp> aligned_highp_dvec3; + + /// 3 components vector aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<3, double, aligned_mediump> aligned_mediump_dvec3; + + /// 3 components vector aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<3, double, aligned_lowp> aligned_lowp_dvec3; + + /// 3 components vector aligned in memory of signed integer numbers. + typedef vec<3, int, aligned_highp> aligned_highp_ivec3; + + /// 3 components vector aligned in memory of signed integer numbers. + typedef vec<3, int, aligned_mediump> aligned_mediump_ivec3; + + /// 3 components vector aligned in memory of signed integer numbers. + typedef vec<3, int, aligned_lowp> aligned_lowp_ivec3; + + /// 3 components vector aligned in memory of unsigned integer numbers. + typedef vec<3, uint, aligned_highp> aligned_highp_uvec3; + + /// 3 components vector aligned in memory of unsigned integer numbers. + typedef vec<3, uint, aligned_mediump> aligned_mediump_uvec3; + + /// 3 components vector aligned in memory of unsigned integer numbers. + typedef vec<3, uint, aligned_lowp> aligned_lowp_uvec3; + + /// 3 components vector aligned in memory of bool values. + typedef vec<3, bool, aligned_highp> aligned_highp_bvec3; + + /// 3 components vector aligned in memory of bool values. + typedef vec<3, bool, aligned_mediump> aligned_mediump_bvec3; + + /// 3 components vector aligned in memory of bool values. + typedef vec<3, bool, aligned_lowp> aligned_lowp_bvec3; + + /// 3 components vector tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<3, float, packed_highp> packed_highp_vec3; + + /// 3 components vector tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<3, float, packed_mediump> packed_mediump_vec3; + + /// 3 components vector tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<3, float, packed_lowp> packed_lowp_vec3; + + /// 3 components vector tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<3, double, packed_highp> packed_highp_dvec3; + + /// 3 components vector tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<3, double, packed_mediump> packed_mediump_dvec3; + + /// 3 components vector tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<3, double, packed_lowp> packed_lowp_dvec3; + + /// 3 components vector tightly packed in memory of signed integer numbers. + typedef vec<3, int, packed_highp> packed_highp_ivec3; + + /// 3 components vector tightly packed in memory of signed integer numbers. + typedef vec<3, int, packed_mediump> packed_mediump_ivec3; + + /// 3 components vector tightly packed in memory of signed integer numbers. + typedef vec<3, int, packed_lowp> packed_lowp_ivec3; + + /// 3 components vector tightly packed in memory of unsigned integer numbers. + typedef vec<3, uint, packed_highp> packed_highp_uvec3; + + /// 3 components vector tightly packed in memory of unsigned integer numbers. + typedef vec<3, uint, packed_mediump> packed_mediump_uvec3; + + /// 3 components vector tightly packed in memory of unsigned integer numbers. + typedef vec<3, uint, packed_lowp> packed_lowp_uvec3; + + /// 3 components vector tightly packed in memory of bool values. + typedef vec<3, bool, packed_highp> packed_highp_bvec3; + + /// 3 components vector tightly packed in memory of bool values. + typedef vec<3, bool, packed_mediump> packed_mediump_bvec3; + + /// 3 components vector tightly packed in memory of bool values. + typedef vec<3, bool, packed_lowp> packed_lowp_bvec3; + + // -- *vec4 -- + + /// 4 components vector aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<4, float, aligned_highp> aligned_highp_vec4; + + /// 4 components vector aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<4, float, aligned_mediump> aligned_mediump_vec4; + + /// 4 components vector aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<4, float, aligned_lowp> aligned_lowp_vec4; + + /// 4 components vector aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<4, double, aligned_highp> aligned_highp_dvec4; + + /// 4 components vector aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<4, double, aligned_mediump> aligned_mediump_dvec4; + + /// 4 components vector aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<4, double, aligned_lowp> aligned_lowp_dvec4; + + /// 4 components vector aligned in memory of signed integer numbers. + typedef vec<4, int, aligned_highp> aligned_highp_ivec4; + + /// 4 components vector aligned in memory of signed integer numbers. + typedef vec<4, int, aligned_mediump> aligned_mediump_ivec4; + + /// 4 components vector aligned in memory of signed integer numbers. + typedef vec<4, int, aligned_lowp> aligned_lowp_ivec4; + + /// 4 components vector aligned in memory of unsigned integer numbers. + typedef vec<4, uint, aligned_highp> aligned_highp_uvec4; + + /// 4 components vector aligned in memory of unsigned integer numbers. + typedef vec<4, uint, aligned_mediump> aligned_mediump_uvec4; + + /// 4 components vector aligned in memory of unsigned integer numbers. + typedef vec<4, uint, aligned_lowp> aligned_lowp_uvec4; + + /// 4 components vector aligned in memory of bool values. + typedef vec<4, bool, aligned_highp> aligned_highp_bvec4; + + /// 4 components vector aligned in memory of bool values. + typedef vec<4, bool, aligned_mediump> aligned_mediump_bvec4; + + /// 4 components vector aligned in memory of bool values. + typedef vec<4, bool, aligned_lowp> aligned_lowp_bvec4; + + /// 4 components vector tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<4, float, packed_highp> packed_highp_vec4; + + /// 4 components vector tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<4, float, packed_mediump> packed_mediump_vec4; + + /// 4 components vector tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<4, float, packed_lowp> packed_lowp_vec4; + + /// 4 components vector tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<4, double, packed_highp> packed_highp_dvec4; + + /// 4 components vector tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<4, double, packed_mediump> packed_mediump_dvec4; + + /// 4 components vector tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<4, double, packed_lowp> packed_lowp_dvec4; + + /// 4 components vector tightly packed in memory of signed integer numbers. + typedef vec<4, int, packed_highp> packed_highp_ivec4; + + /// 4 components vector tightly packed in memory of signed integer numbers. + typedef vec<4, int, packed_mediump> packed_mediump_ivec4; + + /// 4 components vector tightly packed in memory of signed integer numbers. + typedef vec<4, int, packed_lowp> packed_lowp_ivec4; + + /// 4 components vector tightly packed in memory of unsigned integer numbers. + typedef vec<4, uint, packed_highp> packed_highp_uvec4; + + /// 4 components vector tightly packed in memory of unsigned integer numbers. + typedef vec<4, uint, packed_mediump> packed_mediump_uvec4; + + /// 4 components vector tightly packed in memory of unsigned integer numbers. + typedef vec<4, uint, packed_lowp> packed_lowp_uvec4; + + /// 4 components vector tightly packed in memory of bool values. + typedef vec<4, bool, packed_highp> packed_highp_bvec4; + + /// 4 components vector tightly packed in memory of bool values. + typedef vec<4, bool, packed_mediump> packed_mediump_bvec4; + + /// 4 components vector tightly packed in memory of bool values. + typedef vec<4, bool, packed_lowp> packed_lowp_bvec4; + + // -- *mat2 -- + + /// 2 by 2 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 2, float, aligned_highp> aligned_highp_mat2; + + /// 2 by 2 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 2, float, aligned_mediump> aligned_mediump_mat2; + + /// 2 by 2 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 2, float, aligned_lowp> aligned_lowp_mat2; + + /// 2 by 2 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 2, double, aligned_highp> aligned_highp_dmat2; + + /// 2 by 2 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 2, double, aligned_mediump> aligned_mediump_dmat2; + + /// 2 by 2 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 2, double, aligned_lowp> aligned_lowp_dmat2; + + /// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 2, float, packed_highp> packed_highp_mat2; + + /// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 2, float, packed_mediump> packed_mediump_mat2; + + /// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 2, float, packed_lowp> packed_lowp_mat2; + + /// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 2, double, packed_highp> packed_highp_dmat2; + + /// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 2, double, packed_mediump> packed_mediump_dmat2; + + /// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 2, double, packed_lowp> packed_lowp_dmat2; + + // -- *mat3 -- + + /// 3 by 3 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 3, float, aligned_highp> aligned_highp_mat3; + + /// 3 by 3 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 3, float, aligned_mediump> aligned_mediump_mat3; + + /// 3 by 3 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 3, float, aligned_lowp> aligned_lowp_mat3; + + /// 3 by 3 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 3, double, aligned_highp> aligned_highp_dmat3; + + /// 3 by 3 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 3, double, aligned_mediump> aligned_mediump_dmat3; + + /// 3 by 3 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 3, double, aligned_lowp> aligned_lowp_dmat3; + + /// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 3, float, packed_highp> packed_highp_mat3; + + /// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 3, float, packed_mediump> packed_mediump_mat3; + + /// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 3, float, packed_lowp> packed_lowp_mat3; + + /// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 3, double, packed_highp> packed_highp_dmat3; + + /// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 3, double, packed_mediump> packed_mediump_dmat3; + + /// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 3, double, packed_lowp> packed_lowp_dmat3; + + // -- *mat4 -- + + /// 4 by 4 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 4, float, aligned_highp> aligned_highp_mat4; + + /// 4 by 4 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 4, float, aligned_mediump> aligned_mediump_mat4; + + /// 4 by 4 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 4, float, aligned_lowp> aligned_lowp_mat4; + + /// 4 by 4 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 4, double, aligned_highp> aligned_highp_dmat4; + + /// 4 by 4 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 4, double, aligned_mediump> aligned_mediump_dmat4; + + /// 4 by 4 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 4, double, aligned_lowp> aligned_lowp_dmat4; + + /// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 4, float, packed_highp> packed_highp_mat4; + + /// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 4, float, packed_mediump> packed_mediump_mat4; + + /// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 4, float, packed_lowp> packed_lowp_mat4; + + /// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 4, double, packed_highp> packed_highp_dmat4; + + /// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 4, double, packed_mediump> packed_mediump_dmat4; + + /// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 4, double, packed_lowp> packed_lowp_dmat4; + + // -- *mat2x2 -- + + /// 2 by 2 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 2, float, aligned_highp> aligned_highp_mat2x2; + + /// 2 by 2 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 2, float, aligned_mediump> aligned_mediump_mat2x2; + + /// 2 by 2 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 2, float, aligned_lowp> aligned_lowp_mat2x2; + + /// 2 by 2 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 2, double, aligned_highp> aligned_highp_dmat2x2; + + /// 2 by 2 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 2, double, aligned_mediump> aligned_mediump_dmat2x2; + + /// 2 by 2 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 2, double, aligned_lowp> aligned_lowp_dmat2x2; + + /// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 2, float, packed_highp> packed_highp_mat2x2; + + /// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 2, float, packed_mediump> packed_mediump_mat2x2; + + /// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 2, float, packed_lowp> packed_lowp_mat2x2; + + /// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 2, double, packed_highp> packed_highp_dmat2x2; + + /// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 2, double, packed_mediump> packed_mediump_dmat2x2; + + /// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 2, double, packed_lowp> packed_lowp_dmat2x2; + + // -- *mat2x3 -- + + /// 2 by 3 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 3, float, aligned_highp> aligned_highp_mat2x3; + + /// 2 by 3 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 3, float, aligned_mediump> aligned_mediump_mat2x3; + + /// 2 by 3 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 3, float, aligned_lowp> aligned_lowp_mat2x3; + + /// 2 by 3 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 3, double, aligned_highp> aligned_highp_dmat2x3; + + /// 2 by 3 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 3, double, aligned_mediump> aligned_mediump_dmat2x3; + + /// 2 by 3 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 3, double, aligned_lowp> aligned_lowp_dmat2x3; + + /// 2 by 3 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 3, float, packed_highp> packed_highp_mat2x3; + + /// 2 by 3 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 3, float, packed_mediump> packed_mediump_mat2x3; + + /// 2 by 3 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 3, float, packed_lowp> packed_lowp_mat2x3; + + /// 2 by 3 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 3, double, packed_highp> packed_highp_dmat2x3; + + /// 2 by 3 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 3, double, packed_mediump> packed_mediump_dmat2x3; + + /// 2 by 3 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 3, double, packed_lowp> packed_lowp_dmat2x3; + + // -- *mat2x4 -- + + /// 2 by 4 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 4, float, aligned_highp> aligned_highp_mat2x4; + + /// 2 by 4 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 4, float, aligned_mediump> aligned_mediump_mat2x4; + + /// 2 by 4 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 4, float, aligned_lowp> aligned_lowp_mat2x4; + + /// 2 by 4 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 4, double, aligned_highp> aligned_highp_dmat2x4; + + /// 2 by 4 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 4, double, aligned_mediump> aligned_mediump_dmat2x4; + + /// 2 by 4 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 4, double, aligned_lowp> aligned_lowp_dmat2x4; + + /// 2 by 4 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 4, float, packed_highp> packed_highp_mat2x4; + + /// 2 by 4 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 4, float, packed_mediump> packed_mediump_mat2x4; + + /// 2 by 4 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 4, float, packed_lowp> packed_lowp_mat2x4; + + /// 2 by 4 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 4, double, packed_highp> packed_highp_dmat2x4; + + /// 2 by 4 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 4, double, packed_mediump> packed_mediump_dmat2x4; + + /// 2 by 4 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 4, double, packed_lowp> packed_lowp_dmat2x4; + + // -- *mat3x2 -- + + /// 3 by 2 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 2, float, aligned_highp> aligned_highp_mat3x2; + + /// 3 by 2 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 2, float, aligned_mediump> aligned_mediump_mat3x2; + + /// 3 by 2 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 2, float, aligned_lowp> aligned_lowp_mat3x2; + + /// 3 by 2 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 2, double, aligned_highp> aligned_highp_dmat3x2; + + /// 3 by 2 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 2, double, aligned_mediump> aligned_mediump_dmat3x2; + + /// 3 by 2 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 2, double, aligned_lowp> aligned_lowp_dmat3x2; + + /// 3 by 2 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 2, float, packed_highp> packed_highp_mat3x2; + + /// 3 by 2 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 2, float, packed_mediump> packed_mediump_mat3x2; + + /// 3 by 2 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 2, float, packed_lowp> packed_lowp_mat3x2; + + /// 3 by 2 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 2, double, packed_highp> packed_highp_dmat3x2; + + /// 3 by 2 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 2, double, packed_mediump> packed_mediump_dmat3x2; + + /// 3 by 2 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 2, double, packed_lowp> packed_lowp_dmat3x2; + + // -- *mat3x3 -- + + /// 3 by 3 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 3, float, aligned_highp> aligned_highp_mat3x3; + + /// 3 by 3 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 3, float, aligned_mediump> aligned_mediump_mat3x3; + + /// 3 by 3 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 3, float, aligned_lowp> aligned_lowp_mat3x3; + + /// 3 by 3 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 3, double, aligned_highp> aligned_highp_dmat3x3; + + /// 3 by 3 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 3, double, aligned_mediump> aligned_mediump_dmat3x3; + + /// 3 by 3 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 3, double, aligned_lowp> aligned_lowp_dmat3x3; + + /// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 3, float, packed_highp> packed_highp_mat3x3; + + /// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 3, float, packed_mediump> packed_mediump_mat3x3; + + /// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 3, float, packed_lowp> packed_lowp_mat3x3; + + /// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 3, double, packed_highp> packed_highp_dmat3x3; + + /// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 3, double, packed_mediump> packed_mediump_dmat3x3; + + /// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 3, double, packed_lowp> packed_lowp_dmat3x3; + + // -- *mat3x4 -- + + /// 3 by 4 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 4, float, aligned_highp> aligned_highp_mat3x4; + + /// 3 by 4 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 4, float, aligned_mediump> aligned_mediump_mat3x4; + + /// 3 by 4 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 4, float, aligned_lowp> aligned_lowp_mat3x4; + + /// 3 by 4 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 4, double, aligned_highp> aligned_highp_dmat3x4; + + /// 3 by 4 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 4, double, aligned_mediump> aligned_mediump_dmat3x4; + + /// 3 by 4 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 4, double, aligned_lowp> aligned_lowp_dmat3x4; + + /// 3 by 4 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 4, float, packed_highp> packed_highp_mat3x4; + + /// 3 by 4 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 4, float, packed_mediump> packed_mediump_mat3x4; + + /// 3 by 4 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 4, float, packed_lowp> packed_lowp_mat3x4; + + /// 3 by 4 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 4, double, packed_highp> packed_highp_dmat3x4; + + /// 3 by 4 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 4, double, packed_mediump> packed_mediump_dmat3x4; + + /// 3 by 4 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 4, double, packed_lowp> packed_lowp_dmat3x4; + + // -- *mat4x2 -- + + /// 4 by 2 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 2, float, aligned_highp> aligned_highp_mat4x2; + + /// 4 by 2 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 2, float, aligned_mediump> aligned_mediump_mat4x2; + + /// 4 by 2 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 2, float, aligned_lowp> aligned_lowp_mat4x2; + + /// 4 by 2 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 2, double, aligned_highp> aligned_highp_dmat4x2; + + /// 4 by 2 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 2, double, aligned_mediump> aligned_mediump_dmat4x2; + + /// 4 by 2 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 2, double, aligned_lowp> aligned_lowp_dmat4x2; + + /// 4 by 2 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 2, float, packed_highp> packed_highp_mat4x2; + + /// 4 by 2 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 2, float, packed_mediump> packed_mediump_mat4x2; + + /// 4 by 2 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 2, float, packed_lowp> packed_lowp_mat4x2; + + /// 4 by 2 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 2, double, packed_highp> packed_highp_dmat4x2; + + /// 4 by 2 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 2, double, packed_mediump> packed_mediump_dmat4x2; + + /// 4 by 2 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 2, double, packed_lowp> packed_lowp_dmat4x2; + + // -- *mat4x3 -- + + /// 4 by 3 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 3, float, aligned_highp> aligned_highp_mat4x3; + + /// 4 by 3 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 3, float, aligned_mediump> aligned_mediump_mat4x3; + + /// 4 by 3 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 3, float, aligned_lowp> aligned_lowp_mat4x3; + + /// 4 by 3 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 3, double, aligned_highp> aligned_highp_dmat4x3; + + /// 4 by 3 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 3, double, aligned_mediump> aligned_mediump_dmat4x3; + + /// 4 by 3 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 3, double, aligned_lowp> aligned_lowp_dmat4x3; + + /// 4 by 3 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 3, float, packed_highp> packed_highp_mat4x3; + + /// 4 by 3 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 3, float, packed_mediump> packed_mediump_mat4x3; + + /// 4 by 3 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 3, float, packed_lowp> packed_lowp_mat4x3; + + /// 4 by 3 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 3, double, packed_highp> packed_highp_dmat4x3; + + /// 4 by 3 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 3, double, packed_mediump> packed_mediump_dmat4x3; + + /// 4 by 3 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 3, double, packed_lowp> packed_lowp_dmat4x3; + + // -- *mat4x4 -- + + /// 4 by 4 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 4, float, aligned_highp> aligned_highp_mat4x4; + + /// 4 by 4 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 4, float, aligned_mediump> aligned_mediump_mat4x4; + + /// 4 by 4 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 4, float, aligned_lowp> aligned_lowp_mat4x4; + + /// 4 by 4 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 4, double, aligned_highp> aligned_highp_dmat4x4; + + /// 4 by 4 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 4, double, aligned_mediump> aligned_mediump_dmat4x4; + + /// 4 by 4 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 4, double, aligned_lowp> aligned_lowp_dmat4x4; + + /// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 4, float, packed_highp> packed_highp_mat4x4; + + /// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 4, float, packed_mediump> packed_mediump_mat4x4; + + /// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 4, float, packed_lowp> packed_lowp_mat4x4; + + /// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 4, double, packed_highp> packed_highp_dmat4x4; + + /// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 4, double, packed_mediump> packed_mediump_dmat4x4; + + /// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 4, double, packed_lowp> packed_lowp_dmat4x4; + + // -- default -- + +#if(defined(GLM_PRECISION_LOWP_FLOAT)) + typedef aligned_lowp_vec1 aligned_vec1; + typedef aligned_lowp_vec2 aligned_vec2; + typedef aligned_lowp_vec3 aligned_vec3; + typedef aligned_lowp_vec4 aligned_vec4; + typedef packed_lowp_vec1 packed_vec1; + typedef packed_lowp_vec2 packed_vec2; + typedef packed_lowp_vec3 packed_vec3; + typedef packed_lowp_vec4 packed_vec4; + + typedef aligned_lowp_mat2 aligned_mat2; + typedef aligned_lowp_mat3 aligned_mat3; + typedef aligned_lowp_mat4 aligned_mat4; + typedef packed_lowp_mat2 packed_mat2; + typedef packed_lowp_mat3 packed_mat3; + typedef packed_lowp_mat4 packed_mat4; + + typedef aligned_lowp_mat2x2 aligned_mat2x2; + typedef aligned_lowp_mat2x3 aligned_mat2x3; + typedef aligned_lowp_mat2x4 aligned_mat2x4; + typedef aligned_lowp_mat3x2 aligned_mat3x2; + typedef aligned_lowp_mat3x3 aligned_mat3x3; + typedef aligned_lowp_mat3x4 aligned_mat3x4; + typedef aligned_lowp_mat4x2 aligned_mat4x2; + typedef aligned_lowp_mat4x3 aligned_mat4x3; + typedef aligned_lowp_mat4x4 aligned_mat4x4; + typedef packed_lowp_mat2x2 packed_mat2x2; + typedef packed_lowp_mat2x3 packed_mat2x3; + typedef packed_lowp_mat2x4 packed_mat2x4; + typedef packed_lowp_mat3x2 packed_mat3x2; + typedef packed_lowp_mat3x3 packed_mat3x3; + typedef packed_lowp_mat3x4 packed_mat3x4; + typedef packed_lowp_mat4x2 packed_mat4x2; + typedef packed_lowp_mat4x3 packed_mat4x3; + typedef packed_lowp_mat4x4 packed_mat4x4; +#elif(defined(GLM_PRECISION_MEDIUMP_FLOAT)) + typedef aligned_mediump_vec1 aligned_vec1; + typedef aligned_mediump_vec2 aligned_vec2; + typedef aligned_mediump_vec3 aligned_vec3; + typedef aligned_mediump_vec4 aligned_vec4; + typedef packed_mediump_vec1 packed_vec1; + typedef packed_mediump_vec2 packed_vec2; + typedef packed_mediump_vec3 packed_vec3; + typedef packed_mediump_vec4 packed_vec4; + + typedef aligned_mediump_mat2 aligned_mat2; + typedef aligned_mediump_mat3 aligned_mat3; + typedef aligned_mediump_mat4 aligned_mat4; + typedef packed_mediump_mat2 packed_mat2; + typedef packed_mediump_mat3 packed_mat3; + typedef packed_mediump_mat4 packed_mat4; + + typedef aligned_mediump_mat2x2 aligned_mat2x2; + typedef aligned_mediump_mat2x3 aligned_mat2x3; + typedef aligned_mediump_mat2x4 aligned_mat2x4; + typedef aligned_mediump_mat3x2 aligned_mat3x2; + typedef aligned_mediump_mat3x3 aligned_mat3x3; + typedef aligned_mediump_mat3x4 aligned_mat3x4; + typedef aligned_mediump_mat4x2 aligned_mat4x2; + typedef aligned_mediump_mat4x3 aligned_mat4x3; + typedef aligned_mediump_mat4x4 aligned_mat4x4; + typedef packed_mediump_mat2x2 packed_mat2x2; + typedef packed_mediump_mat2x3 packed_mat2x3; + typedef packed_mediump_mat2x4 packed_mat2x4; + typedef packed_mediump_mat3x2 packed_mat3x2; + typedef packed_mediump_mat3x3 packed_mat3x3; + typedef packed_mediump_mat3x4 packed_mat3x4; + typedef packed_mediump_mat4x2 packed_mat4x2; + typedef packed_mediump_mat4x3 packed_mat4x3; + typedef packed_mediump_mat4x4 packed_mat4x4; +#else //defined(GLM_PRECISION_HIGHP_FLOAT) + /// 1 component vector aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_vec1 aligned_vec1; + + /// 2 components vector aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_vec2 aligned_vec2; + + /// 3 components vector aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_vec3 aligned_vec3; + + /// 4 components vector aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_vec4 aligned_vec4; + + /// 1 component vector tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_vec1 packed_vec1; + + /// 2 components vector tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_vec2 packed_vec2; + + /// 3 components vector tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_vec3 packed_vec3; + + /// 4 components vector tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_vec4 packed_vec4; + + /// 2 by 2 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat2 aligned_mat2; + + /// 3 by 3 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat3 aligned_mat3; + + /// 4 by 4 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat4 aligned_mat4; + + /// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat2 packed_mat2; + + /// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat3 packed_mat3; + + /// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat4 packed_mat4; + + /// 2 by 2 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat2x2 aligned_mat2x2; + + /// 2 by 3 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat2x3 aligned_mat2x3; + + /// 2 by 4 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat2x4 aligned_mat2x4; + + /// 3 by 2 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat3x2 aligned_mat3x2; + + /// 3 by 3 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat3x3 aligned_mat3x3; + + /// 3 by 4 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat3x4 aligned_mat3x4; + + /// 4 by 2 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat4x2 aligned_mat4x2; + + /// 4 by 3 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat4x3 aligned_mat4x3; + + /// 4 by 4 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat4x4 aligned_mat4x4; + + /// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat2x2 packed_mat2x2; + + /// 2 by 3 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat2x3 packed_mat2x3; + + /// 2 by 4 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat2x4 packed_mat2x4; + + /// 3 by 2 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat3x2 packed_mat3x2; + + /// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat3x3 packed_mat3x3; + + /// 3 by 4 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat3x4 packed_mat3x4; + + /// 4 by 2 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat4x2 packed_mat4x2; + + /// 4 by 3 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat4x3 packed_mat4x3; + + /// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat4x4 packed_mat4x4; +#endif//GLM_PRECISION + +#if(defined(GLM_PRECISION_LOWP_DOUBLE)) + typedef aligned_lowp_dvec1 aligned_dvec1; + typedef aligned_lowp_dvec2 aligned_dvec2; + typedef aligned_lowp_dvec3 aligned_dvec3; + typedef aligned_lowp_dvec4 aligned_dvec4; + typedef packed_lowp_dvec1 packed_dvec1; + typedef packed_lowp_dvec2 packed_dvec2; + typedef packed_lowp_dvec3 packed_dvec3; + typedef packed_lowp_dvec4 packed_dvec4; + + typedef aligned_lowp_dmat2 aligned_dmat2; + typedef aligned_lowp_dmat3 aligned_dmat3; + typedef aligned_lowp_dmat4 aligned_dmat4; + typedef packed_lowp_dmat2 packed_dmat2; + typedef packed_lowp_dmat3 packed_dmat3; + typedef packed_lowp_dmat4 packed_dmat4; + + typedef aligned_lowp_dmat2x2 aligned_dmat2x2; + typedef aligned_lowp_dmat2x3 aligned_dmat2x3; + typedef aligned_lowp_dmat2x4 aligned_dmat2x4; + typedef aligned_lowp_dmat3x2 aligned_dmat3x2; + typedef aligned_lowp_dmat3x3 aligned_dmat3x3; + typedef aligned_lowp_dmat3x4 aligned_dmat3x4; + typedef aligned_lowp_dmat4x2 aligned_dmat4x2; + typedef aligned_lowp_dmat4x3 aligned_dmat4x3; + typedef aligned_lowp_dmat4x4 aligned_dmat4x4; + typedef packed_lowp_dmat2x2 packed_dmat2x2; + typedef packed_lowp_dmat2x3 packed_dmat2x3; + typedef packed_lowp_dmat2x4 packed_dmat2x4; + typedef packed_lowp_dmat3x2 packed_dmat3x2; + typedef packed_lowp_dmat3x3 packed_dmat3x3; + typedef packed_lowp_dmat3x4 packed_dmat3x4; + typedef packed_lowp_dmat4x2 packed_dmat4x2; + typedef packed_lowp_dmat4x3 packed_dmat4x3; + typedef packed_lowp_dmat4x4 packed_dmat4x4; +#elif(defined(GLM_PRECISION_MEDIUMP_DOUBLE)) + typedef aligned_mediump_dvec1 aligned_dvec1; + typedef aligned_mediump_dvec2 aligned_dvec2; + typedef aligned_mediump_dvec3 aligned_dvec3; + typedef aligned_mediump_dvec4 aligned_dvec4; + typedef packed_mediump_dvec1 packed_dvec1; + typedef packed_mediump_dvec2 packed_dvec2; + typedef packed_mediump_dvec3 packed_dvec3; + typedef packed_mediump_dvec4 packed_dvec4; + + typedef aligned_mediump_dmat2 aligned_dmat2; + typedef aligned_mediump_dmat3 aligned_dmat3; + typedef aligned_mediump_dmat4 aligned_dmat4; + typedef packed_mediump_dmat2 packed_dmat2; + typedef packed_mediump_dmat3 packed_dmat3; + typedef packed_mediump_dmat4 packed_dmat4; + + typedef aligned_mediump_dmat2x2 aligned_dmat2x2; + typedef aligned_mediump_dmat2x3 aligned_dmat2x3; + typedef aligned_mediump_dmat2x4 aligned_dmat2x4; + typedef aligned_mediump_dmat3x2 aligned_dmat3x2; + typedef aligned_mediump_dmat3x3 aligned_dmat3x3; + typedef aligned_mediump_dmat3x4 aligned_dmat3x4; + typedef aligned_mediump_dmat4x2 aligned_dmat4x2; + typedef aligned_mediump_dmat4x3 aligned_dmat4x3; + typedef aligned_mediump_dmat4x4 aligned_dmat4x4; + typedef packed_mediump_dmat2x2 packed_dmat2x2; + typedef packed_mediump_dmat2x3 packed_dmat2x3; + typedef packed_mediump_dmat2x4 packed_dmat2x4; + typedef packed_mediump_dmat3x2 packed_dmat3x2; + typedef packed_mediump_dmat3x3 packed_dmat3x3; + typedef packed_mediump_dmat3x4 packed_dmat3x4; + typedef packed_mediump_dmat4x2 packed_dmat4x2; + typedef packed_mediump_dmat4x3 packed_dmat4x3; + typedef packed_mediump_dmat4x4 packed_dmat4x4; +#else //defined(GLM_PRECISION_HIGHP_DOUBLE) + /// 1 component vector aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dvec1 aligned_dvec1; + + /// 2 components vector aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dvec2 aligned_dvec2; + + /// 3 components vector aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dvec3 aligned_dvec3; + + /// 4 components vector aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dvec4 aligned_dvec4; + + /// 1 component vector tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dvec1 packed_dvec1; + + /// 2 components vector tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dvec2 packed_dvec2; + + /// 3 components vector tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dvec3 packed_dvec3; + + /// 4 components vector tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dvec4 packed_dvec4; + + /// 2 by 2 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat2 aligned_dmat2; + + /// 3 by 3 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat3 aligned_dmat3; + + /// 4 by 4 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat4 aligned_dmat4; + + /// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat2 packed_dmat2; + + /// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat3 packed_dmat3; + + /// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat4 packed_dmat4; + + /// 2 by 2 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat2x2 aligned_dmat2x2; + + /// 2 by 3 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat2x3 aligned_dmat2x3; + + /// 2 by 4 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat2x4 aligned_dmat2x4; + + /// 3 by 2 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat3x2 aligned_dmat3x2; + + /// 3 by 3 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat3x3 aligned_dmat3x3; + + /// 3 by 4 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat3x4 aligned_dmat3x4; + + /// 4 by 2 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat4x2 aligned_dmat4x2; + + /// 4 by 3 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat4x3 aligned_dmat4x3; + + /// 4 by 4 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat4x4 aligned_dmat4x4; + + /// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat2x2 packed_dmat2x2; + + /// 2 by 3 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat2x3 packed_dmat2x3; + + /// 2 by 4 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat2x4 packed_dmat2x4; + + /// 3 by 2 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat3x2 packed_dmat3x2; + + /// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat3x3 packed_dmat3x3; + + /// 3 by 4 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat3x4 packed_dmat3x4; + + /// 4 by 2 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat4x2 packed_dmat4x2; + + /// 4 by 3 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat4x3 packed_dmat4x3; + + /// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat4x4 packed_dmat4x4; +#endif//GLM_PRECISION + +#if(defined(GLM_PRECISION_LOWP_INT)) + typedef aligned_lowp_ivec1 aligned_ivec1; + typedef aligned_lowp_ivec2 aligned_ivec2; + typedef aligned_lowp_ivec3 aligned_ivec3; + typedef aligned_lowp_ivec4 aligned_ivec4; +#elif(defined(GLM_PRECISION_MEDIUMP_INT)) + typedef aligned_mediump_ivec1 aligned_ivec1; + typedef aligned_mediump_ivec2 aligned_ivec2; + typedef aligned_mediump_ivec3 aligned_ivec3; + typedef aligned_mediump_ivec4 aligned_ivec4; +#else //defined(GLM_PRECISION_HIGHP_INT) + /// 1 component vector aligned in memory of signed integer numbers. + typedef aligned_highp_ivec1 aligned_ivec1; + + /// 2 components vector aligned in memory of signed integer numbers. + typedef aligned_highp_ivec2 aligned_ivec2; + + /// 3 components vector aligned in memory of signed integer numbers. + typedef aligned_highp_ivec3 aligned_ivec3; + + /// 4 components vector aligned in memory of signed integer numbers. + typedef aligned_highp_ivec4 aligned_ivec4; + + /// 1 component vector tightly packed in memory of signed integer numbers. + typedef packed_highp_ivec1 packed_ivec1; + + /// 2 components vector tightly packed in memory of signed integer numbers. + typedef packed_highp_ivec2 packed_ivec2; + + /// 3 components vector tightly packed in memory of signed integer numbers. + typedef packed_highp_ivec3 packed_ivec3; + + /// 4 components vector tightly packed in memory of signed integer numbers. + typedef packed_highp_ivec4 packed_ivec4; +#endif//GLM_PRECISION + + // -- Unsigned integer definition -- + +#if(defined(GLM_PRECISION_LOWP_UINT)) + typedef aligned_lowp_uvec1 aligned_uvec1; + typedef aligned_lowp_uvec2 aligned_uvec2; + typedef aligned_lowp_uvec3 aligned_uvec3; + typedef aligned_lowp_uvec4 aligned_uvec4; +#elif(defined(GLM_PRECISION_MEDIUMP_UINT)) + typedef aligned_mediump_uvec1 aligned_uvec1; + typedef aligned_mediump_uvec2 aligned_uvec2; + typedef aligned_mediump_uvec3 aligned_uvec3; + typedef aligned_mediump_uvec4 aligned_uvec4; +#else //defined(GLM_PRECISION_HIGHP_UINT) + /// 1 component vector aligned in memory of unsigned integer numbers. + typedef aligned_highp_uvec1 aligned_uvec1; + + /// 2 components vector aligned in memory of unsigned integer numbers. + typedef aligned_highp_uvec2 aligned_uvec2; + + /// 3 components vector aligned in memory of unsigned integer numbers. + typedef aligned_highp_uvec3 aligned_uvec3; + + /// 4 components vector aligned in memory of unsigned integer numbers. + typedef aligned_highp_uvec4 aligned_uvec4; + + /// 1 component vector tightly packed in memory of unsigned integer numbers. + typedef packed_highp_uvec1 packed_uvec1; + + /// 2 components vector tightly packed in memory of unsigned integer numbers. + typedef packed_highp_uvec2 packed_uvec2; + + /// 3 components vector tightly packed in memory of unsigned integer numbers. + typedef packed_highp_uvec3 packed_uvec3; + + /// 4 components vector tightly packed in memory of unsigned integer numbers. + typedef packed_highp_uvec4 packed_uvec4; +#endif//GLM_PRECISION + +#if(defined(GLM_PRECISION_LOWP_BOOL)) + typedef aligned_lowp_bvec1 aligned_bvec1; + typedef aligned_lowp_bvec2 aligned_bvec2; + typedef aligned_lowp_bvec3 aligned_bvec3; + typedef aligned_lowp_bvec4 aligned_bvec4; +#elif(defined(GLM_PRECISION_MEDIUMP_BOOL)) + typedef aligned_mediump_bvec1 aligned_bvec1; + typedef aligned_mediump_bvec2 aligned_bvec2; + typedef aligned_mediump_bvec3 aligned_bvec3; + typedef aligned_mediump_bvec4 aligned_bvec4; +#else //defined(GLM_PRECISION_HIGHP_BOOL) + /// 1 component vector aligned in memory of bool values. + typedef aligned_highp_bvec1 aligned_bvec1; + + /// 2 components vector aligned in memory of bool values. + typedef aligned_highp_bvec2 aligned_bvec2; + + /// 3 components vector aligned in memory of bool values. + typedef aligned_highp_bvec3 aligned_bvec3; + + /// 4 components vector aligned in memory of bool values. + typedef aligned_highp_bvec4 aligned_bvec4; + + /// 1 components vector tightly packed in memory of bool values. + typedef packed_highp_bvec1 packed_bvec1; + + /// 2 components vector tightly packed in memory of bool values. + typedef packed_highp_bvec2 packed_bvec2; + + /// 3 components vector tightly packed in memory of bool values. + typedef packed_highp_bvec3 packed_bvec3; + + /// 4 components vector tightly packed in memory of bool values. + typedef packed_highp_bvec4 packed_bvec4; +#endif//GLM_PRECISION + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/type_precision.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/type_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..775e2f484d733b162043d8652ab990e70c9b68eb --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/type_precision.hpp @@ -0,0 +1,2094 @@ +/// @ref gtc_type_precision +/// @file glm/gtc/type_precision.hpp +/// +/// @see core (dependence) +/// @see gtc_quaternion (dependence) +/// +/// @defgroup gtc_type_precision GLM_GTC_type_precision +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Defines specific C++-based qualifier types. + +#pragma once + +// Dependency: +#include "../gtc/quaternion.hpp" +#include "../gtc/vec1.hpp" +#include "../ext/vector_int1_sized.hpp" +#include "../ext/vector_int2_sized.hpp" +#include "../ext/vector_int3_sized.hpp" +#include "../ext/vector_int4_sized.hpp" +#include "../ext/scalar_int_sized.hpp" +#include "../ext/vector_uint1_sized.hpp" +#include "../ext/vector_uint2_sized.hpp" +#include "../ext/vector_uint3_sized.hpp" +#include "../ext/vector_uint4_sized.hpp" +#include "../ext/scalar_uint_sized.hpp" +#include "../detail/type_vec2.hpp" +#include "../detail/type_vec3.hpp" +#include "../detail/type_vec4.hpp" +#include "../detail/type_mat2x2.hpp" +#include "../detail/type_mat2x3.hpp" +#include "../detail/type_mat2x4.hpp" +#include "../detail/type_mat3x2.hpp" +#include "../detail/type_mat3x3.hpp" +#include "../detail/type_mat3x4.hpp" +#include "../detail/type_mat4x2.hpp" +#include "../detail/type_mat4x3.hpp" +#include "../detail/type_mat4x4.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_type_precision extension included") +#endif + +namespace glm +{ + /////////////////////////// + // Signed int vector types + + /// @addtogroup gtc_type_precision + /// @{ + + /// Low qualifier 8 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int8 lowp_int8; + + /// Low qualifier 16 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int16 lowp_int16; + + /// Low qualifier 32 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int32 lowp_int32; + + /// Low qualifier 64 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int64 lowp_int64; + + /// Low qualifier 8 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int8 lowp_int8_t; + + /// Low qualifier 16 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int16 lowp_int16_t; + + /// Low qualifier 32 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int32 lowp_int32_t; + + /// Low qualifier 64 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int64 lowp_int64_t; + + /// Low qualifier 8 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int8 lowp_i8; + + /// Low qualifier 16 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int16 lowp_i16; + + /// Low qualifier 32 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int32 lowp_i32; + + /// Low qualifier 64 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int64 lowp_i64; + + /// Medium qualifier 8 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int8 mediump_int8; + + /// Medium qualifier 16 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int16 mediump_int16; + + /// Medium qualifier 32 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int32 mediump_int32; + + /// Medium qualifier 64 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int64 mediump_int64; + + /// Medium qualifier 8 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int8 mediump_int8_t; + + /// Medium qualifier 16 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int16 mediump_int16_t; + + /// Medium qualifier 32 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int32 mediump_int32_t; + + /// Medium qualifier 64 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int64 mediump_int64_t; + + /// Medium qualifier 8 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int8 mediump_i8; + + /// Medium qualifier 16 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int16 mediump_i16; + + /// Medium qualifier 32 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int32 mediump_i32; + + /// Medium qualifier 64 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int64 mediump_i64; + + /// High qualifier 8 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int8 highp_int8; + + /// High qualifier 16 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int16 highp_int16; + + /// High qualifier 32 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int32 highp_int32; + + /// High qualifier 64 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int64 highp_int64; + + /// High qualifier 8 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int8 highp_int8_t; + + /// High qualifier 16 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int16 highp_int16_t; + + /// 32 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int32 highp_int32_t; + + /// High qualifier 64 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int64 highp_int64_t; + + /// High qualifier 8 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int8 highp_i8; + + /// High qualifier 16 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int16 highp_i16; + + /// High qualifier 32 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int32 highp_i32; + + /// High qualifier 64 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int64 highp_i64; + + +#if GLM_HAS_EXTENDED_INTEGER_TYPE + using std::int8_t; + using std::int16_t; + using std::int32_t; + using std::int64_t; +#else + /// 8 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int8 int8_t; + + /// 16 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int16 int16_t; + + /// 32 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int32 int32_t; + + /// 64 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int64 int64_t; +#endif + + /// 8 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int8 i8; + + /// 16 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int16 i16; + + /// 32 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int32 i32; + + /// 64 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int64 i64; + + ///////////////////////////// + // Unsigned int vector types + + /// Low qualifier 8 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint8 lowp_uint8; + + /// Low qualifier 16 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint16 lowp_uint16; + + /// Low qualifier 32 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint32 lowp_uint32; + + /// Low qualifier 64 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint64 lowp_uint64; + + /// Low qualifier 8 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint8 lowp_uint8_t; + + /// Low qualifier 16 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint16 lowp_uint16_t; + + /// Low qualifier 32 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint32 lowp_uint32_t; + + /// Low qualifier 64 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint64 lowp_uint64_t; + + /// Low qualifier 8 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint8 lowp_u8; + + /// Low qualifier 16 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint16 lowp_u16; + + /// Low qualifier 32 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint32 lowp_u32; + + /// Low qualifier 64 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint64 lowp_u64; + + /// Medium qualifier 8 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint8 mediump_uint8; + + /// Medium qualifier 16 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint16 mediump_uint16; + + /// Medium qualifier 32 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint32 mediump_uint32; + + /// Medium qualifier 64 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint64 mediump_uint64; + + /// Medium qualifier 8 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint8 mediump_uint8_t; + + /// Medium qualifier 16 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint16 mediump_uint16_t; + + /// Medium qualifier 32 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint32 mediump_uint32_t; + + /// Medium qualifier 64 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint64 mediump_uint64_t; + + /// Medium qualifier 8 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint8 mediump_u8; + + /// Medium qualifier 16 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint16 mediump_u16; + + /// Medium qualifier 32 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint32 mediump_u32; + + /// Medium qualifier 64 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint64 mediump_u64; + + /// High qualifier 8 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint8 highp_uint8; + + /// High qualifier 16 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint16 highp_uint16; + + /// High qualifier 32 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint32 highp_uint32; + + /// High qualifier 64 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint64 highp_uint64; + + /// High qualifier 8 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint8 highp_uint8_t; + + /// High qualifier 16 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint16 highp_uint16_t; + + /// High qualifier 32 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint32 highp_uint32_t; + + /// High qualifier 64 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint64 highp_uint64_t; + + /// High qualifier 8 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint8 highp_u8; + + /// High qualifier 16 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint16 highp_u16; + + /// High qualifier 32 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint32 highp_u32; + + /// High qualifier 64 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint64 highp_u64; + +#if GLM_HAS_EXTENDED_INTEGER_TYPE + using std::uint8_t; + using std::uint16_t; + using std::uint32_t; + using std::uint64_t; +#else + /// Default qualifier 8 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint8 uint8_t; + + /// Default qualifier 16 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint16 uint16_t; + + /// Default qualifier 32 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint32 uint32_t; + + /// Default qualifier 64 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint64 uint64_t; +#endif + + /// Default qualifier 8 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint8 u8; + + /// Default qualifier 16 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint16 u16; + + /// Default qualifier 32 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint32 u32; + + /// Default qualifier 64 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint64 u64; + + + + + + ////////////////////// + // Float vector types + + /// Single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float float32; + + /// Double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef double float64; + + /// Low 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 lowp_float32; + + /// Low 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 lowp_float64; + + /// Low 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 lowp_float32_t; + + /// Low 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 lowp_float64_t; + + /// Low 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 lowp_f32; + + /// Low 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 lowp_f64; + + /// Low 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 lowp_float32; + + /// Low 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 lowp_float64; + + /// Low 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 lowp_float32_t; + + /// Low 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 lowp_float64_t; + + /// Low 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 lowp_f32; + + /// Low 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 lowp_f64; + + + /// Low 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 lowp_float32; + + /// Low 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 lowp_float64; + + /// Low 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 lowp_float32_t; + + /// Low 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 lowp_float64_t; + + /// Low 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 lowp_f32; + + /// Low 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 lowp_f64; + + + /// Medium 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 mediump_float32; + + /// Medium 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 mediump_float64; + + /// Medium 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 mediump_float32_t; + + /// Medium 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 mediump_float64_t; + + /// Medium 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 mediump_f32; + + /// Medium 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 mediump_f64; + + + /// High 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 highp_float32; + + /// High 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 highp_float64; + + /// High 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 highp_float32_t; + + /// High 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 highp_float64_t; + + /// High 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 highp_f32; + + /// High 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 highp_f64; + + +#if(defined(GLM_PRECISION_LOWP_FLOAT)) + /// Default 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef lowp_float32_t float32_t; + + /// Default 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef lowp_float64_t float64_t; + + /// Default 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef lowp_f32 f32; + + /// Default 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef lowp_f64 f64; + +#elif(defined(GLM_PRECISION_MEDIUMP_FLOAT)) + /// Default 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef mediump_float32 float32_t; + + /// Default 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef mediump_float64 float64_t; + + /// Default 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef mediump_float32 f32; + + /// Default 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef mediump_float64 f64; + +#else//(defined(GLM_PRECISION_HIGHP_FLOAT)) + + /// Default 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef highp_float32_t float32_t; + + /// Default 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef highp_float64_t float64_t; + + /// Default 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef highp_float32_t f32; + + /// Default 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef highp_float64_t f64; +#endif + + + /// Low single-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, float, lowp> lowp_fvec1; + + /// Low single-qualifier floating-point vector of 2 components. + /// @see gtc_type_precision + typedef vec<2, float, lowp> lowp_fvec2; + + /// Low single-qualifier floating-point vector of 3 components. + /// @see gtc_type_precision + typedef vec<3, float, lowp> lowp_fvec3; + + /// Low single-qualifier floating-point vector of 4 components. + /// @see gtc_type_precision + typedef vec<4, float, lowp> lowp_fvec4; + + + /// Medium single-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, float, mediump> mediump_fvec1; + + /// Medium Single-qualifier floating-point vector of 2 components. + /// @see gtc_type_precision + typedef vec<2, float, mediump> mediump_fvec2; + + /// Medium Single-qualifier floating-point vector of 3 components. + /// @see gtc_type_precision + typedef vec<3, float, mediump> mediump_fvec3; + + /// Medium Single-qualifier floating-point vector of 4 components. + /// @see gtc_type_precision + typedef vec<4, float, mediump> mediump_fvec4; + + + /// High single-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, float, highp> highp_fvec1; + + /// High Single-qualifier floating-point vector of 2 components. + /// @see core_precision + typedef vec<2, float, highp> highp_fvec2; + + /// High Single-qualifier floating-point vector of 3 components. + /// @see core_precision + typedef vec<3, float, highp> highp_fvec3; + + /// High Single-qualifier floating-point vector of 4 components. + /// @see core_precision + typedef vec<4, float, highp> highp_fvec4; + + + /// Low single-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, f32, lowp> lowp_f32vec1; + + /// Low single-qualifier floating-point vector of 2 components. + /// @see core_precision + typedef vec<2, f32, lowp> lowp_f32vec2; + + /// Low single-qualifier floating-point vector of 3 components. + /// @see core_precision + typedef vec<3, f32, lowp> lowp_f32vec3; + + /// Low single-qualifier floating-point vector of 4 components. + /// @see core_precision + typedef vec<4, f32, lowp> lowp_f32vec4; + + /// Medium single-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, f32, mediump> mediump_f32vec1; + + /// Medium single-qualifier floating-point vector of 2 components. + /// @see core_precision + typedef vec<2, f32, mediump> mediump_f32vec2; + + /// Medium single-qualifier floating-point vector of 3 components. + /// @see core_precision + typedef vec<3, f32, mediump> mediump_f32vec3; + + /// Medium single-qualifier floating-point vector of 4 components. + /// @see core_precision + typedef vec<4, f32, mediump> mediump_f32vec4; + + /// High single-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, f32, highp> highp_f32vec1; + + /// High single-qualifier floating-point vector of 2 components. + /// @see gtc_type_precision + typedef vec<2, f32, highp> highp_f32vec2; + + /// High single-qualifier floating-point vector of 3 components. + /// @see gtc_type_precision + typedef vec<3, f32, highp> highp_f32vec3; + + /// High single-qualifier floating-point vector of 4 components. + /// @see gtc_type_precision + typedef vec<4, f32, highp> highp_f32vec4; + + + /// Low double-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, f64, lowp> lowp_f64vec1; + + /// Low double-qualifier floating-point vector of 2 components. + /// @see gtc_type_precision + typedef vec<2, f64, lowp> lowp_f64vec2; + + /// Low double-qualifier floating-point vector of 3 components. + /// @see gtc_type_precision + typedef vec<3, f64, lowp> lowp_f64vec3; + + /// Low double-qualifier floating-point vector of 4 components. + /// @see gtc_type_precision + typedef vec<4, f64, lowp> lowp_f64vec4; + + /// Medium double-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, f64, mediump> mediump_f64vec1; + + /// Medium double-qualifier floating-point vector of 2 components. + /// @see gtc_type_precision + typedef vec<2, f64, mediump> mediump_f64vec2; + + /// Medium double-qualifier floating-point vector of 3 components. + /// @see gtc_type_precision + typedef vec<3, f64, mediump> mediump_f64vec3; + + /// Medium double-qualifier floating-point vector of 4 components. + /// @see gtc_type_precision + typedef vec<4, f64, mediump> mediump_f64vec4; + + /// High double-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, f64, highp> highp_f64vec1; + + /// High double-qualifier floating-point vector of 2 components. + /// @see gtc_type_precision + typedef vec<2, f64, highp> highp_f64vec2; + + /// High double-qualifier floating-point vector of 3 components. + /// @see gtc_type_precision + typedef vec<3, f64, highp> highp_f64vec3; + + /// High double-qualifier floating-point vector of 4 components. + /// @see gtc_type_precision + typedef vec<4, f64, highp> highp_f64vec4; + + + + ////////////////////// + // Float matrix types + + /// Low single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef lowp_f32 lowp_fmat1x1; + + /// Low single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f32, lowp> lowp_fmat2x2; + + /// Low single-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f32, lowp> lowp_fmat2x3; + + /// Low single-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f32, lowp> lowp_fmat2x4; + + /// Low single-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f32, lowp> lowp_fmat3x2; + + /// Low single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f32, lowp> lowp_fmat3x3; + + /// Low single-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f32, lowp> lowp_fmat3x4; + + /// Low single-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f32, lowp> lowp_fmat4x2; + + /// Low single-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f32, lowp> lowp_fmat4x3; + + /// Low single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f32, lowp> lowp_fmat4x4; + + /// Low single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef lowp_fmat1x1 lowp_fmat1; + + /// Low single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef lowp_fmat2x2 lowp_fmat2; + + /// Low single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef lowp_fmat3x3 lowp_fmat3; + + /// Low single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef lowp_fmat4x4 lowp_fmat4; + + + /// Medium single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef mediump_f32 mediump_fmat1x1; + + /// Medium single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f32, mediump> mediump_fmat2x2; + + /// Medium single-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f32, mediump> mediump_fmat2x3; + + /// Medium single-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f32, mediump> mediump_fmat2x4; + + /// Medium single-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f32, mediump> mediump_fmat3x2; + + /// Medium single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f32, mediump> mediump_fmat3x3; + + /// Medium single-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f32, mediump> mediump_fmat3x4; + + /// Medium single-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f32, mediump> mediump_fmat4x2; + + /// Medium single-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f32, mediump> mediump_fmat4x3; + + /// Medium single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f32, mediump> mediump_fmat4x4; + + /// Medium single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef mediump_fmat1x1 mediump_fmat1; + + /// Medium single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mediump_fmat2x2 mediump_fmat2; + + /// Medium single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mediump_fmat3x3 mediump_fmat3; + + /// Medium single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mediump_fmat4x4 mediump_fmat4; + + + /// High single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef highp_f32 highp_fmat1x1; + + /// High single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f32, highp> highp_fmat2x2; + + /// High single-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f32, highp> highp_fmat2x3; + + /// High single-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f32, highp> highp_fmat2x4; + + /// High single-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f32, highp> highp_fmat3x2; + + /// High single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f32, highp> highp_fmat3x3; + + /// High single-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f32, highp> highp_fmat3x4; + + /// High single-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f32, highp> highp_fmat4x2; + + /// High single-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f32, highp> highp_fmat4x3; + + /// High single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f32, highp> highp_fmat4x4; + + /// High single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef highp_fmat1x1 highp_fmat1; + + /// High single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef highp_fmat2x2 highp_fmat2; + + /// High single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef highp_fmat3x3 highp_fmat3; + + /// High single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef highp_fmat4x4 highp_fmat4; + + + /// Low single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef f32 lowp_f32mat1x1; + + /// Low single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f32, lowp> lowp_f32mat2x2; + + /// Low single-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f32, lowp> lowp_f32mat2x3; + + /// Low single-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f32, lowp> lowp_f32mat2x4; + + /// Low single-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f32, lowp> lowp_f32mat3x2; + + /// Low single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f32, lowp> lowp_f32mat3x3; + + /// Low single-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f32, lowp> lowp_f32mat3x4; + + /// Low single-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f32, lowp> lowp_f32mat4x2; + + /// Low single-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f32, lowp> lowp_f32mat4x3; + + /// Low single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f32, lowp> lowp_f32mat4x4; + + /// Low single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef detail::tmat1x1 lowp_f32mat1; + + /// Low single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef lowp_f32mat2x2 lowp_f32mat2; + + /// Low single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef lowp_f32mat3x3 lowp_f32mat3; + + /// Low single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef lowp_f32mat4x4 lowp_f32mat4; + + + /// High single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef f32 mediump_f32mat1x1; + + /// Low single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f32, mediump> mediump_f32mat2x2; + + /// Medium single-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f32, mediump> mediump_f32mat2x3; + + /// Medium single-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f32, mediump> mediump_f32mat2x4; + + /// Medium single-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f32, mediump> mediump_f32mat3x2; + + /// Medium single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f32, mediump> mediump_f32mat3x3; + + /// Medium single-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f32, mediump> mediump_f32mat3x4; + + /// Medium single-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f32, mediump> mediump_f32mat4x2; + + /// Medium single-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f32, mediump> mediump_f32mat4x3; + + /// Medium single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f32, mediump> mediump_f32mat4x4; + + /// Medium single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef detail::tmat1x1 f32mat1; + + /// Medium single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mediump_f32mat2x2 mediump_f32mat2; + + /// Medium single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mediump_f32mat3x3 mediump_f32mat3; + + /// Medium single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mediump_f32mat4x4 mediump_f32mat4; + + + /// High single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef f32 highp_f32mat1x1; + + /// High single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f32, highp> highp_f32mat2x2; + + /// High single-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f32, highp> highp_f32mat2x3; + + /// High single-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f32, highp> highp_f32mat2x4; + + /// High single-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f32, highp> highp_f32mat3x2; + + /// High single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f32, highp> highp_f32mat3x3; + + /// High single-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f32, highp> highp_f32mat3x4; + + /// High single-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f32, highp> highp_f32mat4x2; + + /// High single-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f32, highp> highp_f32mat4x3; + + /// High single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f32, highp> highp_f32mat4x4; + + /// High single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef detail::tmat1x1 f32mat1; + + /// High single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef highp_f32mat2x2 highp_f32mat2; + + /// High single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef highp_f32mat3x3 highp_f32mat3; + + /// High single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef highp_f32mat4x4 highp_f32mat4; + + + /// Low double-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef f64 lowp_f64mat1x1; + + /// Low double-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f64, lowp> lowp_f64mat2x2; + + /// Low double-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f64, lowp> lowp_f64mat2x3; + + /// Low double-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f64, lowp> lowp_f64mat2x4; + + /// Low double-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f64, lowp> lowp_f64mat3x2; + + /// Low double-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f64, lowp> lowp_f64mat3x3; + + /// Low double-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f64, lowp> lowp_f64mat3x4; + + /// Low double-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f64, lowp> lowp_f64mat4x2; + + /// Low double-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f64, lowp> lowp_f64mat4x3; + + /// Low double-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f64, lowp> lowp_f64mat4x4; + + /// Low double-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef lowp_f64mat1x1 lowp_f64mat1; + + /// Low double-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef lowp_f64mat2x2 lowp_f64mat2; + + /// Low double-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef lowp_f64mat3x3 lowp_f64mat3; + + /// Low double-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef lowp_f64mat4x4 lowp_f64mat4; + + + /// Medium double-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef f64 Highp_f64mat1x1; + + /// Medium double-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f64, mediump> mediump_f64mat2x2; + + /// Medium double-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f64, mediump> mediump_f64mat2x3; + + /// Medium double-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f64, mediump> mediump_f64mat2x4; + + /// Medium double-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f64, mediump> mediump_f64mat3x2; + + /// Medium double-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f64, mediump> mediump_f64mat3x3; + + /// Medium double-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f64, mediump> mediump_f64mat3x4; + + /// Medium double-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f64, mediump> mediump_f64mat4x2; + + /// Medium double-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f64, mediump> mediump_f64mat4x3; + + /// Medium double-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f64, mediump> mediump_f64mat4x4; + + /// Medium double-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef mediump_f64mat1x1 mediump_f64mat1; + + /// Medium double-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mediump_f64mat2x2 mediump_f64mat2; + + /// Medium double-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mediump_f64mat3x3 mediump_f64mat3; + + /// Medium double-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mediump_f64mat4x4 mediump_f64mat4; + + /// High double-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef f64 highp_f64mat1x1; + + /// High double-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f64, highp> highp_f64mat2x2; + + /// High double-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f64, highp> highp_f64mat2x3; + + /// High double-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f64, highp> highp_f64mat2x4; + + /// High double-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f64, highp> highp_f64mat3x2; + + /// High double-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f64, highp> highp_f64mat3x3; + + /// High double-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f64, highp> highp_f64mat3x4; + + /// High double-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f64, highp> highp_f64mat4x2; + + /// High double-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f64, highp> highp_f64mat4x3; + + /// High double-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f64, highp> highp_f64mat4x4; + + /// High double-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef highp_f64mat1x1 highp_f64mat1; + + /// High double-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef highp_f64mat2x2 highp_f64mat2; + + /// High double-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef highp_f64mat3x3 highp_f64mat3; + + /// High double-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef highp_f64mat4x4 highp_f64mat4; + + + ///////////////////////////// + // Signed int vector types + + /// Low qualifier signed integer vector of 1 component type. + /// @see gtc_type_precision + typedef vec<1, int, lowp> lowp_ivec1; + + /// Low qualifier signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, int, lowp> lowp_ivec2; + + /// Low qualifier signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, int, lowp> lowp_ivec3; + + /// Low qualifier signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, int, lowp> lowp_ivec4; + + + /// Medium qualifier signed integer vector of 1 component type. + /// @see gtc_type_precision + typedef vec<1, int, mediump> mediump_ivec1; + + /// Medium qualifier signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, int, mediump> mediump_ivec2; + + /// Medium qualifier signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, int, mediump> mediump_ivec3; + + /// Medium qualifier signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, int, mediump> mediump_ivec4; + + + /// High qualifier signed integer vector of 1 component type. + /// @see gtc_type_precision + typedef vec<1, int, highp> highp_ivec1; + + /// High qualifier signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, int, highp> highp_ivec2; + + /// High qualifier signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, int, highp> highp_ivec3; + + /// High qualifier signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, int, highp> highp_ivec4; + + + /// Low qualifier 8 bit signed integer vector of 1 component type. + /// @see gtc_type_precision + typedef vec<1, i8, lowp> lowp_i8vec1; + + /// Low qualifier 8 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i8, lowp> lowp_i8vec2; + + /// Low qualifier 8 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i8, lowp> lowp_i8vec3; + + /// Low qualifier 8 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i8, lowp> lowp_i8vec4; + + + /// Medium qualifier 8 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i8, mediump> mediump_i8vec1; + + /// Medium qualifier 8 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i8, mediump> mediump_i8vec2; + + /// Medium qualifier 8 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i8, mediump> mediump_i8vec3; + + /// Medium qualifier 8 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i8, mediump> mediump_i8vec4; + + + /// High qualifier 8 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i8, highp> highp_i8vec1; + + /// High qualifier 8 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i8, highp> highp_i8vec2; + + /// High qualifier 8 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i8, highp> highp_i8vec3; + + /// High qualifier 8 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i8, highp> highp_i8vec4; + + + /// Low qualifier 16 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i16, lowp> lowp_i16vec1; + + /// Low qualifier 16 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i16, lowp> lowp_i16vec2; + + /// Low qualifier 16 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i16, lowp> lowp_i16vec3; + + /// Low qualifier 16 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i16, lowp> lowp_i16vec4; + + + /// Medium qualifier 16 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i16, mediump> mediump_i16vec1; + + /// Medium qualifier 16 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i16, mediump> mediump_i16vec2; + + /// Medium qualifier 16 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i16, mediump> mediump_i16vec3; + + /// Medium qualifier 16 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i16, mediump> mediump_i16vec4; + + + /// High qualifier 16 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i16, highp> highp_i16vec1; + + /// High qualifier 16 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i16, highp> highp_i16vec2; + + /// High qualifier 16 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i16, highp> highp_i16vec3; + + /// High qualifier 16 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i16, highp> highp_i16vec4; + + + /// Low qualifier 32 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i32, lowp> lowp_i32vec1; + + /// Low qualifier 32 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i32, lowp> lowp_i32vec2; + + /// Low qualifier 32 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i32, lowp> lowp_i32vec3; + + /// Low qualifier 32 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i32, lowp> lowp_i32vec4; + + + /// Medium qualifier 32 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i32, mediump> mediump_i32vec1; + + /// Medium qualifier 32 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i32, mediump> mediump_i32vec2; + + /// Medium qualifier 32 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i32, mediump> mediump_i32vec3; + + /// Medium qualifier 32 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i32, mediump> mediump_i32vec4; + + + /// High qualifier 32 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i32, highp> highp_i32vec1; + + /// High qualifier 32 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i32, highp> highp_i32vec2; + + /// High qualifier 32 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i32, highp> highp_i32vec3; + + /// High qualifier 32 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i32, highp> highp_i32vec4; + + + /// Low qualifier 64 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i64, lowp> lowp_i64vec1; + + /// Low qualifier 64 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i64, lowp> lowp_i64vec2; + + /// Low qualifier 64 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i64, lowp> lowp_i64vec3; + + /// Low qualifier 64 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i64, lowp> lowp_i64vec4; + + + /// Medium qualifier 64 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i64, mediump> mediump_i64vec1; + + /// Medium qualifier 64 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i64, mediump> mediump_i64vec2; + + /// Medium qualifier 64 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i64, mediump> mediump_i64vec3; + + /// Medium qualifier 64 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i64, mediump> mediump_i64vec4; + + + /// High qualifier 64 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i64, highp> highp_i64vec1; + + /// High qualifier 64 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i64, highp> highp_i64vec2; + + /// High qualifier 64 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i64, highp> highp_i64vec3; + + /// High qualifier 64 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i64, highp> highp_i64vec4; + + + ///////////////////////////// + // Unsigned int vector types + + /// Low qualifier unsigned integer vector of 1 component type. + /// @see gtc_type_precision + typedef vec<1, uint, lowp> lowp_uvec1; + + /// Low qualifier unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, uint, lowp> lowp_uvec2; + + /// Low qualifier unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, uint, lowp> lowp_uvec3; + + /// Low qualifier unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, uint, lowp> lowp_uvec4; + + + /// Medium qualifier unsigned integer vector of 1 component type. + /// @see gtc_type_precision + typedef vec<1, uint, mediump> mediump_uvec1; + + /// Medium qualifier unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, uint, mediump> mediump_uvec2; + + /// Medium qualifier unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, uint, mediump> mediump_uvec3; + + /// Medium qualifier unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, uint, mediump> mediump_uvec4; + + + /// High qualifier unsigned integer vector of 1 component type. + /// @see gtc_type_precision + typedef vec<1, uint, highp> highp_uvec1; + + /// High qualifier unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, uint, highp> highp_uvec2; + + /// High qualifier unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, uint, highp> highp_uvec3; + + /// High qualifier unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, uint, highp> highp_uvec4; + + + /// Low qualifier 8 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u8, lowp> lowp_u8vec1; + + /// Low qualifier 8 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u8, lowp> lowp_u8vec2; + + /// Low qualifier 8 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u8, lowp> lowp_u8vec3; + + /// Low qualifier 8 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u8, lowp> lowp_u8vec4; + + + /// Medium qualifier 8 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u8, mediump> mediump_u8vec1; + + /// Medium qualifier 8 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u8, mediump> mediump_u8vec2; + + /// Medium qualifier 8 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u8, mediump> mediump_u8vec3; + + /// Medium qualifier 8 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u8, mediump> mediump_u8vec4; + + + /// High qualifier 8 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u8, highp> highp_u8vec1; + + /// High qualifier 8 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u8, highp> highp_u8vec2; + + /// High qualifier 8 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u8, highp> highp_u8vec3; + + /// High qualifier 8 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u8, highp> highp_u8vec4; + + + /// Low qualifier 16 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u16, lowp> lowp_u16vec1; + + /// Low qualifier 16 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u16, lowp> lowp_u16vec2; + + /// Low qualifier 16 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u16, lowp> lowp_u16vec3; + + /// Low qualifier 16 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u16, lowp> lowp_u16vec4; + + + /// Medium qualifier 16 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u16, mediump> mediump_u16vec1; + + /// Medium qualifier 16 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u16, mediump> mediump_u16vec2; + + /// Medium qualifier 16 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u16, mediump> mediump_u16vec3; + + /// Medium qualifier 16 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u16, mediump> mediump_u16vec4; + + + /// High qualifier 16 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u16, highp> highp_u16vec1; + + /// High qualifier 16 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u16, highp> highp_u16vec2; + + /// High qualifier 16 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u16, highp> highp_u16vec3; + + /// High qualifier 16 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u16, highp> highp_u16vec4; + + + /// Low qualifier 32 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u32, lowp> lowp_u32vec1; + + /// Low qualifier 32 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u32, lowp> lowp_u32vec2; + + /// Low qualifier 32 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u32, lowp> lowp_u32vec3; + + /// Low qualifier 32 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u32, lowp> lowp_u32vec4; + + + /// Medium qualifier 32 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u32, mediump> mediump_u32vec1; + + /// Medium qualifier 32 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u32, mediump> mediump_u32vec2; + + /// Medium qualifier 32 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u32, mediump> mediump_u32vec3; + + /// Medium qualifier 32 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u32, mediump> mediump_u32vec4; + + + /// High qualifier 32 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u32, highp> highp_u32vec1; + + /// High qualifier 32 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u32, highp> highp_u32vec2; + + /// High qualifier 32 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u32, highp> highp_u32vec3; + + /// High qualifier 32 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u32, highp> highp_u32vec4; + + + /// Low qualifier 64 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u64, lowp> lowp_u64vec1; + + /// Low qualifier 64 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u64, lowp> lowp_u64vec2; + + /// Low qualifier 64 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u64, lowp> lowp_u64vec3; + + /// Low qualifier 64 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u64, lowp> lowp_u64vec4; + + + /// Medium qualifier 64 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u64, mediump> mediump_u64vec1; + + /// Medium qualifier 64 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u64, mediump> mediump_u64vec2; + + /// Medium qualifier 64 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u64, mediump> mediump_u64vec3; + + /// Medium qualifier 64 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u64, mediump> mediump_u64vec4; + + + /// High qualifier 64 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u64, highp> highp_u64vec1; + + /// High qualifier 64 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u64, highp> highp_u64vec2; + + /// High qualifier 64 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u64, highp> highp_u64vec3; + + /// High qualifier 64 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u64, highp> highp_u64vec4; + + + ////////////////////// + // Float vector types + + /// 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 float32_t; + + /// 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 f32; + +# ifndef GLM_FORCE_SINGLE_ONLY + + /// 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 float64_t; + + /// 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 f64; +# endif//GLM_FORCE_SINGLE_ONLY + + /// Single-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, float, defaultp> fvec1; + + /// Single-qualifier floating-point vector of 2 components. + /// @see gtc_type_precision + typedef vec<2, float, defaultp> fvec2; + + /// Single-qualifier floating-point vector of 3 components. + /// @see gtc_type_precision + typedef vec<3, float, defaultp> fvec3; + + /// Single-qualifier floating-point vector of 4 components. + /// @see gtc_type_precision + typedef vec<4, float, defaultp> fvec4; + + + /// Single-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, f32, defaultp> f32vec1; + + /// Single-qualifier floating-point vector of 2 components. + /// @see gtc_type_precision + typedef vec<2, f32, defaultp> f32vec2; + + /// Single-qualifier floating-point vector of 3 components. + /// @see gtc_type_precision + typedef vec<3, f32, defaultp> f32vec3; + + /// Single-qualifier floating-point vector of 4 components. + /// @see gtc_type_precision + typedef vec<4, f32, defaultp> f32vec4; + +# ifndef GLM_FORCE_SINGLE_ONLY + /// Double-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, f64, defaultp> f64vec1; + + /// Double-qualifier floating-point vector of 2 components. + /// @see gtc_type_precision + typedef vec<2, f64, defaultp> f64vec2; + + /// Double-qualifier floating-point vector of 3 components. + /// @see gtc_type_precision + typedef vec<3, f64, defaultp> f64vec3; + + /// Double-qualifier floating-point vector of 4 components. + /// @see gtc_type_precision + typedef vec<4, f64, defaultp> f64vec4; +# endif//GLM_FORCE_SINGLE_ONLY + + + ////////////////////// + // Float matrix types + + /// Single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef detail::tmat1x1 fmat1; + + /// Single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f32, defaultp> fmat2; + + /// Single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f32, defaultp> fmat3; + + /// Single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f32, defaultp> fmat4; + + + /// Single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef f32 fmat1x1; + + /// Single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f32, defaultp> fmat2x2; + + /// Single-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f32, defaultp> fmat2x3; + + /// Single-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f32, defaultp> fmat2x4; + + /// Single-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f32, defaultp> fmat3x2; + + /// Single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f32, defaultp> fmat3x3; + + /// Single-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f32, defaultp> fmat3x4; + + /// Single-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f32, defaultp> fmat4x2; + + /// Single-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f32, defaultp> fmat4x3; + + /// Single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f32, defaultp> fmat4x4; + + + /// Single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef detail::tmat1x1 f32mat1; + + /// Single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f32, defaultp> f32mat2; + + /// Single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f32, defaultp> f32mat3; + + /// Single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f32, defaultp> f32mat4; + + + /// Single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef f32 f32mat1x1; + + /// Single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f32, defaultp> f32mat2x2; + + /// Single-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f32, defaultp> f32mat2x3; + + /// Single-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f32, defaultp> f32mat2x4; + + /// Single-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f32, defaultp> f32mat3x2; + + /// Single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f32, defaultp> f32mat3x3; + + /// Single-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f32, defaultp> f32mat3x4; + + /// Single-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f32, defaultp> f32mat4x2; + + /// Single-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f32, defaultp> f32mat4x3; + + /// Single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f32, defaultp> f32mat4x4; + + +# ifndef GLM_FORCE_SINGLE_ONLY + + /// Double-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef detail::tmat1x1 f64mat1; + + /// Double-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f64, defaultp> f64mat2; + + /// Double-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f64, defaultp> f64mat3; + + /// Double-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f64, defaultp> f64mat4; + + + /// Double-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef f64 f64mat1x1; + + /// Double-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f64, defaultp> f64mat2x2; + + /// Double-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f64, defaultp> f64mat2x3; + + /// Double-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f64, defaultp> f64mat2x4; + + /// Double-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f64, defaultp> f64mat3x2; + + /// Double-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f64, defaultp> f64mat3x3; + + /// Double-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f64, defaultp> f64mat3x4; + + /// Double-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f64, defaultp> f64mat4x2; + + /// Double-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f64, defaultp> f64mat4x3; + + /// Double-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f64, defaultp> f64mat4x4; + +# endif//GLM_FORCE_SINGLE_ONLY + + ////////////////////////// + // Quaternion types + + /// Single-qualifier floating-point quaternion. + /// @see gtc_type_precision + typedef qua f32quat; + + /// Low single-qualifier floating-point quaternion. + /// @see gtc_type_precision + typedef qua lowp_f32quat; + + /// Low double-qualifier floating-point quaternion. + /// @see gtc_type_precision + typedef qua lowp_f64quat; + + /// Medium single-qualifier floating-point quaternion. + /// @see gtc_type_precision + typedef qua mediump_f32quat; + +# ifndef GLM_FORCE_SINGLE_ONLY + + /// Medium double-qualifier floating-point quaternion. + /// @see gtc_type_precision + typedef qua mediump_f64quat; + + /// High single-qualifier floating-point quaternion. + /// @see gtc_type_precision + typedef qua highp_f32quat; + + /// High double-qualifier floating-point quaternion. + /// @see gtc_type_precision + typedef qua highp_f64quat; + + /// Double-qualifier floating-point quaternion. + /// @see gtc_type_precision + typedef qua f64quat; + +# endif//GLM_FORCE_SINGLE_ONLY + + /// @} +}//namespace glm + +#include "type_precision.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/type_precision.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/type_precision.inl new file mode 100644 index 0000000000000000000000000000000000000000..ae8091206bd402a59d13d86edc1998b78eadb372 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/type_precision.inl @@ -0,0 +1,6 @@ +/// @ref gtc_precision + +namespace glm +{ + +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/type_ptr.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/type_ptr.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d7e625aa591719bb0c7e42db2509c48a2fc89b8e --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/type_ptr.hpp @@ -0,0 +1,230 @@ +/// @ref gtc_type_ptr +/// @file glm/gtc/type_ptr.hpp +/// +/// @see core (dependence) +/// @see gtc_quaternion (dependence) +/// +/// @defgroup gtc_type_ptr GLM_GTC_type_ptr +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Handles the interaction between pointers and vector, matrix types. +/// +/// This extension defines an overloaded function, glm::value_ptr. It returns +/// a pointer to the memory layout of the object. Matrix types store their values +/// in column-major order. +/// +/// This is useful for uploading data to matrices or copying data to buffer objects. +/// +/// Example: +/// @code +/// #include +/// #include +/// +/// glm::vec3 aVector(3); +/// glm::mat4 someMatrix(1.0); +/// +/// glUniform3fv(uniformLoc, 1, glm::value_ptr(aVector)); +/// glUniformMatrix4fv(uniformMatrixLoc, 1, GL_FALSE, glm::value_ptr(someMatrix)); +/// @endcode +/// +/// need to be included to use the features of this extension. + +#pragma once + +// Dependency: +#include "../gtc/quaternion.hpp" +#include "../gtc/vec1.hpp" +#include "../vec2.hpp" +#include "../vec3.hpp" +#include "../vec4.hpp" +#include "../mat2x2.hpp" +#include "../mat2x3.hpp" +#include "../mat2x4.hpp" +#include "../mat3x2.hpp" +#include "../mat3x3.hpp" +#include "../mat3x4.hpp" +#include "../mat4x2.hpp" +#include "../mat4x3.hpp" +#include "../mat4x4.hpp" +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_type_ptr extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_type_ptr + /// @{ + + /// Return the constant address to the data of the input parameter. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL typename genType::value_type const * value_ptr(genType const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<1, T, Q> make_vec1(vec<1, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<1, T, Q> make_vec1(vec<2, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<1, T, Q> make_vec1(vec<3, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<1, T, Q> make_vec1(vec<4, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<2, T, Q> make_vec2(vec<1, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<2, T, Q> make_vec2(vec<2, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<2, T, Q> make_vec2(vec<3, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<2, T, Q> make_vec2(vec<4, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<3, T, Q> make_vec3(vec<1, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<3, T, Q> make_vec3(vec<2, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<3, T, Q> make_vec3(vec<3, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<3, T, Q> make_vec3(vec<4, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<4, T, Q> make_vec4(vec<1, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<4, T, Q> make_vec4(vec<2, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<4, T, Q> make_vec4(vec<3, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<4, T, Q> make_vec4(vec<4, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<2, T, defaultp> make_vec2(T const * const ptr); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<3, T, defaultp> make_vec3(T const * const ptr); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<4, T, defaultp> make_vec4(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<2, 2, T, defaultp> make_mat2x2(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<2, 3, T, defaultp> make_mat2x3(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<2, 4, T, defaultp> make_mat2x4(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<3, 2, T, defaultp> make_mat3x2(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<3, 3, T, defaultp> make_mat3x3(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<3, 4, T, defaultp> make_mat3x4(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<4, 2, T, defaultp> make_mat4x2(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<4, 3, T, defaultp> make_mat4x3(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> make_mat4x4(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<2, 2, T, defaultp> make_mat2(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<3, 3, T, defaultp> make_mat3(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> make_mat4(T const * const ptr); + + /// Build a quaternion from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL qua make_quat(T const * const ptr); + + /// @} +}//namespace glm + +#include "type_ptr.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/type_ptr.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/type_ptr.inl new file mode 100644 index 0000000000000000000000000000000000000000..26b20b52e9a9265536a755ee24ed4bed56ad3117 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/type_ptr.inl @@ -0,0 +1,386 @@ +/// @ref gtc_type_ptr + +#include + +namespace glm +{ + /// @addtogroup gtc_type_ptr + /// @{ + + template + GLM_FUNC_QUALIFIER T const* value_ptr(vec<2, T, Q> const& v) + { + return &(v.x); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(vec<2, T, Q>& v) + { + return &(v.x); + } + + template + GLM_FUNC_QUALIFIER T const * value_ptr(vec<3, T, Q> const& v) + { + return &(v.x); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(vec<3, T, Q>& v) + { + return &(v.x); + } + + template + GLM_FUNC_QUALIFIER T const* value_ptr(vec<4, T, Q> const& v) + { + return &(v.x); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(vec<4, T, Q>& v) + { + return &(v.x); + } + + template + GLM_FUNC_QUALIFIER T const* value_ptr(mat<2, 2, T, Q> const& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(mat<2, 2, T, Q>& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T const* value_ptr(mat<3, 3, T, Q> const& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(mat<3, 3, T, Q>& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T const* value_ptr(mat<4, 4, T, Q> const& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(mat<4, 4, T, Q>& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T const* value_ptr(mat<2, 3, T, Q> const& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(mat<2, 3, T, Q>& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T const* value_ptr(mat<3, 2, T, Q> const& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(mat<3, 2, T, Q>& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T const* value_ptr(mat<2, 4, T, Q> const& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(mat<2, 4, T, Q>& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T const* value_ptr(mat<4, 2, T, Q> const& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(mat<4, 2, T, Q>& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T const* value_ptr(mat<3, 4, T, Q> const& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(mat<3, 4, T, Q>& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T const* value_ptr(mat<4, 3, T, Q> const& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T * value_ptr(mat<4, 3, T, Q>& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T const * value_ptr(qua const& q) + { + return &(q[0]); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(qua& q) + { + return &(q[0]); + } + + template + GLM_FUNC_DECL vec<1, T, Q> make_vec1(vec<1, T, Q> const& v) + { + return v; + } + + template + GLM_FUNC_DECL vec<1, T, Q> make_vec1(vec<2, T, Q> const& v) + { + return vec<1, T, Q>(v); + } + + template + GLM_FUNC_DECL vec<1, T, Q> make_vec1(vec<3, T, Q> const& v) + { + return vec<1, T, Q>(v); + } + + template + GLM_FUNC_DECL vec<1, T, Q> make_vec1(vec<4, T, Q> const& v) + { + return vec<1, T, Q>(v); + } + + template + GLM_FUNC_DECL vec<2, T, Q> make_vec2(vec<1, T, Q> const& v) + { + return vec<2, T, Q>(v.x, static_cast(0)); + } + + template + GLM_FUNC_DECL vec<2, T, Q> make_vec2(vec<2, T, Q> const& v) + { + return v; + } + + template + GLM_FUNC_DECL vec<2, T, Q> make_vec2(vec<3, T, Q> const& v) + { + return vec<2, T, Q>(v); + } + + template + GLM_FUNC_DECL vec<2, T, Q> make_vec2(vec<4, T, Q> const& v) + { + return vec<2, T, Q>(v); + } + + template + GLM_FUNC_DECL vec<3, T, Q> make_vec3(vec<1, T, Q> const& v) + { + return vec<3, T, Q>(v.x, static_cast(0), static_cast(0)); + } + + template + GLM_FUNC_DECL vec<3, T, Q> make_vec3(vec<2, T, Q> const& v) + { + return vec<3, T, Q>(v.x, v.y, static_cast(0)); + } + + template + GLM_FUNC_DECL vec<3, T, Q> make_vec3(vec<3, T, Q> const& v) + { + return v; + } + + template + GLM_FUNC_DECL vec<3, T, Q> make_vec3(vec<4, T, Q> const& v) + { + return vec<3, T, Q>(v); + } + + template + GLM_FUNC_DECL vec<4, T, Q> make_vec4(vec<1, T, Q> const& v) + { + return vec<4, T, Q>(v.x, static_cast(0), static_cast(0), static_cast(1)); + } + + template + GLM_FUNC_DECL vec<4, T, Q> make_vec4(vec<2, T, Q> const& v) + { + return vec<4, T, Q>(v.x, v.y, static_cast(0), static_cast(1)); + } + + template + GLM_FUNC_DECL vec<4, T, Q> make_vec4(vec<3, T, Q> const& v) + { + return vec<4, T, Q>(v.x, v.y, v.z, static_cast(1)); + } + + template + GLM_FUNC_DECL vec<4, T, Q> make_vec4(vec<4, T, Q> const& v) + { + return v; + } + + template + GLM_FUNC_QUALIFIER vec<2, T, defaultp> make_vec2(T const *const ptr) + { + vec<2, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(vec<2, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, defaultp> make_vec3(T const *const ptr) + { + vec<3, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(vec<3, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<4, T, defaultp> make_vec4(T const *const ptr) + { + vec<4, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(vec<4, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, defaultp> make_mat2x2(T const *const ptr) + { + mat<2, 2, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(mat<2, 2, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, defaultp> make_mat2x3(T const *const ptr) + { + mat<2, 3, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(mat<2, 3, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, defaultp> make_mat2x4(T const *const ptr) + { + mat<2, 4, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(mat<2, 4, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, defaultp> make_mat3x2(T const *const ptr) + { + mat<3, 2, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(mat<3, 2, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, defaultp> make_mat3x3(T const *const ptr) + { + mat<3, 3, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(mat<3, 3, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, defaultp> make_mat3x4(T const *const ptr) + { + mat<3, 4, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(mat<3, 4, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, defaultp> make_mat4x2(T const *const ptr) + { + mat<4, 2, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(mat<4, 2, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, defaultp> make_mat4x3(T const *const ptr) + { + mat<4, 3, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(mat<4, 3, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> make_mat4x4(T const *const ptr) + { + mat<4, 4, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(mat<4, 4, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, defaultp> make_mat2(T const *const ptr) + { + return make_mat2x2(ptr); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, defaultp> make_mat3(T const *const ptr) + { + return make_mat3x3(ptr); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> make_mat4(T const *const ptr) + { + return make_mat4x4(ptr); + } + + template + GLM_FUNC_QUALIFIER qua make_quat(T const *const ptr) + { + qua Result; + memcpy(value_ptr(Result), ptr, sizeof(qua)); + return Result; + } + + /// @} +}//namespace glm + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/ulp.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/ulp.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7b918f0fa764671f7e45c6c4e4d1a275eced63d2 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/ulp.hpp @@ -0,0 +1,155 @@ +/// @ref gtc_ulp +/// @file glm/gtc/ulp.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtc_ulp GLM_GTC_ulp +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Allow the measurement of the accuracy of a function against a reference +/// implementation. This extension works on floating-point data and provide results +/// in ULP. + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../detail/qualifier.hpp" +#include "../detail/_vectorize.hpp" +#include "../ext/scalar_int_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_ulp extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_ulp + /// @{ + + /// Return the next ULP value(s) after the input value(s). + /// + /// @tparam genType A floating-point scalar type. + /// + /// @see gtc_ulp + template + GLM_FUNC_DECL genType next_float(genType x); + + /// Return the previous ULP value(s) before the input value(s). + /// + /// @tparam genType A floating-point scalar type. + /// + /// @see gtc_ulp + template + GLM_FUNC_DECL genType prev_float(genType x); + + /// Return the value(s) ULP distance after the input value(s). + /// + /// @tparam genType A floating-point scalar type. + /// + /// @see gtc_ulp + template + GLM_FUNC_DECL genType next_float(genType x, int ULPs); + + /// Return the value(s) ULP distance before the input value(s). + /// + /// @tparam genType A floating-point scalar type. + /// + /// @see gtc_ulp + template + GLM_FUNC_DECL genType prev_float(genType x, int ULPs); + + /// Return the distance in the number of ULP between 2 single-precision floating-point scalars. + /// + /// @see gtc_ulp + GLM_FUNC_DECL int float_distance(float x, float y); + + /// Return the distance in the number of ULP between 2 double-precision floating-point scalars. + /// + /// @see gtc_ulp + GLM_FUNC_DECL int64 float_distance(double x, double y); + + /// Return the next ULP value(s) after the input value(s). + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_ulp + template + GLM_FUNC_DECL vec next_float(vec const& x); + + /// Return the value(s) ULP distance after the input value(s). + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_ulp + template + GLM_FUNC_DECL vec next_float(vec const& x, int ULPs); + + /// Return the value(s) ULP distance after the input value(s). + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_ulp + template + GLM_FUNC_DECL vec next_float(vec const& x, vec const& ULPs); + + /// Return the previous ULP value(s) before the input value(s). + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_ulp + template + GLM_FUNC_DECL vec prev_float(vec const& x); + + /// Return the value(s) ULP distance before the input value(s). + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_ulp + template + GLM_FUNC_DECL vec prev_float(vec const& x, int ULPs); + + /// Return the value(s) ULP distance before the input value(s). + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_ulp + template + GLM_FUNC_DECL vec prev_float(vec const& x, vec const& ULPs); + + /// Return the distance in the number of ULP between 2 single-precision floating-point scalars. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_ulp + template + GLM_FUNC_DECL vec float_distance(vec const& x, vec const& y); + + /// Return the distance in the number of ULP between 2 double-precision floating-point scalars. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_ulp + template + GLM_FUNC_DECL vec float_distance(vec const& x, vec const& y); + + /// @} +}//namespace glm + +#include "ulp.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/ulp.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/ulp.inl new file mode 100644 index 0000000000000000000000000000000000000000..4ecbd3f437a4e4539dc039626380b759d361e978 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/ulp.inl @@ -0,0 +1,173 @@ +/// @ref gtc_ulp + +#include "../ext/scalar_ulp.hpp" + +namespace glm +{ + template<> + GLM_FUNC_QUALIFIER float next_float(float x) + { +# if GLM_HAS_CXX11_STL + return std::nextafter(x, std::numeric_limits::max()); +# elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS))) + return detail::nextafterf(x, FLT_MAX); +# elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID) + return __builtin_nextafterf(x, FLT_MAX); +# else + return nextafterf(x, FLT_MAX); +# endif + } + + template<> + GLM_FUNC_QUALIFIER double next_float(double x) + { +# if GLM_HAS_CXX11_STL + return std::nextafter(x, std::numeric_limits::max()); +# elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS))) + return detail::nextafter(x, std::numeric_limits::max()); +# elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID) + return __builtin_nextafter(x, DBL_MAX); +# else + return nextafter(x, DBL_MAX); +# endif + } + + template + GLM_FUNC_QUALIFIER T next_float(T x, int ULPs) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'next_float' only accept floating-point input"); + assert(ULPs >= 0); + + T temp = x; + for (int i = 0; i < ULPs; ++i) + temp = next_float(temp); + return temp; + } + + GLM_FUNC_QUALIFIER float prev_float(float x) + { +# if GLM_HAS_CXX11_STL + return std::nextafter(x, std::numeric_limits::min()); +# elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS))) + return detail::nextafterf(x, FLT_MIN); +# elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID) + return __builtin_nextafterf(x, FLT_MIN); +# else + return nextafterf(x, FLT_MIN); +# endif + } + + GLM_FUNC_QUALIFIER double prev_float(double x) + { +# if GLM_HAS_CXX11_STL + return std::nextafter(x, std::numeric_limits::min()); +# elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS))) + return _nextafter(x, DBL_MIN); +# elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID) + return __builtin_nextafter(x, DBL_MIN); +# else + return nextafter(x, DBL_MIN); +# endif + } + + template + GLM_FUNC_QUALIFIER T prev_float(T x, int ULPs) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'prev_float' only accept floating-point input"); + assert(ULPs >= 0); + + T temp = x; + for (int i = 0; i < ULPs; ++i) + temp = prev_float(temp); + return temp; + } + + GLM_FUNC_QUALIFIER int float_distance(float x, float y) + { + detail::float_t const a(x); + detail::float_t const b(y); + + return abs(a.i - b.i); + } + + GLM_FUNC_QUALIFIER int64 float_distance(double x, double y) + { + detail::float_t const a(x); + detail::float_t const b(y); + + return abs(a.i - b.i); + } + + template + GLM_FUNC_QUALIFIER vec next_float(vec const& x) + { + vec Result; + for (length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = next_float(x[i]); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec next_float(vec const& x, int ULPs) + { + vec Result; + for (length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = next_float(x[i], ULPs); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec next_float(vec const& x, vec const& ULPs) + { + vec Result; + for (length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = next_float(x[i], ULPs[i]); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec prev_float(vec const& x) + { + vec Result; + for (length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = prev_float(x[i]); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec prev_float(vec const& x, int ULPs) + { + vec Result; + for (length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = prev_float(x[i], ULPs); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec prev_float(vec const& x, vec const& ULPs) + { + vec Result; + for (length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = prev_float(x[i], ULPs[i]); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec float_distance(vec const& x, vec const& y) + { + vec Result; + for (length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = float_distance(x[i], y[i]); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec float_distance(vec const& x, vec const& y) + { + vec Result; + for (length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = float_distance(x[i], y[i]); + return Result; + } +}//namespace glm + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/vec1.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/vec1.hpp new file mode 100644 index 0000000000000000000000000000000000000000..63697a2157508ac9ae597ea885804c7963e919c7 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtc/vec1.hpp @@ -0,0 +1,30 @@ +/// @ref gtc_vec1 +/// @file glm/gtc/vec1.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtc_vec1 GLM_GTC_vec1 +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Add vec1, ivec1, uvec1 and bvec1 types. + +#pragma once + +// Dependency: +#include "../ext/vector_bool1.hpp" +#include "../ext/vector_bool1_precision.hpp" +#include "../ext/vector_float1.hpp" +#include "../ext/vector_float1_precision.hpp" +#include "../ext/vector_double1.hpp" +#include "../ext/vector_double1_precision.hpp" +#include "../ext/vector_int1.hpp" +#include "../ext/vector_int1_sized.hpp" +#include "../ext/vector_uint1.hpp" +#include "../ext/vector_uint1_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_vec1 extension included") +#endif + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/associated_min_max.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/associated_min_max.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4c036add2186533f34417793cb405d242e65bcc4 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/associated_min_max.hpp @@ -0,0 +1,207 @@ +/// @ref gtx_associated_min_max +/// @file glm/gtx/associated_min_max.hpp +/// +/// @see core (dependence) +/// @see gtx_extented_min_max (dependence) +/// +/// @defgroup gtx_associated_min_max GLM_GTX_associated_min_max +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// @brief Min and max functions that return associated values not the compared ones. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_associated_min_max is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_associated_min_max extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_associated_min_max + /// @{ + + /// Minimum comparison between 2 variables and returns 2 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL U associatedMin(T x, U a, T y, U b); + + /// Minimum comparison between 2 variables and returns 2 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMin( + vec const& x, vec const& a, + vec const& y, vec const& b); + + /// Minimum comparison between 2 variables and returns 2 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMin( + T x, const vec& a, + T y, const vec& b); + + /// Minimum comparison between 2 variables and returns 2 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMin( + vec const& x, U a, + vec const& y, U b); + + /// Minimum comparison between 3 variables and returns 3 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL U associatedMin( + T x, U a, + T y, U b, + T z, U c); + + /// Minimum comparison between 3 variables and returns 3 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMin( + vec const& x, vec const& a, + vec const& y, vec const& b, + vec const& z, vec const& c); + + /// Minimum comparison between 4 variables and returns 4 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL U associatedMin( + T x, U a, + T y, U b, + T z, U c, + T w, U d); + + /// Minimum comparison between 4 variables and returns 4 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMin( + vec const& x, vec const& a, + vec const& y, vec const& b, + vec const& z, vec const& c, + vec const& w, vec const& d); + + /// Minimum comparison between 4 variables and returns 4 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMin( + T x, vec const& a, + T y, vec const& b, + T z, vec const& c, + T w, vec const& d); + + /// Minimum comparison between 4 variables and returns 4 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMin( + vec const& x, U a, + vec const& y, U b, + vec const& z, U c, + vec const& w, U d); + + /// Maximum comparison between 2 variables and returns 2 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL U associatedMax(T x, U a, T y, U b); + + /// Maximum comparison between 2 variables and returns 2 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMax( + vec const& x, vec const& a, + vec const& y, vec const& b); + + /// Maximum comparison between 2 variables and returns 2 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMax( + T x, vec const& a, + T y, vec const& b); + + /// Maximum comparison between 2 variables and returns 2 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMax( + vec const& x, U a, + vec const& y, U b); + + /// Maximum comparison between 3 variables and returns 3 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL U associatedMax( + T x, U a, + T y, U b, + T z, U c); + + /// Maximum comparison between 3 variables and returns 3 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMax( + vec const& x, vec const& a, + vec const& y, vec const& b, + vec const& z, vec const& c); + + /// Maximum comparison between 3 variables and returns 3 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMax( + T x, vec const& a, + T y, vec const& b, + T z, vec const& c); + + /// Maximum comparison between 3 variables and returns 3 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMax( + vec const& x, U a, + vec const& y, U b, + vec const& z, U c); + + /// Maximum comparison between 4 variables and returns 4 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL U associatedMax( + T x, U a, + T y, U b, + T z, U c, + T w, U d); + + /// Maximum comparison between 4 variables and returns 4 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMax( + vec const& x, vec const& a, + vec const& y, vec const& b, + vec const& z, vec const& c, + vec const& w, vec const& d); + + /// Maximum comparison between 4 variables and returns 4 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMax( + T x, vec const& a, + T y, vec const& b, + T z, vec const& c, + T w, vec const& d); + + /// Maximum comparison between 4 variables and returns 4 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMax( + vec const& x, U a, + vec const& y, U b, + vec const& z, U c, + vec const& w, U d); + + /// @} +} //namespace glm + +#include "associated_min_max.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/associated_min_max.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/associated_min_max.inl new file mode 100644 index 0000000000000000000000000000000000000000..f09f5bb74c25b9e54a36b54884e700e53a265111 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/associated_min_max.inl @@ -0,0 +1,354 @@ +/// @ref gtx_associated_min_max + +namespace glm{ + +// Min comparison between 2 variables +template +GLM_FUNC_QUALIFIER U associatedMin(T x, U a, T y, U b) +{ + return x < y ? a : b; +} + +template +GLM_FUNC_QUALIFIER vec associatedMin +( + vec const& x, vec const& a, + vec const& y, vec const& b +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = x[i] < y[i] ? a[i] : b[i]; + return Result; +} + +template +GLM_FUNC_QUALIFIER vec associatedMin +( + T x, const vec& a, + T y, const vec& b +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = x < y ? a[i] : b[i]; + return Result; +} + +template +GLM_FUNC_QUALIFIER vec associatedMin +( + vec const& x, U a, + vec const& y, U b +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = x[i] < y[i] ? a : b; + return Result; +} + +// Min comparison between 3 variables +template +GLM_FUNC_QUALIFIER U associatedMin +( + T x, U a, + T y, U b, + T z, U c +) +{ + U Result = x < y ? (x < z ? a : c) : (y < z ? b : c); + return Result; +} + +template +GLM_FUNC_QUALIFIER vec associatedMin +( + vec const& x, vec const& a, + vec const& y, vec const& b, + vec const& z, vec const& c +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = x[i] < y[i] ? (x[i] < z[i] ? a[i] : c[i]) : (y[i] < z[i] ? b[i] : c[i]); + return Result; +} + +// Min comparison between 4 variables +template +GLM_FUNC_QUALIFIER U associatedMin +( + T x, U a, + T y, U b, + T z, U c, + T w, U d +) +{ + T Test1 = min(x, y); + T Test2 = min(z, w); + U Result1 = x < y ? a : b; + U Result2 = z < w ? c : d; + U Result = Test1 < Test2 ? Result1 : Result2; + return Result; +} + +// Min comparison between 4 variables +template +GLM_FUNC_QUALIFIER vec associatedMin +( + vec const& x, vec const& a, + vec const& y, vec const& b, + vec const& z, vec const& c, + vec const& w, vec const& d +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + { + T Test1 = min(x[i], y[i]); + T Test2 = min(z[i], w[i]); + U Result1 = x[i] < y[i] ? a[i] : b[i]; + U Result2 = z[i] < w[i] ? c[i] : d[i]; + Result[i] = Test1 < Test2 ? Result1 : Result2; + } + return Result; +} + +// Min comparison between 4 variables +template +GLM_FUNC_QUALIFIER vec associatedMin +( + T x, vec const& a, + T y, vec const& b, + T z, vec const& c, + T w, vec const& d +) +{ + T Test1 = min(x, y); + T Test2 = min(z, w); + + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + { + U Result1 = x < y ? a[i] : b[i]; + U Result2 = z < w ? c[i] : d[i]; + Result[i] = Test1 < Test2 ? Result1 : Result2; + } + return Result; +} + +// Min comparison between 4 variables +template +GLM_FUNC_QUALIFIER vec associatedMin +( + vec const& x, U a, + vec const& y, U b, + vec const& z, U c, + vec const& w, U d +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + { + T Test1 = min(x[i], y[i]); + T Test2 = min(z[i], w[i]); + U Result1 = x[i] < y[i] ? a : b; + U Result2 = z[i] < w[i] ? c : d; + Result[i] = Test1 < Test2 ? Result1 : Result2; + } + return Result; +} + +// Max comparison between 2 variables +template +GLM_FUNC_QUALIFIER U associatedMax(T x, U a, T y, U b) +{ + return x > y ? a : b; +} + +// Max comparison between 2 variables +template +GLM_FUNC_QUALIFIER vec associatedMax +( + vec const& x, vec const& a, + vec const& y, vec const& b +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = x[i] > y[i] ? a[i] : b[i]; + return Result; +} + +// Max comparison between 2 variables +template +GLM_FUNC_QUALIFIER vec associatedMax +( + T x, vec const& a, + T y, vec const& b +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = x > y ? a[i] : b[i]; + return Result; +} + +// Max comparison between 2 variables +template +GLM_FUNC_QUALIFIER vec associatedMax +( + vec const& x, U a, + vec const& y, U b +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = x[i] > y[i] ? a : b; + return Result; +} + +// Max comparison between 3 variables +template +GLM_FUNC_QUALIFIER U associatedMax +( + T x, U a, + T y, U b, + T z, U c +) +{ + U Result = x > y ? (x > z ? a : c) : (y > z ? b : c); + return Result; +} + +// Max comparison between 3 variables +template +GLM_FUNC_QUALIFIER vec associatedMax +( + vec const& x, vec const& a, + vec const& y, vec const& b, + vec const& z, vec const& c +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = x[i] > y[i] ? (x[i] > z[i] ? a[i] : c[i]) : (y[i] > z[i] ? b[i] : c[i]); + return Result; +} + +// Max comparison between 3 variables +template +GLM_FUNC_QUALIFIER vec associatedMax +( + T x, vec const& a, + T y, vec const& b, + T z, vec const& c +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = x > y ? (x > z ? a[i] : c[i]) : (y > z ? b[i] : c[i]); + return Result; +} + +// Max comparison between 3 variables +template +GLM_FUNC_QUALIFIER vec associatedMax +( + vec const& x, U a, + vec const& y, U b, + vec const& z, U c +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = x[i] > y[i] ? (x[i] > z[i] ? a : c) : (y[i] > z[i] ? b : c); + return Result; +} + +// Max comparison between 4 variables +template +GLM_FUNC_QUALIFIER U associatedMax +( + T x, U a, + T y, U b, + T z, U c, + T w, U d +) +{ + T Test1 = max(x, y); + T Test2 = max(z, w); + U Result1 = x > y ? a : b; + U Result2 = z > w ? c : d; + U Result = Test1 > Test2 ? Result1 : Result2; + return Result; +} + +// Max comparison between 4 variables +template +GLM_FUNC_QUALIFIER vec associatedMax +( + vec const& x, vec const& a, + vec const& y, vec const& b, + vec const& z, vec const& c, + vec const& w, vec const& d +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + { + T Test1 = max(x[i], y[i]); + T Test2 = max(z[i], w[i]); + U Result1 = x[i] > y[i] ? a[i] : b[i]; + U Result2 = z[i] > w[i] ? c[i] : d[i]; + Result[i] = Test1 > Test2 ? Result1 : Result2; + } + return Result; +} + +// Max comparison between 4 variables +template +GLM_FUNC_QUALIFIER vec associatedMax +( + T x, vec const& a, + T y, vec const& b, + T z, vec const& c, + T w, vec const& d +) +{ + T Test1 = max(x, y); + T Test2 = max(z, w); + + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + { + U Result1 = x > y ? a[i] : b[i]; + U Result2 = z > w ? c[i] : d[i]; + Result[i] = Test1 > Test2 ? Result1 : Result2; + } + return Result; +} + +// Max comparison between 4 variables +template +GLM_FUNC_QUALIFIER vec associatedMax +( + vec const& x, U a, + vec const& y, U b, + vec const& z, U c, + vec const& w, U d +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + { + T Test1 = max(x[i], y[i]); + T Test2 = max(z[i], w[i]); + U Result1 = x[i] > y[i] ? a : b; + U Result2 = z[i] > w[i] ? c : d; + Result[i] = Test1 > Test2 ? Result1 : Result2; + } + return Result; +} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/bit.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/bit.hpp new file mode 100644 index 0000000000000000000000000000000000000000..60a7aef1b463f7c945e8e9e8cabf7f02c49343f1 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/bit.hpp @@ -0,0 +1,98 @@ +/// @ref gtx_bit +/// @file glm/gtx/bit.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_bit GLM_GTX_bit +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Allow to perform bit operations on integer values + +#pragma once + +// Dependencies +#include "../gtc/bitfield.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_bit is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_bit extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_bit + /// @{ + + /// @see gtx_bit + template + GLM_FUNC_DECL genIUType highestBitValue(genIUType Value); + + /// @see gtx_bit + template + GLM_FUNC_DECL genIUType lowestBitValue(genIUType Value); + + /// Find the highest bit set to 1 in a integer variable and return its value. + /// + /// @see gtx_bit + template + GLM_FUNC_DECL vec highestBitValue(vec const& value); + + /// Return the power of two number which value is just higher the input value. + /// Deprecated, use ceilPowerOfTwo from GTC_round instead + /// + /// @see gtc_round + /// @see gtx_bit + template + GLM_DEPRECATED GLM_FUNC_DECL genIUType powerOfTwoAbove(genIUType Value); + + /// Return the power of two number which value is just higher the input value. + /// Deprecated, use ceilPowerOfTwo from GTC_round instead + /// + /// @see gtc_round + /// @see gtx_bit + template + GLM_DEPRECATED GLM_FUNC_DECL vec powerOfTwoAbove(vec const& value); + + /// Return the power of two number which value is just lower the input value. + /// Deprecated, use floorPowerOfTwo from GTC_round instead + /// + /// @see gtc_round + /// @see gtx_bit + template + GLM_DEPRECATED GLM_FUNC_DECL genIUType powerOfTwoBelow(genIUType Value); + + /// Return the power of two number which value is just lower the input value. + /// Deprecated, use floorPowerOfTwo from GTC_round instead + /// + /// @see gtc_round + /// @see gtx_bit + template + GLM_DEPRECATED GLM_FUNC_DECL vec powerOfTwoBelow(vec const& value); + + /// Return the power of two number which value is the closet to the input value. + /// Deprecated, use roundPowerOfTwo from GTC_round instead + /// + /// @see gtc_round + /// @see gtx_bit + template + GLM_DEPRECATED GLM_FUNC_DECL genIUType powerOfTwoNearest(genIUType Value); + + /// Return the power of two number which value is the closet to the input value. + /// Deprecated, use roundPowerOfTwo from GTC_round instead + /// + /// @see gtc_round + /// @see gtx_bit + template + GLM_DEPRECATED GLM_FUNC_DECL vec powerOfTwoNearest(vec const& value); + + /// @} +} //namespace glm + + +#include "bit.inl" + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/bit.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/bit.inl new file mode 100644 index 0000000000000000000000000000000000000000..621b6262406de7bcb462e09085fc82f2d638bdeb --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/bit.inl @@ -0,0 +1,92 @@ +/// @ref gtx_bit + +namespace glm +{ + /////////////////// + // highestBitValue + + template + GLM_FUNC_QUALIFIER genIUType highestBitValue(genIUType Value) + { + genIUType tmp = Value; + genIUType result = genIUType(0); + while(tmp) + { + result = (tmp & (~tmp + 1)); // grab lowest bit + tmp &= ~result; // clear lowest bit + } + return result; + } + + template + GLM_FUNC_QUALIFIER vec highestBitValue(vec const& v) + { + return detail::functor1::call(highestBitValue, v); + } + + /////////////////// + // lowestBitValue + + template + GLM_FUNC_QUALIFIER genIUType lowestBitValue(genIUType Value) + { + return (Value & (~Value + 1)); + } + + template + GLM_FUNC_QUALIFIER vec lowestBitValue(vec const& v) + { + return detail::functor1::call(lowestBitValue, v); + } + + /////////////////// + // powerOfTwoAbove + + template + GLM_FUNC_QUALIFIER genType powerOfTwoAbove(genType value) + { + return isPowerOfTwo(value) ? value : highestBitValue(value) << 1; + } + + template + GLM_FUNC_QUALIFIER vec powerOfTwoAbove(vec const& v) + { + return detail::functor1::call(powerOfTwoAbove, v); + } + + /////////////////// + // powerOfTwoBelow + + template + GLM_FUNC_QUALIFIER genType powerOfTwoBelow(genType value) + { + return isPowerOfTwo(value) ? value : highestBitValue(value); + } + + template + GLM_FUNC_QUALIFIER vec powerOfTwoBelow(vec const& v) + { + return detail::functor1::call(powerOfTwoBelow, v); + } + + ///////////////////// + // powerOfTwoNearest + + template + GLM_FUNC_QUALIFIER genType powerOfTwoNearest(genType value) + { + if(isPowerOfTwo(value)) + return value; + + genType const prev = highestBitValue(value); + genType const next = prev << 1; + return (next - value) < (value - prev) ? next : prev; + } + + template + GLM_FUNC_QUALIFIER vec powerOfTwoNearest(vec const& v) + { + return detail::functor1::call(powerOfTwoNearest, v); + } + +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/closest_point.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/closest_point.hpp new file mode 100644 index 0000000000000000000000000000000000000000..de6dbbff94470ffba44d9ddfa6badfbaa176f3a6 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/closest_point.hpp @@ -0,0 +1,49 @@ +/// @ref gtx_closest_point +/// @file glm/gtx/closest_point.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_closest_point GLM_GTX_closest_point +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Find the point on a straight line which is the closet of a point. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_closest_point is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_closest_point extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_closest_point + /// @{ + + /// Find the point on a straight line which is the closet of a point. + /// @see gtx_closest_point + template + GLM_FUNC_DECL vec<3, T, Q> closestPointOnLine( + vec<3, T, Q> const& point, + vec<3, T, Q> const& a, + vec<3, T, Q> const& b); + + /// 2d lines work as well + template + GLM_FUNC_DECL vec<2, T, Q> closestPointOnLine( + vec<2, T, Q> const& point, + vec<2, T, Q> const& a, + vec<2, T, Q> const& b); + + /// @} +}// namespace glm + +#include "closest_point.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/closest_point.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/closest_point.inl new file mode 100644 index 0000000000000000000000000000000000000000..0a39b042b88c9f57052e0580f5fa8bcbba3ccfcc --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/closest_point.inl @@ -0,0 +1,45 @@ +/// @ref gtx_closest_point + +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec<3, T, Q> closestPointOnLine + ( + vec<3, T, Q> const& point, + vec<3, T, Q> const& a, + vec<3, T, Q> const& b + ) + { + T LineLength = distance(a, b); + vec<3, T, Q> Vector = point - a; + vec<3, T, Q> LineDirection = (b - a) / LineLength; + + // Project Vector to LineDirection to get the distance of point from a + T Distance = dot(Vector, LineDirection); + + if(Distance <= T(0)) return a; + if(Distance >= LineLength) return b; + return a + LineDirection * Distance; + } + + template + GLM_FUNC_QUALIFIER vec<2, T, Q> closestPointOnLine + ( + vec<2, T, Q> const& point, + vec<2, T, Q> const& a, + vec<2, T, Q> const& b + ) + { + T LineLength = distance(a, b); + vec<2, T, Q> Vector = point - a; + vec<2, T, Q> LineDirection = (b - a) / LineLength; + + // Project Vector to LineDirection to get the distance of point from a + T Distance = dot(Vector, LineDirection); + + if(Distance <= T(0)) return a; + if(Distance >= LineLength) return b; + return a + LineDirection * Distance; + } + +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/color_encoding.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/color_encoding.hpp new file mode 100644 index 0000000000000000000000000000000000000000..96ded2a2770ffd1e60d147c863bb26c978d93e05 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/color_encoding.hpp @@ -0,0 +1,54 @@ +/// @ref gtx_color_encoding +/// @file glm/gtx/color_encoding.hpp +/// +/// @see core (dependence) +/// @see gtx_color_encoding (dependence) +/// +/// @defgroup gtx_color_encoding GLM_GTX_color_encoding +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// @brief Allow to perform bit operations on integer values + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../detail/qualifier.hpp" +#include "../vec3.hpp" +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTC_color_encoding is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTC_color_encoding extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_color_encoding + /// @{ + + /// Convert a linear sRGB color to D65 YUV. + template + GLM_FUNC_DECL vec<3, T, Q> convertLinearSRGBToD65XYZ(vec<3, T, Q> const& ColorLinearSRGB); + + /// Convert a linear sRGB color to D50 YUV. + template + GLM_FUNC_DECL vec<3, T, Q> convertLinearSRGBToD50XYZ(vec<3, T, Q> const& ColorLinearSRGB); + + /// Convert a D65 YUV color to linear sRGB. + template + GLM_FUNC_DECL vec<3, T, Q> convertD65XYZToLinearSRGB(vec<3, T, Q> const& ColorD65XYZ); + + /// Convert a D65 YUV color to D50 YUV. + template + GLM_FUNC_DECL vec<3, T, Q> convertD65XYZToD50XYZ(vec<3, T, Q> const& ColorD65XYZ); + + /// @} +} //namespace glm + +#include "color_encoding.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/color_encoding.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/color_encoding.inl new file mode 100644 index 0000000000000000000000000000000000000000..e50fa3efa42c9dd0452e11e0158df443d8c7e55b --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/color_encoding.inl @@ -0,0 +1,45 @@ +/// @ref gtx_color_encoding + +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec<3, T, Q> convertLinearSRGBToD65XYZ(vec<3, T, Q> const& ColorLinearSRGB) + { + vec<3, T, Q> const M(0.490f, 0.17697f, 0.2f); + vec<3, T, Q> const N(0.31f, 0.8124f, 0.01063f); + vec<3, T, Q> const O(0.490f, 0.01f, 0.99f); + + return (M * ColorLinearSRGB + N * ColorLinearSRGB + O * ColorLinearSRGB) * static_cast(5.650675255693055f); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> convertLinearSRGBToD50XYZ(vec<3, T, Q> const& ColorLinearSRGB) + { + vec<3, T, Q> const M(0.436030342570117f, 0.222438466210245f, 0.013897440074263f); + vec<3, T, Q> const N(0.385101860087134f, 0.716942745571917f, 0.097076381494207f); + vec<3, T, Q> const O(0.143067806654203f, 0.060618777416563f, 0.713926257896652f); + + return M * ColorLinearSRGB + N * ColorLinearSRGB + O * ColorLinearSRGB; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> convertD65XYZToLinearSRGB(vec<3, T, Q> const& ColorD65XYZ) + { + vec<3, T, Q> const M(0.41847f, -0.091169f, 0.0009209f); + vec<3, T, Q> const N(-0.15866f, 0.25243f, 0.015708f); + vec<3, T, Q> const O(0.0009209f, -0.0025498f, 0.1786f); + + return M * ColorD65XYZ + N * ColorD65XYZ + O * ColorD65XYZ; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> convertD65XYZToD50XYZ(vec<3, T, Q> const& ColorD65XYZ) + { + vec<3, T, Q> const M(+1.047844353856414f, +0.029549007606644f, -0.009250984365223f); + vec<3, T, Q> const N(+0.022898981050086f, +0.990508028941971f, +0.015072338237051f); + vec<3, T, Q> const O(-0.050206647741605f, -0.017074711360960f, +0.751717835079977f); + + return M * ColorD65XYZ + N * ColorD65XYZ + O * ColorD65XYZ; + } + +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/color_space.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/color_space.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a6343921490840150c6930ec9de0518d16103bee --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/color_space.hpp @@ -0,0 +1,72 @@ +/// @ref gtx_color_space +/// @file glm/gtx/color_space.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_color_space GLM_GTX_color_space +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Related to RGB to HSV conversions and operations. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_color_space is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_color_space extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_color_space + /// @{ + + /// Converts a color from HSV color space to its color in RGB color space. + /// @see gtx_color_space + template + GLM_FUNC_DECL vec<3, T, Q> rgbColor( + vec<3, T, Q> const& hsvValue); + + /// Converts a color from RGB color space to its color in HSV color space. + /// @see gtx_color_space + template + GLM_FUNC_DECL vec<3, T, Q> hsvColor( + vec<3, T, Q> const& rgbValue); + + /// Build a saturation matrix. + /// @see gtx_color_space + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> saturation( + T const s); + + /// Modify the saturation of a color. + /// @see gtx_color_space + template + GLM_FUNC_DECL vec<3, T, Q> saturation( + T const s, + vec<3, T, Q> const& color); + + /// Modify the saturation of a color. + /// @see gtx_color_space + template + GLM_FUNC_DECL vec<4, T, Q> saturation( + T const s, + vec<4, T, Q> const& color); + + /// Compute color luminosity associating ratios (0.33, 0.59, 0.11) to RGB canals. + /// @see gtx_color_space + template + GLM_FUNC_DECL T luminosity( + vec<3, T, Q> const& color); + + /// @} +}//namespace glm + +#include "color_space.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/color_space.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/color_space.inl new file mode 100644 index 0000000000000000000000000000000000000000..0a7059fabb7bd8a2f4696c9b5051c3eeb94aad80 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/color_space.inl @@ -0,0 +1,141 @@ +/// @ref gtx_color_space + +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec<3, T, Q> rgbColor(const vec<3, T, Q>& hsvColor) + { + vec<3, T, Q> hsv = hsvColor; + vec<3, T, Q> rgbColor; + + if(hsv.y == static_cast(0)) + // achromatic (grey) + rgbColor = vec<3, T, Q>(hsv.z); + else + { + T sector = floor(hsv.x * (T(1) / T(60))); + T frac = (hsv.x * (T(1) / T(60))) - sector; + // factorial part of h + T o = hsv.z * (T(1) - hsv.y); + T p = hsv.z * (T(1) - hsv.y * frac); + T q = hsv.z * (T(1) - hsv.y * (T(1) - frac)); + + switch(int(sector)) + { + default: + case 0: + rgbColor.r = hsv.z; + rgbColor.g = q; + rgbColor.b = o; + break; + case 1: + rgbColor.r = p; + rgbColor.g = hsv.z; + rgbColor.b = o; + break; + case 2: + rgbColor.r = o; + rgbColor.g = hsv.z; + rgbColor.b = q; + break; + case 3: + rgbColor.r = o; + rgbColor.g = p; + rgbColor.b = hsv.z; + break; + case 4: + rgbColor.r = q; + rgbColor.g = o; + rgbColor.b = hsv.z; + break; + case 5: + rgbColor.r = hsv.z; + rgbColor.g = o; + rgbColor.b = p; + break; + } + } + + return rgbColor; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> hsvColor(const vec<3, T, Q>& rgbColor) + { + vec<3, T, Q> hsv = rgbColor; + T Min = min(min(rgbColor.r, rgbColor.g), rgbColor.b); + T Max = max(max(rgbColor.r, rgbColor.g), rgbColor.b); + T Delta = Max - Min; + + hsv.z = Max; + + if(Max != static_cast(0)) + { + hsv.y = Delta / hsv.z; + T h = static_cast(0); + + if(rgbColor.r == Max) + // between yellow & magenta + h = static_cast(0) + T(60) * (rgbColor.g - rgbColor.b) / Delta; + else if(rgbColor.g == Max) + // between cyan & yellow + h = static_cast(120) + T(60) * (rgbColor.b - rgbColor.r) / Delta; + else + // between magenta & cyan + h = static_cast(240) + T(60) * (rgbColor.r - rgbColor.g) / Delta; + + if(h < T(0)) + hsv.x = h + T(360); + else + hsv.x = h; + } + else + { + // If r = g = b = 0 then s = 0, h is undefined + hsv.y = static_cast(0); + hsv.x = static_cast(0); + } + + return hsv; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> saturation(T const s) + { + vec<3, T, defaultp> rgbw = vec<3, T, defaultp>(T(0.2126), T(0.7152), T(0.0722)); + + vec<3, T, defaultp> const col((T(1) - s) * rgbw); + + mat<4, 4, T, defaultp> result(T(1)); + result[0][0] = col.x + s; + result[0][1] = col.x; + result[0][2] = col.x; + result[1][0] = col.y; + result[1][1] = col.y + s; + result[1][2] = col.y; + result[2][0] = col.z; + result[2][1] = col.z; + result[2][2] = col.z + s; + + return result; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> saturation(const T s, const vec<3, T, Q>& color) + { + return vec<3, T, Q>(saturation(s) * vec<4, T, Q>(color, T(0))); + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> saturation(const T s, const vec<4, T, Q>& color) + { + return saturation(s) * color; + } + + template + GLM_FUNC_QUALIFIER T luminosity(const vec<3, T, Q>& color) + { + const vec<3, T, Q> tmp = vec<3, T, Q>(0.33, 0.59, 0.11); + return dot(color, tmp); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/color_space_YCoCg.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/color_space_YCoCg.hpp new file mode 100644 index 0000000000000000000000000000000000000000..dd2b771693f6fed894e001da530523ed9d32b951 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/color_space_YCoCg.hpp @@ -0,0 +1,60 @@ +/// @ref gtx_color_space_YCoCg +/// @file glm/gtx/color_space_YCoCg.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_color_space_YCoCg GLM_GTX_color_space_YCoCg +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// RGB to YCoCg conversions and operations + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_color_space_YCoCg is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_color_space_YCoCg extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_color_space_YCoCg + /// @{ + + /// Convert a color from RGB color space to YCoCg color space. + /// @see gtx_color_space_YCoCg + template + GLM_FUNC_DECL vec<3, T, Q> rgb2YCoCg( + vec<3, T, Q> const& rgbColor); + + /// Convert a color from YCoCg color space to RGB color space. + /// @see gtx_color_space_YCoCg + template + GLM_FUNC_DECL vec<3, T, Q> YCoCg2rgb( + vec<3, T, Q> const& YCoCgColor); + + /// Convert a color from RGB color space to YCoCgR color space. + /// @see "YCoCg-R: A Color Space with RGB Reversibility and Low Dynamic Range" + /// @see gtx_color_space_YCoCg + template + GLM_FUNC_DECL vec<3, T, Q> rgb2YCoCgR( + vec<3, T, Q> const& rgbColor); + + /// Convert a color from YCoCgR color space to RGB color space. + /// @see "YCoCg-R: A Color Space with RGB Reversibility and Low Dynamic Range" + /// @see gtx_color_space_YCoCg + template + GLM_FUNC_DECL vec<3, T, Q> YCoCgR2rgb( + vec<3, T, Q> const& YCoCgColor); + + /// @} +}//namespace glm + +#include "color_space_YCoCg.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/color_space_YCoCg.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/color_space_YCoCg.inl new file mode 100644 index 0000000000000000000000000000000000000000..83ba857c08bd248e037e0819c9fcb74558e81a77 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/color_space_YCoCg.inl @@ -0,0 +1,107 @@ +/// @ref gtx_color_space_YCoCg + +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec<3, T, Q> rgb2YCoCg + ( + vec<3, T, Q> const& rgbColor + ) + { + vec<3, T, Q> result; + result.x/*Y */ = rgbColor.r / T(4) + rgbColor.g / T(2) + rgbColor.b / T(4); + result.y/*Co*/ = rgbColor.r / T(2) + rgbColor.g * T(0) - rgbColor.b / T(2); + result.z/*Cg*/ = - rgbColor.r / T(4) + rgbColor.g / T(2) - rgbColor.b / T(4); + return result; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> YCoCg2rgb + ( + vec<3, T, Q> const& YCoCgColor + ) + { + vec<3, T, Q> result; + result.r = YCoCgColor.x + YCoCgColor.y - YCoCgColor.z; + result.g = YCoCgColor.x + YCoCgColor.z; + result.b = YCoCgColor.x - YCoCgColor.y - YCoCgColor.z; + return result; + } + + template + class compute_YCoCgR { + public: + static GLM_FUNC_QUALIFIER vec<3, T, Q> rgb2YCoCgR + ( + vec<3, T, Q> const& rgbColor + ) + { + vec<3, T, Q> result; + result.x/*Y */ = rgbColor.g * static_cast(0.5) + (rgbColor.r + rgbColor.b) * static_cast(0.25); + result.y/*Co*/ = rgbColor.r - rgbColor.b; + result.z/*Cg*/ = rgbColor.g - (rgbColor.r + rgbColor.b) * static_cast(0.5); + return result; + } + + static GLM_FUNC_QUALIFIER vec<3, T, Q> YCoCgR2rgb + ( + vec<3, T, Q> const& YCoCgRColor + ) + { + vec<3, T, Q> result; + T tmp = YCoCgRColor.x - (YCoCgRColor.z * static_cast(0.5)); + result.g = YCoCgRColor.z + tmp; + result.b = tmp - (YCoCgRColor.y * static_cast(0.5)); + result.r = result.b + YCoCgRColor.y; + return result; + } + }; + + template + class compute_YCoCgR { + public: + static GLM_FUNC_QUALIFIER vec<3, T, Q> rgb2YCoCgR + ( + vec<3, T, Q> const& rgbColor + ) + { + vec<3, T, Q> result; + result.y/*Co*/ = rgbColor.r - rgbColor.b; + T tmp = rgbColor.b + (result.y >> 1); + result.z/*Cg*/ = rgbColor.g - tmp; + result.x/*Y */ = tmp + (result.z >> 1); + return result; + } + + static GLM_FUNC_QUALIFIER vec<3, T, Q> YCoCgR2rgb + ( + vec<3, T, Q> const& YCoCgRColor + ) + { + vec<3, T, Q> result; + T tmp = YCoCgRColor.x - (YCoCgRColor.z >> 1); + result.g = YCoCgRColor.z + tmp; + result.b = tmp - (YCoCgRColor.y >> 1); + result.r = result.b + YCoCgRColor.y; + return result; + } + }; + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> rgb2YCoCgR + ( + vec<3, T, Q> const& rgbColor + ) + { + return compute_YCoCgR::is_integer>::rgb2YCoCgR(rgbColor); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> YCoCgR2rgb + ( + vec<3, T, Q> const& YCoCgRColor + ) + { + return compute_YCoCgR::is_integer>::YCoCgR2rgb(YCoCgRColor); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/common.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/common.hpp new file mode 100644 index 0000000000000000000000000000000000000000..254ada2d769550538aefe5f91fcb413ede9543a9 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/common.hpp @@ -0,0 +1,76 @@ +/// @ref gtx_common +/// @file glm/gtx/common.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_common GLM_GTX_common +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// @brief Provide functions to increase the compatibility with Cg and HLSL languages + +#pragma once + +// Dependencies: +#include "../vec2.hpp" +#include "../vec3.hpp" +#include "../vec4.hpp" +#include "../gtc/vec1.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_common is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_common extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_common + /// @{ + + /// Returns true if x is a denormalized number + /// Numbers whose absolute value is too small to be represented in the normal format are represented in an alternate, denormalized format. + /// This format is less precise but can represent values closer to zero. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see GLSL isnan man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL typename genType::bool_type isdenormal(genType const& x); + + /// Similar to 'mod' but with a different rounding and integer support. + /// Returns 'x - y * trunc(x/y)' instead of 'x - y * floor(x/y)' + /// + /// @see GLSL mod vs HLSL fmod + /// @see GLSL mod man page + template + GLM_FUNC_DECL vec fmod(vec const& v); + + /// Returns whether vector components values are within an interval. A open interval excludes its endpoints, and is denoted with square brackets. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_vector_relational + template + GLM_FUNC_DECL vec openBounded(vec const& Value, vec const& Min, vec const& Max); + + /// Returns whether vector components values are within an interval. A closed interval includes its endpoints, and is denoted with square brackets. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_vector_relational + template + GLM_FUNC_DECL vec closeBounded(vec const& Value, vec const& Min, vec const& Max); + + /// @} +}//namespace glm + +#include "common.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/common.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/common.inl new file mode 100644 index 0000000000000000000000000000000000000000..4ad2126d965d793dfd999c323039bf05c04da2d3 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/common.inl @@ -0,0 +1,125 @@ +/// @ref gtx_common + +#include +#include "../gtc/epsilon.hpp" +#include "../gtc/constants.hpp" + +namespace glm{ +namespace detail +{ + template + struct compute_fmod + { + GLM_FUNC_QUALIFIER static vec call(vec const& a, vec const& b) + { + return detail::functor2::call(std::fmod, a, b); + } + }; + + template + struct compute_fmod + { + GLM_FUNC_QUALIFIER static vec call(vec const& a, vec const& b) + { + return a % b; + } + }; +}//namespace detail + + template + GLM_FUNC_QUALIFIER bool isdenormal(T const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isdenormal' only accept floating-point inputs"); + +# if GLM_HAS_CXX11_STL + return std::fpclassify(x) == FP_SUBNORMAL; +# else + return epsilonNotEqual(x, static_cast(0), epsilon()) && std::fabs(x) < std::numeric_limits::min(); +# endif + } + + template + GLM_FUNC_QUALIFIER typename vec<1, T, Q>::bool_type isdenormal + ( + vec<1, T, Q> const& x + ) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isdenormal' only accept floating-point inputs"); + + return typename vec<1, T, Q>::bool_type( + isdenormal(x.x)); + } + + template + GLM_FUNC_QUALIFIER typename vec<2, T, Q>::bool_type isdenormal + ( + vec<2, T, Q> const& x + ) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isdenormal' only accept floating-point inputs"); + + return typename vec<2, T, Q>::bool_type( + isdenormal(x.x), + isdenormal(x.y)); + } + + template + GLM_FUNC_QUALIFIER typename vec<3, T, Q>::bool_type isdenormal + ( + vec<3, T, Q> const& x + ) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isdenormal' only accept floating-point inputs"); + + return typename vec<3, T, Q>::bool_type( + isdenormal(x.x), + isdenormal(x.y), + isdenormal(x.z)); + } + + template + GLM_FUNC_QUALIFIER typename vec<4, T, Q>::bool_type isdenormal + ( + vec<4, T, Q> const& x + ) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isdenormal' only accept floating-point inputs"); + + return typename vec<4, T, Q>::bool_type( + isdenormal(x.x), + isdenormal(x.y), + isdenormal(x.z), + isdenormal(x.w)); + } + + // fmod + template + GLM_FUNC_QUALIFIER genType fmod(genType x, genType y) + { + return fmod(vec<1, genType>(x), y).x; + } + + template + GLM_FUNC_QUALIFIER vec fmod(vec const& x, T y) + { + return detail::compute_fmod::is_iec559>::call(x, vec(y)); + } + + template + GLM_FUNC_QUALIFIER vec fmod(vec const& x, vec const& y) + { + return detail::compute_fmod::is_iec559>::call(x, y); + } + + template + GLM_FUNC_QUALIFIER vec openBounded(vec const& Value, vec const& Min, vec const& Max) + { + return greaterThan(Value, Min) && lessThan(Value, Max); + } + + template + GLM_FUNC_QUALIFIER vec closeBounded(vec const& Value, vec const& Min, vec const& Max) + { + return greaterThanEqual(Value, Min) && lessThanEqual(Value, Max); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/compatibility.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/compatibility.hpp new file mode 100644 index 0000000000000000000000000000000000000000..dc2185cee1b1db17f5fc07d719b9d544bf587bd9 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/compatibility.hpp @@ -0,0 +1,133 @@ +/// @ref gtx_compatibility +/// @file glm/gtx/compatibility.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_compatibility GLM_GTX_compatibility +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Provide functions to increase the compatibility with Cg and HLSL languages + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtc/quaternion.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_compatibility is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_compatibility extension included") +# endif +#endif + +#if GLM_COMPILER & GLM_COMPILER_VC +# include +#elif GLM_COMPILER & GLM_COMPILER_GCC +# include +# if(GLM_PLATFORM & GLM_PLATFORM_ANDROID) +# undef isfinite +# endif +#endif//GLM_COMPILER + +namespace glm +{ + /// @addtogroup gtx_compatibility + /// @{ + + template GLM_FUNC_QUALIFIER T lerp(T x, T y, T a){return mix(x, y, a);} //!< \brief Returns x * (1.0 - a) + y * a, i.e., the linear blend of x and y using the floating-point value a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility) + template GLM_FUNC_QUALIFIER vec<2, T, Q> lerp(const vec<2, T, Q>& x, const vec<2, T, Q>& y, T a){return mix(x, y, a);} //!< \brief Returns x * (1.0 - a) + y * a, i.e., the linear blend of x and y using the floating-point value a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility) + + template GLM_FUNC_QUALIFIER vec<3, T, Q> lerp(const vec<3, T, Q>& x, const vec<3, T, Q>& y, T a){return mix(x, y, a);} //!< \brief Returns x * (1.0 - a) + y * a, i.e., the linear blend of x and y using the floating-point value a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility) + template GLM_FUNC_QUALIFIER vec<4, T, Q> lerp(const vec<4, T, Q>& x, const vec<4, T, Q>& y, T a){return mix(x, y, a);} //!< \brief Returns x * (1.0 - a) + y * a, i.e., the linear blend of x and y using the floating-point value a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility) + template GLM_FUNC_QUALIFIER vec<2, T, Q> lerp(const vec<2, T, Q>& x, const vec<2, T, Q>& y, const vec<2, T, Q>& a){return mix(x, y, a);} //!< \brief Returns the component-wise result of x * (1.0 - a) + y * a, i.e., the linear blend of x and y using vector a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility) + template GLM_FUNC_QUALIFIER vec<3, T, Q> lerp(const vec<3, T, Q>& x, const vec<3, T, Q>& y, const vec<3, T, Q>& a){return mix(x, y, a);} //!< \brief Returns the component-wise result of x * (1.0 - a) + y * a, i.e., the linear blend of x and y using vector a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility) + template GLM_FUNC_QUALIFIER vec<4, T, Q> lerp(const vec<4, T, Q>& x, const vec<4, T, Q>& y, const vec<4, T, Q>& a){return mix(x, y, a);} //!< \brief Returns the component-wise result of x * (1.0 - a) + y * a, i.e., the linear blend of x and y using vector a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility) + + template GLM_FUNC_QUALIFIER T saturate(T x){return clamp(x, T(0), T(1));} //!< \brief Returns clamp(x, 0, 1) for each component in x. (From GLM_GTX_compatibility) + template GLM_FUNC_QUALIFIER vec<2, T, Q> saturate(const vec<2, T, Q>& x){return clamp(x, T(0), T(1));} //!< \brief Returns clamp(x, 0, 1) for each component in x. (From GLM_GTX_compatibility) + template GLM_FUNC_QUALIFIER vec<3, T, Q> saturate(const vec<3, T, Q>& x){return clamp(x, T(0), T(1));} //!< \brief Returns clamp(x, 0, 1) for each component in x. (From GLM_GTX_compatibility) + template GLM_FUNC_QUALIFIER vec<4, T, Q> saturate(const vec<4, T, Q>& x){return clamp(x, T(0), T(1));} //!< \brief Returns clamp(x, 0, 1) for each component in x. (From GLM_GTX_compatibility) + + template GLM_FUNC_QUALIFIER T atan2(T x, T y){return atan(x, y);} //!< \brief Arc tangent. Returns an angle whose tangent is y/x. The signs of x and y are used to determine what quadrant the angle is in. The range of values returned by this function is [-PI, PI]. Results are undefined if x and y are both 0. (From GLM_GTX_compatibility) + template GLM_FUNC_QUALIFIER vec<2, T, Q> atan2(const vec<2, T, Q>& x, const vec<2, T, Q>& y){return atan(x, y);} //!< \brief Arc tangent. Returns an angle whose tangent is y/x. The signs of x and y are used to determine what quadrant the angle is in. The range of values returned by this function is [-PI, PI]. Results are undefined if x and y are both 0. (From GLM_GTX_compatibility) + template GLM_FUNC_QUALIFIER vec<3, T, Q> atan2(const vec<3, T, Q>& x, const vec<3, T, Q>& y){return atan(x, y);} //!< \brief Arc tangent. Returns an angle whose tangent is y/x. The signs of x and y are used to determine what quadrant the angle is in. The range of values returned by this function is [-PI, PI]. Results are undefined if x and y are both 0. (From GLM_GTX_compatibility) + template GLM_FUNC_QUALIFIER vec<4, T, Q> atan2(const vec<4, T, Q>& x, const vec<4, T, Q>& y){return atan(x, y);} //!< \brief Arc tangent. Returns an angle whose tangent is y/x. The signs of x and y are used to determine what quadrant the angle is in. The range of values returned by this function is [-PI, PI]. Results are undefined if x and y are both 0. (From GLM_GTX_compatibility) + + template GLM_FUNC_DECL bool isfinite(genType const& x); //!< \brief Test whether or not a scalar or each vector component is a finite value. (From GLM_GTX_compatibility) + template GLM_FUNC_DECL vec<1, bool, Q> isfinite(const vec<1, T, Q>& x); //!< \brief Test whether or not a scalar or each vector component is a finite value. (From GLM_GTX_compatibility) + template GLM_FUNC_DECL vec<2, bool, Q> isfinite(const vec<2, T, Q>& x); //!< \brief Test whether or not a scalar or each vector component is a finite value. (From GLM_GTX_compatibility) + template GLM_FUNC_DECL vec<3, bool, Q> isfinite(const vec<3, T, Q>& x); //!< \brief Test whether or not a scalar or each vector component is a finite value. (From GLM_GTX_compatibility) + template GLM_FUNC_DECL vec<4, bool, Q> isfinite(const vec<4, T, Q>& x); //!< \brief Test whether or not a scalar or each vector component is a finite value. (From GLM_GTX_compatibility) + + typedef bool bool1; //!< \brief boolean type with 1 component. (From GLM_GTX_compatibility extension) + typedef vec<2, bool, highp> bool2; //!< \brief boolean type with 2 components. (From GLM_GTX_compatibility extension) + typedef vec<3, bool, highp> bool3; //!< \brief boolean type with 3 components. (From GLM_GTX_compatibility extension) + typedef vec<4, bool, highp> bool4; //!< \brief boolean type with 4 components. (From GLM_GTX_compatibility extension) + + typedef bool bool1x1; //!< \brief boolean matrix with 1 x 1 component. (From GLM_GTX_compatibility extension) + typedef mat<2, 2, bool, highp> bool2x2; //!< \brief boolean matrix with 2 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<2, 3, bool, highp> bool2x3; //!< \brief boolean matrix with 2 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<2, 4, bool, highp> bool2x4; //!< \brief boolean matrix with 2 x 4 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 2, bool, highp> bool3x2; //!< \brief boolean matrix with 3 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 3, bool, highp> bool3x3; //!< \brief boolean matrix with 3 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 4, bool, highp> bool3x4; //!< \brief boolean matrix with 3 x 4 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 2, bool, highp> bool4x2; //!< \brief boolean matrix with 4 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 3, bool, highp> bool4x3; //!< \brief boolean matrix with 4 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 4, bool, highp> bool4x4; //!< \brief boolean matrix with 4 x 4 components. (From GLM_GTX_compatibility extension) + + typedef int int1; //!< \brief integer vector with 1 component. (From GLM_GTX_compatibility extension) + typedef vec<2, int, highp> int2; //!< \brief integer vector with 2 components. (From GLM_GTX_compatibility extension) + typedef vec<3, int, highp> int3; //!< \brief integer vector with 3 components. (From GLM_GTX_compatibility extension) + typedef vec<4, int, highp> int4; //!< \brief integer vector with 4 components. (From GLM_GTX_compatibility extension) + + typedef int int1x1; //!< \brief integer matrix with 1 component. (From GLM_GTX_compatibility extension) + typedef mat<2, 2, int, highp> int2x2; //!< \brief integer matrix with 2 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<2, 3, int, highp> int2x3; //!< \brief integer matrix with 2 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<2, 4, int, highp> int2x4; //!< \brief integer matrix with 2 x 4 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 2, int, highp> int3x2; //!< \brief integer matrix with 3 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 3, int, highp> int3x3; //!< \brief integer matrix with 3 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 4, int, highp> int3x4; //!< \brief integer matrix with 3 x 4 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 2, int, highp> int4x2; //!< \brief integer matrix with 4 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 3, int, highp> int4x3; //!< \brief integer matrix with 4 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 4, int, highp> int4x4; //!< \brief integer matrix with 4 x 4 components. (From GLM_GTX_compatibility extension) + + typedef float float1; //!< \brief single-qualifier floating-point vector with 1 component. (From GLM_GTX_compatibility extension) + typedef vec<2, float, highp> float2; //!< \brief single-qualifier floating-point vector with 2 components. (From GLM_GTX_compatibility extension) + typedef vec<3, float, highp> float3; //!< \brief single-qualifier floating-point vector with 3 components. (From GLM_GTX_compatibility extension) + typedef vec<4, float, highp> float4; //!< \brief single-qualifier floating-point vector with 4 components. (From GLM_GTX_compatibility extension) + + typedef float float1x1; //!< \brief single-qualifier floating-point matrix with 1 component. (From GLM_GTX_compatibility extension) + typedef mat<2, 2, float, highp> float2x2; //!< \brief single-qualifier floating-point matrix with 2 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<2, 3, float, highp> float2x3; //!< \brief single-qualifier floating-point matrix with 2 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<2, 4, float, highp> float2x4; //!< \brief single-qualifier floating-point matrix with 2 x 4 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 2, float, highp> float3x2; //!< \brief single-qualifier floating-point matrix with 3 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 3, float, highp> float3x3; //!< \brief single-qualifier floating-point matrix with 3 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 4, float, highp> float3x4; //!< \brief single-qualifier floating-point matrix with 3 x 4 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 2, float, highp> float4x2; //!< \brief single-qualifier floating-point matrix with 4 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 3, float, highp> float4x3; //!< \brief single-qualifier floating-point matrix with 4 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 4, float, highp> float4x4; //!< \brief single-qualifier floating-point matrix with 4 x 4 components. (From GLM_GTX_compatibility extension) + + typedef double double1; //!< \brief double-qualifier floating-point vector with 1 component. (From GLM_GTX_compatibility extension) + typedef vec<2, double, highp> double2; //!< \brief double-qualifier floating-point vector with 2 components. (From GLM_GTX_compatibility extension) + typedef vec<3, double, highp> double3; //!< \brief double-qualifier floating-point vector with 3 components. (From GLM_GTX_compatibility extension) + typedef vec<4, double, highp> double4; //!< \brief double-qualifier floating-point vector with 4 components. (From GLM_GTX_compatibility extension) + + typedef double double1x1; //!< \brief double-qualifier floating-point matrix with 1 component. (From GLM_GTX_compatibility extension) + typedef mat<2, 2, double, highp> double2x2; //!< \brief double-qualifier floating-point matrix with 2 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<2, 3, double, highp> double2x3; //!< \brief double-qualifier floating-point matrix with 2 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<2, 4, double, highp> double2x4; //!< \brief double-qualifier floating-point matrix with 2 x 4 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 2, double, highp> double3x2; //!< \brief double-qualifier floating-point matrix with 3 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 3, double, highp> double3x3; //!< \brief double-qualifier floating-point matrix with 3 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 4, double, highp> double3x4; //!< \brief double-qualifier floating-point matrix with 3 x 4 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 2, double, highp> double4x2; //!< \brief double-qualifier floating-point matrix with 4 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 3, double, highp> double4x3; //!< \brief double-qualifier floating-point matrix with 4 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 4, double, highp> double4x4; //!< \brief double-qualifier floating-point matrix with 4 x 4 components. (From GLM_GTX_compatibility extension) + + /// @} +}//namespace glm + +#include "compatibility.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/compatibility.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/compatibility.inl new file mode 100644 index 0000000000000000000000000000000000000000..1d49496b6c6e817f67f416cac7f3881d8b54ece1 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/compatibility.inl @@ -0,0 +1,62 @@ +#include + +namespace glm +{ + // isfinite + template + GLM_FUNC_QUALIFIER bool isfinite( + genType const& x) + { +# if GLM_HAS_CXX11_STL + return std::isfinite(x) != 0; +# elif GLM_COMPILER & GLM_COMPILER_VC + return _finite(x) != 0; +# elif GLM_COMPILER & GLM_COMPILER_GCC && GLM_PLATFORM & GLM_PLATFORM_ANDROID + return _isfinite(x) != 0; +# else + if (std::numeric_limits::is_integer || std::denorm_absent == std::numeric_limits::has_denorm) + return std::numeric_limits::min() <= x && std::numeric_limits::max() >= x; + else + return -std::numeric_limits::max() <= x && std::numeric_limits::max() >= x; +# endif + } + + template + GLM_FUNC_QUALIFIER vec<1, bool, Q> isfinite( + vec<1, T, Q> const& x) + { + return vec<1, bool, Q>( + isfinite(x.x)); + } + + template + GLM_FUNC_QUALIFIER vec<2, bool, Q> isfinite( + vec<2, T, Q> const& x) + { + return vec<2, bool, Q>( + isfinite(x.x), + isfinite(x.y)); + } + + template + GLM_FUNC_QUALIFIER vec<3, bool, Q> isfinite( + vec<3, T, Q> const& x) + { + return vec<3, bool, Q>( + isfinite(x.x), + isfinite(x.y), + isfinite(x.z)); + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> isfinite( + vec<4, T, Q> const& x) + { + return vec<4, bool, Q>( + isfinite(x.x), + isfinite(x.y), + isfinite(x.z), + isfinite(x.w)); + } + +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/component_wise.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/component_wise.hpp new file mode 100644 index 0000000000000000000000000000000000000000..34a2b0a37517023bd31f7466a356924ce6312e0b --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/component_wise.hpp @@ -0,0 +1,69 @@ +/// @ref gtx_component_wise +/// @file glm/gtx/component_wise.hpp +/// @date 2007-05-21 / 2011-06-07 +/// @author Christophe Riccio +/// +/// @see core (dependence) +/// +/// @defgroup gtx_component_wise GLM_GTX_component_wise +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Operations between components of a type + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../detail/qualifier.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_component_wise is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_component_wise extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_component_wise + /// @{ + + /// Convert an integer vector to a normalized float vector. + /// If the parameter value type is already a floating qualifier type, the value is passed through. + /// @see gtx_component_wise + template + GLM_FUNC_DECL vec compNormalize(vec const& v); + + /// Convert a normalized float vector to an integer vector. + /// If the parameter value type is already a floating qualifier type, the value is passed through. + /// @see gtx_component_wise + template + GLM_FUNC_DECL vec compScale(vec const& v); + + /// Add all vector components together. + /// @see gtx_component_wise + template + GLM_FUNC_DECL typename genType::value_type compAdd(genType const& v); + + /// Multiply all vector components together. + /// @see gtx_component_wise + template + GLM_FUNC_DECL typename genType::value_type compMul(genType const& v); + + /// Find the minimum value between single vector components. + /// @see gtx_component_wise + template + GLM_FUNC_DECL typename genType::value_type compMin(genType const& v); + + /// Find the maximum value between single vector components. + /// @see gtx_component_wise + template + GLM_FUNC_DECL typename genType::value_type compMax(genType const& v); + + /// @} +}//namespace glm + +#include "component_wise.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/component_wise.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/component_wise.inl new file mode 100644 index 0000000000000000000000000000000000000000..cbbc7d41ec007021d1f199eb106c87396a5fc03a --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/component_wise.inl @@ -0,0 +1,127 @@ +/// @ref gtx_component_wise + +#include + +namespace glm{ +namespace detail +{ + template + struct compute_compNormalize + {}; + + template + struct compute_compNormalize + { + GLM_FUNC_QUALIFIER static vec call(vec const& v) + { + floatType const Min = static_cast(std::numeric_limits::min()); + floatType const Max = static_cast(std::numeric_limits::max()); + return (vec(v) - Min) / (Max - Min) * static_cast(2) - static_cast(1); + } + }; + + template + struct compute_compNormalize + { + GLM_FUNC_QUALIFIER static vec call(vec const& v) + { + return vec(v) / static_cast(std::numeric_limits::max()); + } + }; + + template + struct compute_compNormalize + { + GLM_FUNC_QUALIFIER static vec call(vec const& v) + { + return v; + } + }; + + template + struct compute_compScale + {}; + + template + struct compute_compScale + { + GLM_FUNC_QUALIFIER static vec call(vec const& v) + { + floatType const Max = static_cast(std::numeric_limits::max()) + static_cast(0.5); + vec const Scaled(v * Max); + vec const Result(Scaled - static_cast(0.5)); + return Result; + } + }; + + template + struct compute_compScale + { + GLM_FUNC_QUALIFIER static vec call(vec const& v) + { + return vec(vec(v) * static_cast(std::numeric_limits::max())); + } + }; + + template + struct compute_compScale + { + GLM_FUNC_QUALIFIER static vec call(vec const& v) + { + return v; + } + }; +}//namespace detail + + template + GLM_FUNC_QUALIFIER vec compNormalize(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'compNormalize' accepts only floating-point types for 'floatType' template parameter"); + + return detail::compute_compNormalize::is_integer, std::numeric_limits::is_signed>::call(v); + } + + template + GLM_FUNC_QUALIFIER vec compScale(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'compScale' accepts only floating-point types for 'floatType' template parameter"); + + return detail::compute_compScale::is_integer, std::numeric_limits::is_signed>::call(v); + } + + template + GLM_FUNC_QUALIFIER T compAdd(vec const& v) + { + T Result(0); + for(length_t i = 0, n = v.length(); i < n; ++i) + Result += v[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER T compMul(vec const& v) + { + T Result(1); + for(length_t i = 0, n = v.length(); i < n; ++i) + Result *= v[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER T compMin(vec const& v) + { + T Result(v[0]); + for(length_t i = 1, n = v.length(); i < n; ++i) + Result = min(Result, v[i]); + return Result; + } + + template + GLM_FUNC_QUALIFIER T compMax(vec const& v) + { + T Result(v[0]); + for(length_t i = 1, n = v.length(); i < n; ++i) + Result = max(Result, v[i]); + return Result; + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/dual_quaternion.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/dual_quaternion.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6a51ab7d39ffd673cb7bb70d48b46b1c7e8b4c03 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/dual_quaternion.hpp @@ -0,0 +1,274 @@ +/// @ref gtx_dual_quaternion +/// @file glm/gtx/dual_quaternion.hpp +/// @author Maksim Vorobiev (msomeone@gmail.com) +/// +/// @see core (dependence) +/// @see gtc_constants (dependence) +/// @see gtc_quaternion (dependence) +/// +/// @defgroup gtx_dual_quaternion GLM_GTX_dual_quaternion +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Defines a templated dual-quaternion type and several dual-quaternion operations. + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtc/constants.hpp" +#include "../gtc/quaternion.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_dual_quaternion is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_dual_quaternion extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_dual_quaternion + /// @{ + + template + struct tdualquat + { + // -- Implementation detail -- + + typedef T value_type; + typedef qua part_type; + + // -- Data -- + + qua real, dual; + + // -- Component accesses -- + + typedef length_t length_type; + /// Return the count of components of a dual quaternion + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length(){return 2;} + + GLM_FUNC_DECL part_type & operator[](length_type i); + GLM_FUNC_DECL part_type const& operator[](length_type i) const; + + // -- Implicit basic constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR tdualquat() GLM_DEFAULT; + GLM_FUNC_DECL GLM_CONSTEXPR tdualquat(tdualquat const& d) GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR tdualquat(tdualquat const& d); + + // -- Explicit basic constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR tdualquat(qua const& real); + GLM_FUNC_DECL GLM_CONSTEXPR tdualquat(qua const& orientation, vec<3, T, Q> const& translation); + GLM_FUNC_DECL GLM_CONSTEXPR tdualquat(qua const& real, qua const& dual); + + // -- Conversion constructors -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT tdualquat(tdualquat const& q); + + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR tdualquat(mat<2, 4, T, Q> const& holder_mat); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR tdualquat(mat<3, 4, T, Q> const& aug_mat); + + // -- Unary arithmetic operators -- + + GLM_FUNC_DECL tdualquat & operator=(tdualquat const& m) GLM_DEFAULT; + + template + GLM_FUNC_DECL tdualquat & operator=(tdualquat const& m); + template + GLM_FUNC_DECL tdualquat & operator*=(U s); + template + GLM_FUNC_DECL tdualquat & operator/=(U s); + }; + + // -- Unary bit operators -- + + template + GLM_FUNC_DECL tdualquat operator+(tdualquat const& q); + + template + GLM_FUNC_DECL tdualquat operator-(tdualquat const& q); + + // -- Binary operators -- + + template + GLM_FUNC_DECL tdualquat operator+(tdualquat const& q, tdualquat const& p); + + template + GLM_FUNC_DECL tdualquat operator*(tdualquat const& q, tdualquat const& p); + + template + GLM_FUNC_DECL vec<3, T, Q> operator*(tdualquat const& q, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL vec<3, T, Q> operator*(vec<3, T, Q> const& v, tdualquat const& q); + + template + GLM_FUNC_DECL vec<4, T, Q> operator*(tdualquat const& q, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL vec<4, T, Q> operator*(vec<4, T, Q> const& v, tdualquat const& q); + + template + GLM_FUNC_DECL tdualquat operator*(tdualquat const& q, T const& s); + + template + GLM_FUNC_DECL tdualquat operator*(T const& s, tdualquat const& q); + + template + GLM_FUNC_DECL tdualquat operator/(tdualquat const& q, T const& s); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL bool operator==(tdualquat const& q1, tdualquat const& q2); + + template + GLM_FUNC_DECL bool operator!=(tdualquat const& q1, tdualquat const& q2); + + /// Creates an identity dual quaternion. + /// + /// @see gtx_dual_quaternion + template + GLM_FUNC_DECL tdualquat dual_quat_identity(); + + /// Returns the normalized quaternion. + /// + /// @see gtx_dual_quaternion + template + GLM_FUNC_DECL tdualquat normalize(tdualquat const& q); + + /// Returns the linear interpolation of two dual quaternion. + /// + /// @see gtc_dual_quaternion + template + GLM_FUNC_DECL tdualquat lerp(tdualquat const& x, tdualquat const& y, T const& a); + + /// Returns the q inverse. + /// + /// @see gtx_dual_quaternion + template + GLM_FUNC_DECL tdualquat inverse(tdualquat const& q); + + /// Converts a quaternion to a 2 * 4 matrix. + /// + /// @see gtx_dual_quaternion + template + GLM_FUNC_DECL mat<2, 4, T, Q> mat2x4_cast(tdualquat const& x); + + /// Converts a quaternion to a 3 * 4 matrix. + /// + /// @see gtx_dual_quaternion + template + GLM_FUNC_DECL mat<3, 4, T, Q> mat3x4_cast(tdualquat const& x); + + /// Converts a 2 * 4 matrix (matrix which holds real and dual parts) to a quaternion. + /// + /// @see gtx_dual_quaternion + template + GLM_FUNC_DECL tdualquat dualquat_cast(mat<2, 4, T, Q> const& x); + + /// Converts a 3 * 4 matrix (augmented matrix rotation + translation) to a quaternion. + /// + /// @see gtx_dual_quaternion + template + GLM_FUNC_DECL tdualquat dualquat_cast(mat<3, 4, T, Q> const& x); + + + /// Dual-quaternion of low single-qualifier floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef tdualquat lowp_dualquat; + + /// Dual-quaternion of medium single-qualifier floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef tdualquat mediump_dualquat; + + /// Dual-quaternion of high single-qualifier floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef tdualquat highp_dualquat; + + + /// Dual-quaternion of low single-qualifier floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef tdualquat lowp_fdualquat; + + /// Dual-quaternion of medium single-qualifier floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef tdualquat mediump_fdualquat; + + /// Dual-quaternion of high single-qualifier floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef tdualquat highp_fdualquat; + + + /// Dual-quaternion of low double-qualifier floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef tdualquat lowp_ddualquat; + + /// Dual-quaternion of medium double-qualifier floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef tdualquat mediump_ddualquat; + + /// Dual-quaternion of high double-qualifier floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef tdualquat highp_ddualquat; + + +#if(!defined(GLM_PRECISION_HIGHP_FLOAT) && !defined(GLM_PRECISION_MEDIUMP_FLOAT) && !defined(GLM_PRECISION_LOWP_FLOAT)) + /// Dual-quaternion of floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef highp_fdualquat dualquat; + + /// Dual-quaternion of single-qualifier floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef highp_fdualquat fdualquat; +#elif(defined(GLM_PRECISION_HIGHP_FLOAT) && !defined(GLM_PRECISION_MEDIUMP_FLOAT) && !defined(GLM_PRECISION_LOWP_FLOAT)) + typedef highp_fdualquat dualquat; + typedef highp_fdualquat fdualquat; +#elif(!defined(GLM_PRECISION_HIGHP_FLOAT) && defined(GLM_PRECISION_MEDIUMP_FLOAT) && !defined(GLM_PRECISION_LOWP_FLOAT)) + typedef mediump_fdualquat dualquat; + typedef mediump_fdualquat fdualquat; +#elif(!defined(GLM_PRECISION_HIGHP_FLOAT) && !defined(GLM_PRECISION_MEDIUMP_FLOAT) && defined(GLM_PRECISION_LOWP_FLOAT)) + typedef lowp_fdualquat dualquat; + typedef lowp_fdualquat fdualquat; +#else +# error "GLM error: multiple default precision requested for single-precision floating-point types" +#endif + + +#if(!defined(GLM_PRECISION_HIGHP_DOUBLE) && !defined(GLM_PRECISION_MEDIUMP_DOUBLE) && !defined(GLM_PRECISION_LOWP_DOUBLE)) + /// Dual-quaternion of default double-qualifier floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef highp_ddualquat ddualquat; +#elif(defined(GLM_PRECISION_HIGHP_DOUBLE) && !defined(GLM_PRECISION_MEDIUMP_DOUBLE) && !defined(GLM_PRECISION_LOWP_DOUBLE)) + typedef highp_ddualquat ddualquat; +#elif(!defined(GLM_PRECISION_HIGHP_DOUBLE) && defined(GLM_PRECISION_MEDIUMP_DOUBLE) && !defined(GLM_PRECISION_LOWP_DOUBLE)) + typedef mediump_ddualquat ddualquat; +#elif(!defined(GLM_PRECISION_HIGHP_DOUBLE) && !defined(GLM_PRECISION_MEDIUMP_DOUBLE) && defined(GLM_PRECISION_LOWP_DOUBLE)) + typedef lowp_ddualquat ddualquat; +#else +# error "GLM error: Multiple default precision requested for double-precision floating-point types" +#endif + + /// @} +} //namespace glm + +#include "dual_quaternion.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/dual_quaternion.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/dual_quaternion.inl new file mode 100644 index 0000000000000000000000000000000000000000..fad07ea842c1f86ce0aba7e7c78bb85c3781fafe --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/dual_quaternion.inl @@ -0,0 +1,352 @@ +/// @ref gtx_dual_quaternion + +#include "../geometric.hpp" +#include + +namespace glm +{ + // -- Component accesses -- + + template + GLM_FUNC_QUALIFIER typename tdualquat::part_type & tdualquat::operator[](typename tdualquat::length_type i) + { + assert(i >= 0 && i < this->length()); + return (&real)[i]; + } + + template + GLM_FUNC_QUALIFIER typename tdualquat::part_type const& tdualquat::operator[](typename tdualquat::length_type i) const + { + assert(i >= 0 && i < this->length()); + return (&real)[i]; + } + + // -- Implicit basic constructors -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat() +# if GLM_CONFIG_DEFAULTED_FUNCTIONS != GLM_DISABLE + : real(qua()) + , dual(qua(0, 0, 0, 0)) +# endif + {} + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat(tdualquat const& d) + : real(d.real) + , dual(d.dual) + {} +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat(tdualquat const& d) + : real(d.real) + , dual(d.dual) + {} + + // -- Explicit basic constructors -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat(qua const& r) + : real(r), dual(qua(0, 0, 0, 0)) + {} + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat(qua const& q, vec<3, T, Q> const& p) + : real(q), dual( + T(-0.5) * ( p.x*q.x + p.y*q.y + p.z*q.z), + T(+0.5) * ( p.x*q.w + p.y*q.z - p.z*q.y), + T(+0.5) * (-p.x*q.z + p.y*q.w + p.z*q.x), + T(+0.5) * ( p.x*q.y - p.y*q.x + p.z*q.w)) + {} + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat(qua const& r, qua const& d) + : real(r), dual(d) + {} + + // -- Conversion constructors -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat(tdualquat const& q) + : real(q.real) + , dual(q.dual) + {} + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat(mat<2, 4, T, Q> const& m) + { + *this = dualquat_cast(m); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat(mat<3, 4, T, Q> const& m) + { + *this = dualquat_cast(m); + } + + // -- Unary arithmetic operators -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER tdualquat & tdualquat::operator=(tdualquat const& q) + { + this->real = q.real; + this->dual = q.dual; + return *this; + } +# endif + + template + template + GLM_FUNC_QUALIFIER tdualquat & tdualquat::operator=(tdualquat const& q) + { + this->real = q.real; + this->dual = q.dual; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER tdualquat & tdualquat::operator*=(U s) + { + this->real *= static_cast(s); + this->dual *= static_cast(s); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER tdualquat & tdualquat::operator/=(U s) + { + this->real /= static_cast(s); + this->dual /= static_cast(s); + return *this; + } + + // -- Unary bit operators -- + + template + GLM_FUNC_QUALIFIER tdualquat operator+(tdualquat const& q) + { + return q; + } + + template + GLM_FUNC_QUALIFIER tdualquat operator-(tdualquat const& q) + { + return tdualquat(-q.real, -q.dual); + } + + // -- Binary operators -- + + template + GLM_FUNC_QUALIFIER tdualquat operator+(tdualquat const& q, tdualquat const& p) + { + return tdualquat(q.real + p.real,q.dual + p.dual); + } + + template + GLM_FUNC_QUALIFIER tdualquat operator*(tdualquat const& p, tdualquat const& o) + { + return tdualquat(p.real * o.real,p.real * o.dual + p.dual * o.real); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> operator*(tdualquat const& q, vec<3, T, Q> const& v) + { + vec<3, T, Q> const real_v3(q.real.x,q.real.y,q.real.z); + vec<3, T, Q> const dual_v3(q.dual.x,q.dual.y,q.dual.z); + return (cross(real_v3, cross(real_v3,v) + v * q.real.w + dual_v3) + dual_v3 * q.real.w - real_v3 * q.dual.w) * T(2) + v; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> operator*(vec<3, T, Q> const& v, tdualquat const& q) + { + return glm::inverse(q) * v; + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> operator*(tdualquat const& q, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(q * vec<3, T, Q>(v), v.w); + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> operator*(vec<4, T, Q> const& v, tdualquat const& q) + { + return glm::inverse(q) * v; + } + + template + GLM_FUNC_QUALIFIER tdualquat operator*(tdualquat const& q, T const& s) + { + return tdualquat(q.real * s, q.dual * s); + } + + template + GLM_FUNC_QUALIFIER tdualquat operator*(T const& s, tdualquat const& q) + { + return q * s; + } + + template + GLM_FUNC_QUALIFIER tdualquat operator/(tdualquat const& q, T const& s) + { + return tdualquat(q.real / s, q.dual / s); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER bool operator==(tdualquat const& q1, tdualquat const& q2) + { + return (q1.real == q2.real) && (q1.dual == q2.dual); + } + + template + GLM_FUNC_QUALIFIER bool operator!=(tdualquat const& q1, tdualquat const& q2) + { + return (q1.real != q2.real) || (q1.dual != q2.dual); + } + + // -- Operations -- + + template + GLM_FUNC_QUALIFIER tdualquat dual_quat_identity() + { + return tdualquat( + qua(static_cast(1), static_cast(0), static_cast(0), static_cast(0)), + qua(static_cast(0), static_cast(0), static_cast(0), static_cast(0))); + } + + template + GLM_FUNC_QUALIFIER tdualquat normalize(tdualquat const& q) + { + return q / length(q.real); + } + + template + GLM_FUNC_QUALIFIER tdualquat lerp(tdualquat const& x, tdualquat const& y, T const& a) + { + // Dual Quaternion Linear blend aka DLB: + // Lerp is only defined in [0, 1] + assert(a >= static_cast(0)); + assert(a <= static_cast(1)); + T const k = dot(x.real,y.real) < static_cast(0) ? -a : a; + T const one(1); + return tdualquat(x * (one - a) + y * k); + } + + template + GLM_FUNC_QUALIFIER tdualquat inverse(tdualquat const& q) + { + const glm::qua real = conjugate(q.real); + const glm::qua dual = conjugate(q.dual); + return tdualquat(real, dual + (real * (-2.0f * dot(real,dual)))); + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> mat2x4_cast(tdualquat const& x) + { + return mat<2, 4, T, Q>( x[0].x, x[0].y, x[0].z, x[0].w, x[1].x, x[1].y, x[1].z, x[1].w ); + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> mat3x4_cast(tdualquat const& x) + { + qua r = x.real / length2(x.real); + + qua const rr(r.w * x.real.w, r.x * x.real.x, r.y * x.real.y, r.z * x.real.z); + r *= static_cast(2); + + T const xy = r.x * x.real.y; + T const xz = r.x * x.real.z; + T const yz = r.y * x.real.z; + T const wx = r.w * x.real.x; + T const wy = r.w * x.real.y; + T const wz = r.w * x.real.z; + + vec<4, T, Q> const a( + rr.w + rr.x - rr.y - rr.z, + xy - wz, + xz + wy, + -(x.dual.w * r.x - x.dual.x * r.w + x.dual.y * r.z - x.dual.z * r.y)); + + vec<4, T, Q> const b( + xy + wz, + rr.w + rr.y - rr.x - rr.z, + yz - wx, + -(x.dual.w * r.y - x.dual.x * r.z - x.dual.y * r.w + x.dual.z * r.x)); + + vec<4, T, Q> const c( + xz - wy, + yz + wx, + rr.w + rr.z - rr.x - rr.y, + -(x.dual.w * r.z + x.dual.x * r.y - x.dual.y * r.x - x.dual.z * r.w)); + + return mat<3, 4, T, Q>(a, b, c); + } + + template + GLM_FUNC_QUALIFIER tdualquat dualquat_cast(mat<2, 4, T, Q> const& x) + { + return tdualquat( + qua( x[0].w, x[0].x, x[0].y, x[0].z ), + qua( x[1].w, x[1].x, x[1].y, x[1].z )); + } + + template + GLM_FUNC_QUALIFIER tdualquat dualquat_cast(mat<3, 4, T, Q> const& x) + { + qua real; + + T const trace = x[0].x + x[1].y + x[2].z; + if(trace > static_cast(0)) + { + T const r = sqrt(T(1) + trace); + T const invr = static_cast(0.5) / r; + real.w = static_cast(0.5) * r; + real.x = (x[2].y - x[1].z) * invr; + real.y = (x[0].z - x[2].x) * invr; + real.z = (x[1].x - x[0].y) * invr; + } + else if(x[0].x > x[1].y && x[0].x > x[2].z) + { + T const r = sqrt(T(1) + x[0].x - x[1].y - x[2].z); + T const invr = static_cast(0.5) / r; + real.x = static_cast(0.5)*r; + real.y = (x[1].x + x[0].y) * invr; + real.z = (x[0].z + x[2].x) * invr; + real.w = (x[2].y - x[1].z) * invr; + } + else if(x[1].y > x[2].z) + { + T const r = sqrt(T(1) + x[1].y - x[0].x - x[2].z); + T const invr = static_cast(0.5) / r; + real.x = (x[1].x + x[0].y) * invr; + real.y = static_cast(0.5) * r; + real.z = (x[2].y + x[1].z) * invr; + real.w = (x[0].z - x[2].x) * invr; + } + else + { + T const r = sqrt(T(1) + x[2].z - x[0].x - x[1].y); + T const invr = static_cast(0.5) / r; + real.x = (x[0].z + x[2].x) * invr; + real.y = (x[2].y + x[1].z) * invr; + real.z = static_cast(0.5) * r; + real.w = (x[1].x - x[0].y) * invr; + } + + qua dual; + dual.x = static_cast(0.5) * ( x[0].w * real.w + x[1].w * real.z - x[2].w * real.y); + dual.y = static_cast(0.5) * (-x[0].w * real.z + x[1].w * real.w + x[2].w * real.x); + dual.z = static_cast(0.5) * ( x[0].w * real.y - x[1].w * real.x + x[2].w * real.w); + dual.w = -static_cast(0.5) * ( x[0].w * real.x + x[1].w * real.y + x[2].w * real.z); + return tdualquat(real, dual); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/easing.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/easing.hpp new file mode 100644 index 0000000000000000000000000000000000000000..da89826a90eb82a8fcbfd2861d4bc9d43179edb2 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/easing.hpp @@ -0,0 +1,219 @@ +/// @ref gtx_easing +/// @file glm/gtx/easing.hpp +/// @author Robert Chisholm +/// +/// @see core (dependence) +/// +/// @defgroup gtx_easing GLM_GTX_easing +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Easing functions for animations and transitions +/// All functions take a parameter x in the range [0.0,1.0] +/// +/// Based on the AHEasing project of Warren Moore (https://github.com/warrenm/AHEasing) + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtc/constants.hpp" +#include "../detail/qualifier.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_easing is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_easing extension included") +# endif +#endif + +namespace glm{ + /// @addtogroup gtx_easing + /// @{ + + /// Modelled after the line y = x + /// @see gtx_easing + template + GLM_FUNC_DECL genType linearInterpolation(genType const & a); + + /// Modelled after the parabola y = x^2 + /// @see gtx_easing + template + GLM_FUNC_DECL genType quadraticEaseIn(genType const & a); + + /// Modelled after the parabola y = -x^2 + 2x + /// @see gtx_easing + template + GLM_FUNC_DECL genType quadraticEaseOut(genType const & a); + + /// Modelled after the piecewise quadratic + /// y = (1/2)((2x)^2) ; [0, 0.5) + /// y = -(1/2)((2x-1)*(2x-3) - 1) ; [0.5, 1] + /// @see gtx_easing + template + GLM_FUNC_DECL genType quadraticEaseInOut(genType const & a); + + /// Modelled after the cubic y = x^3 + template + GLM_FUNC_DECL genType cubicEaseIn(genType const & a); + + /// Modelled after the cubic y = (x - 1)^3 + 1 + /// @see gtx_easing + template + GLM_FUNC_DECL genType cubicEaseOut(genType const & a); + + /// Modelled after the piecewise cubic + /// y = (1/2)((2x)^3) ; [0, 0.5) + /// y = (1/2)((2x-2)^3 + 2) ; [0.5, 1] + /// @see gtx_easing + template + GLM_FUNC_DECL genType cubicEaseInOut(genType const & a); + + /// Modelled after the quartic x^4 + /// @see gtx_easing + template + GLM_FUNC_DECL genType quarticEaseIn(genType const & a); + + /// Modelled after the quartic y = 1 - (x - 1)^4 + /// @see gtx_easing + template + GLM_FUNC_DECL genType quarticEaseOut(genType const & a); + + /// Modelled after the piecewise quartic + /// y = (1/2)((2x)^4) ; [0, 0.5) + /// y = -(1/2)((2x-2)^4 - 2) ; [0.5, 1] + /// @see gtx_easing + template + GLM_FUNC_DECL genType quarticEaseInOut(genType const & a); + + /// Modelled after the quintic y = x^5 + /// @see gtx_easing + template + GLM_FUNC_DECL genType quinticEaseIn(genType const & a); + + /// Modelled after the quintic y = (x - 1)^5 + 1 + /// @see gtx_easing + template + GLM_FUNC_DECL genType quinticEaseOut(genType const & a); + + /// Modelled after the piecewise quintic + /// y = (1/2)((2x)^5) ; [0, 0.5) + /// y = (1/2)((2x-2)^5 + 2) ; [0.5, 1] + /// @see gtx_easing + template + GLM_FUNC_DECL genType quinticEaseInOut(genType const & a); + + /// Modelled after quarter-cycle of sine wave + /// @see gtx_easing + template + GLM_FUNC_DECL genType sineEaseIn(genType const & a); + + /// Modelled after quarter-cycle of sine wave (different phase) + /// @see gtx_easing + template + GLM_FUNC_DECL genType sineEaseOut(genType const & a); + + /// Modelled after half sine wave + /// @see gtx_easing + template + GLM_FUNC_DECL genType sineEaseInOut(genType const & a); + + /// Modelled after shifted quadrant IV of unit circle + /// @see gtx_easing + template + GLM_FUNC_DECL genType circularEaseIn(genType const & a); + + /// Modelled after shifted quadrant II of unit circle + /// @see gtx_easing + template + GLM_FUNC_DECL genType circularEaseOut(genType const & a); + + /// Modelled after the piecewise circular function + /// y = (1/2)(1 - sqrt(1 - 4x^2)) ; [0, 0.5) + /// y = (1/2)(sqrt(-(2x - 3)*(2x - 1)) + 1) ; [0.5, 1] + /// @see gtx_easing + template + GLM_FUNC_DECL genType circularEaseInOut(genType const & a); + + /// Modelled after the exponential function y = 2^(10(x - 1)) + /// @see gtx_easing + template + GLM_FUNC_DECL genType exponentialEaseIn(genType const & a); + + /// Modelled after the exponential function y = -2^(-10x) + 1 + /// @see gtx_easing + template + GLM_FUNC_DECL genType exponentialEaseOut(genType const & a); + + /// Modelled after the piecewise exponential + /// y = (1/2)2^(10(2x - 1)) ; [0,0.5) + /// y = -(1/2)*2^(-10(2x - 1))) + 1 ; [0.5,1] + /// @see gtx_easing + template + GLM_FUNC_DECL genType exponentialEaseInOut(genType const & a); + + /// Modelled after the damped sine wave y = sin(13pi/2*x)*pow(2, 10 * (x - 1)) + /// @see gtx_easing + template + GLM_FUNC_DECL genType elasticEaseIn(genType const & a); + + /// Modelled after the damped sine wave y = sin(-13pi/2*(x + 1))*pow(2, -10x) + 1 + /// @see gtx_easing + template + GLM_FUNC_DECL genType elasticEaseOut(genType const & a); + + /// Modelled after the piecewise exponentially-damped sine wave: + /// y = (1/2)*sin(13pi/2*(2*x))*pow(2, 10 * ((2*x) - 1)) ; [0,0.5) + /// y = (1/2)*(sin(-13pi/2*((2x-1)+1))*pow(2,-10(2*x-1)) + 2) ; [0.5, 1] + /// @see gtx_easing + template + GLM_FUNC_DECL genType elasticEaseInOut(genType const & a); + + /// @see gtx_easing + template + GLM_FUNC_DECL genType backEaseIn(genType const& a); + + /// @see gtx_easing + template + GLM_FUNC_DECL genType backEaseOut(genType const& a); + + /// @see gtx_easing + template + GLM_FUNC_DECL genType backEaseInOut(genType const& a); + + /// @param a parameter + /// @param o Optional overshoot modifier + /// @see gtx_easing + template + GLM_FUNC_DECL genType backEaseIn(genType const& a, genType const& o); + + /// @param a parameter + /// @param o Optional overshoot modifier + /// @see gtx_easing + template + GLM_FUNC_DECL genType backEaseOut(genType const& a, genType const& o); + + /// @param a parameter + /// @param o Optional overshoot modifier + /// @see gtx_easing + template + GLM_FUNC_DECL genType backEaseInOut(genType const& a, genType const& o); + + /// @see gtx_easing + template + GLM_FUNC_DECL genType bounceEaseIn(genType const& a); + + /// @see gtx_easing + template + GLM_FUNC_DECL genType bounceEaseOut(genType const& a); + + /// @see gtx_easing + template + GLM_FUNC_DECL genType bounceEaseInOut(genType const& a); + + /// @} +}//namespace glm + +#include "easing.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/easing.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/easing.inl new file mode 100644 index 0000000000000000000000000000000000000000..b599c30664af45088ac167d43e3831c4d8956835 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/easing.inl @@ -0,0 +1,436 @@ +/// @ref gtx_easing + +#include + +namespace glm{ + + template + GLM_FUNC_QUALIFIER genType linearInterpolation(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return a; + } + + template + GLM_FUNC_QUALIFIER genType quadraticEaseIn(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return a * a; + } + + template + GLM_FUNC_QUALIFIER genType quadraticEaseOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return -(a * (a - static_cast(2))); + } + + template + GLM_FUNC_QUALIFIER genType quadraticEaseInOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + if(a < static_cast(0.5)) + { + return static_cast(2) * a * a; + } + else + { + return (-static_cast(2) * a * a) + (4 * a) - one(); + } + } + + template + GLM_FUNC_QUALIFIER genType cubicEaseIn(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return a * a * a; + } + + template + GLM_FUNC_QUALIFIER genType cubicEaseOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + genType const f = a - one(); + return f * f * f + one(); + } + + template + GLM_FUNC_QUALIFIER genType cubicEaseInOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + if (a < static_cast(0.5)) + { + return static_cast(4) * a * a * a; + } + else + { + genType const f = ((static_cast(2) * a) - static_cast(2)); + return static_cast(0.5) * f * f * f + one(); + } + } + + template + GLM_FUNC_QUALIFIER genType quarticEaseIn(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return a * a * a * a; + } + + template + GLM_FUNC_QUALIFIER genType quarticEaseOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + genType const f = (a - one()); + return f * f * f * (one() - a) + one(); + } + + template + GLM_FUNC_QUALIFIER genType quarticEaseInOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + if(a < static_cast(0.5)) + { + return static_cast(8) * a * a * a * a; + } + else + { + genType const f = (a - one()); + return -static_cast(8) * f * f * f * f + one(); + } + } + + template + GLM_FUNC_QUALIFIER genType quinticEaseIn(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return a * a * a * a * a; + } + + template + GLM_FUNC_QUALIFIER genType quinticEaseOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + genType const f = (a - one()); + return f * f * f * f * f + one(); + } + + template + GLM_FUNC_QUALIFIER genType quinticEaseInOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + if(a < static_cast(0.5)) + { + return static_cast(16) * a * a * a * a * a; + } + else + { + genType const f = ((static_cast(2) * a) - static_cast(2)); + return static_cast(0.5) * f * f * f * f * f + one(); + } + } + + template + GLM_FUNC_QUALIFIER genType sineEaseIn(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return sin((a - one()) * half_pi()) + one(); + } + + template + GLM_FUNC_QUALIFIER genType sineEaseOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return sin(a * half_pi()); + } + + template + GLM_FUNC_QUALIFIER genType sineEaseInOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return static_cast(0.5) * (one() - cos(a * pi())); + } + + template + GLM_FUNC_QUALIFIER genType circularEaseIn(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return one() - sqrt(one() - (a * a)); + } + + template + GLM_FUNC_QUALIFIER genType circularEaseOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return sqrt((static_cast(2) - a) * a); + } + + template + GLM_FUNC_QUALIFIER genType circularEaseInOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + if(a < static_cast(0.5)) + { + return static_cast(0.5) * (one() - std::sqrt(one() - static_cast(4) * (a * a))); + } + else + { + return static_cast(0.5) * (std::sqrt(-((static_cast(2) * a) - static_cast(3)) * ((static_cast(2) * a) - one())) + one()); + } + } + + template + GLM_FUNC_QUALIFIER genType exponentialEaseIn(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + if(a <= zero()) + return a; + else + { + genType const Complementary = a - one(); + genType const Two = static_cast(2); + + return glm::pow(Two, Complementary * static_cast(10)); + } + } + + template + GLM_FUNC_QUALIFIER genType exponentialEaseOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + if(a >= one()) + return a; + else + { + return one() - glm::pow(static_cast(2), -static_cast(10) * a); + } + } + + template + GLM_FUNC_QUALIFIER genType exponentialEaseInOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + if(a < static_cast(0.5)) + return static_cast(0.5) * glm::pow(static_cast(2), (static_cast(20) * a) - static_cast(10)); + else + return -static_cast(0.5) * glm::pow(static_cast(2), (-static_cast(20) * a) + static_cast(10)) + one(); + } + + template + GLM_FUNC_QUALIFIER genType elasticEaseIn(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return std::sin(static_cast(13) * half_pi() * a) * glm::pow(static_cast(2), static_cast(10) * (a - one())); + } + + template + GLM_FUNC_QUALIFIER genType elasticEaseOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return std::sin(-static_cast(13) * half_pi() * (a + one())) * glm::pow(static_cast(2), -static_cast(10) * a) + one(); + } + + template + GLM_FUNC_QUALIFIER genType elasticEaseInOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + if(a < static_cast(0.5)) + return static_cast(0.5) * std::sin(static_cast(13) * half_pi() * (static_cast(2) * a)) * glm::pow(static_cast(2), static_cast(10) * ((static_cast(2) * a) - one())); + else + return static_cast(0.5) * (std::sin(-static_cast(13) * half_pi() * ((static_cast(2) * a - one()) + one())) * glm::pow(static_cast(2), -static_cast(10) * (static_cast(2) * a - one())) + static_cast(2)); + } + + template + GLM_FUNC_QUALIFIER genType backEaseIn(genType const& a, genType const& o) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + genType z = ((o + one()) * a) - o; + return (a * a * z); + } + + template + GLM_FUNC_QUALIFIER genType backEaseOut(genType const& a, genType const& o) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + genType n = a - one(); + genType z = ((o + one()) * n) + o; + return (n * n * z) + one(); + } + + template + GLM_FUNC_QUALIFIER genType backEaseInOut(genType const& a, genType const& o) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + genType s = o * static_cast(1.525); + genType x = static_cast(0.5); + genType n = a / static_cast(0.5); + + if (n < static_cast(1)) + { + genType z = ((s + static_cast(1)) * n) - s; + genType m = n * n * z; + return x * m; + } + else + { + n -= static_cast(2); + genType z = ((s + static_cast(1)) * n) + s; + genType m = (n*n*z) + static_cast(2); + return x * m; + } + } + + template + GLM_FUNC_QUALIFIER genType backEaseIn(genType const& a) + { + return backEaseIn(a, static_cast(1.70158)); + } + + template + GLM_FUNC_QUALIFIER genType backEaseOut(genType const& a) + { + return backEaseOut(a, static_cast(1.70158)); + } + + template + GLM_FUNC_QUALIFIER genType backEaseInOut(genType const& a) + { + return backEaseInOut(a, static_cast(1.70158)); + } + + template + GLM_FUNC_QUALIFIER genType bounceEaseOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + if(a < static_cast(4.0 / 11.0)) + { + return (static_cast(121) * a * a) / static_cast(16); + } + else if(a < static_cast(8.0 / 11.0)) + { + return (static_cast(363.0 / 40.0) * a * a) - (static_cast(99.0 / 10.0) * a) + static_cast(17.0 / 5.0); + } + else if(a < static_cast(9.0 / 10.0)) + { + return (static_cast(4356.0 / 361.0) * a * a) - (static_cast(35442.0 / 1805.0) * a) + static_cast(16061.0 / 1805.0); + } + else + { + return (static_cast(54.0 / 5.0) * a * a) - (static_cast(513.0 / 25.0) * a) + static_cast(268.0 / 25.0); + } + } + + template + GLM_FUNC_QUALIFIER genType bounceEaseIn(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return one() - bounceEaseOut(one() - a); + } + + template + GLM_FUNC_QUALIFIER genType bounceEaseInOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + if(a < static_cast(0.5)) + { + return static_cast(0.5) * (one() - bounceEaseOut(one() - a * static_cast(2))); + } + else + { + return static_cast(0.5) * bounceEaseOut(a * static_cast(2) - one()) + static_cast(0.5); + } + } + +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/euler_angles.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/euler_angles.hpp new file mode 100644 index 0000000000000000000000000000000000000000..27236973af6079a54aa1183d3d50f38d381a1ab3 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/euler_angles.hpp @@ -0,0 +1,335 @@ +/// @ref gtx_euler_angles +/// @file glm/gtx/euler_angles.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_euler_angles GLM_GTX_euler_angles +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Build matrices from Euler angles. +/// +/// Extraction of Euler angles from rotation matrix. +/// Based on the original paper 2014 Mike Day - Extracting Euler Angles from a Rotation Matrix. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_euler_angles is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_euler_angles extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_euler_angles + /// @{ + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from an euler angle X. + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleX( + T const& angleX); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from an euler angle Y. + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleY( + T const& angleY); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from an euler angle Z. + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleZ( + T const& angleZ); + + /// Creates a 3D 4 * 4 homogeneous derived matrix from the rotation matrix about X-axis. + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> derivedEulerAngleX( + T const & angleX, T const & angularVelocityX); + + /// Creates a 3D 4 * 4 homogeneous derived matrix from the rotation matrix about Y-axis. + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> derivedEulerAngleY( + T const & angleY, T const & angularVelocityY); + + /// Creates a 3D 4 * 4 homogeneous derived matrix from the rotation matrix about Z-axis. + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> derivedEulerAngleZ( + T const & angleZ, T const & angularVelocityZ); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (X * Y). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleXY( + T const& angleX, + T const& angleY); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * X). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleYX( + T const& angleY, + T const& angleX); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (X * Z). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleXZ( + T const& angleX, + T const& angleZ); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Z * X). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleZX( + T const& angle, + T const& angleX); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * Z). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleYZ( + T const& angleY, + T const& angleZ); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Z * Y). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleZY( + T const& angleZ, + T const& angleY); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (X * Y * Z). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleXYZ( + T const& t1, + T const& t2, + T const& t3); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * X * Z). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleYXZ( + T const& yaw, + T const& pitch, + T const& roll); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (X * Z * X). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleXZX( + T const & t1, + T const & t2, + T const & t3); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (X * Y * X). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleXYX( + T const & t1, + T const & t2, + T const & t3); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * X * Y). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleYXY( + T const & t1, + T const & t2, + T const & t3); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * Z * Y). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleYZY( + T const & t1, + T const & t2, + T const & t3); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Z * Y * Z). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleZYZ( + T const & t1, + T const & t2, + T const & t3); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Z * X * Z). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleZXZ( + T const & t1, + T const & t2, + T const & t3); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (X * Z * Y). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleXZY( + T const & t1, + T const & t2, + T const & t3); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * Z * X). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleYZX( + T const & t1, + T const & t2, + T const & t3); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Z * Y * X). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleZYX( + T const & t1, + T const & t2, + T const & t3); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Z * X * Y). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleZXY( + T const & t1, + T const & t2, + T const & t3); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * X * Z). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> yawPitchRoll( + T const& yaw, + T const& pitch, + T const& roll); + + /// Creates a 2D 2 * 2 rotation matrix from an euler angle. + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<2, 2, T, defaultp> orientate2(T const& angle); + + /// Creates a 2D 4 * 4 homogeneous rotation matrix from an euler angle. + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<3, 3, T, defaultp> orientate3(T const& angle); + + /// Creates a 3D 3 * 3 rotation matrix from euler angles (Y * X * Z). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<3, 3, T, Q> orientate3(vec<3, T, Q> const& angles); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * X * Z). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, Q> orientate4(vec<3, T, Q> const& angles); + + /// Extracts the (X * Y * Z) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleXYZ(mat<4, 4, T, defaultp> const& M, + T & t1, + T & t2, + T & t3); + + /// Extracts the (Y * X * Z) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleYXZ(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3); + + /// Extracts the (X * Z * X) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleXZX(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3); + + /// Extracts the (X * Y * X) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleXYX(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3); + + /// Extracts the (Y * X * Y) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleYXY(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3); + + /// Extracts the (Y * Z * Y) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleYZY(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3); + + /// Extracts the (Z * Y * Z) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleZYZ(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3); + + /// Extracts the (Z * X * Z) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleZXZ(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3); + + /// Extracts the (X * Z * Y) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleXZY(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3); + + /// Extracts the (Y * Z * X) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleYZX(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3); + + /// Extracts the (Z * Y * X) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleZYX(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3); + + /// Extracts the (Z * X * Y) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleZXY(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3); + + /// @} +}//namespace glm + +#include "euler_angles.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/euler_angles.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/euler_angles.inl new file mode 100644 index 0000000000000000000000000000000000000000..134d499d91fc999525443af4ab773177d4744d83 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/euler_angles.inl @@ -0,0 +1,899 @@ +/// @ref gtx_euler_angles + +#include "compatibility.hpp" // glm::atan2 + +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleX + ( + T const& angleX + ) + { + T cosX = glm::cos(angleX); + T sinX = glm::sin(angleX); + + return mat<4, 4, T, defaultp>( + T(1), T(0), T(0), T(0), + T(0), cosX, sinX, T(0), + T(0),-sinX, cosX, T(0), + T(0), T(0), T(0), T(1)); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleY + ( + T const& angleY + ) + { + T cosY = glm::cos(angleY); + T sinY = glm::sin(angleY); + + return mat<4, 4, T, defaultp>( + cosY, T(0), -sinY, T(0), + T(0), T(1), T(0), T(0), + sinY, T(0), cosY, T(0), + T(0), T(0), T(0), T(1)); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleZ + ( + T const& angleZ + ) + { + T cosZ = glm::cos(angleZ); + T sinZ = glm::sin(angleZ); + + return mat<4, 4, T, defaultp>( + cosZ, sinZ, T(0), T(0), + -sinZ, cosZ, T(0), T(0), + T(0), T(0), T(1), T(0), + T(0), T(0), T(0), T(1)); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> derivedEulerAngleX + ( + T const & angleX, + T const & angularVelocityX + ) + { + T cosX = glm::cos(angleX) * angularVelocityX; + T sinX = glm::sin(angleX) * angularVelocityX; + + return mat<4, 4, T, defaultp>( + T(0), T(0), T(0), T(0), + T(0),-sinX, cosX, T(0), + T(0),-cosX,-sinX, T(0), + T(0), T(0), T(0), T(0)); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> derivedEulerAngleY + ( + T const & angleY, + T const & angularVelocityY + ) + { + T cosY = glm::cos(angleY) * angularVelocityY; + T sinY = glm::sin(angleY) * angularVelocityY; + + return mat<4, 4, T, defaultp>( + -sinY, T(0), -cosY, T(0), + T(0), T(0), T(0), T(0), + cosY, T(0), -sinY, T(0), + T(0), T(0), T(0), T(0)); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> derivedEulerAngleZ + ( + T const & angleZ, + T const & angularVelocityZ + ) + { + T cosZ = glm::cos(angleZ) * angularVelocityZ; + T sinZ = glm::sin(angleZ) * angularVelocityZ; + + return mat<4, 4, T, defaultp>( + -sinZ, cosZ, T(0), T(0), + -cosZ, -sinZ, T(0), T(0), + T(0), T(0), T(0), T(0), + T(0), T(0), T(0), T(0)); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleXY + ( + T const& angleX, + T const& angleY + ) + { + T cosX = glm::cos(angleX); + T sinX = glm::sin(angleX); + T cosY = glm::cos(angleY); + T sinY = glm::sin(angleY); + + return mat<4, 4, T, defaultp>( + cosY, -sinX * -sinY, cosX * -sinY, T(0), + T(0), cosX, sinX, T(0), + sinY, -sinX * cosY, cosX * cosY, T(0), + T(0), T(0), T(0), T(1)); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleYX + ( + T const& angleY, + T const& angleX + ) + { + T cosX = glm::cos(angleX); + T sinX = glm::sin(angleX); + T cosY = glm::cos(angleY); + T sinY = glm::sin(angleY); + + return mat<4, 4, T, defaultp>( + cosY, 0, -sinY, T(0), + sinY * sinX, cosX, cosY * sinX, T(0), + sinY * cosX, -sinX, cosY * cosX, T(0), + T(0), T(0), T(0), T(1)); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleXZ + ( + T const& angleX, + T const& angleZ + ) + { + return eulerAngleX(angleX) * eulerAngleZ(angleZ); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleZX + ( + T const& angleZ, + T const& angleX + ) + { + return eulerAngleZ(angleZ) * eulerAngleX(angleX); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleYZ + ( + T const& angleY, + T const& angleZ + ) + { + return eulerAngleY(angleY) * eulerAngleZ(angleZ); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleZY + ( + T const& angleZ, + T const& angleY + ) + { + return eulerAngleZ(angleZ) * eulerAngleY(angleY); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleXYZ + ( + T const& t1, + T const& t2, + T const& t3 + ) + { + T c1 = glm::cos(-t1); + T c2 = glm::cos(-t2); + T c3 = glm::cos(-t3); + T s1 = glm::sin(-t1); + T s2 = glm::sin(-t2); + T s3 = glm::sin(-t3); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = c2 * c3; + Result[0][1] =-c1 * s3 + s1 * s2 * c3; + Result[0][2] = s1 * s3 + c1 * s2 * c3; + Result[0][3] = static_cast(0); + Result[1][0] = c2 * s3; + Result[1][1] = c1 * c3 + s1 * s2 * s3; + Result[1][2] =-s1 * c3 + c1 * s2 * s3; + Result[1][3] = static_cast(0); + Result[2][0] =-s2; + Result[2][1] = s1 * c2; + Result[2][2] = c1 * c2; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleYXZ + ( + T const& yaw, + T const& pitch, + T const& roll + ) + { + T tmp_ch = glm::cos(yaw); + T tmp_sh = glm::sin(yaw); + T tmp_cp = glm::cos(pitch); + T tmp_sp = glm::sin(pitch); + T tmp_cb = glm::cos(roll); + T tmp_sb = glm::sin(roll); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = tmp_ch * tmp_cb + tmp_sh * tmp_sp * tmp_sb; + Result[0][1] = tmp_sb * tmp_cp; + Result[0][2] = -tmp_sh * tmp_cb + tmp_ch * tmp_sp * tmp_sb; + Result[0][3] = static_cast(0); + Result[1][0] = -tmp_ch * tmp_sb + tmp_sh * tmp_sp * tmp_cb; + Result[1][1] = tmp_cb * tmp_cp; + Result[1][2] = tmp_sb * tmp_sh + tmp_ch * tmp_sp * tmp_cb; + Result[1][3] = static_cast(0); + Result[2][0] = tmp_sh * tmp_cp; + Result[2][1] = -tmp_sp; + Result[2][2] = tmp_ch * tmp_cp; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleXZX + ( + T const & t1, + T const & t2, + T const & t3 + ) + { + T c1 = glm::cos(t1); + T s1 = glm::sin(t1); + T c2 = glm::cos(t2); + T s2 = glm::sin(t2); + T c3 = glm::cos(t3); + T s3 = glm::sin(t3); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = c2; + Result[0][1] = c1 * s2; + Result[0][2] = s1 * s2; + Result[0][3] = static_cast(0); + Result[1][0] =-c3 * s2; + Result[1][1] = c1 * c2 * c3 - s1 * s3; + Result[1][2] = c1 * s3 + c2 * c3 * s1; + Result[1][3] = static_cast(0); + Result[2][0] = s2 * s3; + Result[2][1] =-c3 * s1 - c1 * c2 * s3; + Result[2][2] = c1 * c3 - c2 * s1 * s3; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleXYX + ( + T const & t1, + T const & t2, + T const & t3 + ) + { + T c1 = glm::cos(t1); + T s1 = glm::sin(t1); + T c2 = glm::cos(t2); + T s2 = glm::sin(t2); + T c3 = glm::cos(t3); + T s3 = glm::sin(t3); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = c2; + Result[0][1] = s1 * s2; + Result[0][2] =-c1 * s2; + Result[0][3] = static_cast(0); + Result[1][0] = s2 * s3; + Result[1][1] = c1 * c3 - c2 * s1 * s3; + Result[1][2] = c3 * s1 + c1 * c2 * s3; + Result[1][3] = static_cast(0); + Result[2][0] = c3 * s2; + Result[2][1] =-c1 * s3 - c2 * c3 * s1; + Result[2][2] = c1 * c2 * c3 - s1 * s3; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleYXY + ( + T const & t1, + T const & t2, + T const & t3 + ) + { + T c1 = glm::cos(t1); + T s1 = glm::sin(t1); + T c2 = glm::cos(t2); + T s2 = glm::sin(t2); + T c3 = glm::cos(t3); + T s3 = glm::sin(t3); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = c1 * c3 - c2 * s1 * s3; + Result[0][1] = s2* s3; + Result[0][2] =-c3 * s1 - c1 * c2 * s3; + Result[0][3] = static_cast(0); + Result[1][0] = s1 * s2; + Result[1][1] = c2; + Result[1][2] = c1 * s2; + Result[1][3] = static_cast(0); + Result[2][0] = c1 * s3 + c2 * c3 * s1; + Result[2][1] =-c3 * s2; + Result[2][2] = c1 * c2 * c3 - s1 * s3; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleYZY + ( + T const & t1, + T const & t2, + T const & t3 + ) + { + T c1 = glm::cos(t1); + T s1 = glm::sin(t1); + T c2 = glm::cos(t2); + T s2 = glm::sin(t2); + T c3 = glm::cos(t3); + T s3 = glm::sin(t3); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = c1 * c2 * c3 - s1 * s3; + Result[0][1] = c3 * s2; + Result[0][2] =-c1 * s3 - c2 * c3 * s1; + Result[0][3] = static_cast(0); + Result[1][0] =-c1 * s2; + Result[1][1] = c2; + Result[1][2] = s1 * s2; + Result[1][3] = static_cast(0); + Result[2][0] = c3 * s1 + c1 * c2 * s3; + Result[2][1] = s2 * s3; + Result[2][2] = c1 * c3 - c2 * s1 * s3; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleZYZ + ( + T const & t1, + T const & t2, + T const & t3 + ) + { + T c1 = glm::cos(t1); + T s1 = glm::sin(t1); + T c2 = glm::cos(t2); + T s2 = glm::sin(t2); + T c3 = glm::cos(t3); + T s3 = glm::sin(t3); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = c1 * c2 * c3 - s1 * s3; + Result[0][1] = c1 * s3 + c2 * c3 * s1; + Result[0][2] =-c3 * s2; + Result[0][3] = static_cast(0); + Result[1][0] =-c3 * s1 - c1 * c2 * s3; + Result[1][1] = c1 * c3 - c2 * s1 * s3; + Result[1][2] = s2 * s3; + Result[1][3] = static_cast(0); + Result[2][0] = c1 * s2; + Result[2][1] = s1 * s2; + Result[2][2] = c2; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleZXZ + ( + T const & t1, + T const & t2, + T const & t3 + ) + { + T c1 = glm::cos(t1); + T s1 = glm::sin(t1); + T c2 = glm::cos(t2); + T s2 = glm::sin(t2); + T c3 = glm::cos(t3); + T s3 = glm::sin(t3); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = c1 * c3 - c2 * s1 * s3; + Result[0][1] = c3 * s1 + c1 * c2 * s3; + Result[0][2] = s2 *s3; + Result[0][3] = static_cast(0); + Result[1][0] =-c1 * s3 - c2 * c3 * s1; + Result[1][1] = c1 * c2 * c3 - s1 * s3; + Result[1][2] = c3 * s2; + Result[1][3] = static_cast(0); + Result[2][0] = s1 * s2; + Result[2][1] =-c1 * s2; + Result[2][2] = c2; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleXZY + ( + T const & t1, + T const & t2, + T const & t3 + ) + { + T c1 = glm::cos(t1); + T s1 = glm::sin(t1); + T c2 = glm::cos(t2); + T s2 = glm::sin(t2); + T c3 = glm::cos(t3); + T s3 = glm::sin(t3); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = c2 * c3; + Result[0][1] = s1 * s3 + c1 * c3 * s2; + Result[0][2] = c3 * s1 * s2 - c1 * s3; + Result[0][3] = static_cast(0); + Result[1][0] =-s2; + Result[1][1] = c1 * c2; + Result[1][2] = c2 * s1; + Result[1][3] = static_cast(0); + Result[2][0] = c2 * s3; + Result[2][1] = c1 * s2 * s3 - c3 * s1; + Result[2][2] = c1 * c3 + s1 * s2 *s3; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleYZX + ( + T const & t1, + T const & t2, + T const & t3 + ) + { + T c1 = glm::cos(t1); + T s1 = glm::sin(t1); + T c2 = glm::cos(t2); + T s2 = glm::sin(t2); + T c3 = glm::cos(t3); + T s3 = glm::sin(t3); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = c1 * c2; + Result[0][1] = s2; + Result[0][2] =-c2 * s1; + Result[0][3] = static_cast(0); + Result[1][0] = s1 * s3 - c1 * c3 * s2; + Result[1][1] = c2 * c3; + Result[1][2] = c1 * s3 + c3 * s1 * s2; + Result[1][3] = static_cast(0); + Result[2][0] = c3 * s1 + c1 * s2 * s3; + Result[2][1] =-c2 * s3; + Result[2][2] = c1 * c3 - s1 * s2 * s3; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleZYX + ( + T const & t1, + T const & t2, + T const & t3 + ) + { + T c1 = glm::cos(t1); + T s1 = glm::sin(t1); + T c2 = glm::cos(t2); + T s2 = glm::sin(t2); + T c3 = glm::cos(t3); + T s3 = glm::sin(t3); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = c1 * c2; + Result[0][1] = c2 * s1; + Result[0][2] =-s2; + Result[0][3] = static_cast(0); + Result[1][0] = c1 * s2 * s3 - c3 * s1; + Result[1][1] = c1 * c3 + s1 * s2 * s3; + Result[1][2] = c2 * s3; + Result[1][3] = static_cast(0); + Result[2][0] = s1 * s3 + c1 * c3 * s2; + Result[2][1] = c3 * s1 * s2 - c1 * s3; + Result[2][2] = c2 * c3; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleZXY + ( + T const & t1, + T const & t2, + T const & t3 + ) + { + T c1 = glm::cos(t1); + T s1 = glm::sin(t1); + T c2 = glm::cos(t2); + T s2 = glm::sin(t2); + T c3 = glm::cos(t3); + T s3 = glm::sin(t3); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = c1 * c3 - s1 * s2 * s3; + Result[0][1] = c3 * s1 + c1 * s2 * s3; + Result[0][2] =-c2 * s3; + Result[0][3] = static_cast(0); + Result[1][0] =-c2 * s1; + Result[1][1] = c1 * c2; + Result[1][2] = s2; + Result[1][3] = static_cast(0); + Result[2][0] = c1 * s3 + c3 * s1 * s2; + Result[2][1] = s1 * s3 - c1 * c3 * s2; + Result[2][2] = c2 * c3; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> yawPitchRoll + ( + T const& yaw, + T const& pitch, + T const& roll + ) + { + T tmp_ch = glm::cos(yaw); + T tmp_sh = glm::sin(yaw); + T tmp_cp = glm::cos(pitch); + T tmp_sp = glm::sin(pitch); + T tmp_cb = glm::cos(roll); + T tmp_sb = glm::sin(roll); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = tmp_ch * tmp_cb + tmp_sh * tmp_sp * tmp_sb; + Result[0][1] = tmp_sb * tmp_cp; + Result[0][2] = -tmp_sh * tmp_cb + tmp_ch * tmp_sp * tmp_sb; + Result[0][3] = static_cast(0); + Result[1][0] = -tmp_ch * tmp_sb + tmp_sh * tmp_sp * tmp_cb; + Result[1][1] = tmp_cb * tmp_cp; + Result[1][2] = tmp_sb * tmp_sh + tmp_ch * tmp_sp * tmp_cb; + Result[1][3] = static_cast(0); + Result[2][0] = tmp_sh * tmp_cp; + Result[2][1] = -tmp_sp; + Result[2][2] = tmp_ch * tmp_cp; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, defaultp> orientate2 + ( + T const& angle + ) + { + T c = glm::cos(angle); + T s = glm::sin(angle); + + mat<2, 2, T, defaultp> Result; + Result[0][0] = c; + Result[0][1] = s; + Result[1][0] = -s; + Result[1][1] = c; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, defaultp> orientate3 + ( + T const& angle + ) + { + T c = glm::cos(angle); + T s = glm::sin(angle); + + mat<3, 3, T, defaultp> Result; + Result[0][0] = c; + Result[0][1] = s; + Result[0][2] = T(0.0); + Result[1][0] = -s; + Result[1][1] = c; + Result[1][2] = T(0.0); + Result[2][0] = T(0.0); + Result[2][1] = T(0.0); + Result[2][2] = T(1.0); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> orientate3 + ( + vec<3, T, Q> const& angles + ) + { + return mat<3, 3, T, Q>(yawPitchRoll(angles.z, angles.x, angles.y)); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> orientate4 + ( + vec<3, T, Q> const& angles + ) + { + return yawPitchRoll(angles.z, angles.x, angles.y); + } + + template + GLM_FUNC_DECL void extractEulerAngleXYZ(mat<4, 4, T, defaultp> const& M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(M[2][1], M[2][2]); + T C2 = glm::sqrt(M[0][0]*M[0][0] + M[1][0]*M[1][0]); + T T2 = glm::atan2(-M[2][0], C2); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(S1*M[0][2] - C1*M[0][1], C1*M[1][1] - S1*M[1][2 ]); + t1 = -T1; + t2 = -T2; + t3 = -T3; + } + + template + GLM_FUNC_QUALIFIER void extractEulerAngleYXZ(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(M[2][0], M[2][2]); + T C2 = glm::sqrt(M[0][1]*M[0][1] + M[1][1]*M[1][1]); + T T2 = glm::atan2(-M[2][1], C2); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(S1*M[1][2] - C1*M[1][0], C1*M[0][0] - S1*M[0][2]); + t1 = T1; + t2 = T2; + t3 = T3; + } + + template + GLM_FUNC_QUALIFIER void extractEulerAngleXZX(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(M[0][2], M[0][1]); + T S2 = glm::sqrt(M[1][0]*M[1][0] + M[2][0]*M[2][0]); + T T2 = glm::atan2(S2, M[0][0]); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(C1*M[1][2] - S1*M[1][1], C1*M[2][2] - S1*M[2][1]); + t1 = T1; + t2 = T2; + t3 = T3; + } + + template + GLM_FUNC_QUALIFIER void extractEulerAngleXYX(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(M[0][1], -M[0][2]); + T S2 = glm::sqrt(M[1][0]*M[1][0] + M[2][0]*M[2][0]); + T T2 = glm::atan2(S2, M[0][0]); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(-C1*M[2][1] - S1*M[2][2], C1*M[1][1] + S1*M[1][2]); + t1 = T1; + t2 = T2; + t3 = T3; + } + + template + GLM_FUNC_QUALIFIER void extractEulerAngleYXY(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(M[1][0], M[1][2]); + T S2 = glm::sqrt(M[0][1]*M[0][1] + M[2][1]*M[2][1]); + T T2 = glm::atan2(S2, M[1][1]); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(C1*M[2][0] - S1*M[2][2], C1*M[0][0] - S1*M[0][2]); + t1 = T1; + t2 = T2; + t3 = T3; + } + + template + GLM_FUNC_QUALIFIER void extractEulerAngleYZY(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(M[1][2], -M[1][0]); + T S2 = glm::sqrt(M[0][1]*M[0][1] + M[2][1]*M[2][1]); + T T2 = glm::atan2(S2, M[1][1]); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(-S1*M[0][0] - C1*M[0][2], S1*M[2][0] + C1*M[2][2]); + t1 = T1; + t2 = T2; + t3 = T3; + } + + template + GLM_FUNC_QUALIFIER void extractEulerAngleZYZ(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(M[2][1], M[2][0]); + T S2 = glm::sqrt(M[0][2]*M[0][2] + M[1][2]*M[1][2]); + T T2 = glm::atan2(S2, M[2][2]); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(C1*M[0][1] - S1*M[0][0], C1*M[1][1] - S1*M[1][0]); + t1 = T1; + t2 = T2; + t3 = T3; + } + + template + GLM_FUNC_QUALIFIER void extractEulerAngleZXZ(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(M[2][0], -M[2][1]); + T S2 = glm::sqrt(M[0][2]*M[0][2] + M[1][2]*M[1][2]); + T T2 = glm::atan2(S2, M[2][2]); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(-C1*M[1][0] - S1*M[1][1], C1*M[0][0] + S1*M[0][1]); + t1 = T1; + t2 = T2; + t3 = T3; + } + + template + GLM_FUNC_QUALIFIER void extractEulerAngleXZY(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(M[1][2], M[1][1]); + T C2 = glm::sqrt(M[0][0]*M[0][0] + M[2][0]*M[2][0]); + T T2 = glm::atan2(-M[1][0], C2); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(S1*M[0][1] - C1*M[0][2], C1*M[2][2] - S1*M[2][1]); + t1 = T1; + t2 = T2; + t3 = T3; + } + + template + GLM_FUNC_QUALIFIER void extractEulerAngleYZX(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(-M[0][2], M[0][0]); + T C2 = glm::sqrt(M[1][1]*M[1][1] + M[2][1]*M[2][1]); + T T2 = glm::atan2(M[0][1], C2); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(S1*M[1][0] + C1*M[1][2], S1*M[2][0] + C1*M[2][2]); + t1 = T1; + t2 = T2; + t3 = T3; + } + + template + GLM_FUNC_QUALIFIER void extractEulerAngleZYX(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(M[0][1], M[0][0]); + T C2 = glm::sqrt(M[1][2]*M[1][2] + M[2][2]*M[2][2]); + T T2 = glm::atan2(-M[0][2], C2); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(S1*M[2][0] - C1*M[2][1], C1*M[1][1] - S1*M[1][0]); + t1 = T1; + t2 = T2; + t3 = T3; + } + + template + GLM_FUNC_QUALIFIER void extractEulerAngleZXY(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(-M[1][0], M[1][1]); + T C2 = glm::sqrt(M[0][2]*M[0][2] + M[2][2]*M[2][2]); + T T2 = glm::atan2(M[1][2], C2); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(C1*M[2][0] + S1*M[2][1], C1*M[0][0] + S1*M[0][1]); + t1 = T1; + t2 = T2; + t3 = T3; + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/extend.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/extend.hpp new file mode 100644 index 0000000000000000000000000000000000000000..28b7c5c014a45222c522ef146d687ec77ce62651 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/extend.hpp @@ -0,0 +1,42 @@ +/// @ref gtx_extend +/// @file glm/gtx/extend.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_extend GLM_GTX_extend +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Extend a position from a source to a position at a defined length. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_extend is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_extend extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_extend + /// @{ + + /// Extends of Length the Origin position using the (Source - Origin) direction. + /// @see gtx_extend + template + GLM_FUNC_DECL genType extend( + genType const& Origin, + genType const& Source, + typename genType::value_type const Length); + + /// @} +}//namespace glm + +#include "extend.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/extend.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/extend.inl new file mode 100644 index 0000000000000000000000000000000000000000..32128eb209ac74cf9c875c501cdc2c98956a3528 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/extend.inl @@ -0,0 +1,48 @@ +/// @ref gtx_extend + +namespace glm +{ + template + GLM_FUNC_QUALIFIER genType extend + ( + genType const& Origin, + genType const& Source, + genType const& Distance + ) + { + return Origin + (Source - Origin) * Distance; + } + + template + GLM_FUNC_QUALIFIER vec<2, T, Q> extend + ( + vec<2, T, Q> const& Origin, + vec<2, T, Q> const& Source, + T const& Distance + ) + { + return Origin + (Source - Origin) * Distance; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> extend + ( + vec<3, T, Q> const& Origin, + vec<3, T, Q> const& Source, + T const& Distance + ) + { + return Origin + (Source - Origin) * Distance; + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> extend + ( + vec<4, T, Q> const& Origin, + vec<4, T, Q> const& Source, + T const& Distance + ) + { + return Origin + (Source - Origin) * Distance; + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/extended_min_max.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/extended_min_max.hpp new file mode 100644 index 0000000000000000000000000000000000000000..20cd89b0d519e04f7dc0726e50c292d776be741d --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/extended_min_max.hpp @@ -0,0 +1,137 @@ +/// @ref gtx_extended_min_max +/// @file glm/gtx/extended_min_max.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_extended_min_max GLM_GTX_extended_min_max +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Min and max functions for 3 to 4 parameters. + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../ext/vector_common.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_extended_min_max is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_extended_min_max extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_extended_min_max + /// @{ + + /// Return the minimum component-wise values of 3 inputs + /// @see gtx_extented_min_max + template + GLM_FUNC_DECL T min( + T const& x, + T const& y, + T const& z); + + /// Return the minimum component-wise values of 3 inputs + /// @see gtx_extented_min_max + template class C> + GLM_FUNC_DECL C min( + C const& x, + typename C::T const& y, + typename C::T const& z); + + /// Return the minimum component-wise values of 3 inputs + /// @see gtx_extented_min_max + template class C> + GLM_FUNC_DECL C min( + C const& x, + C const& y, + C const& z); + + /// Return the minimum component-wise values of 4 inputs + /// @see gtx_extented_min_max + template + GLM_FUNC_DECL T min( + T const& x, + T const& y, + T const& z, + T const& w); + + /// Return the minimum component-wise values of 4 inputs + /// @see gtx_extented_min_max + template class C> + GLM_FUNC_DECL C min( + C const& x, + typename C::T const& y, + typename C::T const& z, + typename C::T const& w); + + /// Return the minimum component-wise values of 4 inputs + /// @see gtx_extented_min_max + template class C> + GLM_FUNC_DECL C min( + C const& x, + C const& y, + C const& z, + C const& w); + + /// Return the maximum component-wise values of 3 inputs + /// @see gtx_extented_min_max + template + GLM_FUNC_DECL T max( + T const& x, + T const& y, + T const& z); + + /// Return the maximum component-wise values of 3 inputs + /// @see gtx_extented_min_max + template class C> + GLM_FUNC_DECL C max( + C const& x, + typename C::T const& y, + typename C::T const& z); + + /// Return the maximum component-wise values of 3 inputs + /// @see gtx_extented_min_max + template class C> + GLM_FUNC_DECL C max( + C const& x, + C const& y, + C const& z); + + /// Return the maximum component-wise values of 4 inputs + /// @see gtx_extented_min_max + template + GLM_FUNC_DECL T max( + T const& x, + T const& y, + T const& z, + T const& w); + + /// Return the maximum component-wise values of 4 inputs + /// @see gtx_extented_min_max + template class C> + GLM_FUNC_DECL C max( + C const& x, + typename C::T const& y, + typename C::T const& z, + typename C::T const& w); + + /// Return the maximum component-wise values of 4 inputs + /// @see gtx_extented_min_max + template class C> + GLM_FUNC_DECL C max( + C const& x, + C const& y, + C const& z, + C const& w); + + /// @} +}//namespace glm + +#include "extended_min_max.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/extended_min_max.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/extended_min_max.inl new file mode 100644 index 0000000000000000000000000000000000000000..de5998fadd654ac9cfdcdcb8deb298fd02f5ca9f --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/extended_min_max.inl @@ -0,0 +1,138 @@ +/// @ref gtx_extended_min_max + +namespace glm +{ + template + GLM_FUNC_QUALIFIER T min( + T const& x, + T const& y, + T const& z) + { + return glm::min(glm::min(x, y), z); + } + + template class C> + GLM_FUNC_QUALIFIER C min + ( + C const& x, + typename C::T const& y, + typename C::T const& z + ) + { + return glm::min(glm::min(x, y), z); + } + + template class C> + GLM_FUNC_QUALIFIER C min + ( + C const& x, + C const& y, + C const& z + ) + { + return glm::min(glm::min(x, y), z); + } + + template + GLM_FUNC_QUALIFIER T min + ( + T const& x, + T const& y, + T const& z, + T const& w + ) + { + return glm::min(glm::min(x, y), glm::min(z, w)); + } + + template class C> + GLM_FUNC_QUALIFIER C min + ( + C const& x, + typename C::T const& y, + typename C::T const& z, + typename C::T const& w + ) + { + return glm::min(glm::min(x, y), glm::min(z, w)); + } + + template class C> + GLM_FUNC_QUALIFIER C min + ( + C const& x, + C const& y, + C const& z, + C const& w + ) + { + return glm::min(glm::min(x, y), glm::min(z, w)); + } + + template + GLM_FUNC_QUALIFIER T max( + T const& x, + T const& y, + T const& z) + { + return glm::max(glm::max(x, y), z); + } + + template class C> + GLM_FUNC_QUALIFIER C max + ( + C const& x, + typename C::T const& y, + typename C::T const& z + ) + { + return glm::max(glm::max(x, y), z); + } + + template class C> + GLM_FUNC_QUALIFIER C max + ( + C const& x, + C const& y, + C const& z + ) + { + return glm::max(glm::max(x, y), z); + } + + template + GLM_FUNC_QUALIFIER T max + ( + T const& x, + T const& y, + T const& z, + T const& w + ) + { + return glm::max(glm::max(x, y), glm::max(z, w)); + } + + template class C> + GLM_FUNC_QUALIFIER C max + ( + C const& x, + typename C::T const& y, + typename C::T const& z, + typename C::T const& w + ) + { + return glm::max(glm::max(x, y), glm::max(z, w)); + } + + template class C> + GLM_FUNC_QUALIFIER C max + ( + C const& x, + C const& y, + C const& z, + C const& w + ) + { + return glm::max(glm::max(x, y), glm::max(z, w)); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/exterior_product.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/exterior_product.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5522df7883c8bdaec64f287606d0a2aa526ed0d5 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/exterior_product.hpp @@ -0,0 +1,45 @@ +/// @ref gtx_exterior_product +/// @file glm/gtx/exterior_product.hpp +/// +/// @see core (dependence) +/// @see gtx_exterior_product (dependence) +/// +/// @defgroup gtx_exterior_product GLM_GTX_exterior_product +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// @brief Allow to perform bit operations on integer values + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../detail/qualifier.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_exterior_product is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_exterior_product extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_exterior_product + /// @{ + + /// Returns the cross product of x and y. + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see Exterior product + template + GLM_FUNC_DECL T cross(vec<2, T, Q> const& v, vec<2, T, Q> const& u); + + /// @} +} //namespace glm + +#include "exterior_product.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/exterior_product.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/exterior_product.inl new file mode 100644 index 0000000000000000000000000000000000000000..93661fd3fd7f581806610df4293bdc8bf5c4a71c --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/exterior_product.inl @@ -0,0 +1,26 @@ +/// @ref gtx_exterior_product + +#include + +namespace glm { +namespace detail +{ + template + struct compute_cross_vec2 + { + GLM_FUNC_QUALIFIER static T call(vec<2, T, Q> const& v, vec<2, T, Q> const& u) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'cross' accepts only floating-point inputs"); + + return v.x * u.y - u.x * v.y; + } + }; +}//namespace detail + + template + GLM_FUNC_QUALIFIER T cross(vec<2, T, Q> const& x, vec<2, T, Q> const& y) + { + return detail::compute_cross_vec2::value>::call(x, y); + } +}//namespace glm + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/fast_exponential.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/fast_exponential.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6fb7286528cf085a623f66bbfc836261159a0354 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/fast_exponential.hpp @@ -0,0 +1,95 @@ +/// @ref gtx_fast_exponential +/// @file glm/gtx/fast_exponential.hpp +/// +/// @see core (dependence) +/// @see gtx_half_float (dependence) +/// +/// @defgroup gtx_fast_exponential GLM_GTX_fast_exponential +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Fast but less accurate implementations of exponential based functions. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_fast_exponential is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_fast_exponential extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_fast_exponential + /// @{ + + /// Faster than the common pow function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL genType fastPow(genType x, genType y); + + /// Faster than the common pow function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL vec fastPow(vec const& x, vec const& y); + + /// Faster than the common pow function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL genTypeT fastPow(genTypeT x, genTypeU y); + + /// Faster than the common pow function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL vec fastPow(vec const& x); + + /// Faster than the common exp function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL T fastExp(T x); + + /// Faster than the common exp function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL vec fastExp(vec const& x); + + /// Faster than the common log function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL T fastLog(T x); + + /// Faster than the common exp2 function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL vec fastLog(vec const& x); + + /// Faster than the common exp2 function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL T fastExp2(T x); + + /// Faster than the common exp2 function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL vec fastExp2(vec const& x); + + /// Faster than the common log2 function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL T fastLog2(T x); + + /// Faster than the common log2 function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL vec fastLog2(vec const& x); + + /// @} +}//namespace glm + +#include "fast_exponential.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/fast_exponential.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/fast_exponential.inl new file mode 100644 index 0000000000000000000000000000000000000000..5b1174246bbc4e14a130324df20b22978eb605b4 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/fast_exponential.inl @@ -0,0 +1,136 @@ +/// @ref gtx_fast_exponential + +namespace glm +{ + // fastPow: + template + GLM_FUNC_QUALIFIER genType fastPow(genType x, genType y) + { + return exp(y * log(x)); + } + + template + GLM_FUNC_QUALIFIER vec fastPow(vec const& x, vec const& y) + { + return exp(y * log(x)); + } + + template + GLM_FUNC_QUALIFIER T fastPow(T x, int y) + { + T f = static_cast(1); + for(int i = 0; i < y; ++i) + f *= x; + return f; + } + + template + GLM_FUNC_QUALIFIER vec fastPow(vec const& x, vec const& y) + { + vec Result; + for(length_t i = 0, n = x.length(); i < n; ++i) + Result[i] = fastPow(x[i], y[i]); + return Result; + } + + // fastExp + // Note: This function provides accurate results only for value between -1 and 1, else avoid it. + template + GLM_FUNC_QUALIFIER T fastExp(T x) + { + // This has a better looking and same performance in release mode than the following code. However, in debug mode it's slower. + // return 1.0f + x * (1.0f + x * 0.5f * (1.0f + x * 0.3333333333f * (1.0f + x * 0.25 * (1.0f + x * 0.2f)))); + T x2 = x * x; + T x3 = x2 * x; + T x4 = x3 * x; + T x5 = x4 * x; + return T(1) + x + (x2 * T(0.5)) + (x3 * T(0.1666666667)) + (x4 * T(0.041666667)) + (x5 * T(0.008333333333)); + } + /* // Try to handle all values of float... but often shower than std::exp, glm::floor and the loop kill the performance + GLM_FUNC_QUALIFIER float fastExp(float x) + { + const float e = 2.718281828f; + const float IntegerPart = floor(x); + const float FloatPart = x - IntegerPart; + float z = 1.f; + + for(int i = 0; i < int(IntegerPart); ++i) + z *= e; + + const float x2 = FloatPart * FloatPart; + const float x3 = x2 * FloatPart; + const float x4 = x3 * FloatPart; + const float x5 = x4 * FloatPart; + return z * (1.0f + FloatPart + (x2 * 0.5f) + (x3 * 0.1666666667f) + (x4 * 0.041666667f) + (x5 * 0.008333333333f)); + } + + // Increase accuracy on number bigger that 1 and smaller than -1 but it's not enough for high and negative numbers + GLM_FUNC_QUALIFIER float fastExp(float x) + { + // This has a better looking and same performance in release mode than the following code. However, in debug mode it's slower. + // return 1.0f + x * (1.0f + x * 0.5f * (1.0f + x * 0.3333333333f * (1.0f + x * 0.25 * (1.0f + x * 0.2f)))); + float x2 = x * x; + float x3 = x2 * x; + float x4 = x3 * x; + float x5 = x4 * x; + float x6 = x5 * x; + float x7 = x6 * x; + float x8 = x7 * x; + return 1.0f + x + (x2 * 0.5f) + (x3 * 0.1666666667f) + (x4 * 0.041666667f) + (x5 * 0.008333333333f)+ (x6 * 0.00138888888888f) + (x7 * 0.000198412698f) + (x8 * 0.0000248015873f);; + } + */ + + template + GLM_FUNC_QUALIFIER vec fastExp(vec const& x) + { + return detail::functor1::call(fastExp, x); + } + + // fastLog + template + GLM_FUNC_QUALIFIER genType fastLog(genType x) + { + return std::log(x); + } + + /* Slower than the VC7.1 function... + GLM_FUNC_QUALIFIER float fastLog(float x) + { + float y1 = (x - 1.0f) / (x + 1.0f); + float y2 = y1 * y1; + return 2.0f * y1 * (1.0f + y2 * (0.3333333333f + y2 * (0.2f + y2 * 0.1428571429f))); + } + */ + + template + GLM_FUNC_QUALIFIER vec fastLog(vec const& x) + { + return detail::functor1::call(fastLog, x); + } + + //fastExp2, ln2 = 0.69314718055994530941723212145818f + template + GLM_FUNC_QUALIFIER genType fastExp2(genType x) + { + return fastExp(static_cast(0.69314718055994530941723212145818) * x); + } + + template + GLM_FUNC_QUALIFIER vec fastExp2(vec const& x) + { + return detail::functor1::call(fastExp2, x); + } + + // fastLog2, ln2 = 0.69314718055994530941723212145818f + template + GLM_FUNC_QUALIFIER genType fastLog2(genType x) + { + return fastLog(x) / static_cast(0.69314718055994530941723212145818); + } + + template + GLM_FUNC_QUALIFIER vec fastLog2(vec const& x) + { + return detail::functor1::call(fastLog2, x); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/fast_square_root.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/fast_square_root.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ac42a9c006cb850ffb04e6a295c7e4d7c68e61ec --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/fast_square_root.hpp @@ -0,0 +1,98 @@ +/// @ref gtx_fast_square_root +/// @file glm/gtx/fast_square_root.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_fast_square_root GLM_GTX_fast_square_root +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Fast but less accurate implementations of square root based functions. +/// - Sqrt optimisation based on Newton's method, +/// www.gamedev.net/community/forums/topic.asp?topic id=139956 + +#pragma once + +// Dependency: +#include "../common.hpp" +#include "../exponential.hpp" +#include "../geometric.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_fast_square_root is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_fast_square_root extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_fast_square_root + /// @{ + + /// Faster than the common sqrt function but less accurate. + /// + /// @see gtx_fast_square_root extension. + template + GLM_FUNC_DECL genType fastSqrt(genType x); + + /// Faster than the common sqrt function but less accurate. + /// + /// @see gtx_fast_square_root extension. + template + GLM_FUNC_DECL vec fastSqrt(vec const& x); + + /// Faster than the common inversesqrt function but less accurate. + /// + /// @see gtx_fast_square_root extension. + template + GLM_FUNC_DECL genType fastInverseSqrt(genType x); + + /// Faster than the common inversesqrt function but less accurate. + /// + /// @see gtx_fast_square_root extension. + template + GLM_FUNC_DECL vec fastInverseSqrt(vec const& x); + + /// Faster than the common length function but less accurate. + /// + /// @see gtx_fast_square_root extension. + template + GLM_FUNC_DECL genType fastLength(genType x); + + /// Faster than the common length function but less accurate. + /// + /// @see gtx_fast_square_root extension. + template + GLM_FUNC_DECL T fastLength(vec const& x); + + /// Faster than the common distance function but less accurate. + /// + /// @see gtx_fast_square_root extension. + template + GLM_FUNC_DECL genType fastDistance(genType x, genType y); + + /// Faster than the common distance function but less accurate. + /// + /// @see gtx_fast_square_root extension. + template + GLM_FUNC_DECL T fastDistance(vec const& x, vec const& y); + + /// Faster than the common normalize function but less accurate. + /// + /// @see gtx_fast_square_root extension. + template + GLM_FUNC_DECL genType fastNormalize(genType x); + + /// Faster than the common normalize function but less accurate. + /// + /// @see gtx_fast_square_root extension. + template + GLM_FUNC_DECL vec fastNormalize(vec const& x); + + /// @} +}// namespace glm + +#include "fast_square_root.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/fast_square_root.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/fast_square_root.inl new file mode 100644 index 0000000000000000000000000000000000000000..4e6c6de90e2dd3dad64fc3bc54ee5235f6fe4ead --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/fast_square_root.inl @@ -0,0 +1,75 @@ +/// @ref gtx_fast_square_root + +namespace glm +{ + // fastSqrt + template + GLM_FUNC_QUALIFIER genType fastSqrt(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fastSqrt' only accept floating-point input"); + + return genType(1) / fastInverseSqrt(x); + } + + template + GLM_FUNC_QUALIFIER vec fastSqrt(vec const& x) + { + return detail::functor1::call(fastSqrt, x); + } + + // fastInversesqrt + template + GLM_FUNC_QUALIFIER genType fastInverseSqrt(genType x) + { + return detail::compute_inversesqrt<1, genType, lowp, detail::is_aligned::value>::call(vec<1, genType, lowp>(x)).x; + } + + template + GLM_FUNC_QUALIFIER vec fastInverseSqrt(vec const& x) + { + return detail::compute_inversesqrt::value>::call(x); + } + + // fastLength + template + GLM_FUNC_QUALIFIER genType fastLength(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fastLength' only accept floating-point inputs"); + + return abs(x); + } + + template + GLM_FUNC_QUALIFIER T fastLength(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fastLength' only accept floating-point inputs"); + + return fastSqrt(dot(x, x)); + } + + // fastDistance + template + GLM_FUNC_QUALIFIER genType fastDistance(genType x, genType y) + { + return fastLength(y - x); + } + + template + GLM_FUNC_QUALIFIER T fastDistance(vec const& x, vec const& y) + { + return fastLength(y - x); + } + + // fastNormalize + template + GLM_FUNC_QUALIFIER genType fastNormalize(genType x) + { + return x > genType(0) ? genType(1) : -genType(1); + } + + template + GLM_FUNC_QUALIFIER vec fastNormalize(vec const& x) + { + return x * fastInverseSqrt(dot(x, x)); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/fast_trigonometry.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/fast_trigonometry.hpp new file mode 100644 index 0000000000000000000000000000000000000000..2650d6e4d6e3f0b1e12a4c44b8a046d788bcbc90 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/fast_trigonometry.hpp @@ -0,0 +1,79 @@ +/// @ref gtx_fast_trigonometry +/// @file glm/gtx/fast_trigonometry.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_fast_trigonometry GLM_GTX_fast_trigonometry +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Fast but less accurate implementations of trigonometric functions. + +#pragma once + +// Dependency: +#include "../gtc/constants.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_fast_trigonometry is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_fast_trigonometry extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_fast_trigonometry + /// @{ + + /// Wrap an angle to [0 2pi[ + /// From GLM_GTX_fast_trigonometry extension. + template + GLM_FUNC_DECL T wrapAngle(T angle); + + /// Faster than the common sin function but less accurate. + /// From GLM_GTX_fast_trigonometry extension. + template + GLM_FUNC_DECL T fastSin(T angle); + + /// Faster than the common cos function but less accurate. + /// From GLM_GTX_fast_trigonometry extension. + template + GLM_FUNC_DECL T fastCos(T angle); + + /// Faster than the common tan function but less accurate. + /// Defined between -2pi and 2pi. + /// From GLM_GTX_fast_trigonometry extension. + template + GLM_FUNC_DECL T fastTan(T angle); + + /// Faster than the common asin function but less accurate. + /// Defined between -2pi and 2pi. + /// From GLM_GTX_fast_trigonometry extension. + template + GLM_FUNC_DECL T fastAsin(T angle); + + /// Faster than the common acos function but less accurate. + /// Defined between -2pi and 2pi. + /// From GLM_GTX_fast_trigonometry extension. + template + GLM_FUNC_DECL T fastAcos(T angle); + + /// Faster than the common atan function but less accurate. + /// Defined between -2pi and 2pi. + /// From GLM_GTX_fast_trigonometry extension. + template + GLM_FUNC_DECL T fastAtan(T y, T x); + + /// Faster than the common atan function but less accurate. + /// Defined between -2pi and 2pi. + /// From GLM_GTX_fast_trigonometry extension. + template + GLM_FUNC_DECL T fastAtan(T angle); + + /// @} +}//namespace glm + +#include "fast_trigonometry.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/fast_trigonometry.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/fast_trigonometry.inl new file mode 100644 index 0000000000000000000000000000000000000000..1a710cbcd08d48ebabfaa09e6314c3397e0d0fd5 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/fast_trigonometry.inl @@ -0,0 +1,142 @@ +/// @ref gtx_fast_trigonometry + +namespace glm{ +namespace detail +{ + template + GLM_FUNC_QUALIFIER vec taylorCos(vec const& x) + { + return static_cast(1) + - (x * x) * (1.f / 2.f) + + ((x * x) * (x * x)) * (1.f / 24.f) + - (((x * x) * (x * x)) * (x * x)) * (1.f / 720.f) + + (((x * x) * (x * x)) * ((x * x) * (x * x))) * (1.f / 40320.f); + } + + template + GLM_FUNC_QUALIFIER T cos_52s(T x) + { + T const xx(x * x); + return (T(0.9999932946) + xx * (T(-0.4999124376) + xx * (T(0.0414877472) + xx * T(-0.0012712095)))); + } + + template + GLM_FUNC_QUALIFIER vec cos_52s(vec const& x) + { + return detail::functor1::call(cos_52s, x); + } +}//namespace detail + + // wrapAngle + template + GLM_FUNC_QUALIFIER T wrapAngle(T angle) + { + return abs(mod(angle, two_pi())); + } + + template + GLM_FUNC_QUALIFIER vec wrapAngle(vec const& x) + { + return detail::functor1::call(wrapAngle, x); + } + + // cos + template + GLM_FUNC_QUALIFIER T fastCos(T x) + { + T const angle(wrapAngle(x)); + + if(angle < half_pi()) + return detail::cos_52s(angle); + if(angle < pi()) + return -detail::cos_52s(pi() - angle); + if(angle < (T(3) * half_pi())) + return -detail::cos_52s(angle - pi()); + + return detail::cos_52s(two_pi() - angle); + } + + template + GLM_FUNC_QUALIFIER vec fastCos(vec const& x) + { + return detail::functor1::call(fastCos, x); + } + + // sin + template + GLM_FUNC_QUALIFIER T fastSin(T x) + { + return fastCos(half_pi() - x); + } + + template + GLM_FUNC_QUALIFIER vec fastSin(vec const& x) + { + return detail::functor1::call(fastSin, x); + } + + // tan + template + GLM_FUNC_QUALIFIER T fastTan(T x) + { + return x + (x * x * x * T(0.3333333333)) + (x * x * x * x * x * T(0.1333333333333)) + (x * x * x * x * x * x * x * T(0.0539682539)); + } + + template + GLM_FUNC_QUALIFIER vec fastTan(vec const& x) + { + return detail::functor1::call(fastTan, x); + } + + // asin + template + GLM_FUNC_QUALIFIER T fastAsin(T x) + { + return x + (x * x * x * T(0.166666667)) + (x * x * x * x * x * T(0.075)) + (x * x * x * x * x * x * x * T(0.0446428571)) + (x * x * x * x * x * x * x * x * x * T(0.0303819444));// + (x * x * x * x * x * x * x * x * x * x * x * T(0.022372159)); + } + + template + GLM_FUNC_QUALIFIER vec fastAsin(vec const& x) + { + return detail::functor1::call(fastAsin, x); + } + + // acos + template + GLM_FUNC_QUALIFIER T fastAcos(T x) + { + return T(1.5707963267948966192313216916398) - fastAsin(x); //(PI / 2) + } + + template + GLM_FUNC_QUALIFIER vec fastAcos(vec const& x) + { + return detail::functor1::call(fastAcos, x); + } + + // atan + template + GLM_FUNC_QUALIFIER T fastAtan(T y, T x) + { + T sgn = sign(y) * sign(x); + return abs(fastAtan(y / x)) * sgn; + } + + template + GLM_FUNC_QUALIFIER vec fastAtan(vec const& y, vec const& x) + { + return detail::functor2::call(fastAtan, y, x); + } + + template + GLM_FUNC_QUALIFIER T fastAtan(T x) + { + return x - (x * x * x * T(0.333333333333)) + (x * x * x * x * x * T(0.2)) - (x * x * x * x * x * x * x * T(0.1428571429)) + (x * x * x * x * x * x * x * x * x * T(0.111111111111)) - (x * x * x * x * x * x * x * x * x * x * x * T(0.0909090909)); + } + + template + GLM_FUNC_QUALIFIER vec fastAtan(vec const& x) + { + return detail::functor1::call(fastAtan, x); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/float_notmalize.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/float_notmalize.inl new file mode 100644 index 0000000000000000000000000000000000000000..8cdbc5aaa9c3895ea1f0e7e3a817f78b813e10c3 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/float_notmalize.inl @@ -0,0 +1,13 @@ +/// @ref gtx_float_normalize + +#include + +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec floatNormalize(vec const& v) + { + return vec(v) / static_cast(std::numeric_limits::max()); + } + +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/functions.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/functions.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9f4166c4c1c809bc1c4e88a190e172f1f8138fc7 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/functions.hpp @@ -0,0 +1,56 @@ +/// @ref gtx_functions +/// @file glm/gtx/functions.hpp +/// +/// @see core (dependence) +/// @see gtc_quaternion (dependence) +/// +/// @defgroup gtx_functions GLM_GTX_functions +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// List of useful common functions. + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../detail/qualifier.hpp" +#include "../detail/type_vec2.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_functions is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_functions extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_functions + /// @{ + + /// 1D gauss function + /// + /// @see gtc_epsilon + template + GLM_FUNC_DECL T gauss( + T x, + T ExpectedValue, + T StandardDeviation); + + /// 2D gauss function + /// + /// @see gtc_epsilon + template + GLM_FUNC_DECL T gauss( + vec<2, T, Q> const& Coord, + vec<2, T, Q> const& ExpectedValue, + vec<2, T, Q> const& StandardDeviation); + + /// @} +}//namespace glm + +#include "functions.inl" + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/functions.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/functions.inl new file mode 100644 index 0000000000000000000000000000000000000000..29cbb20b80fa501931a5bf9203a52171b4a42773 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/functions.inl @@ -0,0 +1,30 @@ +/// @ref gtx_functions + +#include "../exponential.hpp" + +namespace glm +{ + template + GLM_FUNC_QUALIFIER T gauss + ( + T x, + T ExpectedValue, + T StandardDeviation + ) + { + return exp(-((x - ExpectedValue) * (x - ExpectedValue)) / (static_cast(2) * StandardDeviation * StandardDeviation)) / (StandardDeviation * sqrt(static_cast(6.28318530717958647692528676655900576))); + } + + template + GLM_FUNC_QUALIFIER T gauss + ( + vec<2, T, Q> const& Coord, + vec<2, T, Q> const& ExpectedValue, + vec<2, T, Q> const& StandardDeviation + ) + { + vec<2, T, Q> const Squared = ((Coord - ExpectedValue) * (Coord - ExpectedValue)) / (static_cast(2) * StandardDeviation * StandardDeviation); + return exp(-(Squared.x + Squared.y)); + } +}//namespace glm + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/gradient_paint.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/gradient_paint.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6f85bf482d9fdd16ab823462741b98c43d337b01 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/gradient_paint.hpp @@ -0,0 +1,53 @@ +/// @ref gtx_gradient_paint +/// @file glm/gtx/gradient_paint.hpp +/// +/// @see core (dependence) +/// @see gtx_optimum_pow (dependence) +/// +/// @defgroup gtx_gradient_paint GLM_GTX_gradient_paint +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Functions that return the color of procedural gradient for specific coordinates. + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtx/optimum_pow.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_gradient_paint is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_gradient_paint extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_gradient_paint + /// @{ + + /// Return a color from a radial gradient. + /// @see - gtx_gradient_paint + template + GLM_FUNC_DECL T radialGradient( + vec<2, T, Q> const& Center, + T const& Radius, + vec<2, T, Q> const& Focal, + vec<2, T, Q> const& Position); + + /// Return a color from a linear gradient. + /// @see - gtx_gradient_paint + template + GLM_FUNC_DECL T linearGradient( + vec<2, T, Q> const& Point0, + vec<2, T, Q> const& Point1, + vec<2, T, Q> const& Position); + + /// @} +}// namespace glm + +#include "gradient_paint.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/gradient_paint.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/gradient_paint.inl new file mode 100644 index 0000000000000000000000000000000000000000..4c495e62cbffd88b88fcd7086c692c2f67f157d1 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/gradient_paint.inl @@ -0,0 +1,36 @@ +/// @ref gtx_gradient_paint + +namespace glm +{ + template + GLM_FUNC_QUALIFIER T radialGradient + ( + vec<2, T, Q> const& Center, + T const& Radius, + vec<2, T, Q> const& Focal, + vec<2, T, Q> const& Position + ) + { + vec<2, T, Q> F = Focal - Center; + vec<2, T, Q> D = Position - Focal; + T Radius2 = pow2(Radius); + T Fx2 = pow2(F.x); + T Fy2 = pow2(F.y); + + T Numerator = (D.x * F.x + D.y * F.y) + sqrt(Radius2 * (pow2(D.x) + pow2(D.y)) - pow2(D.x * F.y - D.y * F.x)); + T Denominator = Radius2 - (Fx2 + Fy2); + return Numerator / Denominator; + } + + template + GLM_FUNC_QUALIFIER T linearGradient + ( + vec<2, T, Q> const& Point0, + vec<2, T, Q> const& Point1, + vec<2, T, Q> const& Position + ) + { + vec<2, T, Q> Dist = Point1 - Point0; + return (Dist.x * (Position.x - Point0.x) + Dist.y * (Position.y - Point0.y)) / glm::dot(Dist, Dist); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/handed_coordinate_space.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/handed_coordinate_space.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e59e3e2ac273119102d87560f7797c11d3d65465 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/handed_coordinate_space.hpp @@ -0,0 +1,50 @@ +/// @ref gtx_handed_coordinate_space +/// @file glm/gtx/handed_coordinate_space.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_handed_coordinate_space GLM_GTX_handed_coordinate_space +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// To know if a set of three basis vectors defines a right or left-handed coordinate system. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_handed_coordinate_space is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_handed_coordinate_space extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_handed_coordinate_space + /// @{ + + //! Return if a trihedron right handed or not. + //! From GLM_GTX_handed_coordinate_space extension. + template + GLM_FUNC_DECL bool rightHanded( + vec<3, T, Q> const& tangent, + vec<3, T, Q> const& binormal, + vec<3, T, Q> const& normal); + + //! Return if a trihedron left handed or not. + //! From GLM_GTX_handed_coordinate_space extension. + template + GLM_FUNC_DECL bool leftHanded( + vec<3, T, Q> const& tangent, + vec<3, T, Q> const& binormal, + vec<3, T, Q> const& normal); + + /// @} +}// namespace glm + +#include "handed_coordinate_space.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/handed_coordinate_space.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/handed_coordinate_space.inl new file mode 100644 index 0000000000000000000000000000000000000000..e43c17bd3120931fff5438f5db175852896a1bbb --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/handed_coordinate_space.inl @@ -0,0 +1,26 @@ +/// @ref gtx_handed_coordinate_space + +namespace glm +{ + template + GLM_FUNC_QUALIFIER bool rightHanded + ( + vec<3, T, Q> const& tangent, + vec<3, T, Q> const& binormal, + vec<3, T, Q> const& normal + ) + { + return dot(cross(normal, tangent), binormal) > T(0); + } + + template + GLM_FUNC_QUALIFIER bool leftHanded + ( + vec<3, T, Q> const& tangent, + vec<3, T, Q> const& binormal, + vec<3, T, Q> const& normal + ) + { + return dot(cross(normal, tangent), binormal) < T(0); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/hash.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/hash.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1601428d0d38d804da2d4a60c263e9fd580d62f5 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/hash.hpp @@ -0,0 +1,142 @@ +/// @ref gtx_hash +/// @file glm/gtx/hash.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_hash GLM_GTX_hash +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Add std::hash support for glm types + +#pragma once + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_hash is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_hash extension included") +# endif +#endif + +#include + +#include "../vec2.hpp" +#include "../vec3.hpp" +#include "../vec4.hpp" +#include "../gtc/vec1.hpp" + +#include "../gtc/quaternion.hpp" +#include "../gtx/dual_quaternion.hpp" + +#include "../mat2x2.hpp" +#include "../mat2x3.hpp" +#include "../mat2x4.hpp" + +#include "../mat3x2.hpp" +#include "../mat3x3.hpp" +#include "../mat3x4.hpp" + +#include "../mat4x2.hpp" +#include "../mat4x3.hpp" +#include "../mat4x4.hpp" + +#if !GLM_HAS_CXX11_STL +# error "GLM_GTX_hash requires C++11 standard library support" +#endif + +namespace std +{ + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::vec<1, T, Q> const& v) const GLM_NOEXCEPT; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::vec<2, T, Q> const& v) const GLM_NOEXCEPT; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::vec<3, T, Q> const& v) const GLM_NOEXCEPT; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::vec<4, T, Q> const& v) const GLM_NOEXCEPT; + }; + + template + struct hash> + { + GLM_FUNC_DECL size_t operator()(glm::qua const& q) const GLM_NOEXCEPT; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::tdualquat const& q) const GLM_NOEXCEPT; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::mat<2, 2, T,Q> const& m) const GLM_NOEXCEPT; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::mat<2, 3, T,Q> const& m) const GLM_NOEXCEPT; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::mat<2, 4, T,Q> const& m) const GLM_NOEXCEPT; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::mat<3, 2, T,Q> const& m) const GLM_NOEXCEPT; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::mat<3, 3, T,Q> const& m) const GLM_NOEXCEPT; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::mat<3, 4, T,Q> const& m) const GLM_NOEXCEPT; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::mat<4, 2, T,Q> const& m) const GLM_NOEXCEPT; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::mat<4, 3, T,Q> const& m) const GLM_NOEXCEPT; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::mat<4, 4, T,Q> const& m) const GLM_NOEXCEPT; + }; +} // namespace std + +#include "hash.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/hash.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/hash.inl new file mode 100644 index 0000000000000000000000000000000000000000..fc822d3e604b098c6991f8ad95424bd671913a30 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/hash.inl @@ -0,0 +1,175 @@ +/// @ref gtx_hash + +namespace glm { +namespace detail +{ + GLM_INLINE void hash_combine(size_t &seed, size_t hash) + { + hash += 0x9e3779b9 + (seed << 6) + (seed >> 2); + seed ^= hash; + } +}} + +namespace std +{ + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::vec<1, T, Q> const& v) const GLM_NOEXCEPT + { + hash hasher; + return hasher(v.x); + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::vec<2, T, Q> const& v) const GLM_NOEXCEPT + { + size_t seed = 0; + hash hasher; + glm::detail::hash_combine(seed, hasher(v.x)); + glm::detail::hash_combine(seed, hasher(v.y)); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::vec<3, T, Q> const& v) const GLM_NOEXCEPT + { + size_t seed = 0; + hash hasher; + glm::detail::hash_combine(seed, hasher(v.x)); + glm::detail::hash_combine(seed, hasher(v.y)); + glm::detail::hash_combine(seed, hasher(v.z)); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::vec<4, T, Q> const& v) const GLM_NOEXCEPT + { + size_t seed = 0; + hash hasher; + glm::detail::hash_combine(seed, hasher(v.x)); + glm::detail::hash_combine(seed, hasher(v.y)); + glm::detail::hash_combine(seed, hasher(v.z)); + glm::detail::hash_combine(seed, hasher(v.w)); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::qua const& q) const GLM_NOEXCEPT + { + size_t seed = 0; + hash hasher; + glm::detail::hash_combine(seed, hasher(q.x)); + glm::detail::hash_combine(seed, hasher(q.y)); + glm::detail::hash_combine(seed, hasher(q.z)); + glm::detail::hash_combine(seed, hasher(q.w)); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::tdualquat const& q) const GLM_NOEXCEPT + { + size_t seed = 0; + hash> hasher; + glm::detail::hash_combine(seed, hasher(q.real)); + glm::detail::hash_combine(seed, hasher(q.dual)); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<2, 2, T, Q> const& m) const GLM_NOEXCEPT + { + size_t seed = 0; + hash> hasher; + glm::detail::hash_combine(seed, hasher(m[0])); + glm::detail::hash_combine(seed, hasher(m[1])); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<2, 3, T, Q> const& m) const GLM_NOEXCEPT + { + size_t seed = 0; + hash> hasher; + glm::detail::hash_combine(seed, hasher(m[0])); + glm::detail::hash_combine(seed, hasher(m[1])); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<2, 4, T, Q> const& m) const GLM_NOEXCEPT + { + size_t seed = 0; + hash> hasher; + glm::detail::hash_combine(seed, hasher(m[0])); + glm::detail::hash_combine(seed, hasher(m[1])); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<3, 2, T, Q> const& m) const GLM_NOEXCEPT + { + size_t seed = 0; + hash> hasher; + glm::detail::hash_combine(seed, hasher(m[0])); + glm::detail::hash_combine(seed, hasher(m[1])); + glm::detail::hash_combine(seed, hasher(m[2])); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<3, 3, T, Q> const& m) const GLM_NOEXCEPT + { + size_t seed = 0; + hash> hasher; + glm::detail::hash_combine(seed, hasher(m[0])); + glm::detail::hash_combine(seed, hasher(m[1])); + glm::detail::hash_combine(seed, hasher(m[2])); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<3, 4, T, Q> const& m) const GLM_NOEXCEPT + { + size_t seed = 0; + hash> hasher; + glm::detail::hash_combine(seed, hasher(m[0])); + glm::detail::hash_combine(seed, hasher(m[1])); + glm::detail::hash_combine(seed, hasher(m[2])); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<4, 2, T,Q> const& m) const GLM_NOEXCEPT + { + size_t seed = 0; + hash> hasher; + glm::detail::hash_combine(seed, hasher(m[0])); + glm::detail::hash_combine(seed, hasher(m[1])); + glm::detail::hash_combine(seed, hasher(m[2])); + glm::detail::hash_combine(seed, hasher(m[3])); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<4, 3, T,Q> const& m) const GLM_NOEXCEPT + { + size_t seed = 0; + hash> hasher; + glm::detail::hash_combine(seed, hasher(m[0])); + glm::detail::hash_combine(seed, hasher(m[1])); + glm::detail::hash_combine(seed, hasher(m[2])); + glm::detail::hash_combine(seed, hasher(m[3])); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<4, 4, T, Q> const& m) const GLM_NOEXCEPT + { + size_t seed = 0; + hash> hasher; + glm::detail::hash_combine(seed, hasher(m[0])); + glm::detail::hash_combine(seed, hasher(m[1])); + glm::detail::hash_combine(seed, hasher(m[2])); + glm::detail::hash_combine(seed, hasher(m[3])); + return seed; + } +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/integer.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/integer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d0b4c61a3fd41484952f38aec2d97c7a2db8c47d --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/integer.hpp @@ -0,0 +1,76 @@ +/// @ref gtx_integer +/// @file glm/gtx/integer.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_integer GLM_GTX_integer +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Add support for integer for core functions + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtc/integer.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_integer is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_integer extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_integer + /// @{ + + //! Returns x raised to the y power. + //! From GLM_GTX_integer extension. + GLM_FUNC_DECL int pow(int x, uint y); + + //! Returns the positive square root of x. + //! From GLM_GTX_integer extension. + GLM_FUNC_DECL int sqrt(int x); + + //! Returns the floor log2 of x. + //! From GLM_GTX_integer extension. + GLM_FUNC_DECL unsigned int floor_log2(unsigned int x); + + //! Modulus. Returns x - y * floor(x / y) for each component in x using the floating point value y. + //! From GLM_GTX_integer extension. + GLM_FUNC_DECL int mod(int x, int y); + + //! Return the factorial value of a number (!12 max, integer only) + //! From GLM_GTX_integer extension. + template + GLM_FUNC_DECL genType factorial(genType const& x); + + //! 32bit signed integer. + //! From GLM_GTX_integer extension. + typedef signed int sint; + + //! Returns x raised to the y power. + //! From GLM_GTX_integer extension. + GLM_FUNC_DECL uint pow(uint x, uint y); + + //! Returns the positive square root of x. + //! From GLM_GTX_integer extension. + GLM_FUNC_DECL uint sqrt(uint x); + + //! Modulus. Returns x - y * floor(x / y) for each component in x using the floating point value y. + //! From GLM_GTX_integer extension. + GLM_FUNC_DECL uint mod(uint x, uint y); + + //! Returns the number of leading zeros. + //! From GLM_GTX_integer extension. + GLM_FUNC_DECL uint nlz(uint x); + + /// @} +}//namespace glm + +#include "integer.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/integer.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/integer.inl new file mode 100644 index 0000000000000000000000000000000000000000..956366b250f8c84e94d638dcd5f8a8744991bf51 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/integer.inl @@ -0,0 +1,185 @@ +/// @ref gtx_integer + +namespace glm +{ + // pow + GLM_FUNC_QUALIFIER int pow(int x, uint y) + { + if(y == 0) + return x >= 0 ? 1 : -1; + + int result = x; + for(uint i = 1; i < y; ++i) + result *= x; + return result; + } + + // sqrt: From Christopher J. Musial, An integer square root, Graphics Gems, 1990, page 387 + GLM_FUNC_QUALIFIER int sqrt(int x) + { + if(x <= 1) return x; + + int NextTrial = x >> 1; + int CurrentAnswer; + + do + { + CurrentAnswer = NextTrial; + NextTrial = (NextTrial + x / NextTrial) >> 1; + } while(NextTrial < CurrentAnswer); + + return CurrentAnswer; + } + +// Henry Gordon Dietz: http://aggregate.org/MAGIC/ +namespace detail +{ + GLM_FUNC_QUALIFIER unsigned int ones32(unsigned int x) + { + /* 32-bit recursive reduction using SWAR... + but first step is mapping 2-bit values + into sum of 2 1-bit values in sneaky way + */ + x -= ((x >> 1) & 0x55555555); + x = (((x >> 2) & 0x33333333) + (x & 0x33333333)); + x = (((x >> 4) + x) & 0x0f0f0f0f); + x += (x >> 8); + x += (x >> 16); + return(x & 0x0000003f); + } +}//namespace detail + + // Henry Gordon Dietz: http://aggregate.org/MAGIC/ +/* + GLM_FUNC_QUALIFIER unsigned int floor_log2(unsigned int x) + { + x |= (x >> 1); + x |= (x >> 2); + x |= (x >> 4); + x |= (x >> 8); + x |= (x >> 16); + + return _detail::ones32(x) >> 1; + } +*/ + // mod + GLM_FUNC_QUALIFIER int mod(int x, int y) + { + return ((x % y) + y) % y; + } + + // factorial (!12 max, integer only) + template + GLM_FUNC_QUALIFIER genType factorial(genType const& x) + { + genType Temp = x; + genType Result; + for(Result = 1; Temp > 1; --Temp) + Result *= Temp; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<2, T, Q> factorial( + vec<2, T, Q> const& x) + { + return vec<2, T, Q>( + factorial(x.x), + factorial(x.y)); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> factorial( + vec<3, T, Q> const& x) + { + return vec<3, T, Q>( + factorial(x.x), + factorial(x.y), + factorial(x.z)); + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> factorial( + vec<4, T, Q> const& x) + { + return vec<4, T, Q>( + factorial(x.x), + factorial(x.y), + factorial(x.z), + factorial(x.w)); + } + + GLM_FUNC_QUALIFIER uint pow(uint x, uint y) + { + if (y == 0) + return 1u; + + uint result = x; + for(uint i = 1; i < y; ++i) + result *= x; + return result; + } + + GLM_FUNC_QUALIFIER uint sqrt(uint x) + { + if(x <= 1) return x; + + uint NextTrial = x >> 1; + uint CurrentAnswer; + + do + { + CurrentAnswer = NextTrial; + NextTrial = (NextTrial + x / NextTrial) >> 1; + } while(NextTrial < CurrentAnswer); + + return CurrentAnswer; + } + + GLM_FUNC_QUALIFIER uint mod(uint x, uint y) + { + return x - y * (x / y); + } + +#if(GLM_COMPILER & (GLM_COMPILER_VC | GLM_COMPILER_GCC)) + + GLM_FUNC_QUALIFIER unsigned int nlz(unsigned int x) + { + return 31u - findMSB(x); + } + +#else + + // Hackers Delight: http://www.hackersdelight.org/HDcode/nlz.c.txt + GLM_FUNC_QUALIFIER unsigned int nlz(unsigned int x) + { + int y, m, n; + + y = -int(x >> 16); // If left half of x is 0, + m = (y >> 16) & 16; // set n = 16. If left half + n = 16 - m; // is nonzero, set n = 0 and + x = x >> m; // shift x right 16. + // Now x is of the form 0000xxxx. + y = x - 0x100; // If positions 8-15 are 0, + m = (y >> 16) & 8; // add 8 to n and shift x left 8. + n = n + m; + x = x << m; + + y = x - 0x1000; // If positions 12-15 are 0, + m = (y >> 16) & 4; // add 4 to n and shift x left 4. + n = n + m; + x = x << m; + + y = x - 0x4000; // If positions 14-15 are 0, + m = (y >> 16) & 2; // add 2 to n and shift x left 2. + n = n + m; + x = x << m; + + y = x >> 14; // Set y = 0, 1, 2, or 3. + m = y & ~(y >> 1); // Set m = 0, 1, 2, or 2 resp. + return unsigned(n + 2 - m); + } + +#endif//(GLM_COMPILER) + +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/intersect.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/intersect.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f5c0621deb1a108c5f09b2a6e1ffc2820dd82ce3 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/intersect.hpp @@ -0,0 +1,92 @@ +/// @ref gtx_intersect +/// @file glm/gtx/intersect.hpp +/// +/// @see core (dependence) +/// @see gtx_closest_point (dependence) +/// +/// @defgroup gtx_intersect GLM_GTX_intersect +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Add intersection functions + +#pragma once + +// Dependency: +#include +#include +#include "../glm.hpp" +#include "../geometric.hpp" +#include "../gtx/closest_point.hpp" +#include "../gtx/vector_query.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_closest_point is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_closest_point extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_intersect + /// @{ + + //! Compute the intersection of a ray and a plane. + //! Ray direction and plane normal must be unit length. + //! From GLM_GTX_intersect extension. + template + GLM_FUNC_DECL bool intersectRayPlane( + genType const& orig, genType const& dir, + genType const& planeOrig, genType const& planeNormal, + typename genType::value_type & intersectionDistance); + + //! Compute the intersection of a ray and a triangle. + /// Based om Tomas Mâller implementation http://fileadmin.cs.lth.se/cs/Personal/Tomas_Akenine-Moller/raytri/ + //! From GLM_GTX_intersect extension. + template + GLM_FUNC_DECL bool intersectRayTriangle( + vec<3, T, Q> const& orig, vec<3, T, Q> const& dir, + vec<3, T, Q> const& v0, vec<3, T, Q> const& v1, vec<3, T, Q> const& v2, + vec<2, T, Q>& baryPosition, T& distance); + + //! Compute the intersection of a line and a triangle. + //! From GLM_GTX_intersect extension. + template + GLM_FUNC_DECL bool intersectLineTriangle( + genType const& orig, genType const& dir, + genType const& vert0, genType const& vert1, genType const& vert2, + genType & position); + + //! Compute the intersection distance of a ray and a sphere. + //! The ray direction vector is unit length. + //! From GLM_GTX_intersect extension. + template + GLM_FUNC_DECL bool intersectRaySphere( + genType const& rayStarting, genType const& rayNormalizedDirection, + genType const& sphereCenter, typename genType::value_type const sphereRadiusSquared, + typename genType::value_type & intersectionDistance); + + //! Compute the intersection of a ray and a sphere. + //! From GLM_GTX_intersect extension. + template + GLM_FUNC_DECL bool intersectRaySphere( + genType const& rayStarting, genType const& rayNormalizedDirection, + genType const& sphereCenter, const typename genType::value_type sphereRadius, + genType & intersectionPosition, genType & intersectionNormal); + + //! Compute the intersection of a line and a sphere. + //! From GLM_GTX_intersect extension + template + GLM_FUNC_DECL bool intersectLineSphere( + genType const& point0, genType const& point1, + genType const& sphereCenter, typename genType::value_type sphereRadius, + genType & intersectionPosition1, genType & intersectionNormal1, + genType & intersectionPosition2 = genType(), genType & intersectionNormal2 = genType()); + + /// @} +}//namespace glm + +#include "intersect.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/intersect.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/intersect.inl new file mode 100644 index 0000000000000000000000000000000000000000..d7393557fb960a80afc480e580fa12a9f3ba5a1c --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/intersect.inl @@ -0,0 +1,200 @@ +/// @ref gtx_intersect + +namespace glm +{ + template + GLM_FUNC_QUALIFIER bool intersectRayPlane + ( + genType const& orig, genType const& dir, + genType const& planeOrig, genType const& planeNormal, + typename genType::value_type & intersectionDistance + ) + { + typename genType::value_type d = glm::dot(dir, planeNormal); + typename genType::value_type Epsilon = std::numeric_limits::epsilon(); + + if(glm::abs(d) > Epsilon) // if dir and planeNormal are not perpendicular + { + typename genType::value_type const tmp_intersectionDistance = glm::dot(planeOrig - orig, planeNormal) / d; + if (tmp_intersectionDistance > static_cast(0)) { // allow only intersections + intersectionDistance = tmp_intersectionDistance; + return true; + } + } + + return false; + } + + template + GLM_FUNC_QUALIFIER bool intersectRayTriangle + ( + vec<3, T, Q> const& orig, vec<3, T, Q> const& dir, + vec<3, T, Q> const& vert0, vec<3, T, Q> const& vert1, vec<3, T, Q> const& vert2, + vec<2, T, Q>& baryPosition, T& distance + ) + { + // find vectors for two edges sharing vert0 + vec<3, T, Q> const edge1 = vert1 - vert0; + vec<3, T, Q> const edge2 = vert2 - vert0; + + // begin calculating determinant - also used to calculate U parameter + vec<3, T, Q> const p = glm::cross(dir, edge2); + + // if determinant is near zero, ray lies in plane of triangle + T const det = glm::dot(edge1, p); + + vec<3, T, Q> Perpendicular(0); + + if(det > std::numeric_limits::epsilon()) + { + // calculate distance from vert0 to ray origin + vec<3, T, Q> const dist = orig - vert0; + + // calculate U parameter and test bounds + baryPosition.x = glm::dot(dist, p); + if(baryPosition.x < static_cast(0) || baryPosition.x > det) + return false; + + // prepare to test V parameter + Perpendicular = glm::cross(dist, edge1); + + // calculate V parameter and test bounds + baryPosition.y = glm::dot(dir, Perpendicular); + if((baryPosition.y < static_cast(0)) || ((baryPosition.x + baryPosition.y) > det)) + return false; + } + else if(det < -std::numeric_limits::epsilon()) + { + // calculate distance from vert0 to ray origin + vec<3, T, Q> const dist = orig - vert0; + + // calculate U parameter and test bounds + baryPosition.x = glm::dot(dist, p); + if((baryPosition.x > static_cast(0)) || (baryPosition.x < det)) + return false; + + // prepare to test V parameter + Perpendicular = glm::cross(dist, edge1); + + // calculate V parameter and test bounds + baryPosition.y = glm::dot(dir, Perpendicular); + if((baryPosition.y > static_cast(0)) || (baryPosition.x + baryPosition.y < det)) + return false; + } + else + return false; // ray is parallel to the plane of the triangle + + T inv_det = static_cast(1) / det; + + // calculate distance, ray intersects triangle + distance = glm::dot(edge2, Perpendicular) * inv_det; + baryPosition *= inv_det; + + return true; + } + + template + GLM_FUNC_QUALIFIER bool intersectLineTriangle + ( + genType const& orig, genType const& dir, + genType const& vert0, genType const& vert1, genType const& vert2, + genType & position + ) + { + typename genType::value_type Epsilon = std::numeric_limits::epsilon(); + + genType edge1 = vert1 - vert0; + genType edge2 = vert2 - vert0; + + genType Perpendicular = cross(dir, edge2); + + typename genType::value_type det = dot(edge1, Perpendicular); + + if (det > -Epsilon && det < Epsilon) + return false; + typename genType::value_type inv_det = typename genType::value_type(1) / det; + + genType Tangent = orig - vert0; + + position.y = dot(Tangent, Perpendicular) * inv_det; + if (position.y < typename genType::value_type(0) || position.y > typename genType::value_type(1)) + return false; + + genType Cotangent = cross(Tangent, edge1); + + position.z = dot(dir, Cotangent) * inv_det; + if (position.z < typename genType::value_type(0) || position.y + position.z > typename genType::value_type(1)) + return false; + + position.x = dot(edge2, Cotangent) * inv_det; + + return true; + } + + template + GLM_FUNC_QUALIFIER bool intersectRaySphere + ( + genType const& rayStarting, genType const& rayNormalizedDirection, + genType const& sphereCenter, const typename genType::value_type sphereRadiusSquared, + typename genType::value_type & intersectionDistance + ) + { + typename genType::value_type Epsilon = std::numeric_limits::epsilon(); + genType diff = sphereCenter - rayStarting; + typename genType::value_type t0 = dot(diff, rayNormalizedDirection); + typename genType::value_type dSquared = dot(diff, diff) - t0 * t0; + if( dSquared > sphereRadiusSquared ) + { + return false; + } + typename genType::value_type t1 = sqrt( sphereRadiusSquared - dSquared ); + intersectionDistance = t0 > t1 + Epsilon ? t0 - t1 : t0 + t1; + return intersectionDistance > Epsilon; + } + + template + GLM_FUNC_QUALIFIER bool intersectRaySphere + ( + genType const& rayStarting, genType const& rayNormalizedDirection, + genType const& sphereCenter, const typename genType::value_type sphereRadius, + genType & intersectionPosition, genType & intersectionNormal + ) + { + typename genType::value_type distance; + if( intersectRaySphere( rayStarting, rayNormalizedDirection, sphereCenter, sphereRadius * sphereRadius, distance ) ) + { + intersectionPosition = rayStarting + rayNormalizedDirection * distance; + intersectionNormal = (intersectionPosition - sphereCenter) / sphereRadius; + return true; + } + return false; + } + + template + GLM_FUNC_QUALIFIER bool intersectLineSphere + ( + genType const& point0, genType const& point1, + genType const& sphereCenter, typename genType::value_type sphereRadius, + genType & intersectionPoint1, genType & intersectionNormal1, + genType & intersectionPoint2, genType & intersectionNormal2 + ) + { + typename genType::value_type Epsilon = std::numeric_limits::epsilon(); + genType dir = normalize(point1 - point0); + genType diff = sphereCenter - point0; + typename genType::value_type t0 = dot(diff, dir); + typename genType::value_type dSquared = dot(diff, diff) - t0 * t0; + if( dSquared > sphereRadius * sphereRadius ) + { + return false; + } + typename genType::value_type t1 = sqrt( sphereRadius * sphereRadius - dSquared ); + if( t0 < t1 + Epsilon ) + t1 = -t1; + intersectionPoint1 = point0 + dir * (t0 - t1); + intersectionNormal1 = (intersectionPoint1 - sphereCenter) / sphereRadius; + intersectionPoint2 = point0 + dir * (t0 + t1); + intersectionNormal2 = (intersectionPoint2 - sphereCenter) / sphereRadius; + return true; + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/io.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/io.hpp new file mode 100644 index 0000000000000000000000000000000000000000..68b5499bfbe71ce441a5d5b798eb475794720cc5 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/io.hpp @@ -0,0 +1,201 @@ +/// @ref gtx_io +/// @file glm/gtx/io.hpp +/// @author Jan P Springer (regnirpsj@gmail.com) +/// +/// @see core (dependence) +/// @see gtc_matrix_access (dependence) +/// @see gtc_quaternion (dependence) +/// +/// @defgroup gtx_io GLM_GTX_io +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// std::[w]ostream support for glm types +/// +/// std::[w]ostream support for glm types + qualifier/width/etc. manipulators +/// based on howard hinnant's std::chrono io proposal +/// [http://home.roadrunner.com/~hinnant/bloomington/chrono_io.html] + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtx/quaternion.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_io is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_io extension included") +# endif +#endif + +#include // std::basic_ostream<> (fwd) +#include // std::locale, std::locale::facet, std::locale::id +#include // std::pair<> + +namespace glm +{ + /// @addtogroup gtx_io + /// @{ + + namespace io + { + enum order_type { column_major, row_major}; + + template + class format_punct : public std::locale::facet + { + typedef CTy char_type; + + public: + + static std::locale::id id; + + bool formatted; + unsigned precision; + unsigned width; + char_type separator; + char_type delim_left; + char_type delim_right; + char_type space; + char_type newline; + order_type order; + + GLM_FUNC_DECL explicit format_punct(size_t a = 0); + GLM_FUNC_DECL explicit format_punct(format_punct const&); + }; + + template > + class basic_state_saver { + + public: + + GLM_FUNC_DECL explicit basic_state_saver(std::basic_ios&); + GLM_FUNC_DECL ~basic_state_saver(); + + private: + + typedef ::std::basic_ios state_type; + typedef typename state_type::char_type char_type; + typedef ::std::ios_base::fmtflags flags_type; + typedef ::std::streamsize streamsize_type; + typedef ::std::locale const locale_type; + + state_type& state_; + flags_type flags_; + streamsize_type precision_; + streamsize_type width_; + char_type fill_; + locale_type locale_; + + GLM_FUNC_DECL basic_state_saver& operator=(basic_state_saver const&); + }; + + typedef basic_state_saver state_saver; + typedef basic_state_saver wstate_saver; + + template > + class basic_format_saver + { + public: + + GLM_FUNC_DECL explicit basic_format_saver(std::basic_ios&); + GLM_FUNC_DECL ~basic_format_saver(); + + private: + + basic_state_saver const bss_; + + GLM_FUNC_DECL basic_format_saver& operator=(basic_format_saver const&); + }; + + typedef basic_format_saver format_saver; + typedef basic_format_saver wformat_saver; + + struct precision + { + unsigned value; + + GLM_FUNC_DECL explicit precision(unsigned); + }; + + struct width + { + unsigned value; + + GLM_FUNC_DECL explicit width(unsigned); + }; + + template + struct delimeter + { + CTy value[3]; + + GLM_FUNC_DECL explicit delimeter(CTy /* left */, CTy /* right */, CTy /* separator */ = ','); + }; + + struct order + { + order_type value; + + GLM_FUNC_DECL explicit order(order_type); + }; + + // functions, inlined (inline) + + template + FTy const& get_facet(std::basic_ios&); + template + std::basic_ios& formatted(std::basic_ios&); + template + std::basic_ios& unformatted(std::basic_ios&); + + template + std::basic_ostream& operator<<(std::basic_ostream&, precision const&); + template + std::basic_ostream& operator<<(std::basic_ostream&, width const&); + template + std::basic_ostream& operator<<(std::basic_ostream&, delimeter const&); + template + std::basic_ostream& operator<<(std::basic_ostream&, order const&); + }//namespace io + + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, qua const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, vec<1, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, vec<2, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, vec<3, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, vec<4, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<2, 2, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<2, 3, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<2, 4, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<3, 2, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<3, 3, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<3, 4, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<4, 2, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<4, 3, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<4, 4, T, Q> const&); + + template + GLM_FUNC_DECL std::basic_ostream & operator<<(std::basic_ostream &, + std::pair const, mat<4, 4, T, Q> const> const&); + + /// @} +}//namespace glm + +#include "io.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/io.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/io.inl new file mode 100644 index 0000000000000000000000000000000000000000..a3a1bb6c26b4175373a6ec45595cada792567c1c --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/io.inl @@ -0,0 +1,440 @@ +/// @ref gtx_io +/// @author Jan P Springer (regnirpsj@gmail.com) + +#include // std::fixed, std::setfill<>, std::setprecision, std::right, std::setw +#include // std::basic_ostream<> +#include "../gtc/matrix_access.hpp" // glm::col, glm::row +#include "../gtx/type_trait.hpp" // glm::type<> + +namespace glm{ +namespace io +{ + template + GLM_FUNC_QUALIFIER format_punct::format_punct(size_t a) + : std::locale::facet(a) + , formatted(true) + , precision(3) + , width(1 + 4 + 1 + precision) + , separator(',') + , delim_left('[') + , delim_right(']') + , space(' ') + , newline('\n') + , order(column_major) + {} + + template + GLM_FUNC_QUALIFIER format_punct::format_punct(format_punct const& a) + : std::locale::facet(0) + , formatted(a.formatted) + , precision(a.precision) + , width(a.width) + , separator(a.separator) + , delim_left(a.delim_left) + , delim_right(a.delim_right) + , space(a.space) + , newline(a.newline) + , order(a.order) + {} + + template std::locale::id format_punct::id; + + template + GLM_FUNC_QUALIFIER basic_state_saver::basic_state_saver(std::basic_ios& a) + : state_(a) + , flags_(a.flags()) + , precision_(a.precision()) + , width_(a.width()) + , fill_(a.fill()) + , locale_(a.getloc()) + {} + + template + GLM_FUNC_QUALIFIER basic_state_saver::~basic_state_saver() + { + state_.imbue(locale_); + state_.fill(fill_); + state_.width(width_); + state_.precision(precision_); + state_.flags(flags_); + } + + template + GLM_FUNC_QUALIFIER basic_format_saver::basic_format_saver(std::basic_ios& a) + : bss_(a) + { + a.imbue(std::locale(a.getloc(), new format_punct(get_facet >(a)))); + } + + template + GLM_FUNC_QUALIFIER + basic_format_saver::~basic_format_saver() + {} + + GLM_FUNC_QUALIFIER precision::precision(unsigned a) + : value(a) + {} + + GLM_FUNC_QUALIFIER width::width(unsigned a) + : value(a) + {} + + template + GLM_FUNC_QUALIFIER delimeter::delimeter(CTy a, CTy b, CTy c) + : value() + { + value[0] = a; + value[1] = b; + value[2] = c; + } + + GLM_FUNC_QUALIFIER order::order(order_type a) + : value(a) + {} + + template + GLM_FUNC_QUALIFIER FTy const& get_facet(std::basic_ios& ios) + { + if(!std::has_facet(ios.getloc())) + ios.imbue(std::locale(ios.getloc(), new FTy)); + + return std::use_facet(ios.getloc()); + } + + template + GLM_FUNC_QUALIFIER std::basic_ios& formatted(std::basic_ios& ios) + { + const_cast&>(get_facet >(ios)).formatted = true; + return ios; + } + + template + GLM_FUNC_QUALIFIER std::basic_ios& unformatted(std::basic_ios& ios) + { + const_cast&>(get_facet >(ios)).formatted = false; + return ios; + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, precision const& a) + { + const_cast&>(get_facet >(os)).precision = a.value; + return os; + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, width const& a) + { + const_cast&>(get_facet >(os)).width = a.value; + return os; + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, delimeter const& a) + { + format_punct & fmt(const_cast&>(get_facet >(os))); + + fmt.delim_left = a.value[0]; + fmt.delim_right = a.value[1]; + fmt.separator = a.value[2]; + + return os; + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, order const& a) + { + const_cast&>(get_facet >(os)).order = a.value; + return os; + } +} // namespace io + +namespace detail +{ + template + GLM_FUNC_QUALIFIER std::basic_ostream& + print_vector_on(std::basic_ostream& os, V const& a) + { + typename std::basic_ostream::sentry const cerberus(os); + + if(cerberus) + { + io::format_punct const& fmt(io::get_facet >(os)); + + length_t const& components(type::components); + + if(fmt.formatted) + { + io::basic_state_saver const bss(os); + + os << std::fixed << std::right << std::setprecision(fmt.precision) << std::setfill(fmt.space) << fmt.delim_left; + + for(length_t i(0); i < components; ++i) + { + os << std::setw(fmt.width) << a[i]; + if(components-1 != i) + os << fmt.separator; + } + + os << fmt.delim_right; + } + else + { + for(length_t i(0); i < components; ++i) + { + os << a[i]; + + if(components-1 != i) + os << fmt.space; + } + } + } + + return os; + } +}//namespace detail + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, qua const& a) + { + return detail::print_vector_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, vec<1, T, Q> const& a) + { + return detail::print_vector_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, vec<2, T, Q> const& a) + { + return detail::print_vector_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, vec<3, T, Q> const& a) + { + return detail::print_vector_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, vec<4, T, Q> const& a) + { + return detail::print_vector_on(os, a); + } + +namespace detail +{ + template class M, length_t C, length_t R, typename T, qualifier Q> + GLM_FUNC_QUALIFIER std::basic_ostream& print_matrix_on(std::basic_ostream& os, M const& a) + { + typename std::basic_ostream::sentry const cerberus(os); + + if(cerberus) + { + io::format_punct const& fmt(io::get_facet >(os)); + + length_t const& cols(type >::cols); + length_t const& rows(type >::rows); + + if(fmt.formatted) + { + os << fmt.newline << fmt.delim_left; + + switch(fmt.order) + { + case io::column_major: + { + for(length_t i(0); i < rows; ++i) + { + if (0 != i) + os << fmt.space; + + os << row(a, i); + + if(rows-1 != i) + os << fmt.newline; + } + } + break; + + case io::row_major: + { + for(length_t i(0); i < cols; ++i) + { + if(0 != i) + os << fmt.space; + + os << column(a, i); + + if(cols-1 != i) + os << fmt.newline; + } + } + break; + } + + os << fmt.delim_right; + } + else + { + switch (fmt.order) + { + case io::column_major: + { + for(length_t i(0); i < cols; ++i) + { + os << column(a, i); + + if(cols - 1 != i) + os << fmt.space; + } + } + break; + + case io::row_major: + { + for (length_t i(0); i < rows; ++i) + { + os << row(a, i); + + if (rows-1 != i) + os << fmt.space; + } + } + break; + } + } + } + + return os; + } +}//namespace detail + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, mat<2, 2, T, Q> const& a) + { + return detail::print_matrix_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, mat<2, 3, T, Q> const& a) + { + return detail::print_matrix_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, mat<2, 4, T, Q> const& a) + { + return detail::print_matrix_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, mat<3, 2, T, Q> const& a) + { + return detail::print_matrix_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, mat<3, 3, T, Q> const& a) + { + return detail::print_matrix_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream & operator<<(std::basic_ostream& os, mat<3, 4, T, Q> const& a) + { + return detail::print_matrix_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream & operator<<(std::basic_ostream& os, mat<4, 2, T, Q> const& a) + { + return detail::print_matrix_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream & operator<<(std::basic_ostream& os, mat<4, 3, T, Q> const& a) + { + return detail::print_matrix_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream & operator<<(std::basic_ostream& os, mat<4, 4, T, Q> const& a) + { + return detail::print_matrix_on(os, a); + } + +namespace detail +{ + template class M, length_t C, length_t R, typename T, qualifier Q> + GLM_FUNC_QUALIFIER std::basic_ostream& print_matrix_pair_on(std::basic_ostream& os, std::pair const, M const> const& a) + { + typename std::basic_ostream::sentry const cerberus(os); + + if(cerberus) + { + io::format_punct const& fmt(io::get_facet >(os)); + M const& ml(a.first); + M const& mr(a.second); + length_t const& cols(type >::cols); + length_t const& rows(type >::rows); + + if(fmt.formatted) + { + os << fmt.newline << fmt.delim_left; + + switch(fmt.order) + { + case io::column_major: + { + for(length_t i(0); i < rows; ++i) + { + if(0 != i) + os << fmt.space; + + os << row(ml, i) << ((rows-1 != i) ? fmt.space : fmt.delim_right) << fmt.space << ((0 != i) ? fmt.space : fmt.delim_left) << row(mr, i); + + if(rows-1 != i) + os << fmt.newline; + } + } + break; + case io::row_major: + { + for(length_t i(0); i < cols; ++i) + { + if(0 != i) + os << fmt.space; + + os << column(ml, i) << ((cols-1 != i) ? fmt.space : fmt.delim_right) << fmt.space << ((0 != i) ? fmt.space : fmt.delim_left) << column(mr, i); + + if(cols-1 != i) + os << fmt.newline; + } + } + break; + } + + os << fmt.delim_right; + } + else + { + os << ml << fmt.space << mr; + } + } + + return os; + } +}//namespace detail + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<( + std::basic_ostream & os, + std::pair const, + mat<4, 4, T, Q> const> const& a) + { + return detail::print_matrix_pair_on(os, a); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/log_base.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/log_base.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ba28c9d7bffcb27c32dc13818eeaac4d9f231dd8 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/log_base.hpp @@ -0,0 +1,48 @@ +/// @ref gtx_log_base +/// @file glm/gtx/log_base.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_log_base GLM_GTX_log_base +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Logarithm for any base. base can be a vector or a scalar. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_log_base is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_log_base extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_log_base + /// @{ + + /// Logarithm for any base. + /// From GLM_GTX_log_base. + template + GLM_FUNC_DECL genType log( + genType const& x, + genType const& base); + + /// Logarithm for any base. + /// From GLM_GTX_log_base. + template + GLM_FUNC_DECL vec sign( + vec const& x, + vec const& base); + + /// @} +}//namespace glm + +#include "log_base.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/log_base.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/log_base.inl new file mode 100644 index 0000000000000000000000000000000000000000..4bbb8e895abbdac32e58cc4e66f700ac86ba17a4 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/log_base.inl @@ -0,0 +1,16 @@ +/// @ref gtx_log_base + +namespace glm +{ + template + GLM_FUNC_QUALIFIER genType log(genType const& x, genType const& base) + { + return glm::log(x) / glm::log(base); + } + + template + GLM_FUNC_QUALIFIER vec log(vec const& x, vec const& base) + { + return glm::log(x) / glm::log(base); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_cross_product.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_cross_product.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1e585f9a4ffe8e9eadae27a26c6cb9dd5f5b294b --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_cross_product.hpp @@ -0,0 +1,47 @@ +/// @ref gtx_matrix_cross_product +/// @file glm/gtx/matrix_cross_product.hpp +/// +/// @see core (dependence) +/// @see gtx_extented_min_max (dependence) +/// +/// @defgroup gtx_matrix_cross_product GLM_GTX_matrix_cross_product +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Build cross product matrices + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_matrix_cross_product is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_matrix_cross_product extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_matrix_cross_product + /// @{ + + //! Build a cross product matrix. + //! From GLM_GTX_matrix_cross_product extension. + template + GLM_FUNC_DECL mat<3, 3, T, Q> matrixCross3( + vec<3, T, Q> const& x); + + //! Build a cross product matrix. + //! From GLM_GTX_matrix_cross_product extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> matrixCross4( + vec<3, T, Q> const& x); + + /// @} +}//namespace glm + +#include "matrix_cross_product.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_cross_product.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_cross_product.inl new file mode 100644 index 0000000000000000000000000000000000000000..3a153977cf59d977d3f4c318569751dee4f27331 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_cross_product.inl @@ -0,0 +1,37 @@ +/// @ref gtx_matrix_cross_product + +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> matrixCross3 + ( + vec<3, T, Q> const& x + ) + { + mat<3, 3, T, Q> Result(T(0)); + Result[0][1] = x.z; + Result[1][0] = -x.z; + Result[0][2] = -x.y; + Result[2][0] = x.y; + Result[1][2] = x.x; + Result[2][1] = -x.x; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> matrixCross4 + ( + vec<3, T, Q> const& x + ) + { + mat<4, 4, T, Q> Result(T(0)); + Result[0][1] = x.z; + Result[1][0] = -x.z; + Result[0][2] = -x.y; + Result[2][0] = x.y; + Result[1][2] = x.x; + Result[2][1] = -x.x; + return Result; + } + +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_decompose.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_decompose.hpp new file mode 100644 index 0000000000000000000000000000000000000000..acd7a7f0681a20ffeaa34d6ad9e911508776bf7f --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_decompose.hpp @@ -0,0 +1,46 @@ +/// @ref gtx_matrix_decompose +/// @file glm/gtx/matrix_decompose.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_matrix_decompose GLM_GTX_matrix_decompose +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Decomposes a model matrix to translations, rotation and scale components + +#pragma once + +// Dependencies +#include "../mat4x4.hpp" +#include "../vec3.hpp" +#include "../vec4.hpp" +#include "../geometric.hpp" +#include "../gtc/quaternion.hpp" +#include "../gtc/matrix_transform.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_matrix_decompose is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_matrix_decompose extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_matrix_decompose + /// @{ + + /// Decomposes a model matrix to translations, rotation and scale components + /// @see gtx_matrix_decompose + template + GLM_FUNC_DECL bool decompose( + mat<4, 4, T, Q> const& modelMatrix, + vec<3, T, Q> & scale, qua & orientation, vec<3, T, Q> & translation, vec<3, T, Q> & skew, vec<4, T, Q> & perspective); + + /// @} +}//namespace glm + +#include "matrix_decompose.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_decompose.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_decompose.inl new file mode 100644 index 0000000000000000000000000000000000000000..aa4386af0a7729833d550ca486e3fd8df7d5b633 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_decompose.inl @@ -0,0 +1,192 @@ +/// @ref gtx_matrix_decompose + +#include "../gtc/constants.hpp" +#include "../gtc/epsilon.hpp" + +namespace glm{ +namespace detail +{ + /// Make a linear combination of two vectors and return the result. + // result = (a * ascl) + (b * bscl) + template + GLM_FUNC_QUALIFIER vec<3, T, Q> combine( + vec<3, T, Q> const& a, + vec<3, T, Q> const& b, + T ascl, T bscl) + { + return (a * ascl) + (b * bscl); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> scale(vec<3, T, Q> const& v, T desiredLength) + { + return v * desiredLength / length(v); + } +}//namespace detail + + // Matrix decompose + // http://www.opensource.apple.com/source/WebCore/WebCore-514/platform/graphics/transforms/TransformationMatrix.cpp + // Decomposes the mode matrix to translations,rotation scale components + + template + GLM_FUNC_QUALIFIER bool decompose(mat<4, 4, T, Q> const& ModelMatrix, vec<3, T, Q> & Scale, qua & Orientation, vec<3, T, Q> & Translation, vec<3, T, Q> & Skew, vec<4, T, Q> & Perspective) + { + mat<4, 4, T, Q> LocalMatrix(ModelMatrix); + + // Normalize the matrix. + if(epsilonEqual(LocalMatrix[3][3], static_cast(0), epsilon())) + return false; + + for(length_t i = 0; i < 4; ++i) + for(length_t j = 0; j < 4; ++j) + LocalMatrix[i][j] /= LocalMatrix[3][3]; + + // perspectiveMatrix is used to solve for perspective, but it also provides + // an easy way to test for singularity of the upper 3x3 component. + mat<4, 4, T, Q> PerspectiveMatrix(LocalMatrix); + + for(length_t i = 0; i < 3; i++) + PerspectiveMatrix[i][3] = static_cast(0); + PerspectiveMatrix[3][3] = static_cast(1); + + /// TODO: Fixme! + if(epsilonEqual(determinant(PerspectiveMatrix), static_cast(0), epsilon())) + return false; + + // First, isolate perspective. This is the messiest. + if( + epsilonNotEqual(LocalMatrix[0][3], static_cast(0), epsilon()) || + epsilonNotEqual(LocalMatrix[1][3], static_cast(0), epsilon()) || + epsilonNotEqual(LocalMatrix[2][3], static_cast(0), epsilon())) + { + // rightHandSide is the right hand side of the equation. + vec<4, T, Q> RightHandSide; + RightHandSide[0] = LocalMatrix[0][3]; + RightHandSide[1] = LocalMatrix[1][3]; + RightHandSide[2] = LocalMatrix[2][3]; + RightHandSide[3] = LocalMatrix[3][3]; + + // Solve the equation by inverting PerspectiveMatrix and multiplying + // rightHandSide by the inverse. (This is the easiest way, not + // necessarily the best.) + mat<4, 4, T, Q> InversePerspectiveMatrix = glm::inverse(PerspectiveMatrix);// inverse(PerspectiveMatrix, inversePerspectiveMatrix); + mat<4, 4, T, Q> TransposedInversePerspectiveMatrix = glm::transpose(InversePerspectiveMatrix);// transposeMatrix4(inversePerspectiveMatrix, transposedInversePerspectiveMatrix); + + Perspective = TransposedInversePerspectiveMatrix * RightHandSide; + // v4MulPointByMatrix(rightHandSide, transposedInversePerspectiveMatrix, perspectivePoint); + + // Clear the perspective partition + LocalMatrix[0][3] = LocalMatrix[1][3] = LocalMatrix[2][3] = static_cast(0); + LocalMatrix[3][3] = static_cast(1); + } + else + { + // No perspective. + Perspective = vec<4, T, Q>(0, 0, 0, 1); + } + + // Next take care of translation (easy). + Translation = vec<3, T, Q>(LocalMatrix[3]); + LocalMatrix[3] = vec<4, T, Q>(0, 0, 0, LocalMatrix[3].w); + + vec<3, T, Q> Row[3], Pdum3; + + // Now get scale and shear. + for(length_t i = 0; i < 3; ++i) + for(length_t j = 0; j < 3; ++j) + Row[i][j] = LocalMatrix[i][j]; + + // Compute X scale factor and normalize first row. + Scale.x = length(Row[0]);// v3Length(Row[0]); + + Row[0] = detail::scale(Row[0], static_cast(1)); + + // Compute XY shear factor and make 2nd row orthogonal to 1st. + Skew.z = dot(Row[0], Row[1]); + Row[1] = detail::combine(Row[1], Row[0], static_cast(1), -Skew.z); + + // Now, compute Y scale and normalize 2nd row. + Scale.y = length(Row[1]); + Row[1] = detail::scale(Row[1], static_cast(1)); + Skew.z /= Scale.y; + + // Compute XZ and YZ shears, orthogonalize 3rd row. + Skew.y = glm::dot(Row[0], Row[2]); + Row[2] = detail::combine(Row[2], Row[0], static_cast(1), -Skew.y); + Skew.x = glm::dot(Row[1], Row[2]); + Row[2] = detail::combine(Row[2], Row[1], static_cast(1), -Skew.x); + + // Next, get Z scale and normalize 3rd row. + Scale.z = length(Row[2]); + Row[2] = detail::scale(Row[2], static_cast(1)); + Skew.y /= Scale.z; + Skew.x /= Scale.z; + + // At this point, the matrix (in rows[]) is orthonormal. + // Check for a coordinate system flip. If the determinant + // is -1, then negate the matrix and the scaling factors. + Pdum3 = cross(Row[1], Row[2]); // v3Cross(row[1], row[2], Pdum3); + if(dot(Row[0], Pdum3) < 0) + { + for(length_t i = 0; i < 3; i++) + { + Scale[i] *= static_cast(-1); + Row[i] *= static_cast(-1); + } + } + + // Now, get the rotations out, as described in the gem. + + // FIXME - Add the ability to return either quaternions (which are + // easier to recompose with) or Euler angles (rx, ry, rz), which + // are easier for authors to deal with. The latter will only be useful + // when we fix https://bugs.webkit.org/show_bug.cgi?id=23799, so I + // will leave the Euler angle code here for now. + + // ret.rotateY = asin(-Row[0][2]); + // if (cos(ret.rotateY) != 0) { + // ret.rotateX = atan2(Row[1][2], Row[2][2]); + // ret.rotateZ = atan2(Row[0][1], Row[0][0]); + // } else { + // ret.rotateX = atan2(-Row[2][0], Row[1][1]); + // ret.rotateZ = 0; + // } + + int i, j, k = 0; + T root, trace = Row[0].x + Row[1].y + Row[2].z; + if(trace > static_cast(0)) + { + root = sqrt(trace + static_cast(1.0)); + Orientation.w = static_cast(0.5) * root; + root = static_cast(0.5) / root; + Orientation.x = root * (Row[1].z - Row[2].y); + Orientation.y = root * (Row[2].x - Row[0].z); + Orientation.z = root * (Row[0].y - Row[1].x); + } // End if > 0 + else + { + static int Next[3] = {1, 2, 0}; + i = 0; + if(Row[1].y > Row[0].x) i = 1; + if(Row[2].z > Row[i][i]) i = 2; + j = Next[i]; + k = Next[j]; + +# ifdef GLM_FORCE_QUAT_DATA_XYZW + int off = 0; +# else + int off = 1; +# endif + + root = sqrt(Row[i][i] - Row[j][j] - Row[k][k] + static_cast(1.0)); + + Orientation[i + off] = static_cast(0.5) * root; + root = static_cast(0.5) / root; + Orientation[j + off] = root * (Row[i][j] + Row[j][i]); + Orientation[k + off] = root * (Row[i][k] + Row[k][i]); + Orientation.w = root * (Row[j][k] - Row[k][j]); + } // End if <= 0 + + return true; + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_factorisation.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_factorisation.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5a975d60b6c2ca9fb03b9a92541679ebe75f988c --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_factorisation.hpp @@ -0,0 +1,69 @@ +/// @ref gtx_matrix_factorisation +/// @file glm/gtx/matrix_factorisation.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_matrix_factorisation GLM_GTX_matrix_factorisation +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Functions to factor matrices in various forms + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_matrix_factorisation is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_matrix_factorisation extension included") +# endif +#endif + +/* +Suggestions: + - Move helper functions flipud and fliplr to another file: They may be helpful in more general circumstances. + - Implement other types of matrix factorisation, such as: QL and LQ, L(D)U, eigendecompositions, etc... +*/ + +namespace glm +{ + /// @addtogroup gtx_matrix_factorisation + /// @{ + + /// Flips the matrix rows up and down. + /// + /// From GLM_GTX_matrix_factorisation extension. + template + GLM_FUNC_DECL mat flipud(mat const& in); + + /// Flips the matrix columns right and left. + /// + /// From GLM_GTX_matrix_factorisation extension. + template + GLM_FUNC_DECL mat fliplr(mat const& in); + + /// Performs QR factorisation of a matrix. + /// Returns 2 matrices, q and r, such that the columns of q are orthonormal and span the same subspace than those of the input matrix, r is an upper triangular matrix, and q*r=in. + /// Given an n-by-m input matrix, q has dimensions min(n,m)-by-m, and r has dimensions n-by-min(n,m). + /// + /// From GLM_GTX_matrix_factorisation extension. + template + GLM_FUNC_DECL void qr_decompose(mat const& in, mat<(C < R ? C : R), R, T, Q>& q, mat& r); + + /// Performs RQ factorisation of a matrix. + /// Returns 2 matrices, r and q, such that r is an upper triangular matrix, the rows of q are orthonormal and span the same subspace than those of the input matrix, and r*q=in. + /// Note that in the context of RQ factorisation, the diagonal is seen as starting in the lower-right corner of the matrix, instead of the usual upper-left. + /// Given an n-by-m input matrix, r has dimensions min(n,m)-by-m, and q has dimensions n-by-min(n,m). + /// + /// From GLM_GTX_matrix_factorisation extension. + template + GLM_FUNC_DECL void rq_decompose(mat const& in, mat<(C < R ? C : R), R, T, Q>& r, mat& q); + + /// @} +} + +#include "matrix_factorisation.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_factorisation.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_factorisation.inl new file mode 100644 index 0000000000000000000000000000000000000000..c479b8ad99094b0a301ef29b31e112e7441ea143 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_factorisation.inl @@ -0,0 +1,84 @@ +/// @ref gtx_matrix_factorisation + +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat flipud(mat const& in) + { + mat tin = transpose(in); + tin = fliplr(tin); + mat out = transpose(tin); + + return out; + } + + template + GLM_FUNC_QUALIFIER mat fliplr(mat const& in) + { + mat out; + for (length_t i = 0; i < C; i++) + { + out[i] = in[(C - i) - 1]; + } + + return out; + } + + template + GLM_FUNC_QUALIFIER void qr_decompose(mat const& in, mat<(C < R ? C : R), R, T, Q>& q, mat& r) + { + // Uses modified Gram-Schmidt method + // Source: https://en.wikipedia.org/wiki/Gram�Schmidt_process + // And https://en.wikipedia.org/wiki/QR_decomposition + + //For all the linearly independs columns of the input... + // (there can be no more linearly independents columns than there are rows.) + for (length_t i = 0; i < (C < R ? C : R); i++) + { + //Copy in Q the input's i-th column. + q[i] = in[i]; + + //j = [0,i[ + // Make that column orthogonal to all the previous ones by substracting to it the non-orthogonal projection of all the previous columns. + // Also: Fill the zero elements of R + for (length_t j = 0; j < i; j++) + { + q[i] -= dot(q[i], q[j])*q[j]; + r[j][i] = 0; + } + + //Now, Q i-th column is orthogonal to all the previous columns. Normalize it. + q[i] = normalize(q[i]); + + //j = [i,C[ + //Finally, compute the corresponding coefficients of R by computing the projection of the resulting column on the other columns of the input. + for (length_t j = i; j < C; j++) + { + r[j][i] = dot(in[j], q[i]); + } + } + } + + template + GLM_FUNC_QUALIFIER void rq_decompose(mat const& in, mat<(C < R ? C : R), R, T, Q>& r, mat& q) + { + // From https://en.wikipedia.org/wiki/QR_decomposition: + // The RQ decomposition transforms a matrix A into the product of an upper triangular matrix R (also known as right-triangular) and an orthogonal matrix Q. The only difference from QR decomposition is the order of these matrices. + // QR decomposition is Gram�Schmidt orthogonalization of columns of A, started from the first column. + // RQ decomposition is Gram�Schmidt orthogonalization of rows of A, started from the last row. + + mat tin = transpose(in); + tin = fliplr(tin); + + mat tr; + mat<(C < R ? C : R), C, T, Q> tq; + qr_decompose(tin, tq, tr); + + tr = fliplr(tr); + r = transpose(tr); + r = fliplr(r); + + tq = fliplr(tq); + q = transpose(tq); + } +} //namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_interpolation.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_interpolation.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7d5ad4cd9ad9f1a845a9fe7327a73399d1ea58a6 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_interpolation.hpp @@ -0,0 +1,60 @@ +/// @ref gtx_matrix_interpolation +/// @file glm/gtx/matrix_interpolation.hpp +/// @author Ghenadii Ursachi (the.asteroth@gmail.com) +/// +/// @see core (dependence) +/// +/// @defgroup gtx_matrix_interpolation GLM_GTX_matrix_interpolation +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Allows to directly interpolate two matrices. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_matrix_interpolation is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_matrix_interpolation extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_matrix_interpolation + /// @{ + + /// Get the axis and angle of the rotation from a matrix. + /// From GLM_GTX_matrix_interpolation extension. + template + GLM_FUNC_DECL void axisAngle( + mat<4, 4, T, Q> const& Mat, vec<3, T, Q> & Axis, T & Angle); + + /// Build a matrix from axis and angle. + /// From GLM_GTX_matrix_interpolation extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> axisAngleMatrix( + vec<3, T, Q> const& Axis, T const Angle); + + /// Extracts the rotation part of a matrix. + /// From GLM_GTX_matrix_interpolation extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> extractMatrixRotation( + mat<4, 4, T, Q> const& Mat); + + /// Build a interpolation of 4 * 4 matrixes. + /// From GLM_GTX_matrix_interpolation extension. + /// Warning! works only with rotation and/or translation matrixes, scale will generate unexpected results. + template + GLM_FUNC_DECL mat<4, 4, T, Q> interpolate( + mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2, T const Delta); + + /// @} +}//namespace glm + +#include "matrix_interpolation.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_interpolation.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_interpolation.inl new file mode 100644 index 0000000000000000000000000000000000000000..f4ba3a6f3ac63e5f19135d23ce3f9210458304dd --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_interpolation.inl @@ -0,0 +1,146 @@ +/// @ref gtx_matrix_interpolation + +#include "../ext/scalar_constants.hpp" + +#include + +namespace glm +{ + template + GLM_FUNC_QUALIFIER void axisAngle(mat<4, 4, T, Q> const& m, vec<3, T, Q>& axis, T& angle) + { + T const epsilon = + std::numeric_limits::epsilon() * static_cast(1e2); + + bool const nearSymmetrical = + abs(m[1][0] - m[0][1]) < epsilon && + abs(m[2][0] - m[0][2]) < epsilon && + abs(m[2][1] - m[1][2]) < epsilon; + + if(nearSymmetrical) + { + bool const nearIdentity = + abs(m[1][0] + m[0][1]) < epsilon && + abs(m[2][0] + m[0][2]) < epsilon && + abs(m[2][1] + m[1][2]) < epsilon && + abs(m[0][0] + m[1][1] + m[2][2] - T(3.0)) < epsilon; + if (nearIdentity) + { + angle = static_cast(0.0); + axis = vec<3, T, Q>( + static_cast(1.0), static_cast(0.0), static_cast(0.0)); + return; + } + angle = pi(); + T xx = (m[0][0] + static_cast(1.0)) * static_cast(0.5); + T yy = (m[1][1] + static_cast(1.0)) * static_cast(0.5); + T zz = (m[2][2] + static_cast(1.0)) * static_cast(0.5); + T xy = (m[1][0] + m[0][1]) * static_cast(0.25); + T xz = (m[2][0] + m[0][2]) * static_cast(0.25); + T yz = (m[2][1] + m[1][2]) * static_cast(0.25); + if((xx > yy) && (xx > zz)) + { + if(xx < epsilon) + { + axis.x = static_cast(0.0); + axis.y = static_cast(0.7071); + axis.z = static_cast(0.7071); + } + else + { + axis.x = sqrt(xx); + axis.y = xy / axis.x; + axis.z = xz / axis.x; + } + } + else if (yy > zz) + { + if(yy < epsilon) + { + axis.x = static_cast(0.7071); + axis.y = static_cast(0.0); + axis.z = static_cast(0.7071); + } + else + { + axis.y = sqrt(yy); + axis.x = xy / axis.y; + axis.z = yz / axis.y; + } + } + else + { + if (zz < epsilon) + { + axis.x = static_cast(0.7071); + axis.y = static_cast(0.7071); + axis.z = static_cast(0.0); + } + else + { + axis.z = sqrt(zz); + axis.x = xz / axis.z; + axis.y = yz / axis.z; + } + } + return; + } + + T const angleCos = (m[0][0] + m[1][1] + m[2][2] - static_cast(1)) * static_cast(0.5); + if(angleCos >= static_cast(1.0)) + { + angle = static_cast(0.0); + } + else if (angleCos <= static_cast(-1.0)) + { + angle = pi(); + } + else + { + angle = acos(angleCos); + } + + axis = glm::normalize(glm::vec<3, T, Q>( + m[1][2] - m[2][1], m[2][0] - m[0][2], m[0][1] - m[1][0])); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> axisAngleMatrix(vec<3, T, Q> const& axis, T const angle) + { + T c = cos(angle); + T s = sin(angle); + T t = static_cast(1) - c; + vec<3, T, Q> n = normalize(axis); + + return mat<4, 4, T, Q>( + t * n.x * n.x + c, t * n.x * n.y + n.z * s, t * n.x * n.z - n.y * s, static_cast(0.0), + t * n.x * n.y - n.z * s, t * n.y * n.y + c, t * n.y * n.z + n.x * s, static_cast(0.0), + t * n.x * n.z + n.y * s, t * n.y * n.z - n.x * s, t * n.z * n.z + c, static_cast(0.0), + static_cast(0.0), static_cast(0.0), static_cast(0.0), static_cast(1.0)); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> extractMatrixRotation(mat<4, 4, T, Q> const& m) + { + return mat<4, 4, T, Q>( + m[0][0], m[0][1], m[0][2], static_cast(0.0), + m[1][0], m[1][1], m[1][2], static_cast(0.0), + m[2][0], m[2][1], m[2][2], static_cast(0.0), + static_cast(0.0), static_cast(0.0), static_cast(0.0), static_cast(1.0)); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> interpolate(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2, T const delta) + { + mat<4, 4, T, Q> m1rot = extractMatrixRotation(m1); + mat<4, 4, T, Q> dltRotation = m2 * transpose(m1rot); + vec<3, T, Q> dltAxis; + T dltAngle; + axisAngle(dltRotation, dltAxis, dltAngle); + mat<4, 4, T, Q> out = axisAngleMatrix(dltAxis, dltAngle * delta) * m1rot; + out[3][0] = m1[3][0] + delta * (m2[3][0] - m1[3][0]); + out[3][1] = m1[3][1] + delta * (m2[3][1] - m1[3][1]); + out[3][2] = m1[3][2] + delta * (m2[3][2] - m1[3][2]); + return out; + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_major_storage.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_major_storage.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8c6bc22d14e96da6a01552dde90f5fecf6a2e1b8 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_major_storage.hpp @@ -0,0 +1,119 @@ +/// @ref gtx_matrix_major_storage +/// @file glm/gtx/matrix_major_storage.hpp +/// +/// @see core (dependence) +/// @see gtx_extented_min_max (dependence) +/// +/// @defgroup gtx_matrix_major_storage GLM_GTX_matrix_major_storage +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Build matrices with specific matrix order, row or column + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_matrix_major_storage is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_matrix_major_storage extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_matrix_major_storage + /// @{ + + //! Build a row major matrix from row vectors. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<2, 2, T, Q> rowMajor2( + vec<2, T, Q> const& v1, + vec<2, T, Q> const& v2); + + //! Build a row major matrix from other matrix. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<2, 2, T, Q> rowMajor2( + mat<2, 2, T, Q> const& m); + + //! Build a row major matrix from row vectors. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<3, 3, T, Q> rowMajor3( + vec<3, T, Q> const& v1, + vec<3, T, Q> const& v2, + vec<3, T, Q> const& v3); + + //! Build a row major matrix from other matrix. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<3, 3, T, Q> rowMajor3( + mat<3, 3, T, Q> const& m); + + //! Build a row major matrix from row vectors. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> rowMajor4( + vec<4, T, Q> const& v1, + vec<4, T, Q> const& v2, + vec<4, T, Q> const& v3, + vec<4, T, Q> const& v4); + + //! Build a row major matrix from other matrix. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> rowMajor4( + mat<4, 4, T, Q> const& m); + + //! Build a column major matrix from column vectors. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<2, 2, T, Q> colMajor2( + vec<2, T, Q> const& v1, + vec<2, T, Q> const& v2); + + //! Build a column major matrix from other matrix. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<2, 2, T, Q> colMajor2( + mat<2, 2, T, Q> const& m); + + //! Build a column major matrix from column vectors. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<3, 3, T, Q> colMajor3( + vec<3, T, Q> const& v1, + vec<3, T, Q> const& v2, + vec<3, T, Q> const& v3); + + //! Build a column major matrix from other matrix. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<3, 3, T, Q> colMajor3( + mat<3, 3, T, Q> const& m); + + //! Build a column major matrix from column vectors. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> colMajor4( + vec<4, T, Q> const& v1, + vec<4, T, Q> const& v2, + vec<4, T, Q> const& v3, + vec<4, T, Q> const& v4); + + //! Build a column major matrix from other matrix. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> colMajor4( + mat<4, 4, T, Q> const& m); + + /// @} +}//namespace glm + +#include "matrix_major_storage.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_major_storage.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_major_storage.inl new file mode 100644 index 0000000000000000000000000000000000000000..279dd3433d0bd6dd5509cc1da75ee5b212eac784 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_major_storage.inl @@ -0,0 +1,166 @@ +/// @ref gtx_matrix_major_storage + +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> rowMajor2 + ( + vec<2, T, Q> const& v1, + vec<2, T, Q> const& v2 + ) + { + mat<2, 2, T, Q> Result; + Result[0][0] = v1.x; + Result[1][0] = v1.y; + Result[0][1] = v2.x; + Result[1][1] = v2.y; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> rowMajor2( + const mat<2, 2, T, Q>& m) + { + mat<2, 2, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> rowMajor3( + const vec<3, T, Q>& v1, + const vec<3, T, Q>& v2, + const vec<3, T, Q>& v3) + { + mat<3, 3, T, Q> Result; + Result[0][0] = v1.x; + Result[1][0] = v1.y; + Result[2][0] = v1.z; + Result[0][1] = v2.x; + Result[1][1] = v2.y; + Result[2][1] = v2.z; + Result[0][2] = v3.x; + Result[1][2] = v3.y; + Result[2][2] = v3.z; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> rowMajor3( + const mat<3, 3, T, Q>& m) + { + mat<3, 3, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[0][2] = m[2][0]; + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + Result[1][2] = m[2][1]; + Result[2][0] = m[0][2]; + Result[2][1] = m[1][2]; + Result[2][2] = m[2][2]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> rowMajor4( + const vec<4, T, Q>& v1, + const vec<4, T, Q>& v2, + const vec<4, T, Q>& v3, + const vec<4, T, Q>& v4) + { + mat<4, 4, T, Q> Result; + Result[0][0] = v1.x; + Result[1][0] = v1.y; + Result[2][0] = v1.z; + Result[3][0] = v1.w; + Result[0][1] = v2.x; + Result[1][1] = v2.y; + Result[2][1] = v2.z; + Result[3][1] = v2.w; + Result[0][2] = v3.x; + Result[1][2] = v3.y; + Result[2][2] = v3.z; + Result[3][2] = v3.w; + Result[0][3] = v4.x; + Result[1][3] = v4.y; + Result[2][3] = v4.z; + Result[3][3] = v4.w; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> rowMajor4( + const mat<4, 4, T, Q>& m) + { + mat<4, 4, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[0][2] = m[2][0]; + Result[0][3] = m[3][0]; + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + Result[1][2] = m[2][1]; + Result[1][3] = m[3][1]; + Result[2][0] = m[0][2]; + Result[2][1] = m[1][2]; + Result[2][2] = m[2][2]; + Result[2][3] = m[3][2]; + Result[3][0] = m[0][3]; + Result[3][1] = m[1][3]; + Result[3][2] = m[2][3]; + Result[3][3] = m[3][3]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> colMajor2( + const vec<2, T, Q>& v1, + const vec<2, T, Q>& v2) + { + return mat<2, 2, T, Q>(v1, v2); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> colMajor2( + const mat<2, 2, T, Q>& m) + { + return mat<2, 2, T, Q>(m); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> colMajor3( + const vec<3, T, Q>& v1, + const vec<3, T, Q>& v2, + const vec<3, T, Q>& v3) + { + return mat<3, 3, T, Q>(v1, v2, v3); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> colMajor3( + const mat<3, 3, T, Q>& m) + { + return mat<3, 3, T, Q>(m); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> colMajor4( + const vec<4, T, Q>& v1, + const vec<4, T, Q>& v2, + const vec<4, T, Q>& v3, + const vec<4, T, Q>& v4) + { + return mat<4, 4, T, Q>(v1, v2, v3, v4); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> colMajor4( + const mat<4, 4, T, Q>& m) + { + return mat<4, 4, T, Q>(m); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_operation.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_operation.hpp new file mode 100644 index 0000000000000000000000000000000000000000..de6ff1f86f47f5b99d7be8d48637e97d5f98e668 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_operation.hpp @@ -0,0 +1,103 @@ +/// @ref gtx_matrix_operation +/// @file glm/gtx/matrix_operation.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_matrix_operation GLM_GTX_matrix_operation +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Build diagonal matrices from vectors. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_matrix_operation is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_matrix_operation extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_matrix_operation + /// @{ + + //! Build a diagonal matrix. + //! From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<2, 2, T, Q> diagonal2x2( + vec<2, T, Q> const& v); + + //! Build a diagonal matrix. + //! From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<2, 3, T, Q> diagonal2x3( + vec<2, T, Q> const& v); + + //! Build a diagonal matrix. + //! From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<2, 4, T, Q> diagonal2x4( + vec<2, T, Q> const& v); + + //! Build a diagonal matrix. + //! From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<3, 2, T, Q> diagonal3x2( + vec<2, T, Q> const& v); + + //! Build a diagonal matrix. + //! From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<3, 3, T, Q> diagonal3x3( + vec<3, T, Q> const& v); + + //! Build a diagonal matrix. + //! From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<3, 4, T, Q> diagonal3x4( + vec<3, T, Q> const& v); + + //! Build a diagonal matrix. + //! From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<4, 2, T, Q> diagonal4x2( + vec<2, T, Q> const& v); + + //! Build a diagonal matrix. + //! From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<4, 3, T, Q> diagonal4x3( + vec<3, T, Q> const& v); + + //! Build a diagonal matrix. + //! From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> diagonal4x4( + vec<4, T, Q> const& v); + + /// Build an adjugate matrix. + /// From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<2, 2, T, Q> adjugate(mat<2, 2, T, Q> const& m); + + /// Build an adjugate matrix. + /// From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<3, 3, T, Q> adjugate(mat<3, 3, T, Q> const& m); + + /// Build an adjugate matrix. + /// From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> adjugate(mat<4, 4, T, Q> const& m); + + /// @} +}//namespace glm + +#include "matrix_operation.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_operation.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_operation.inl new file mode 100644 index 0000000000000000000000000000000000000000..a4f4a850002fd6982aa16571900c558932c5c724 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_operation.inl @@ -0,0 +1,176 @@ +/// @ref gtx_matrix_operation + +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> diagonal2x2 + ( + vec<2, T, Q> const& v + ) + { + mat<2, 2, T, Q> Result(static_cast(1)); + Result[0][0] = v[0]; + Result[1][1] = v[1]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> diagonal2x3 + ( + vec<2, T, Q> const& v + ) + { + mat<2, 3, T, Q> Result(static_cast(1)); + Result[0][0] = v[0]; + Result[1][1] = v[1]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> diagonal2x4 + ( + vec<2, T, Q> const& v + ) + { + mat<2, 4, T, Q> Result(static_cast(1)); + Result[0][0] = v[0]; + Result[1][1] = v[1]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> diagonal3x2 + ( + vec<2, T, Q> const& v + ) + { + mat<3, 2, T, Q> Result(static_cast(1)); + Result[0][0] = v[0]; + Result[1][1] = v[1]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> diagonal3x3 + ( + vec<3, T, Q> const& v + ) + { + mat<3, 3, T, Q> Result(static_cast(1)); + Result[0][0] = v[0]; + Result[1][1] = v[1]; + Result[2][2] = v[2]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> diagonal3x4 + ( + vec<3, T, Q> const& v + ) + { + mat<3, 4, T, Q> Result(static_cast(1)); + Result[0][0] = v[0]; + Result[1][1] = v[1]; + Result[2][2] = v[2]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> diagonal4x4 + ( + vec<4, T, Q> const& v + ) + { + mat<4, 4, T, Q> Result(static_cast(1)); + Result[0][0] = v[0]; + Result[1][1] = v[1]; + Result[2][2] = v[2]; + Result[3][3] = v[3]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> diagonal4x3 + ( + vec<3, T, Q> const& v + ) + { + mat<4, 3, T, Q> Result(static_cast(1)); + Result[0][0] = v[0]; + Result[1][1] = v[1]; + Result[2][2] = v[2]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> diagonal4x2 + ( + vec<2, T, Q> const& v + ) + { + mat<4, 2, T, Q> Result(static_cast(1)); + Result[0][0] = v[0]; + Result[1][1] = v[1]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> adjugate(mat<2, 2, T, Q> const& m) + { + return mat<2, 2, T, Q>( + +m[1][1], -m[0][1], + -m[1][0], +m[0][0]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> adjugate(mat<3, 3, T, Q> const& m) + { + T const m00 = determinant(mat<2, 2, T, Q>(m[1][1], m[2][1], m[1][2], m[2][2])); + T const m01 = determinant(mat<2, 2, T, Q>(m[0][1], m[2][1], m[0][2], m[2][2])); + T const m02 = determinant(mat<2, 2, T, Q>(m[0][1], m[1][1], m[0][2], m[1][2])); + + T const m10 = determinant(mat<2, 2, T, Q>(m[1][0], m[2][0], m[1][2], m[2][2])); + T const m11 = determinant(mat<2, 2, T, Q>(m[0][0], m[2][0], m[0][2], m[2][2])); + T const m12 = determinant(mat<2, 2, T, Q>(m[0][0], m[1][0], m[0][2], m[1][2])); + + T const m20 = determinant(mat<2, 2, T, Q>(m[1][0], m[2][0], m[1][1], m[2][1])); + T const m21 = determinant(mat<2, 2, T, Q>(m[0][0], m[2][0], m[0][1], m[2][1])); + T const m22 = determinant(mat<2, 2, T, Q>(m[0][0], m[1][0], m[0][1], m[1][1])); + + return mat<3, 3, T, Q>( + +m00, -m01, +m02, + -m10, +m11, -m12, + +m20, -m21, +m22); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> adjugate(mat<4, 4, T, Q> const& m) + { + T const m00 = determinant(mat<3, 3, T, Q>(m[1][1], m[1][2], m[1][3], m[2][1], m[2][2], m[2][3], m[3][1], m[3][2], m[3][3])); + T const m01 = determinant(mat<3, 3, T, Q>(m[1][0], m[1][2], m[1][3], m[2][0], m[2][2], m[2][3], m[3][0], m[3][2], m[3][3])); + T const m02 = determinant(mat<3, 3, T, Q>(m[1][0], m[1][1], m[1][3], m[2][0], m[2][1], m[2][3], m[3][0], m[3][1], m[3][3])); + T const m03 = determinant(mat<3, 3, T, Q>(m[1][0], m[1][1], m[1][2], m[2][0], m[2][1], m[2][2], m[3][0], m[3][1], m[3][2])); + + T const m10 = determinant(mat<3, 3, T, Q>(m[0][1], m[0][2], m[0][3], m[2][1], m[2][2], m[2][3], m[3][1], m[3][2], m[3][3])); + T const m11 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][2], m[0][3], m[2][0], m[2][2], m[2][3], m[3][0], m[3][2], m[3][3])); + T const m12 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][1], m[0][3], m[2][0], m[2][1], m[2][3], m[3][0], m[3][1], m[3][3])); + T const m13 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][1], m[0][2], m[2][0], m[2][1], m[2][2], m[3][0], m[3][1], m[3][2])); + + T const m20 = determinant(mat<3, 3, T, Q>(m[0][1], m[0][2], m[0][3], m[1][1], m[1][2], m[1][3], m[3][1], m[3][2], m[3][3])); + T const m21 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][2], m[0][3], m[1][0], m[1][2], m[1][3], m[3][0], m[3][2], m[3][3])); + T const m22 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][1], m[0][3], m[1][0], m[1][1], m[1][3], m[3][0], m[3][1], m[3][3])); + T const m23 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][1], m[0][2], m[1][0], m[1][1], m[1][2], m[3][0], m[3][1], m[3][2])); + + T const m30 = determinant(mat<3, 3, T, Q>(m[0][1], m[0][2], m[0][3], m[1][1], m[1][2], m[1][3], m[2][1], m[2][2], m[2][3])); + T const m31 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][2], m[0][3], m[1][0], m[1][2], m[1][3], m[2][0], m[2][2], m[2][3])); + T const m32 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][1], m[0][3], m[1][0], m[1][1], m[1][3], m[2][0], m[2][1], m[2][3])); + T const m33 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][1], m[0][2], m[1][0], m[1][1], m[1][2], m[2][0], m[2][1], m[2][2])); + + return mat<4, 4, T, Q>( + +m00, -m10, +m20, -m30, + -m01, +m11, -m21, +m31, + +m02, -m12, +m22, -m32, + -m03, +m13, -m23, +m33); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_query.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_query.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8011b2b1d469efdb98c2c5f1fe98538644e2ac05 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_query.hpp @@ -0,0 +1,77 @@ +/// @ref gtx_matrix_query +/// @file glm/gtx/matrix_query.hpp +/// +/// @see core (dependence) +/// @see gtx_vector_query (dependence) +/// +/// @defgroup gtx_matrix_query GLM_GTX_matrix_query +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Query to evaluate matrix properties + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtx/vector_query.hpp" +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_matrix_query is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_matrix_query extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_matrix_query + /// @{ + + /// Return whether a matrix a null matrix. + /// From GLM_GTX_matrix_query extension. + template + GLM_FUNC_DECL bool isNull(mat<2, 2, T, Q> const& m, T const& epsilon); + + /// Return whether a matrix a null matrix. + /// From GLM_GTX_matrix_query extension. + template + GLM_FUNC_DECL bool isNull(mat<3, 3, T, Q> const& m, T const& epsilon); + + /// Return whether a matrix is a null matrix. + /// From GLM_GTX_matrix_query extension. + template + GLM_FUNC_DECL bool isNull(mat<4, 4, T, Q> const& m, T const& epsilon); + + /// Return whether a matrix is an identity matrix. + /// From GLM_GTX_matrix_query extension. + template class matType> + GLM_FUNC_DECL bool isIdentity(matType const& m, T const& epsilon); + + /// Return whether a matrix is a normalized matrix. + /// From GLM_GTX_matrix_query extension. + template + GLM_FUNC_DECL bool isNormalized(mat<2, 2, T, Q> const& m, T const& epsilon); + + /// Return whether a matrix is a normalized matrix. + /// From GLM_GTX_matrix_query extension. + template + GLM_FUNC_DECL bool isNormalized(mat<3, 3, T, Q> const& m, T const& epsilon); + + /// Return whether a matrix is a normalized matrix. + /// From GLM_GTX_matrix_query extension. + template + GLM_FUNC_DECL bool isNormalized(mat<4, 4, T, Q> const& m, T const& epsilon); + + /// Return whether a matrix is an orthonormalized matrix. + /// From GLM_GTX_matrix_query extension. + template class matType> + GLM_FUNC_DECL bool isOrthogonal(matType const& m, T const& epsilon); + + /// @} +}//namespace glm + +#include "matrix_query.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_query.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_query.inl new file mode 100644 index 0000000000000000000000000000000000000000..b763c1ab70863c82a7ae9aaa1e0dd41fb659c80e --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_query.inl @@ -0,0 +1,113 @@ +/// @ref gtx_matrix_query + +namespace glm +{ + template + GLM_FUNC_QUALIFIER bool isNull(mat<2, 2, T, Q> const& m, T const& epsilon) + { + bool result = true; + for(length_t i = 0; result && i < m.length() ; ++i) + result = isNull(m[i], epsilon); + return result; + } + + template + GLM_FUNC_QUALIFIER bool isNull(mat<3, 3, T, Q> const& m, T const& epsilon) + { + bool result = true; + for(length_t i = 0; result && i < m.length() ; ++i) + result = isNull(m[i], epsilon); + return result; + } + + template + GLM_FUNC_QUALIFIER bool isNull(mat<4, 4, T, Q> const& m, T const& epsilon) + { + bool result = true; + for(length_t i = 0; result && i < m.length() ; ++i) + result = isNull(m[i], epsilon); + return result; + } + + template + GLM_FUNC_QUALIFIER bool isIdentity(mat const& m, T const& epsilon) + { + bool result = true; + for(length_t i = 0; result && i < m.length(); ++i) + { + for(length_t j = 0; result && j < glm::min(i, m[0].length()); ++j) + result = abs(m[i][j]) <= epsilon; + if(result && i < m[0].length()) + result = abs(m[i][i] - 1) <= epsilon; + for(length_t j = i + 1; result && j < m[0].length(); ++j) + result = abs(m[i][j]) <= epsilon; + } + return result; + } + + template + GLM_FUNC_QUALIFIER bool isNormalized(mat<2, 2, T, Q> const& m, T const& epsilon) + { + bool result(true); + for(length_t i = 0; result && i < m.length(); ++i) + result = isNormalized(m[i], epsilon); + for(length_t i = 0; result && i < m.length(); ++i) + { + typename mat<2, 2, T, Q>::col_type v; + for(length_t j = 0; j < m.length(); ++j) + v[j] = m[j][i]; + result = isNormalized(v, epsilon); + } + return result; + } + + template + GLM_FUNC_QUALIFIER bool isNormalized(mat<3, 3, T, Q> const& m, T const& epsilon) + { + bool result(true); + for(length_t i = 0; result && i < m.length(); ++i) + result = isNormalized(m[i], epsilon); + for(length_t i = 0; result && i < m.length(); ++i) + { + typename mat<3, 3, T, Q>::col_type v; + for(length_t j = 0; j < m.length(); ++j) + v[j] = m[j][i]; + result = isNormalized(v, epsilon); + } + return result; + } + + template + GLM_FUNC_QUALIFIER bool isNormalized(mat<4, 4, T, Q> const& m, T const& epsilon) + { + bool result(true); + for(length_t i = 0; result && i < m.length(); ++i) + result = isNormalized(m[i], epsilon); + for(length_t i = 0; result && i < m.length(); ++i) + { + typename mat<4, 4, T, Q>::col_type v; + for(length_t j = 0; j < m.length(); ++j) + v[j] = m[j][i]; + result = isNormalized(v, epsilon); + } + return result; + } + + template + GLM_FUNC_QUALIFIER bool isOrthogonal(mat const& m, T const& epsilon) + { + bool result = true; + for(length_t i(0); result && i < m.length() - 1; ++i) + for(length_t j(i + 1); result && j < m.length(); ++j) + result = areOrthogonal(m[i], m[j], epsilon); + + if(result) + { + mat tmp = transpose(m); + for(length_t i(0); result && i < m.length() - 1 ; ++i) + for(length_t j(i + 1); result && j < m.length(); ++j) + result = areOrthogonal(tmp[i], tmp[j], epsilon); + } + return result; + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_transform_2d.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_transform_2d.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5f9c540218511a9c47c79044049e534d30b9bfcb --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_transform_2d.hpp @@ -0,0 +1,81 @@ +/// @ref gtx_matrix_transform_2d +/// @file glm/gtx/matrix_transform_2d.hpp +/// @author Miguel Ángel Pérez Martínez +/// +/// @see core (dependence) +/// +/// @defgroup gtx_matrix_transform_2d GLM_GTX_matrix_transform_2d +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Defines functions that generate common 2d transformation matrices. + +#pragma once + +// Dependency: +#include "../mat3x3.hpp" +#include "../vec2.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_matrix_transform_2d is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_matrix_transform_2d extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_matrix_transform_2d + /// @{ + + /// Builds a translation 3 * 3 matrix created from a vector of 2 components. + /// + /// @param m Input matrix multiplied by this translation matrix. + /// @param v Coordinates of a translation vector. + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> translate( + mat<3, 3, T, Q> const& m, + vec<2, T, Q> const& v); + + /// Builds a rotation 3 * 3 matrix created from an angle. + /// + /// @param m Input matrix multiplied by this translation matrix. + /// @param angle Rotation angle expressed in radians. + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> rotate( + mat<3, 3, T, Q> const& m, + T angle); + + /// Builds a scale 3 * 3 matrix created from a vector of 2 components. + /// + /// @param m Input matrix multiplied by this translation matrix. + /// @param v Coordinates of a scale vector. + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> scale( + mat<3, 3, T, Q> const& m, + vec<2, T, Q> const& v); + + /// Builds an horizontal (parallel to the x axis) shear 3 * 3 matrix. + /// + /// @param m Input matrix multiplied by this translation matrix. + /// @param y Shear factor. + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> shearX( + mat<3, 3, T, Q> const& m, + T y); + + /// Builds a vertical (parallel to the y axis) shear 3 * 3 matrix. + /// + /// @param m Input matrix multiplied by this translation matrix. + /// @param x Shear factor. + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> shearY( + mat<3, 3, T, Q> const& m, + T x); + + /// @} +}//namespace glm + +#include "matrix_transform_2d.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_transform_2d.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_transform_2d.inl new file mode 100644 index 0000000000000000000000000000000000000000..a68d24dc9825c97cf47753779ed97834ea77aba0 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/matrix_transform_2d.inl @@ -0,0 +1,68 @@ +/// @ref gtx_matrix_transform_2d +/// @author Miguel Ángel Pérez Martínez + +#include "../trigonometric.hpp" + +namespace glm +{ + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> translate( + mat<3, 3, T, Q> const& m, + vec<2, T, Q> const& v) + { + mat<3, 3, T, Q> Result(m); + Result[2] = m[0] * v[0] + m[1] * v[1] + m[2]; + return Result; + } + + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> rotate( + mat<3, 3, T, Q> const& m, + T angle) + { + T const a = angle; + T const c = cos(a); + T const s = sin(a); + + mat<3, 3, T, Q> Result; + Result[0] = m[0] * c + m[1] * s; + Result[1] = m[0] * -s + m[1] * c; + Result[2] = m[2]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> scale( + mat<3, 3, T, Q> const& m, + vec<2, T, Q> const& v) + { + mat<3, 3, T, Q> Result; + Result[0] = m[0] * v[0]; + Result[1] = m[1] * v[1]; + Result[2] = m[2]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> shearX( + mat<3, 3, T, Q> const& m, + T y) + { + mat<3, 3, T, Q> Result(1); + Result[0][1] = y; + return m * Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> shearY( + mat<3, 3, T, Q> const& m, + T x) + { + mat<3, 3, T, Q> Result(1); + Result[1][0] = x; + return m * Result; + } + +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/mixed_product.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/mixed_product.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b242e357e57a1b6e4c8b837e2d90841a0d0d5f7d --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/mixed_product.hpp @@ -0,0 +1,41 @@ +/// @ref gtx_mixed_product +/// @file glm/gtx/mixed_product.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_mixed_product GLM_GTX_mixed_producte +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Mixed product of 3 vectors. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_mixed_product is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_mixed_product extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_mixed_product + /// @{ + + /// @brief Mixed product of 3 vectors (from GLM_GTX_mixed_product extension) + template + GLM_FUNC_DECL T mixedProduct( + vec<3, T, Q> const& v1, + vec<3, T, Q> const& v2, + vec<3, T, Q> const& v3); + + /// @} +}// namespace glm + +#include "mixed_product.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/mixed_product.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/mixed_product.inl new file mode 100644 index 0000000000000000000000000000000000000000..e5cdbdb49a2bb7457dd74ca08cdac0615d26b9c4 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/mixed_product.inl @@ -0,0 +1,15 @@ +/// @ref gtx_mixed_product + +namespace glm +{ + template + GLM_FUNC_QUALIFIER T mixedProduct + ( + vec<3, T, Q> const& v1, + vec<3, T, Q> const& v2, + vec<3, T, Q> const& v3 + ) + { + return dot(cross(v1, v2), v3); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/norm.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/norm.hpp new file mode 100644 index 0000000000000000000000000000000000000000..dfaebb7a8be26a65ed6769d87f75bcdc1d75bdb7 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/norm.hpp @@ -0,0 +1,88 @@ +/// @ref gtx_norm +/// @file glm/gtx/norm.hpp +/// +/// @see core (dependence) +/// @see gtx_quaternion (dependence) +/// @see gtx_component_wise (dependence) +/// +/// @defgroup gtx_norm GLM_GTX_norm +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Various ways to compute vector norms. + +#pragma once + +// Dependency: +#include "../geometric.hpp" +#include "../gtx/quaternion.hpp" +#include "../gtx/component_wise.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_norm is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_norm extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_norm + /// @{ + + /// Returns the squared length of x. + /// From GLM_GTX_norm extension. + template + GLM_FUNC_DECL T length2(vec const& x); + + /// Returns the squared distance between p0 and p1, i.e., length2(p0 - p1). + /// From GLM_GTX_norm extension. + template + GLM_FUNC_DECL T distance2(vec const& p0, vec const& p1); + + //! Returns the L1 norm between x and y. + //! From GLM_GTX_norm extension. + template + GLM_FUNC_DECL T l1Norm(vec<3, T, Q> const& x, vec<3, T, Q> const& y); + + //! Returns the L1 norm of v. + //! From GLM_GTX_norm extension. + template + GLM_FUNC_DECL T l1Norm(vec<3, T, Q> const& v); + + //! Returns the L2 norm between x and y. + //! From GLM_GTX_norm extension. + template + GLM_FUNC_DECL T l2Norm(vec<3, T, Q> const& x, vec<3, T, Q> const& y); + + //! Returns the L2 norm of v. + //! From GLM_GTX_norm extension. + template + GLM_FUNC_DECL T l2Norm(vec<3, T, Q> const& x); + + //! Returns the L norm between x and y. + //! From GLM_GTX_norm extension. + template + GLM_FUNC_DECL T lxNorm(vec<3, T, Q> const& x, vec<3, T, Q> const& y, unsigned int Depth); + + //! Returns the L norm of v. + //! From GLM_GTX_norm extension. + template + GLM_FUNC_DECL T lxNorm(vec<3, T, Q> const& x, unsigned int Depth); + + //! Returns the LMax norm between x and y. + //! From GLM_GTX_norm extension. + template + GLM_FUNC_DECL T lMaxNorm(vec<3, T, Q> const& x, vec<3, T, Q> const& y); + + //! Returns the LMax norm of v. + //! From GLM_GTX_norm extension. + template + GLM_FUNC_DECL T lMaxNorm(vec<3, T, Q> const& x); + + /// @} +}//namespace glm + +#include "norm.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/norm.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/norm.inl new file mode 100644 index 0000000000000000000000000000000000000000..6db561b37e0a062c71c6c3cdaabe021d0c1a62a4 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/norm.inl @@ -0,0 +1,95 @@ +/// @ref gtx_norm + +#include "../detail/qualifier.hpp" + +namespace glm{ +namespace detail +{ + template + struct compute_length2 + { + GLM_FUNC_QUALIFIER static T call(vec const& v) + { + return dot(v, v); + } + }; +}//namespace detail + + template + GLM_FUNC_QUALIFIER genType length2(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'length2' accepts only floating-point inputs"); + return x * x; + } + + template + GLM_FUNC_QUALIFIER T length2(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'length2' accepts only floating-point inputs"); + return detail::compute_length2::value>::call(v); + } + + template + GLM_FUNC_QUALIFIER T distance2(T p0, T p1) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'distance2' accepts only floating-point inputs"); + return length2(p1 - p0); + } + + template + GLM_FUNC_QUALIFIER T distance2(vec const& p0, vec const& p1) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'distance2' accepts only floating-point inputs"); + return length2(p1 - p0); + } + + template + GLM_FUNC_QUALIFIER T l1Norm(vec<3, T, Q> const& a, vec<3, T, Q> const& b) + { + return abs(b.x - a.x) + abs(b.y - a.y) + abs(b.z - a.z); + } + + template + GLM_FUNC_QUALIFIER T l1Norm(vec<3, T, Q> const& v) + { + return abs(v.x) + abs(v.y) + abs(v.z); + } + + template + GLM_FUNC_QUALIFIER T l2Norm(vec<3, T, Q> const& a, vec<3, T, Q> const& b + ) + { + return length(b - a); + } + + template + GLM_FUNC_QUALIFIER T l2Norm(vec<3, T, Q> const& v) + { + return length(v); + } + + template + GLM_FUNC_QUALIFIER T lxNorm(vec<3, T, Q> const& x, vec<3, T, Q> const& y, unsigned int Depth) + { + return pow(pow(abs(y.x - x.x), T(Depth)) + pow(abs(y.y - x.y), T(Depth)) + pow(abs(y.z - x.z), T(Depth)), T(1) / T(Depth)); + } + + template + GLM_FUNC_QUALIFIER T lxNorm(vec<3, T, Q> const& v, unsigned int Depth) + { + return pow(pow(abs(v.x), T(Depth)) + pow(abs(v.y), T(Depth)) + pow(abs(v.z), T(Depth)), T(1) / T(Depth)); + } + + template + GLM_FUNC_QUALIFIER T lMaxNorm(vec<3, T, Q> const& a, vec<3, T, Q> const& b) + { + return compMax(abs(b - a)); + } + + template + GLM_FUNC_QUALIFIER T lMaxNorm(vec<3, T, Q> const& v) + { + return compMax(abs(v)); + } + +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/normal.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/normal.hpp new file mode 100644 index 0000000000000000000000000000000000000000..068682f75f2dac6596b58c6bac6d1dd02a49175c --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/normal.hpp @@ -0,0 +1,41 @@ +/// @ref gtx_normal +/// @file glm/gtx/normal.hpp +/// +/// @see core (dependence) +/// @see gtx_extented_min_max (dependence) +/// +/// @defgroup gtx_normal GLM_GTX_normal +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Compute the normal of a triangle. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_normal is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_normal extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_normal + /// @{ + + /// Computes triangle normal from triangle points. + /// + /// @see gtx_normal + template + GLM_FUNC_DECL vec<3, T, Q> triangleNormal(vec<3, T, Q> const& p1, vec<3, T, Q> const& p2, vec<3, T, Q> const& p3); + + /// @} +}//namespace glm + +#include "normal.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/normal.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/normal.inl new file mode 100644 index 0000000000000000000000000000000000000000..74f9fc9945854fbe607e87ef47bf506a332b8966 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/normal.inl @@ -0,0 +1,15 @@ +/// @ref gtx_normal + +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec<3, T, Q> triangleNormal + ( + vec<3, T, Q> const& p1, + vec<3, T, Q> const& p2, + vec<3, T, Q> const& p3 + ) + { + return normalize(cross(p1 - p2, p1 - p3)); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/normalize_dot.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/normalize_dot.hpp new file mode 100644 index 0000000000000000000000000000000000000000..127aa1f65a8591d773cfbb8bd53107006d097282 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/normalize_dot.hpp @@ -0,0 +1,49 @@ +/// @ref gtx_normalize_dot +/// @file glm/gtx/normalize_dot.hpp +/// +/// @see core (dependence) +/// @see gtx_fast_square_root (dependence) +/// +/// @defgroup gtx_normalize_dot GLM_GTX_normalize_dot +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Dot product of vectors that need to be normalize with a single square root. + +#pragma once + +// Dependency: +#include "../gtx/fast_square_root.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_normalize_dot is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_normalize_dot extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_normalize_dot + /// @{ + + /// Normalize parameters and returns the dot product of x and y. + /// It's faster that dot(normalize(x), normalize(y)). + /// + /// @see gtx_normalize_dot extension. + template + GLM_FUNC_DECL T normalizeDot(vec const& x, vec const& y); + + /// Normalize parameters and returns the dot product of x and y. + /// Faster that dot(fastNormalize(x), fastNormalize(y)). + /// + /// @see gtx_normalize_dot extension. + template + GLM_FUNC_DECL T fastNormalizeDot(vec const& x, vec const& y); + + /// @} +}//namespace glm + +#include "normalize_dot.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/normalize_dot.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/normalize_dot.inl new file mode 100644 index 0000000000000000000000000000000000000000..7bcd9a534a8f4df3a12118c746aadd6f264e264e --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/normalize_dot.inl @@ -0,0 +1,16 @@ +/// @ref gtx_normalize_dot + +namespace glm +{ + template + GLM_FUNC_QUALIFIER T normalizeDot(vec const& x, vec const& y) + { + return glm::dot(x, y) * glm::inversesqrt(glm::dot(x, x) * glm::dot(y, y)); + } + + template + GLM_FUNC_QUALIFIER T fastNormalizeDot(vec const& x, vec const& y) + { + return glm::dot(x, y) * glm::fastInverseSqrt(glm::dot(x, x) * glm::dot(y, y)); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/number_precision.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/number_precision.hpp new file mode 100644 index 0000000000000000000000000000000000000000..3a606bda040c8d91763c57fec09ea35e5890a24d --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/number_precision.hpp @@ -0,0 +1,61 @@ +/// @ref gtx_number_precision +/// @file glm/gtx/number_precision.hpp +/// +/// @see core (dependence) +/// @see gtc_type_precision (dependence) +/// @see gtc_quaternion (dependence) +/// +/// @defgroup gtx_number_precision GLM_GTX_number_precision +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Defined size types. + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtc/type_precision.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_number_precision is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_number_precision extension included") +# endif +#endif + +namespace glm{ +namespace gtx +{ + ///////////////////////////// + // Unsigned int vector types + + /// @addtogroup gtx_number_precision + /// @{ + + typedef u8 u8vec1; //!< \brief 8bit unsigned integer scalar. (from GLM_GTX_number_precision extension) + typedef u16 u16vec1; //!< \brief 16bit unsigned integer scalar. (from GLM_GTX_number_precision extension) + typedef u32 u32vec1; //!< \brief 32bit unsigned integer scalar. (from GLM_GTX_number_precision extension) + typedef u64 u64vec1; //!< \brief 64bit unsigned integer scalar. (from GLM_GTX_number_precision extension) + + ////////////////////// + // Float vector types + + typedef f32 f32vec1; //!< \brief Single-qualifier floating-point scalar. (from GLM_GTX_number_precision extension) + typedef f64 f64vec1; //!< \brief Single-qualifier floating-point scalar. (from GLM_GTX_number_precision extension) + + ////////////////////// + // Float matrix types + + typedef f32 f32mat1; //!< \brief Single-qualifier floating-point scalar. (from GLM_GTX_number_precision extension) + typedef f32 f32mat1x1; //!< \brief Single-qualifier floating-point scalar. (from GLM_GTX_number_precision extension) + typedef f64 f64mat1; //!< \brief Double-qualifier floating-point scalar. (from GLM_GTX_number_precision extension) + typedef f64 f64mat1x1; //!< \brief Double-qualifier floating-point scalar. (from GLM_GTX_number_precision extension) + + /// @} +}//namespace gtx +}//namespace glm + +#include "number_precision.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/number_precision.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/number_precision.inl new file mode 100644 index 0000000000000000000000000000000000000000..b39d71c3b49d322835a883ed9e5825206c2dc354 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/number_precision.inl @@ -0,0 +1,6 @@ +/// @ref gtx_number_precision + +namespace glm +{ + +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/optimum_pow.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/optimum_pow.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9284a474d491f748dfcf43c8ccbd3578622cb04b --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/optimum_pow.hpp @@ -0,0 +1,54 @@ +/// @ref gtx_optimum_pow +/// @file glm/gtx/optimum_pow.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_optimum_pow GLM_GTX_optimum_pow +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Integer exponentiation of power functions. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_optimum_pow is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_optimum_pow extension included") +# endif +#endif + +namespace glm{ +namespace gtx +{ + /// @addtogroup gtx_optimum_pow + /// @{ + + /// Returns x raised to the power of 2. + /// + /// @see gtx_optimum_pow + template + GLM_FUNC_DECL genType pow2(genType const& x); + + /// Returns x raised to the power of 3. + /// + /// @see gtx_optimum_pow + template + GLM_FUNC_DECL genType pow3(genType const& x); + + /// Returns x raised to the power of 4. + /// + /// @see gtx_optimum_pow + template + GLM_FUNC_DECL genType pow4(genType const& x); + + /// @} +}//namespace gtx +}//namespace glm + +#include "optimum_pow.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/optimum_pow.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/optimum_pow.inl new file mode 100644 index 0000000000000000000000000000000000000000..a26c19c18bfbd6b84d7c1be07d9448c6fbcb7e01 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/optimum_pow.inl @@ -0,0 +1,22 @@ +/// @ref gtx_optimum_pow + +namespace glm +{ + template + GLM_FUNC_QUALIFIER genType pow2(genType const& x) + { + return x * x; + } + + template + GLM_FUNC_QUALIFIER genType pow3(genType const& x) + { + return x * x * x; + } + + template + GLM_FUNC_QUALIFIER genType pow4(genType const& x) + { + return (x * x) * (x * x); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/orthonormalize.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/orthonormalize.hpp new file mode 100644 index 0000000000000000000000000000000000000000..3e004fb06f9cd2e8d68f6a1cb073017a1bacfaf0 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/orthonormalize.hpp @@ -0,0 +1,49 @@ +/// @ref gtx_orthonormalize +/// @file glm/gtx/orthonormalize.hpp +/// +/// @see core (dependence) +/// @see gtx_extented_min_max (dependence) +/// +/// @defgroup gtx_orthonormalize GLM_GTX_orthonormalize +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Orthonormalize matrices. + +#pragma once + +// Dependency: +#include "../vec3.hpp" +#include "../mat3x3.hpp" +#include "../geometric.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_orthonormalize is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_orthonormalize extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_orthonormalize + /// @{ + + /// Returns the orthonormalized matrix of m. + /// + /// @see gtx_orthonormalize + template + GLM_FUNC_DECL mat<3, 3, T, Q> orthonormalize(mat<3, 3, T, Q> const& m); + + /// Orthonormalizes x according y. + /// + /// @see gtx_orthonormalize + template + GLM_FUNC_DECL vec<3, T, Q> orthonormalize(vec<3, T, Q> const& x, vec<3, T, Q> const& y); + + /// @} +}//namespace glm + +#include "orthonormalize.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/orthonormalize.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/orthonormalize.inl new file mode 100644 index 0000000000000000000000000000000000000000..cb553ba62157b3fca6c704777242bf473cdbe483 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/orthonormalize.inl @@ -0,0 +1,29 @@ +/// @ref gtx_orthonormalize + +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> orthonormalize(mat<3, 3, T, Q> const& m) + { + mat<3, 3, T, Q> r = m; + + r[0] = normalize(r[0]); + + T d0 = dot(r[0], r[1]); + r[1] -= r[0] * d0; + r[1] = normalize(r[1]); + + T d1 = dot(r[1], r[2]); + d0 = dot(r[0], r[2]); + r[2] -= r[0] * d0 + r[1] * d1; + r[2] = normalize(r[2]); + + return r; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> orthonormalize(vec<3, T, Q> const& x, vec<3, T, Q> const& y) + { + return normalize(x - y * dot(y, x)); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/pca.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/pca.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d89c408e36ef2ab3c907702e0b21e3ee5293af87 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/pca.hpp @@ -0,0 +1,115 @@ +/// @ref gtx_pca +/// @file glm/gtx/pca.hpp +/// +/// @see core (dependence) +/// @see ext_scalar_relational (dependence) +/// +/// @defgroup gtx_pca GLM_GTX_pca +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Implements functions required for fundamental 'princple component analysis' in 2D, 3D, and 4D: +/// 1) Computing a covariance matrics from a list of _relative_ position vectors +/// 2) Compute the eigenvalues and eigenvectors of the covariance matrics +/// This is useful, e.g., to compute an object-aligned bounding box from vertices of an object. +/// https://en.wikipedia.org/wiki/Principal_component_analysis +/// +/// Example: +/// ``` +/// std::vector ptData; +/// // ... fill ptData with some point data, e.g. vertices +/// +/// glm::dvec3 center = computeCenter(ptData); +/// +/// glm::dmat3 covarMat = glm::computeCovarianceMatrix(ptData.data(), ptData.size(), center); +/// +/// glm::dvec3 evals; +/// glm::dmat3 evecs; +/// int evcnt = glm::findEigenvaluesSymReal(covarMat, evals, evecs); +/// +/// if(evcnt != 3) +/// // ... error handling +/// +/// glm::sortEigenvalues(evals, evecs); +/// +/// // ... now evecs[0] points in the direction (symmetric) of the largest spatial distribution within ptData +/// ``` + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../ext/scalar_relational.hpp" + + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_pca is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_pca extension included") +# endif +#endif + +namespace glm { + /// @addtogroup gtx_pca + /// @{ + + /// Compute a covariance matrix form an array of relative coordinates `v` (e.g., relative to the center of gravity of the object) + /// @param v Points to a memory holding `n` times vectors + /// @param n Number of points in v + template + GLM_INLINE mat computeCovarianceMatrix(vec const* v, size_t n); + + /// Compute a covariance matrix form an array of absolute coordinates `v` and a precomputed center of gravity `c` + /// @param v Points to a memory holding `n` times vectors + /// @param n Number of points in v + /// @param c Precomputed center of gravity + template + GLM_INLINE mat computeCovarianceMatrix(vec const* v, size_t n, vec const& c); + + /// Compute a covariance matrix form a pair of iterators `b` (begin) and `e` (end) of a container with relative coordinates (e.g., relative to the center of gravity of the object) + /// Dereferencing an iterator of type I must yield a `vec<D, T, Q%gt;` + template + GLM_FUNC_DECL mat computeCovarianceMatrix(I const& b, I const& e); + + /// Compute a covariance matrix form a pair of iterators `b` (begin) and `e` (end) of a container with absolute coordinates and a precomputed center of gravity `c` + /// Dereferencing an iterator of type I must yield a `vec<D, T, Q%gt;` + template + GLM_FUNC_DECL mat computeCovarianceMatrix(I const& b, I const& e, vec const& c); + + /// Assuming the provided covariance matrix `covarMat` is symmetric and real-valued, this function find the `D` Eigenvalues of the matrix, and also provides the corresponding Eigenvectors. + /// Note: the data in `outEigenvalues` and `outEigenvectors` are in matching order, i.e. `outEigenvector[i]` is the Eigenvector of the Eigenvalue `outEigenvalue[i]`. + /// This is a numeric implementation to find the Eigenvalues, using 'QL decomposition` (variant of QR decomposition: https://en.wikipedia.org/wiki/QR_decomposition). + /// + /// @param[in] covarMat A symmetric, real-valued covariance matrix, e.g. computed from computeCovarianceMatrix + /// @param[out] outEigenvalues Vector to receive the found eigenvalues + /// @param[out] outEigenvectors Matrix to receive the found eigenvectors corresponding to the found eigenvalues, as column vectors + /// @return The number of eigenvalues found, usually D if the precondition of the covariance matrix is met. + template + GLM_FUNC_DECL unsigned int findEigenvaluesSymReal + ( + mat const& covarMat, + vec& outEigenvalues, + mat& outEigenvectors + ); + + /// Sorts a group of Eigenvalues&Eigenvectors, for largest Eigenvalue to smallest Eigenvalue. + /// The data in `outEigenvalues` and `outEigenvectors` are assumed to be matching order, i.e. `outEigenvector[i]` is the Eigenvector of the Eigenvalue `outEigenvalue[i]`. + template + GLM_FUNC_DECL void sortEigenvalues(vec<2, T, Q>& eigenvalues, mat<2, 2, T, Q>& eigenvectors); + + /// Sorts a group of Eigenvalues&Eigenvectors, for largest Eigenvalue to smallest Eigenvalue. + /// The data in `outEigenvalues` and `outEigenvectors` are assumed to be matching order, i.e. `outEigenvector[i]` is the Eigenvector of the Eigenvalue `outEigenvalue[i]`. + template + GLM_FUNC_DECL void sortEigenvalues(vec<3, T, Q>& eigenvalues, mat<3, 3, T, Q>& eigenvectors); + + /// Sorts a group of Eigenvalues&Eigenvectors, for largest Eigenvalue to smallest Eigenvalue. + /// The data in `outEigenvalues` and `outEigenvectors` are assumed to be matching order, i.e. `outEigenvector[i]` is the Eigenvector of the Eigenvalue `outEigenvalue[i]`. + template + GLM_FUNC_DECL void sortEigenvalues(vec<4, T, Q>& eigenvalues, mat<4, 4, T, Q>& eigenvectors); + + /// @} +}//namespace glm + +#include "pca.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/pca.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/pca.inl new file mode 100644 index 0000000000000000000000000000000000000000..94cae946e8a26b19bf8773dcec615ec42900b10b --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/pca.inl @@ -0,0 +1,343 @@ +/// @ref gtx_pca + +#ifndef GLM_HAS_CXX11_STL +#include +#else +#include +#endif + +namespace glm { + + + template + GLM_FUNC_QUALIFIER mat computeCovarianceMatrix(vec const* v, size_t n) + { + return computeCovarianceMatrix const*>(v, v + n); + } + + + template + GLM_FUNC_QUALIFIER mat computeCovarianceMatrix(vec const* v, size_t n, vec const& c) + { + return computeCovarianceMatrix const*>(v, v + n, c); + } + + + template + GLM_FUNC_QUALIFIER mat computeCovarianceMatrix(I const& b, I const& e) + { + glm::mat m(0); + + size_t cnt = 0; + for(I i = b; i != e; i++) + { + vec const& v = *i; + for(length_t x = 0; x < D; ++x) + for(length_t y = 0; y < D; ++y) + m[x][y] += static_cast(v[x] * v[y]); + cnt++; + } + if(cnt > 0) + m /= static_cast(cnt); + + return m; + } + + + template + GLM_FUNC_QUALIFIER mat computeCovarianceMatrix(I const& b, I const& e, vec const& c) + { + glm::mat m(0); + glm::vec v; + + size_t cnt = 0; + for(I i = b; i != e; i++) + { + v = *i - c; + for(length_t x = 0; x < D; ++x) + for(length_t y = 0; y < D; ++y) + m[x][y] += static_cast(v[x] * v[y]); + cnt++; + } + if(cnt > 0) + m /= static_cast(cnt); + + return m; + } + + namespace _internal_ + { + + template + GLM_FUNC_QUALIFIER static T transferSign(T const& v, T const& s) + { + return ((s) >= 0 ? glm::abs(v) : -glm::abs(v)); + } + + template + GLM_FUNC_QUALIFIER static T pythag(T const& a, T const& b) { + static const T epsilon = static_cast(0.0000001); + T absa = glm::abs(a); + T absb = glm::abs(b); + if(absa > absb) { + absb /= absa; + absb *= absb; + return absa * glm::sqrt(static_cast(1) + absb); + } + if(glm::equal(absb, 0, epsilon)) return static_cast(0); + absa /= absb; + absa *= absa; + return absb * glm::sqrt(static_cast(1) + absa); + } + + } + + template + GLM_FUNC_QUALIFIER unsigned int findEigenvaluesSymReal + ( + mat const& covarMat, + vec& outEigenvalues, + mat& outEigenvectors + ) + { + using _internal_::transferSign; + using _internal_::pythag; + + T a[D * D]; // matrix -- input and workspace for algorithm (will be changed inplace) + T d[D]; // diagonal elements + T e[D]; // off-diagonal elements + + for(length_t r = 0; r < D; r++) + for(length_t c = 0; c < D; c++) + a[(r) * D + (c)] = covarMat[c][r]; + + // 1. Householder reduction. + length_t l, k, j, i; + T scale, hh, h, g, f; + static const T epsilon = static_cast(0.0000001); + + for(i = D; i >= 2; i--) + { + l = i - 1; + h = scale = 0; + if(l > 1) + { + for(k = 1; k <= l; k++) + { + scale += glm::abs(a[(i - 1) * D + (k - 1)]); + } + if(glm::equal(scale, 0, epsilon)) + { + e[i - 1] = a[(i - 1) * D + (l - 1)]; + } + else + { + for(k = 1; k <= l; k++) + { + a[(i - 1) * D + (k - 1)] /= scale; + h += a[(i - 1) * D + (k - 1)] * a[(i - 1) * D + (k - 1)]; + } + f = a[(i - 1) * D + (l - 1)]; + g = ((f >= 0) ? -glm::sqrt(h) : glm::sqrt(h)); + e[i - 1] = scale * g; + h -= f * g; + a[(i - 1) * D + (l - 1)] = f - g; + f = 0; + for(j = 1; j <= l; j++) + { + a[(j - 1) * D + (i - 1)] = a[(i - 1) * D + (j - 1)] / h; + g = 0; + for(k = 1; k <= j; k++) + { + g += a[(j - 1) * D + (k - 1)] * a[(i - 1) * D + (k - 1)]; + } + for(k = j + 1; k <= l; k++) + { + g += a[(k - 1) * D + (j - 1)] * a[(i - 1) * D + (k - 1)]; + } + e[j - 1] = g / h; + f += e[j - 1] * a[(i - 1) * D + (j - 1)]; + } + hh = f / (h + h); + for(j = 1; j <= l; j++) + { + f = a[(i - 1) * D + (j - 1)]; + e[j - 1] = g = e[j - 1] - hh * f; + for(k = 1; k <= j; k++) + { + a[(j - 1) * D + (k - 1)] -= (f * e[k - 1] + g * a[(i - 1) * D + (k - 1)]); + } + } + } + } + else + { + e[i - 1] = a[(i - 1) * D + (l - 1)]; + } + d[i - 1] = h; + } + d[0] = 0; + e[0] = 0; + for(i = 1; i <= D; i++) + { + l = i - 1; + if(!glm::equal(d[i - 1], 0, epsilon)) + { + for(j = 1; j <= l; j++) + { + g = 0; + for(k = 1; k <= l; k++) + { + g += a[(i - 1) * D + (k - 1)] * a[(k - 1) * D + (j - 1)]; + } + for(k = 1; k <= l; k++) + { + a[(k - 1) * D + (j - 1)] -= g * a[(k - 1) * D + (i - 1)]; + } + } + } + d[i - 1] = a[(i - 1) * D + (i - 1)]; + a[(i - 1) * D + (i - 1)] = 1; + for(j = 1; j <= l; j++) + { + a[(j - 1) * D + (i - 1)] = a[(i - 1) * D + (j - 1)] = 0; + } + } + + // 2. Calculation of eigenvalues and eigenvectors (QL algorithm) + length_t m, iter; + T s, r, p, dd, c, b; + const length_t MAX_ITER = 30; + + for(i = 2; i <= D; i++) + { + e[i - 2] = e[i - 1]; + } + e[D - 1] = 0; + + for(l = 1; l <= D; l++) + { + iter = 0; + do + { + for(m = l; m <= D - 1; m++) + { + dd = glm::abs(d[m - 1]) + glm::abs(d[m - 1 + 1]); + if(glm::equal(glm::abs(e[m - 1]) + dd, dd, epsilon)) + break; + } + if(m != l) + { + if(iter++ == MAX_ITER) + { + return 0; // Too many iterations in FindEigenvalues + } + g = (d[l - 1 + 1] - d[l - 1]) / (2 * e[l - 1]); + r = pythag(g, 1); + g = d[m - 1] - d[l - 1] + e[l - 1] / (g + transferSign(r, g)); + s = c = 1; + p = 0; + for(i = m - 1; i >= l; i--) + { + f = s * e[i - 1]; + b = c * e[i - 1]; + e[i - 1 + 1] = r = pythag(f, g); + if(glm::equal(r, 0, epsilon)) + { + d[i - 1 + 1] -= p; + e[m - 1] = 0; + break; + } + s = f / r; + c = g / r; + g = d[i - 1 + 1] - p; + r = (d[i - 1] - g) * s + 2 * c * b; + d[i - 1 + 1] = g + (p = s * r); + g = c * r - b; + for(k = 1; k <= D; k++) + { + f = a[(k - 1) * D + (i - 1 + 1)]; + a[(k - 1) * D + (i - 1 + 1)] = s * a[(k - 1) * D + (i - 1)] + c * f; + a[(k - 1) * D + (i - 1)] = c * a[(k - 1) * D + (i - 1)] - s * f; + } + } + if(glm::equal(r, 0, epsilon) && (i >= l)) + continue; + d[l - 1] -= p; + e[l - 1] = g; + e[m - 1] = 0; + } + } while(m != l); + } + + // 3. output + for(i = 0; i < D; i++) + outEigenvalues[i] = d[i]; + for(i = 0; i < D; i++) + for(j = 0; j < D; j++) + outEigenvectors[i][j] = a[(j) * D + (i)]; + + return D; + } + + template + GLM_FUNC_QUALIFIER void sortEigenvalues(vec<2, T, Q>& eigenvalues, mat<2, 2, T, Q>& eigenvectors) + { + if (eigenvalues[0] < eigenvalues[1]) + { + std::swap(eigenvalues[0], eigenvalues[1]); + std::swap(eigenvectors[0], eigenvectors[1]); + } + } + + template + GLM_FUNC_QUALIFIER void sortEigenvalues(vec<3, T, Q>& eigenvalues, mat<3, 3, T, Q>& eigenvectors) + { + if (eigenvalues[0] < eigenvalues[1]) + { + std::swap(eigenvalues[0], eigenvalues[1]); + std::swap(eigenvectors[0], eigenvectors[1]); + } + if (eigenvalues[0] < eigenvalues[2]) + { + std::swap(eigenvalues[0], eigenvalues[2]); + std::swap(eigenvectors[0], eigenvectors[2]); + } + if (eigenvalues[1] < eigenvalues[2]) + { + std::swap(eigenvalues[1], eigenvalues[2]); + std::swap(eigenvectors[1], eigenvectors[2]); + } + } + + template + GLM_FUNC_QUALIFIER void sortEigenvalues(vec<4, T, Q>& eigenvalues, mat<4, 4, T, Q>& eigenvectors) + { + if (eigenvalues[0] < eigenvalues[2]) + { + std::swap(eigenvalues[0], eigenvalues[2]); + std::swap(eigenvectors[0], eigenvectors[2]); + } + if (eigenvalues[1] < eigenvalues[3]) + { + std::swap(eigenvalues[1], eigenvalues[3]); + std::swap(eigenvectors[1], eigenvectors[3]); + } + if (eigenvalues[0] < eigenvalues[1]) + { + std::swap(eigenvalues[0], eigenvalues[1]); + std::swap(eigenvectors[0], eigenvectors[1]); + } + if (eigenvalues[2] < eigenvalues[3]) + { + std::swap(eigenvalues[2], eigenvalues[3]); + std::swap(eigenvectors[2], eigenvectors[3]); + } + if (eigenvalues[1] < eigenvalues[2]) + { + std::swap(eigenvalues[1], eigenvalues[2]); + std::swap(eigenvectors[1], eigenvectors[2]); + } + } + +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/perpendicular.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/perpendicular.hpp new file mode 100644 index 0000000000000000000000000000000000000000..72b77b6e2388aada9c12070c804e0a02ba42ed86 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/perpendicular.hpp @@ -0,0 +1,41 @@ +/// @ref gtx_perpendicular +/// @file glm/gtx/perpendicular.hpp +/// +/// @see core (dependence) +/// @see gtx_projection (dependence) +/// +/// @defgroup gtx_perpendicular GLM_GTX_perpendicular +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Perpendicular of a vector from other one + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtx/projection.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_perpendicular is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_perpendicular extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_perpendicular + /// @{ + + //! Projects x a perpendicular axis of Normal. + //! From GLM_GTX_perpendicular extension. + template + GLM_FUNC_DECL genType perp(genType const& x, genType const& Normal); + + /// @} +}//namespace glm + +#include "perpendicular.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/perpendicular.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/perpendicular.inl new file mode 100644 index 0000000000000000000000000000000000000000..1e72f334230dee397361c2bae3af71600ee0a722 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/perpendicular.inl @@ -0,0 +1,10 @@ +/// @ref gtx_perpendicular + +namespace glm +{ + template + GLM_FUNC_QUALIFIER genType perp(genType const& x, genType const& Normal) + { + return x - proj(x, Normal); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/polar_coordinates.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/polar_coordinates.hpp new file mode 100644 index 0000000000000000000000000000000000000000..76beb82bd57c89ab1e8bcfa169b132f949f79e1a --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/polar_coordinates.hpp @@ -0,0 +1,48 @@ +/// @ref gtx_polar_coordinates +/// @file glm/gtx/polar_coordinates.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_polar_coordinates GLM_GTX_polar_coordinates +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Conversion from Euclidean space to polar space and revert. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_polar_coordinates is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_polar_coordinates extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_polar_coordinates + /// @{ + + /// Convert Euclidean to Polar coordinates, x is the latitude, y the longitude and z the xz distance. + /// + /// @see gtx_polar_coordinates + template + GLM_FUNC_DECL vec<3, T, Q> polar( + vec<3, T, Q> const& euclidean); + + /// Convert Polar to Euclidean coordinates. + /// + /// @see gtx_polar_coordinates + template + GLM_FUNC_DECL vec<3, T, Q> euclidean( + vec<2, T, Q> const& polar); + + /// @} +}//namespace glm + +#include "polar_coordinates.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/polar_coordinates.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/polar_coordinates.inl new file mode 100644 index 0000000000000000000000000000000000000000..371c8dddebd1cf197ab8527b4bb8098edf733814 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/polar_coordinates.inl @@ -0,0 +1,36 @@ +/// @ref gtx_polar_coordinates + +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec<3, T, Q> polar + ( + vec<3, T, Q> const& euclidean + ) + { + T const Length(length(euclidean)); + vec<3, T, Q> const tmp(euclidean / Length); + T const xz_dist(sqrt(tmp.x * tmp.x + tmp.z * tmp.z)); + + return vec<3, T, Q>( + asin(tmp.y), // latitude + atan(tmp.x, tmp.z), // longitude + xz_dist); // xz distance + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> euclidean + ( + vec<2, T, Q> const& polar + ) + { + T const latitude(polar.x); + T const longitude(polar.y); + + return vec<3, T, Q>( + cos(latitude) * sin(longitude), + sin(latitude), + cos(latitude) * cos(longitude)); + } + +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/projection.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/projection.hpp new file mode 100644 index 0000000000000000000000000000000000000000..678f3ad5a585f83b1a83d7d99960fae383dfb396 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/projection.hpp @@ -0,0 +1,43 @@ +/// @ref gtx_projection +/// @file glm/gtx/projection.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_projection GLM_GTX_projection +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Projection of a vector to other one + +#pragma once + +// Dependency: +#include "../geometric.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_projection is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_projection extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_projection + /// @{ + + /// Projects x on Normal. + /// + /// @param[in] x A vector to project + /// @param[in] Normal A normal that doesn't need to be of unit length. + /// + /// @see gtx_projection + template + GLM_FUNC_DECL genType proj(genType const& x, genType const& Normal); + + /// @} +}//namespace glm + +#include "projection.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/projection.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/projection.inl new file mode 100644 index 0000000000000000000000000000000000000000..f23f884fb93a2c246d4560ec1f18c7292f9205c6 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/projection.inl @@ -0,0 +1,10 @@ +/// @ref gtx_projection + +namespace glm +{ + template + GLM_FUNC_QUALIFIER genType proj(genType const& x, genType const& Normal) + { + return glm::dot(x, Normal) / glm::dot(Normal, Normal) * Normal; + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/quaternion.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/quaternion.hpp new file mode 100644 index 0000000000000000000000000000000000000000..259cd40bf85566ed0a55a5da856f66b7b6998643 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/quaternion.hpp @@ -0,0 +1,174 @@ +/// @ref gtx_quaternion +/// @file glm/gtx/quaternion.hpp +/// +/// @see core (dependence) +/// @see gtx_extented_min_max (dependence) +/// +/// @defgroup gtx_quaternion GLM_GTX_quaternion +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Extended quaternion types and functions + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtc/constants.hpp" +#include "../gtc/quaternion.hpp" +#include "../ext/quaternion_exponential.hpp" +#include "../gtx/norm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_quaternion is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_quaternion extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_quaternion + /// @{ + + /// Create an identity quaternion. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL GLM_CONSTEXPR qua quat_identity(); + + /// Compute a cross product between a quaternion and a vector. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL vec<3, T, Q> cross( + qua const& q, + vec<3, T, Q> const& v); + + //! Compute a cross product between a vector and a quaternion. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL vec<3, T, Q> cross( + vec<3, T, Q> const& v, + qua const& q); + + //! Compute a point on a path according squad equation. + //! q1 and q2 are control points; s1 and s2 are intermediate control points. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL qua squad( + qua const& q1, + qua const& q2, + qua const& s1, + qua const& s2, + T const& h); + + //! Returns an intermediate control point for squad interpolation. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL qua intermediate( + qua const& prev, + qua const& curr, + qua const& next); + + //! Returns quarternion square root. + /// + /// @see gtx_quaternion + //template + //qua sqrt( + // qua const& q); + + //! Rotates a 3 components vector by a quaternion. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL vec<3, T, Q> rotate( + qua const& q, + vec<3, T, Q> const& v); + + /// Rotates a 4 components vector by a quaternion. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL vec<4, T, Q> rotate( + qua const& q, + vec<4, T, Q> const& v); + + /// Extract the real component of a quaternion. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL T extractRealComponent( + qua const& q); + + /// Converts a quaternion to a 3 * 3 matrix. + /// + /// @see gtx_quaternion + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> toMat3( + qua const& x){return mat3_cast(x);} + + /// Converts a quaternion to a 4 * 4 matrix. + /// + /// @see gtx_quaternion + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> toMat4( + qua const& x){return mat4_cast(x);} + + /// Converts a 3 * 3 matrix to a quaternion. + /// + /// @see gtx_quaternion + template + GLM_FUNC_QUALIFIER qua toQuat( + mat<3, 3, T, Q> const& x){return quat_cast(x);} + + /// Converts a 4 * 4 matrix to a quaternion. + /// + /// @see gtx_quaternion + template + GLM_FUNC_QUALIFIER qua toQuat( + mat<4, 4, T, Q> const& x){return quat_cast(x);} + + /// Quaternion interpolation using the rotation short path. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL qua shortMix( + qua const& x, + qua const& y, + T const& a); + + /// Quaternion normalized linear interpolation. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL qua fastMix( + qua const& x, + qua const& y, + T const& a); + + /// Compute the rotation between two vectors. + /// @param orig vector, needs to be normalized + /// @param dest vector, needs to be normalized + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL qua rotation( + vec<3, T, Q> const& orig, + vec<3, T, Q> const& dest); + + /// Returns the squared length of x. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL GLM_CONSTEXPR T length2(qua const& q); + + /// @} +}//namespace glm + +#include "quaternion.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/quaternion.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/quaternion.inl new file mode 100644 index 0000000000000000000000000000000000000000..d125bccc9a704a23035cca06fa592857ca91f87c --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/quaternion.inl @@ -0,0 +1,159 @@ +/// @ref gtx_quaternion + +#include +#include "../gtc/constants.hpp" + +namespace glm +{ + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua quat_identity() + { + return qua(static_cast(1), static_cast(0), static_cast(0), static_cast(0)); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> cross(vec<3, T, Q> const& v, qua const& q) + { + return inverse(q) * v; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> cross(qua const& q, vec<3, T, Q> const& v) + { + return q * v; + } + + template + GLM_FUNC_QUALIFIER qua squad + ( + qua const& q1, + qua const& q2, + qua const& s1, + qua const& s2, + T const& h) + { + return mix(mix(q1, q2, h), mix(s1, s2, h), static_cast(2) * (static_cast(1) - h) * h); + } + + template + GLM_FUNC_QUALIFIER qua intermediate + ( + qua const& prev, + qua const& curr, + qua const& next + ) + { + qua invQuat = inverse(curr); + return exp((log(next * invQuat) + log(prev * invQuat)) / static_cast(-4)) * curr; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> rotate(qua const& q, vec<3, T, Q> const& v) + { + return q * v; + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> rotate(qua const& q, vec<4, T, Q> const& v) + { + return q * v; + } + + template + GLM_FUNC_QUALIFIER T extractRealComponent(qua const& q) + { + T w = static_cast(1) - q.x * q.x - q.y * q.y - q.z * q.z; + if(w < T(0)) + return T(0); + else + return -sqrt(w); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T length2(qua const& q) + { + return q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w; + } + + template + GLM_FUNC_QUALIFIER qua shortMix(qua const& x, qua const& y, T const& a) + { + if(a <= static_cast(0)) return x; + if(a >= static_cast(1)) return y; + + T fCos = dot(x, y); + qua y2(y); //BUG!!! qua y2; + if(fCos < static_cast(0)) + { + y2 = -y; + fCos = -fCos; + } + + //if(fCos > 1.0f) // problem + T k0, k1; + if(fCos > (static_cast(1) - epsilon())) + { + k0 = static_cast(1) - a; + k1 = static_cast(0) + a; //BUG!!! 1.0f + a; + } + else + { + T fSin = sqrt(T(1) - fCos * fCos); + T fAngle = atan(fSin, fCos); + T fOneOverSin = static_cast(1) / fSin; + k0 = sin((static_cast(1) - a) * fAngle) * fOneOverSin; + k1 = sin((static_cast(0) + a) * fAngle) * fOneOverSin; + } + + return qua( + k0 * x.w + k1 * y2.w, + k0 * x.x + k1 * y2.x, + k0 * x.y + k1 * y2.y, + k0 * x.z + k1 * y2.z); + } + + template + GLM_FUNC_QUALIFIER qua fastMix(qua const& x, qua const& y, T const& a) + { + return glm::normalize(x * (static_cast(1) - a) + (y * a)); + } + + template + GLM_FUNC_QUALIFIER qua rotation(vec<3, T, Q> const& orig, vec<3, T, Q> const& dest) + { + T cosTheta = dot(orig, dest); + vec<3, T, Q> rotationAxis; + + if(cosTheta >= static_cast(1) - epsilon()) { + // orig and dest point in the same direction + return quat_identity(); + } + + if(cosTheta < static_cast(-1) + epsilon()) + { + // special case when vectors in opposite directions : + // there is no "ideal" rotation axis + // So guess one; any will do as long as it's perpendicular to start + // This implementation favors a rotation around the Up axis (Y), + // since it's often what you want to do. + rotationAxis = cross(vec<3, T, Q>(0, 0, 1), orig); + if(length2(rotationAxis) < epsilon()) // bad luck, they were parallel, try again! + rotationAxis = cross(vec<3, T, Q>(1, 0, 0), orig); + + rotationAxis = normalize(rotationAxis); + return angleAxis(pi(), rotationAxis); + } + + // Implementation from Stan Melax's Game Programming Gems 1 article + rotationAxis = cross(orig, dest); + + T s = sqrt((T(1) + cosTheta) * static_cast(2)); + T invs = static_cast(1) / s; + + return qua( + s * static_cast(0.5f), + rotationAxis.x * invs, + rotationAxis.y * invs, + rotationAxis.z * invs); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/range.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/range.hpp new file mode 100644 index 0000000000000000000000000000000000000000..93bcb9a65a0afc615bec388fe99681b95849ea4f --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/range.hpp @@ -0,0 +1,98 @@ +/// @ref gtx_range +/// @file glm/gtx/range.hpp +/// @author Joshua Moerman +/// +/// @defgroup gtx_range GLM_GTX_range +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Defines begin and end for vectors and matrices. Useful for range-based for loop. +/// The range is defined over the elements, not over columns or rows (e.g. mat4 has 16 elements). + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_range is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_range extension included") +# endif +#endif + +#include "../gtc/type_ptr.hpp" +#include "../gtc/vec1.hpp" + +namespace glm +{ + /// @addtogroup gtx_range + /// @{ + +# if GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(push) +# pragma warning(disable : 4100) // unreferenced formal parameter +# endif + + template + inline length_t components(vec<1, T, Q> const& v) + { + return v.length(); + } + + template + inline length_t components(vec<2, T, Q> const& v) + { + return v.length(); + } + + template + inline length_t components(vec<3, T, Q> const& v) + { + return v.length(); + } + + template + inline length_t components(vec<4, T, Q> const& v) + { + return v.length(); + } + + template + inline length_t components(genType const& m) + { + return m.length() * m[0].length(); + } + + template + inline typename genType::value_type const * begin(genType const& v) + { + return value_ptr(v); + } + + template + inline typename genType::value_type const * end(genType const& v) + { + return begin(v) + components(v); + } + + template + inline typename genType::value_type * begin(genType& v) + { + return value_ptr(v); + } + + template + inline typename genType::value_type * end(genType& v) + { + return begin(v) + components(v); + } + +# if GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(pop) +# endif + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/raw_data.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/raw_data.hpp new file mode 100644 index 0000000000000000000000000000000000000000..86cbe77d9ae537ca6537a89d14f6ee0bfe50696b --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/raw_data.hpp @@ -0,0 +1,51 @@ +/// @ref gtx_raw_data +/// @file glm/gtx/raw_data.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_raw_data GLM_GTX_raw_data +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Projection of a vector to other one + +#pragma once + +// Dependencies +#include "../ext/scalar_uint_sized.hpp" +#include "../detail/setup.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_raw_data is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_raw_data extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_raw_data + /// @{ + + //! Type for byte numbers. + //! From GLM_GTX_raw_data extension. + typedef detail::uint8 byte; + + //! Type for word numbers. + //! From GLM_GTX_raw_data extension. + typedef detail::uint16 word; + + //! Type for dword numbers. + //! From GLM_GTX_raw_data extension. + typedef detail::uint32 dword; + + //! Type for qword numbers. + //! From GLM_GTX_raw_data extension. + typedef detail::uint64 qword; + + /// @} +}// namespace glm + +#include "raw_data.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/raw_data.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/raw_data.inl new file mode 100644 index 0000000000000000000000000000000000000000..c740317d334e7f08181df5ac2522aef7e85bbdb4 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/raw_data.inl @@ -0,0 +1,2 @@ +/// @ref gtx_raw_data + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/rotate_normalized_axis.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/rotate_normalized_axis.hpp new file mode 100644 index 0000000000000000000000000000000000000000..2103ca08f15ea9576b25bdb0955771ee313d6e79 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/rotate_normalized_axis.hpp @@ -0,0 +1,68 @@ +/// @ref gtx_rotate_normalized_axis +/// @file glm/gtx/rotate_normalized_axis.hpp +/// +/// @see core (dependence) +/// @see gtc_matrix_transform +/// @see gtc_quaternion +/// +/// @defgroup gtx_rotate_normalized_axis GLM_GTX_rotate_normalized_axis +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Quaternions and matrices rotations around normalized axis. + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtc/epsilon.hpp" +#include "../gtc/quaternion.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_rotate_normalized_axis is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_rotate_normalized_axis extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_rotate_normalized_axis + /// @{ + + /// Builds a rotation 4 * 4 matrix created from a normalized axis and an angle. + /// + /// @param m Input matrix multiplied by this rotation matrix. + /// @param angle Rotation angle expressed in radians. + /// @param axis Rotation axis, must be normalized. + /// @tparam T Value type used to build the matrix. Currently supported: half (not recommended), float or double. + /// + /// @see gtx_rotate_normalized_axis + /// @see - rotate(T angle, T x, T y, T z) + /// @see - rotate(mat<4, 4, T, Q> const& m, T angle, T x, T y, T z) + /// @see - rotate(T angle, vec<3, T, Q> const& v) + template + GLM_FUNC_DECL mat<4, 4, T, Q> rotateNormalizedAxis( + mat<4, 4, T, Q> const& m, + T const& angle, + vec<3, T, Q> const& axis); + + /// Rotates a quaternion from a vector of 3 components normalized axis and an angle. + /// + /// @param q Source orientation + /// @param angle Angle expressed in radians. + /// @param axis Normalized axis of the rotation, must be normalized. + /// + /// @see gtx_rotate_normalized_axis + template + GLM_FUNC_DECL qua rotateNormalizedAxis( + qua const& q, + T const& angle, + vec<3, T, Q> const& axis); + + /// @} +}//namespace glm + +#include "rotate_normalized_axis.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/rotate_normalized_axis.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/rotate_normalized_axis.inl new file mode 100644 index 0000000000000000000000000000000000000000..b2e9278c0ae5d18775fbe93919e410a1b963ca06 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/rotate_normalized_axis.inl @@ -0,0 +1,58 @@ +/// @ref gtx_rotate_normalized_axis + +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> rotateNormalizedAxis + ( + mat<4, 4, T, Q> const& m, + T const& angle, + vec<3, T, Q> const& v + ) + { + T const a = angle; + T const c = cos(a); + T const s = sin(a); + + vec<3, T, Q> const axis(v); + + vec<3, T, Q> const temp((static_cast(1) - c) * axis); + + mat<4, 4, T, Q> Rotate; + Rotate[0][0] = c + temp[0] * axis[0]; + Rotate[0][1] = 0 + temp[0] * axis[1] + s * axis[2]; + Rotate[0][2] = 0 + temp[0] * axis[2] - s * axis[1]; + + Rotate[1][0] = 0 + temp[1] * axis[0] - s * axis[2]; + Rotate[1][1] = c + temp[1] * axis[1]; + Rotate[1][2] = 0 + temp[1] * axis[2] + s * axis[0]; + + Rotate[2][0] = 0 + temp[2] * axis[0] + s * axis[1]; + Rotate[2][1] = 0 + temp[2] * axis[1] - s * axis[0]; + Rotate[2][2] = c + temp[2] * axis[2]; + + mat<4, 4, T, Q> Result; + Result[0] = m[0] * Rotate[0][0] + m[1] * Rotate[0][1] + m[2] * Rotate[0][2]; + Result[1] = m[0] * Rotate[1][0] + m[1] * Rotate[1][1] + m[2] * Rotate[1][2]; + Result[2] = m[0] * Rotate[2][0] + m[1] * Rotate[2][1] + m[2] * Rotate[2][2]; + Result[3] = m[3]; + return Result; + } + + template + GLM_FUNC_QUALIFIER qua rotateNormalizedAxis + ( + qua const& q, + T const& angle, + vec<3, T, Q> const& v + ) + { + vec<3, T, Q> const Tmp(v); + + T const AngleRad(angle); + T const Sin = sin(AngleRad * T(0.5)); + + return q * qua(cos(AngleRad * static_cast(0.5)), Tmp.x * Sin, Tmp.y * Sin, Tmp.z * Sin); + //return gtc::quaternion::cross(q, tquat(cos(AngleRad * T(0.5)), Tmp.x * fSin, Tmp.y * fSin, Tmp.z * fSin)); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/rotate_vector.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/rotate_vector.hpp new file mode 100644 index 0000000000000000000000000000000000000000..dcd5b95a6e5b1b484cec1261e4c00e93babba754 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/rotate_vector.hpp @@ -0,0 +1,123 @@ +/// @ref gtx_rotate_vector +/// @file glm/gtx/rotate_vector.hpp +/// +/// @see core (dependence) +/// @see gtx_transform (dependence) +/// +/// @defgroup gtx_rotate_vector GLM_GTX_rotate_vector +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Function to directly rotate a vector + +#pragma once + +// Dependency: +#include "../gtx/transform.hpp" +#include "../gtc/epsilon.hpp" +#include "../ext/vector_relational.hpp" +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_rotate_vector is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_rotate_vector extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_rotate_vector + /// @{ + + /// Returns Spherical interpolation between two vectors + /// + /// @param x A first vector + /// @param y A second vector + /// @param a Interpolation factor. The interpolation is defined beyond the range [0, 1]. + /// + /// @see gtx_rotate_vector + template + GLM_FUNC_DECL vec<3, T, Q> slerp( + vec<3, T, Q> const& x, + vec<3, T, Q> const& y, + T const& a); + + //! Rotate a two dimensional vector. + //! From GLM_GTX_rotate_vector extension. + template + GLM_FUNC_DECL vec<2, T, Q> rotate( + vec<2, T, Q> const& v, + T const& angle); + + //! Rotate a three dimensional vector around an axis. + //! From GLM_GTX_rotate_vector extension. + template + GLM_FUNC_DECL vec<3, T, Q> rotate( + vec<3, T, Q> const& v, + T const& angle, + vec<3, T, Q> const& normal); + + //! Rotate a four dimensional vector around an axis. + //! From GLM_GTX_rotate_vector extension. + template + GLM_FUNC_DECL vec<4, T, Q> rotate( + vec<4, T, Q> const& v, + T const& angle, + vec<3, T, Q> const& normal); + + //! Rotate a three dimensional vector around the X axis. + //! From GLM_GTX_rotate_vector extension. + template + GLM_FUNC_DECL vec<3, T, Q> rotateX( + vec<3, T, Q> const& v, + T const& angle); + + //! Rotate a three dimensional vector around the Y axis. + //! From GLM_GTX_rotate_vector extension. + template + GLM_FUNC_DECL vec<3, T, Q> rotateY( + vec<3, T, Q> const& v, + T const& angle); + + //! Rotate a three dimensional vector around the Z axis. + //! From GLM_GTX_rotate_vector extension. + template + GLM_FUNC_DECL vec<3, T, Q> rotateZ( + vec<3, T, Q> const& v, + T const& angle); + + //! Rotate a four dimensional vector around the X axis. + //! From GLM_GTX_rotate_vector extension. + template + GLM_FUNC_DECL vec<4, T, Q> rotateX( + vec<4, T, Q> const& v, + T const& angle); + + //! Rotate a four dimensional vector around the Y axis. + //! From GLM_GTX_rotate_vector extension. + template + GLM_FUNC_DECL vec<4, T, Q> rotateY( + vec<4, T, Q> const& v, + T const& angle); + + //! Rotate a four dimensional vector around the Z axis. + //! From GLM_GTX_rotate_vector extension. + template + GLM_FUNC_DECL vec<4, T, Q> rotateZ( + vec<4, T, Q> const& v, + T const& angle); + + //! Build a rotation matrix from a normal and a up vector. + //! From GLM_GTX_rotate_vector extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> orientation( + vec<3, T, Q> const& Normal, + vec<3, T, Q> const& Up); + + /// @} +}//namespace glm + +#include "rotate_vector.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/rotate_vector.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/rotate_vector.inl new file mode 100644 index 0000000000000000000000000000000000000000..f8136e765e0567723bfcfe6b3b13c6334ab4d5c1 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/rotate_vector.inl @@ -0,0 +1,187 @@ +/// @ref gtx_rotate_vector + +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec<3, T, Q> slerp + ( + vec<3, T, Q> const& x, + vec<3, T, Q> const& y, + T const& a + ) + { + // get cosine of angle between vectors (-1 -> 1) + T CosAlpha = dot(x, y); + // get angle (0 -> pi) + T Alpha = acos(CosAlpha); + // get sine of angle between vectors (0 -> 1) + T SinAlpha = sin(Alpha); + // this breaks down when SinAlpha = 0, i.e. Alpha = 0 or pi + T t1 = sin((static_cast(1) - a) * Alpha) / SinAlpha; + T t2 = sin(a * Alpha) / SinAlpha; + + // interpolate src vectors + return x * t1 + y * t2; + } + + template + GLM_FUNC_QUALIFIER vec<2, T, Q> rotate + ( + vec<2, T, Q> const& v, + T const& angle + ) + { + vec<2, T, Q> Result; + T const Cos(cos(angle)); + T const Sin(sin(angle)); + + Result.x = v.x * Cos - v.y * Sin; + Result.y = v.x * Sin + v.y * Cos; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> rotate + ( + vec<3, T, Q> const& v, + T const& angle, + vec<3, T, Q> const& normal + ) + { + return mat<3, 3, T, Q>(glm::rotate(angle, normal)) * v; + } + /* + template + GLM_FUNC_QUALIFIER vec<3, T, Q> rotateGTX( + const vec<3, T, Q>& x, + T angle, + const vec<3, T, Q>& normal) + { + const T Cos = cos(radians(angle)); + const T Sin = sin(radians(angle)); + return x * Cos + ((x * normal) * (T(1) - Cos)) * normal + cross(x, normal) * Sin; + } + */ + template + GLM_FUNC_QUALIFIER vec<4, T, Q> rotate + ( + vec<4, T, Q> const& v, + T const& angle, + vec<3, T, Q> const& normal + ) + { + return rotate(angle, normal) * v; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> rotateX + ( + vec<3, T, Q> const& v, + T const& angle + ) + { + vec<3, T, Q> Result(v); + T const Cos(cos(angle)); + T const Sin(sin(angle)); + + Result.y = v.y * Cos - v.z * Sin; + Result.z = v.y * Sin + v.z * Cos; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> rotateY + ( + vec<3, T, Q> const& v, + T const& angle + ) + { + vec<3, T, Q> Result = v; + T const Cos(cos(angle)); + T const Sin(sin(angle)); + + Result.x = v.x * Cos + v.z * Sin; + Result.z = -v.x * Sin + v.z * Cos; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> rotateZ + ( + vec<3, T, Q> const& v, + T const& angle + ) + { + vec<3, T, Q> Result = v; + T const Cos(cos(angle)); + T const Sin(sin(angle)); + + Result.x = v.x * Cos - v.y * Sin; + Result.y = v.x * Sin + v.y * Cos; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> rotateX + ( + vec<4, T, Q> const& v, + T const& angle + ) + { + vec<4, T, Q> Result = v; + T const Cos(cos(angle)); + T const Sin(sin(angle)); + + Result.y = v.y * Cos - v.z * Sin; + Result.z = v.y * Sin + v.z * Cos; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> rotateY + ( + vec<4, T, Q> const& v, + T const& angle + ) + { + vec<4, T, Q> Result = v; + T const Cos(cos(angle)); + T const Sin(sin(angle)); + + Result.x = v.x * Cos + v.z * Sin; + Result.z = -v.x * Sin + v.z * Cos; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> rotateZ + ( + vec<4, T, Q> const& v, + T const& angle + ) + { + vec<4, T, Q> Result = v; + T const Cos(cos(angle)); + T const Sin(sin(angle)); + + Result.x = v.x * Cos - v.y * Sin; + Result.y = v.x * Sin + v.y * Cos; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> orientation + ( + vec<3, T, Q> const& Normal, + vec<3, T, Q> const& Up + ) + { + if(all(equal(Normal, Up, epsilon()))) + return mat<4, 4, T, Q>(static_cast(1)); + + vec<3, T, Q> RotationAxis = cross(Up, Normal); + T Angle = acos(dot(Normal, Up)); + + return rotate(Angle, RotationAxis); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/scalar_multiplication.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/scalar_multiplication.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9f9f2fb3edbca28c378e9428b3c8603f82803d22 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/scalar_multiplication.hpp @@ -0,0 +1,82 @@ +/// @ref gtx_scalar_multiplication +/// @file glm/gtx/scalar_multiplication.hpp +/// @author Joshua Moerman +/// +/// @defgroup gtx_scalar_multiplication GLM_GTX_scalar_multiplication +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Enables scalar multiplication for all types +/// +/// Since GLSL is very strict about types, the following (often used) combinations do not work: +/// double * vec4 +/// int * vec4 +/// vec4 / int +/// So we'll fix that! Of course "float * vec4" should remain the same (hence the enable_if magic) + +#pragma once + +#include "../detail/setup.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_scalar_multiplication is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_scalar_multiplication extension included") +# endif +#endif + +#include "../vec2.hpp" +#include "../vec3.hpp" +#include "../vec4.hpp" +#include "../mat2x2.hpp" +#include + +namespace glm +{ + /// @addtogroup gtx_scalar_multiplication + /// @{ + + template + using return_type_scalar_multiplication = typename std::enable_if< + !std::is_same::value // T may not be a float + && std::is_arithmetic::value, Vec // But it may be an int or double (no vec3 or mat3, ...) + >::type; + +#define GLM_IMPLEMENT_SCAL_MULT(Vec) \ + template \ + return_type_scalar_multiplication \ + operator*(T const& s, Vec rh){ \ + return rh *= static_cast(s); \ + } \ + \ + template \ + return_type_scalar_multiplication \ + operator*(Vec lh, T const& s){ \ + return lh *= static_cast(s); \ + } \ + \ + template \ + return_type_scalar_multiplication \ + operator/(Vec lh, T const& s){ \ + return lh *= 1.0f / static_cast(s); \ + } + +GLM_IMPLEMENT_SCAL_MULT(vec2) +GLM_IMPLEMENT_SCAL_MULT(vec3) +GLM_IMPLEMENT_SCAL_MULT(vec4) + +GLM_IMPLEMENT_SCAL_MULT(mat2) +GLM_IMPLEMENT_SCAL_MULT(mat2x3) +GLM_IMPLEMENT_SCAL_MULT(mat2x4) +GLM_IMPLEMENT_SCAL_MULT(mat3x2) +GLM_IMPLEMENT_SCAL_MULT(mat3) +GLM_IMPLEMENT_SCAL_MULT(mat3x4) +GLM_IMPLEMENT_SCAL_MULT(mat4x2) +GLM_IMPLEMENT_SCAL_MULT(mat4x3) +GLM_IMPLEMENT_SCAL_MULT(mat4) + +#undef GLM_IMPLEMENT_SCAL_MULT + /// @} +} // namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/scalar_relational.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/scalar_relational.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8be9c57b8b3501f28e2f35b692d5397c43f3a63a --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/scalar_relational.hpp @@ -0,0 +1,36 @@ +/// @ref gtx_scalar_relational +/// @file glm/gtx/scalar_relational.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_scalar_relational GLM_GTX_scalar_relational +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Extend a position from a source to a position at a defined length. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_extend is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_extend extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_scalar_relational + /// @{ + + + + /// @} +}//namespace glm + +#include "scalar_relational.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/scalar_relational.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/scalar_relational.inl new file mode 100644 index 0000000000000000000000000000000000000000..c2a121cff9771266eb1de59182a1dc962f9a5e54 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/scalar_relational.inl @@ -0,0 +1,88 @@ +/// @ref gtx_scalar_relational + +namespace glm +{ + template + GLM_FUNC_QUALIFIER bool lessThan + ( + T const& x, + T const& y + ) + { + return x < y; + } + + template + GLM_FUNC_QUALIFIER bool lessThanEqual + ( + T const& x, + T const& y + ) + { + return x <= y; + } + + template + GLM_FUNC_QUALIFIER bool greaterThan + ( + T const& x, + T const& y + ) + { + return x > y; + } + + template + GLM_FUNC_QUALIFIER bool greaterThanEqual + ( + T const& x, + T const& y + ) + { + return x >= y; + } + + template + GLM_FUNC_QUALIFIER bool equal + ( + T const& x, + T const& y + ) + { + return detail::compute_equal::is_iec559>::call(x, y); + } + + template + GLM_FUNC_QUALIFIER bool notEqual + ( + T const& x, + T const& y + ) + { + return !detail::compute_equal::is_iec559>::call(x, y); + } + + GLM_FUNC_QUALIFIER bool any + ( + bool const& x + ) + { + return x; + } + + GLM_FUNC_QUALIFIER bool all + ( + bool const& x + ) + { + return x; + } + + GLM_FUNC_QUALIFIER bool not_ + ( + bool const& x + ) + { + return !x; + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/spline.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/spline.hpp new file mode 100644 index 0000000000000000000000000000000000000000..731c979e358a8f2967ab5b71da57bf68abefa94d --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/spline.hpp @@ -0,0 +1,65 @@ +/// @ref gtx_spline +/// @file glm/gtx/spline.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_spline GLM_GTX_spline +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Spline functions + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtx/optimum_pow.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_spline is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_spline extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_spline + /// @{ + + /// Return a point from a catmull rom curve. + /// @see gtx_spline extension. + template + GLM_FUNC_DECL genType catmullRom( + genType const& v1, + genType const& v2, + genType const& v3, + genType const& v4, + typename genType::value_type const& s); + + /// Return a point from a hermite curve. + /// @see gtx_spline extension. + template + GLM_FUNC_DECL genType hermite( + genType const& v1, + genType const& t1, + genType const& v2, + genType const& t2, + typename genType::value_type const& s); + + /// Return a point from a cubic curve. + /// @see gtx_spline extension. + template + GLM_FUNC_DECL genType cubic( + genType const& v1, + genType const& v2, + genType const& v3, + genType const& v4, + typename genType::value_type const& s); + + /// @} +}//namespace glm + +#include "spline.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/spline.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/spline.inl new file mode 100644 index 0000000000000000000000000000000000000000..c3fd0565629139357a81ffdcae55f8e89b4831dd --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/spline.inl @@ -0,0 +1,60 @@ +/// @ref gtx_spline + +namespace glm +{ + template + GLM_FUNC_QUALIFIER genType catmullRom + ( + genType const& v1, + genType const& v2, + genType const& v3, + genType const& v4, + typename genType::value_type const& s + ) + { + typename genType::value_type s2 = pow2(s); + typename genType::value_type s3 = pow3(s); + + typename genType::value_type f1 = -s3 + typename genType::value_type(2) * s2 - s; + typename genType::value_type f2 = typename genType::value_type(3) * s3 - typename genType::value_type(5) * s2 + typename genType::value_type(2); + typename genType::value_type f3 = typename genType::value_type(-3) * s3 + typename genType::value_type(4) * s2 + s; + typename genType::value_type f4 = s3 - s2; + + return (f1 * v1 + f2 * v2 + f3 * v3 + f4 * v4) / typename genType::value_type(2); + + } + + template + GLM_FUNC_QUALIFIER genType hermite + ( + genType const& v1, + genType const& t1, + genType const& v2, + genType const& t2, + typename genType::value_type const& s + ) + { + typename genType::value_type s2 = pow2(s); + typename genType::value_type s3 = pow3(s); + + typename genType::value_type f1 = typename genType::value_type(2) * s3 - typename genType::value_type(3) * s2 + typename genType::value_type(1); + typename genType::value_type f2 = typename genType::value_type(-2) * s3 + typename genType::value_type(3) * s2; + typename genType::value_type f3 = s3 - typename genType::value_type(2) * s2 + s; + typename genType::value_type f4 = s3 - s2; + + return f1 * v1 + f2 * v2 + f3 * t1 + f4 * t2; + } + + template + GLM_FUNC_QUALIFIER genType cubic + ( + genType const& v1, + genType const& v2, + genType const& v3, + genType const& v4, + typename genType::value_type const& s + ) + { + return ((v1 * s + v2) * s + v3) * s + v4; + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/std_based_type.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/std_based_type.hpp new file mode 100644 index 0000000000000000000000000000000000000000..cd3be8cb78926ab1f9620e848c30a43aa4198185 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/std_based_type.hpp @@ -0,0 +1,68 @@ +/// @ref gtx_std_based_type +/// @file glm/gtx/std_based_type.hpp +/// +/// @see core (dependence) +/// @see gtx_extented_min_max (dependence) +/// +/// @defgroup gtx_std_based_type GLM_GTX_std_based_type +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Adds vector types based on STL value types. + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_std_based_type is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_std_based_type extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_std_based_type + /// @{ + + /// Vector type based of one std::size_t component. + /// @see GLM_GTX_std_based_type + typedef vec<1, std::size_t, defaultp> size1; + + /// Vector type based of two std::size_t components. + /// @see GLM_GTX_std_based_type + typedef vec<2, std::size_t, defaultp> size2; + + /// Vector type based of three std::size_t components. + /// @see GLM_GTX_std_based_type + typedef vec<3, std::size_t, defaultp> size3; + + /// Vector type based of four std::size_t components. + /// @see GLM_GTX_std_based_type + typedef vec<4, std::size_t, defaultp> size4; + + /// Vector type based of one std::size_t component. + /// @see GLM_GTX_std_based_type + typedef vec<1, std::size_t, defaultp> size1_t; + + /// Vector type based of two std::size_t components. + /// @see GLM_GTX_std_based_type + typedef vec<2, std::size_t, defaultp> size2_t; + + /// Vector type based of three std::size_t components. + /// @see GLM_GTX_std_based_type + typedef vec<3, std::size_t, defaultp> size3_t; + + /// Vector type based of four std::size_t components. + /// @see GLM_GTX_std_based_type + typedef vec<4, std::size_t, defaultp> size4_t; + + /// @} +}//namespace glm + +#include "std_based_type.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/std_based_type.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/std_based_type.inl new file mode 100644 index 0000000000000000000000000000000000000000..9c34bdb6e0f7348895bd59a256588731bb759da5 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/std_based_type.inl @@ -0,0 +1,6 @@ +/// @ref gtx_std_based_type + +namespace glm +{ + +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/string_cast.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/string_cast.hpp new file mode 100644 index 0000000000000000000000000000000000000000..71f6ece4c9f164b8483f62d6859dedb1ea912754 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/string_cast.hpp @@ -0,0 +1,46 @@ +/// @ref gtx_string_cast +/// @file glm/gtx/string_cast.hpp +/// +/// @see core (dependence) +/// @see gtx_integer (dependence) +/// @see gtx_quaternion (dependence) +/// +/// @defgroup gtx_string_cast GLM_GTX_string_cast +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Setup strings for GLM type values + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtc/type_precision.hpp" +#include "../gtc/quaternion.hpp" +#include "../gtx/dual_quaternion.hpp" +#include +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_string_cast is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_string_cast extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_string_cast + /// @{ + + /// Create a string from a GLM vector or matrix typed variable. + /// @see gtx_string_cast extension. + template + GLM_FUNC_DECL std::string to_string(genType const& x); + + /// @} +}//namespace glm + +#include "string_cast.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/string_cast.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/string_cast.inl new file mode 100644 index 0000000000000000000000000000000000000000..f67751d41c2af4128d44bf73c055147d3b1c156d --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/string_cast.inl @@ -0,0 +1,492 @@ +/// @ref gtx_string_cast + +#include +#include + +namespace glm{ +namespace detail +{ + template + struct cast + { + typedef T value_type; + }; + + template <> + struct cast + { + typedef double value_type; + }; + + GLM_FUNC_QUALIFIER std::string format(const char* msg, ...) + { + std::size_t const STRING_BUFFER(4096); + char text[STRING_BUFFER]; + va_list list; + + if(msg == GLM_NULLPTR) + return std::string(); + + va_start(list, msg); +# if (GLM_COMPILER & GLM_COMPILER_VC) + vsprintf_s(text, STRING_BUFFER, msg, list); +# else// + std::vsprintf(text, msg, list); +# endif// + va_end(list); + + return std::string(text); + } + + static const char* LabelTrue = "true"; + static const char* LabelFalse = "false"; + + template + struct literal + { + GLM_FUNC_QUALIFIER static char const * value() {return "%d";} + }; + + template + struct literal + { + GLM_FUNC_QUALIFIER static char const * value() {return "%f";} + }; + +# if GLM_MODEL == GLM_MODEL_32 && GLM_COMPILER && GLM_COMPILER_VC + template<> + struct literal + { + GLM_FUNC_QUALIFIER static char const * value() {return "%lld";} + }; + + template<> + struct literal + { + GLM_FUNC_QUALIFIER static char const * value() {return "%lld";} + }; +# endif//GLM_MODEL == GLM_MODEL_32 && GLM_COMPILER && GLM_COMPILER_VC + + template + struct prefix{}; + + template<> + struct prefix + { + GLM_FUNC_QUALIFIER static char const * value() {return "";} + }; + + template<> + struct prefix + { + GLM_FUNC_QUALIFIER static char const * value() {return "d";} + }; + + template<> + struct prefix + { + GLM_FUNC_QUALIFIER static char const * value() {return "b";} + }; + + template<> + struct prefix + { + GLM_FUNC_QUALIFIER static char const * value() {return "u8";} + }; + + template<> + struct prefix + { + GLM_FUNC_QUALIFIER static char const * value() {return "i8";} + }; + + template<> + struct prefix + { + GLM_FUNC_QUALIFIER static char const * value() {return "u16";} + }; + + template<> + struct prefix + { + GLM_FUNC_QUALIFIER static char const * value() {return "i16";} + }; + + template<> + struct prefix + { + GLM_FUNC_QUALIFIER static char const * value() {return "u";} + }; + + template<> + struct prefix + { + GLM_FUNC_QUALIFIER static char const * value() {return "i";} + }; + + template<> + struct prefix + { + GLM_FUNC_QUALIFIER static char const * value() {return "u64";} + }; + + template<> + struct prefix + { + GLM_FUNC_QUALIFIER static char const * value() {return "i64";} + }; + + template + struct compute_to_string + {}; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(vec<1, bool, Q> const& x) + { + return detail::format("bvec1(%s)", + x[0] ? detail::LabelTrue : detail::LabelFalse); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(vec<2, bool, Q> const& x) + { + return detail::format("bvec2(%s, %s)", + x[0] ? detail::LabelTrue : detail::LabelFalse, + x[1] ? detail::LabelTrue : detail::LabelFalse); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(vec<3, bool, Q> const& x) + { + return detail::format("bvec3(%s, %s, %s)", + x[0] ? detail::LabelTrue : detail::LabelFalse, + x[1] ? detail::LabelTrue : detail::LabelFalse, + x[2] ? detail::LabelTrue : detail::LabelFalse); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(vec<4, bool, Q> const& x) + { + return detail::format("bvec4(%s, %s, %s, %s)", + x[0] ? detail::LabelTrue : detail::LabelFalse, + x[1] ? detail::LabelTrue : detail::LabelFalse, + x[2] ? detail::LabelTrue : detail::LabelFalse, + x[3] ? detail::LabelTrue : detail::LabelFalse); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(vec<1, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%svec1(%s)", + PrefixStr, + LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0])); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(vec<2, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%svec2(%s, %s)", + PrefixStr, + LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0]), + static_cast::value_type>(x[1])); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(vec<3, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%svec3(%s, %s, %s)", + PrefixStr, + LiteralStr, LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0]), + static_cast::value_type>(x[1]), + static_cast::value_type>(x[2])); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(vec<4, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%svec4(%s, %s, %s, %s)", + PrefixStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0]), + static_cast::value_type>(x[1]), + static_cast::value_type>(x[2]), + static_cast::value_type>(x[3])); + } + }; + + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(mat<2, 2, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%smat2x2((%s, %s), (%s, %s))", + PrefixStr, + LiteralStr, LiteralStr, + LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), + static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1])); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(mat<2, 3, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%smat2x3((%s, %s, %s), (%s, %s, %s))", + PrefixStr, + LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), static_cast::value_type>(x[0][2]), + static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1]), static_cast::value_type>(x[1][2])); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(mat<2, 4, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%smat2x4((%s, %s, %s, %s), (%s, %s, %s, %s))", + PrefixStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), static_cast::value_type>(x[0][2]), static_cast::value_type>(x[0][3]), + static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1]), static_cast::value_type>(x[1][2]), static_cast::value_type>(x[1][3])); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(mat<3, 2, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%smat3x2((%s, %s), (%s, %s), (%s, %s))", + PrefixStr, + LiteralStr, LiteralStr, + LiteralStr, LiteralStr, + LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), + static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1]), + static_cast::value_type>(x[2][0]), static_cast::value_type>(x[2][1])); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(mat<3, 3, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%smat3x3((%s, %s, %s), (%s, %s, %s), (%s, %s, %s))", + PrefixStr, + LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), static_cast::value_type>(x[0][2]), + static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1]), static_cast::value_type>(x[1][2]), + static_cast::value_type>(x[2][0]), static_cast::value_type>(x[2][1]), static_cast::value_type>(x[2][2])); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(mat<3, 4, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%smat3x4((%s, %s, %s, %s), (%s, %s, %s, %s), (%s, %s, %s, %s))", + PrefixStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), static_cast::value_type>(x[0][2]), static_cast::value_type>(x[0][3]), + static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1]), static_cast::value_type>(x[1][2]), static_cast::value_type>(x[1][3]), + static_cast::value_type>(x[2][0]), static_cast::value_type>(x[2][1]), static_cast::value_type>(x[2][2]), static_cast::value_type>(x[2][3])); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(mat<4, 2, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%smat4x2((%s, %s), (%s, %s), (%s, %s), (%s, %s))", + PrefixStr, + LiteralStr, LiteralStr, + LiteralStr, LiteralStr, + LiteralStr, LiteralStr, + LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), + static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1]), + static_cast::value_type>(x[2][0]), static_cast::value_type>(x[2][1]), + static_cast::value_type>(x[3][0]), static_cast::value_type>(x[3][1])); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(mat<4, 3, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%smat4x3((%s, %s, %s), (%s, %s, %s), (%s, %s, %s), (%s, %s, %s))", + PrefixStr, + LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), static_cast::value_type>(x[0][2]), + static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1]), static_cast::value_type>(x[1][2]), + static_cast::value_type>(x[2][0]), static_cast::value_type>(x[2][1]), static_cast::value_type>(x[2][2]), + static_cast::value_type>(x[3][0]), static_cast::value_type>(x[3][1]), static_cast::value_type>(x[3][2])); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(mat<4, 4, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%smat4x4((%s, %s, %s, %s), (%s, %s, %s, %s), (%s, %s, %s, %s), (%s, %s, %s, %s))", + PrefixStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), static_cast::value_type>(x[0][2]), static_cast::value_type>(x[0][3]), + static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1]), static_cast::value_type>(x[1][2]), static_cast::value_type>(x[1][3]), + static_cast::value_type>(x[2][0]), static_cast::value_type>(x[2][1]), static_cast::value_type>(x[2][2]), static_cast::value_type>(x[2][3]), + static_cast::value_type>(x[3][0]), static_cast::value_type>(x[3][1]), static_cast::value_type>(x[3][2]), static_cast::value_type>(x[3][3])); + } + }; + + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(qua const& q) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%squat(%s, {%s, %s, %s})", + PrefixStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(q.w), + static_cast::value_type>(q.x), + static_cast::value_type>(q.y), + static_cast::value_type>(q.z)); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(tdualquat const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%sdualquat((%s, {%s, %s, %s}), (%s, {%s, %s, %s}))", + PrefixStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x.real.w), + static_cast::value_type>(x.real.x), + static_cast::value_type>(x.real.y), + static_cast::value_type>(x.real.z), + static_cast::value_type>(x.dual.w), + static_cast::value_type>(x.dual.x), + static_cast::value_type>(x.dual.y), + static_cast::value_type>(x.dual.z)); + } + }; + +}//namespace detail + +template +GLM_FUNC_QUALIFIER std::string to_string(matType const& x) +{ + return detail::compute_to_string::call(x); +} + +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/texture.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/texture.hpp new file mode 100644 index 0000000000000000000000000000000000000000..20585e68ce11419c27f637290beaede9b56c6cf4 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/texture.hpp @@ -0,0 +1,46 @@ +/// @ref gtx_texture +/// @file glm/gtx/texture.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_texture GLM_GTX_texture +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Wrapping mode of texture coordinates. + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtc/integer.hpp" +#include "../gtx/component_wise.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_texture is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_texture extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_texture + /// @{ + + /// Compute the number of mipmaps levels necessary to create a mipmap complete texture + /// + /// @param Extent Extent of the texture base level mipmap + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or signed integer scalar types + /// @tparam Q Value from qualifier enum + template + T levels(vec const& Extent); + + /// @} +}// namespace glm + +#include "texture.inl" + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/texture.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/texture.inl new file mode 100644 index 0000000000000000000000000000000000000000..593c826141b0e0c35b513bfbac623e9a6ecb3168 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/texture.inl @@ -0,0 +1,17 @@ +/// @ref gtx_texture + +namespace glm +{ + template + inline T levels(vec const& Extent) + { + return glm::log2(compMax(Extent)) + static_cast(1); + } + + template + inline T levels(T Extent) + { + return vec<1, T, defaultp>(Extent).x; + } +}//namespace glm + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/transform.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/transform.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0279fc8bd329d592288a90256ce1ff7d3c711e45 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/transform.hpp @@ -0,0 +1,60 @@ +/// @ref gtx_transform +/// @file glm/gtx/transform.hpp +/// +/// @see core (dependence) +/// @see gtc_matrix_transform (dependence) +/// @see gtx_transform +/// @see gtx_transform2 +/// +/// @defgroup gtx_transform GLM_GTX_transform +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Add transformation matrices + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtc/matrix_transform.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_transform is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_transform extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_transform + /// @{ + + /// Transforms a matrix with a translation 4 * 4 matrix created from 3 scalars. + /// @see gtc_matrix_transform + /// @see gtx_transform + template + GLM_FUNC_DECL mat<4, 4, T, Q> translate( + vec<3, T, Q> const& v); + + /// Builds a rotation 4 * 4 matrix created from an axis of 3 scalars and an angle expressed in radians. + /// @see gtc_matrix_transform + /// @see gtx_transform + template + GLM_FUNC_DECL mat<4, 4, T, Q> rotate( + T angle, + vec<3, T, Q> const& v); + + /// Transforms a matrix with a scale 4 * 4 matrix created from a vector of 3 components. + /// @see gtc_matrix_transform + /// @see gtx_transform + template + GLM_FUNC_DECL mat<4, 4, T, Q> scale( + vec<3, T, Q> const& v); + + /// @} +}// namespace glm + +#include "transform.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/transform.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/transform.inl new file mode 100644 index 0000000000000000000000000000000000000000..48ee6801b6515266b1cfd9f389258ea5b200c5d1 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/transform.inl @@ -0,0 +1,23 @@ +/// @ref gtx_transform + +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> translate(vec<3, T, Q> const& v) + { + return translate(mat<4, 4, T, Q>(static_cast(1)), v); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> rotate(T angle, vec<3, T, Q> const& v) + { + return rotate(mat<4, 4, T, Q>(static_cast(1)), angle, v); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> scale(vec<3, T, Q> const& v) + { + return scale(mat<4, 4, T, Q>(static_cast(1)), v); + } + +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/transform2.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/transform2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0d8ba9d90bc51a7b094c87ca3fed3a61601c6138 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/transform2.hpp @@ -0,0 +1,89 @@ +/// @ref gtx_transform2 +/// @file glm/gtx/transform2.hpp +/// +/// @see core (dependence) +/// @see gtx_transform (dependence) +/// +/// @defgroup gtx_transform2 GLM_GTX_transform2 +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Add extra transformation matrices + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtx/transform.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_transform2 is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_transform2 extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_transform2 + /// @{ + + //! Transforms a matrix with a shearing on X axis. + //! From GLM_GTX_transform2 extension. + template + GLM_FUNC_DECL mat<3, 3, T, Q> shearX2D(mat<3, 3, T, Q> const& m, T y); + + //! Transforms a matrix with a shearing on Y axis. + //! From GLM_GTX_transform2 extension. + template + GLM_FUNC_DECL mat<3, 3, T, Q> shearY2D(mat<3, 3, T, Q> const& m, T x); + + //! Transforms a matrix with a shearing on X axis + //! From GLM_GTX_transform2 extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> shearX3D(mat<4, 4, T, Q> const& m, T y, T z); + + //! Transforms a matrix with a shearing on Y axis. + //! From GLM_GTX_transform2 extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> shearY3D(mat<4, 4, T, Q> const& m, T x, T z); + + //! Transforms a matrix with a shearing on Z axis. + //! From GLM_GTX_transform2 extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> shearZ3D(mat<4, 4, T, Q> const& m, T x, T y); + + //template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> shear(const mat<4, 4, T, Q> & m, shearPlane, planePoint, angle) + // Identity + tan(angle) * cross(Normal, OnPlaneVector) 0 + // - dot(PointOnPlane, normal) * OnPlaneVector 1 + + // Reflect functions seem to don't work + //template mat<3, 3, T, Q> reflect2D(const mat<3, 3, T, Q> & m, const vec<3, T, Q>& normal){return reflect2DGTX(m, normal);} //!< \brief Build a reflection matrix (from GLM_GTX_transform2 extension) + //template mat<4, 4, T, Q> reflect3D(const mat<4, 4, T, Q> & m, const vec<3, T, Q>& normal){return reflect3DGTX(m, normal);} //!< \brief Build a reflection matrix (from GLM_GTX_transform2 extension) + + //! Build planar projection matrix along normal axis. + //! From GLM_GTX_transform2 extension. + template + GLM_FUNC_DECL mat<3, 3, T, Q> proj2D(mat<3, 3, T, Q> const& m, vec<3, T, Q> const& normal); + + //! Build planar projection matrix along normal axis. + //! From GLM_GTX_transform2 extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> proj3D(mat<4, 4, T, Q> const & m, vec<3, T, Q> const& normal); + + //! Build a scale bias matrix. + //! From GLM_GTX_transform2 extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> scaleBias(T scale, T bias); + + //! Build a scale bias matrix. + //! From GLM_GTX_transform2 extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> scaleBias(mat<4, 4, T, Q> const& m, T scale, T bias); + + /// @} +}// namespace glm + +#include "transform2.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/transform2.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/transform2.inl new file mode 100644 index 0000000000000000000000000000000000000000..0118ab09603a10e9020a593bdd26f164c37c75e0 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/transform2.inl @@ -0,0 +1,125 @@ +/// @ref gtx_transform2 + +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> shearX2D(mat<3, 3, T, Q> const& m, T s) + { + mat<3, 3, T, Q> r(1); + r[1][0] = s; + return m * r; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> shearY2D(mat<3, 3, T, Q> const& m, T s) + { + mat<3, 3, T, Q> r(1); + r[0][1] = s; + return m * r; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> shearX3D(mat<4, 4, T, Q> const& m, T s, T t) + { + mat<4, 4, T, Q> r(1); + r[0][1] = s; + r[0][2] = t; + return m * r; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> shearY3D(mat<4, 4, T, Q> const& m, T s, T t) + { + mat<4, 4, T, Q> r(1); + r[1][0] = s; + r[1][2] = t; + return m * r; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> shearZ3D(mat<4, 4, T, Q> const& m, T s, T t) + { + mat<4, 4, T, Q> r(1); + r[2][0] = s; + r[2][1] = t; + return m * r; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> reflect2D(mat<3, 3, T, Q> const& m, vec<3, T, Q> const& normal) + { + mat<3, 3, T, Q> r(static_cast(1)); + r[0][0] = static_cast(1) - static_cast(2) * normal.x * normal.x; + r[0][1] = -static_cast(2) * normal.x * normal.y; + r[1][0] = -static_cast(2) * normal.x * normal.y; + r[1][1] = static_cast(1) - static_cast(2) * normal.y * normal.y; + return m * r; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> reflect3D(mat<4, 4, T, Q> const& m, vec<3, T, Q> const& normal) + { + mat<4, 4, T, Q> r(static_cast(1)); + r[0][0] = static_cast(1) - static_cast(2) * normal.x * normal.x; + r[0][1] = -static_cast(2) * normal.x * normal.y; + r[0][2] = -static_cast(2) * normal.x * normal.z; + + r[1][0] = -static_cast(2) * normal.x * normal.y; + r[1][1] = static_cast(1) - static_cast(2) * normal.y * normal.y; + r[1][2] = -static_cast(2) * normal.y * normal.z; + + r[2][0] = -static_cast(2) * normal.x * normal.z; + r[2][1] = -static_cast(2) * normal.y * normal.z; + r[2][2] = static_cast(1) - static_cast(2) * normal.z * normal.z; + return m * r; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> proj2D( + const mat<3, 3, T, Q>& m, + const vec<3, T, Q>& normal) + { + mat<3, 3, T, Q> r(static_cast(1)); + r[0][0] = static_cast(1) - normal.x * normal.x; + r[0][1] = - normal.x * normal.y; + r[1][0] = - normal.x * normal.y; + r[1][1] = static_cast(1) - normal.y * normal.y; + return m * r; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> proj3D( + const mat<4, 4, T, Q>& m, + const vec<3, T, Q>& normal) + { + mat<4, 4, T, Q> r(static_cast(1)); + r[0][0] = static_cast(1) - normal.x * normal.x; + r[0][1] = - normal.x * normal.y; + r[0][2] = - normal.x * normal.z; + r[1][0] = - normal.x * normal.y; + r[1][1] = static_cast(1) - normal.y * normal.y; + r[1][2] = - normal.y * normal.z; + r[2][0] = - normal.x * normal.z; + r[2][1] = - normal.y * normal.z; + r[2][2] = static_cast(1) - normal.z * normal.z; + return m * r; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> scaleBias(T scale, T bias) + { + mat<4, 4, T, Q> result; + result[3] = vec<4, T, Q>(vec<3, T, Q>(bias), static_cast(1)); + result[0][0] = scale; + result[1][1] = scale; + result[2][2] = scale; + return result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> scaleBias(mat<4, 4, T, Q> const& m, T scale, T bias) + { + return m * scaleBias(scale, bias); + } +}//namespace glm + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/type_aligned.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/type_aligned.hpp new file mode 100644 index 0000000000000000000000000000000000000000..2ae522c1fc7e383c8b1d2a903210acd0196c10fc --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/type_aligned.hpp @@ -0,0 +1,982 @@ +/// @ref gtx_type_aligned +/// @file glm/gtx/type_aligned.hpp +/// +/// @see core (dependence) +/// @see gtc_quaternion (dependence) +/// +/// @defgroup gtx_type_aligned GLM_GTX_type_aligned +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Defines aligned types. + +#pragma once + +// Dependency: +#include "../gtc/type_precision.hpp" +#include "../gtc/quaternion.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_type_aligned is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_type_aligned extension included") +# endif +#endif + +namespace glm +{ + /////////////////////////// + // Signed int vector types + + /// @addtogroup gtx_type_aligned + /// @{ + + /// Low qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_int8, aligned_lowp_int8, 1); + + /// Low qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_int16, aligned_lowp_int16, 2); + + /// Low qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_int32, aligned_lowp_int32, 4); + + /// Low qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_int64, aligned_lowp_int64, 8); + + + /// Low qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_int8_t, aligned_lowp_int8_t, 1); + + /// Low qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_int16_t, aligned_lowp_int16_t, 2); + + /// Low qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_int32_t, aligned_lowp_int32_t, 4); + + /// Low qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_int64_t, aligned_lowp_int64_t, 8); + + + /// Low qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_i8, aligned_lowp_i8, 1); + + /// Low qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_i16, aligned_lowp_i16, 2); + + /// Low qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_i32, aligned_lowp_i32, 4); + + /// Low qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_i64, aligned_lowp_i64, 8); + + + /// Medium qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_int8, aligned_mediump_int8, 1); + + /// Medium qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_int16, aligned_mediump_int16, 2); + + /// Medium qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_int32, aligned_mediump_int32, 4); + + /// Medium qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_int64, aligned_mediump_int64, 8); + + + /// Medium qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_int8_t, aligned_mediump_int8_t, 1); + + /// Medium qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_int16_t, aligned_mediump_int16_t, 2); + + /// Medium qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_int32_t, aligned_mediump_int32_t, 4); + + /// Medium qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_int64_t, aligned_mediump_int64_t, 8); + + + /// Medium qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_i8, aligned_mediump_i8, 1); + + /// Medium qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_i16, aligned_mediump_i16, 2); + + /// Medium qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_i32, aligned_mediump_i32, 4); + + /// Medium qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_i64, aligned_mediump_i64, 8); + + + /// High qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_int8, aligned_highp_int8, 1); + + /// High qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_int16, aligned_highp_int16, 2); + + /// High qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_int32, aligned_highp_int32, 4); + + /// High qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_int64, aligned_highp_int64, 8); + + + /// High qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_int8_t, aligned_highp_int8_t, 1); + + /// High qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_int16_t, aligned_highp_int16_t, 2); + + /// High qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_int32_t, aligned_highp_int32_t, 4); + + /// High qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_int64_t, aligned_highp_int64_t, 8); + + + /// High qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_i8, aligned_highp_i8, 1); + + /// High qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_i16, aligned_highp_i16, 2); + + /// High qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_i32, aligned_highp_i32, 4); + + /// High qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_i64, aligned_highp_i64, 8); + + + /// Default qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(int8, aligned_int8, 1); + + /// Default qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(int16, aligned_int16, 2); + + /// Default qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(int32, aligned_int32, 4); + + /// Default qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(int64, aligned_int64, 8); + + + /// Default qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(int8_t, aligned_int8_t, 1); + + /// Default qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(int16_t, aligned_int16_t, 2); + + /// Default qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(int32_t, aligned_int32_t, 4); + + /// Default qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(int64_t, aligned_int64_t, 8); + + + /// Default qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i8, aligned_i8, 1); + + /// Default qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i16, aligned_i16, 2); + + /// Default qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i32, aligned_i32, 4); + + /// Default qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i64, aligned_i64, 8); + + + /// Default qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(ivec1, aligned_ivec1, 4); + + /// Default qualifier 32 bit signed integer aligned vector of 2 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(ivec2, aligned_ivec2, 8); + + /// Default qualifier 32 bit signed integer aligned vector of 3 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(ivec3, aligned_ivec3, 16); + + /// Default qualifier 32 bit signed integer aligned vector of 4 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(ivec4, aligned_ivec4, 16); + + + /// Default qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i8vec1, aligned_i8vec1, 1); + + /// Default qualifier 8 bit signed integer aligned vector of 2 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i8vec2, aligned_i8vec2, 2); + + /// Default qualifier 8 bit signed integer aligned vector of 3 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i8vec3, aligned_i8vec3, 4); + + /// Default qualifier 8 bit signed integer aligned vector of 4 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i8vec4, aligned_i8vec4, 4); + + + /// Default qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i16vec1, aligned_i16vec1, 2); + + /// Default qualifier 16 bit signed integer aligned vector of 2 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i16vec2, aligned_i16vec2, 4); + + /// Default qualifier 16 bit signed integer aligned vector of 3 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i16vec3, aligned_i16vec3, 8); + + /// Default qualifier 16 bit signed integer aligned vector of 4 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i16vec4, aligned_i16vec4, 8); + + + /// Default qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i32vec1, aligned_i32vec1, 4); + + /// Default qualifier 32 bit signed integer aligned vector of 2 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i32vec2, aligned_i32vec2, 8); + + /// Default qualifier 32 bit signed integer aligned vector of 3 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i32vec3, aligned_i32vec3, 16); + + /// Default qualifier 32 bit signed integer aligned vector of 4 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i32vec4, aligned_i32vec4, 16); + + + /// Default qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i64vec1, aligned_i64vec1, 8); + + /// Default qualifier 64 bit signed integer aligned vector of 2 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i64vec2, aligned_i64vec2, 16); + + /// Default qualifier 64 bit signed integer aligned vector of 3 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i64vec3, aligned_i64vec3, 32); + + /// Default qualifier 64 bit signed integer aligned vector of 4 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i64vec4, aligned_i64vec4, 32); + + + ///////////////////////////// + // Unsigned int vector types + + /// Low qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_uint8, aligned_lowp_uint8, 1); + + /// Low qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_uint16, aligned_lowp_uint16, 2); + + /// Low qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_uint32, aligned_lowp_uint32, 4); + + /// Low qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_uint64, aligned_lowp_uint64, 8); + + + /// Low qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_uint8_t, aligned_lowp_uint8_t, 1); + + /// Low qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_uint16_t, aligned_lowp_uint16_t, 2); + + /// Low qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_uint32_t, aligned_lowp_uint32_t, 4); + + /// Low qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_uint64_t, aligned_lowp_uint64_t, 8); + + + /// Low qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_u8, aligned_lowp_u8, 1); + + /// Low qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_u16, aligned_lowp_u16, 2); + + /// Low qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_u32, aligned_lowp_u32, 4); + + /// Low qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_u64, aligned_lowp_u64, 8); + + + /// Medium qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_uint8, aligned_mediump_uint8, 1); + + /// Medium qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_uint16, aligned_mediump_uint16, 2); + + /// Medium qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_uint32, aligned_mediump_uint32, 4); + + /// Medium qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_uint64, aligned_mediump_uint64, 8); + + + /// Medium qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_uint8_t, aligned_mediump_uint8_t, 1); + + /// Medium qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_uint16_t, aligned_mediump_uint16_t, 2); + + /// Medium qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_uint32_t, aligned_mediump_uint32_t, 4); + + /// Medium qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_uint64_t, aligned_mediump_uint64_t, 8); + + + /// Medium qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_u8, aligned_mediump_u8, 1); + + /// Medium qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_u16, aligned_mediump_u16, 2); + + /// Medium qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_u32, aligned_mediump_u32, 4); + + /// Medium qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_u64, aligned_mediump_u64, 8); + + + /// High qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_uint8, aligned_highp_uint8, 1); + + /// High qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_uint16, aligned_highp_uint16, 2); + + /// High qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_uint32, aligned_highp_uint32, 4); + + /// High qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_uint64, aligned_highp_uint64, 8); + + + /// High qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_uint8_t, aligned_highp_uint8_t, 1); + + /// High qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_uint16_t, aligned_highp_uint16_t, 2); + + /// High qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_uint32_t, aligned_highp_uint32_t, 4); + + /// High qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_uint64_t, aligned_highp_uint64_t, 8); + + + /// High qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_u8, aligned_highp_u8, 1); + + /// High qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_u16, aligned_highp_u16, 2); + + /// High qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_u32, aligned_highp_u32, 4); + + /// High qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_u64, aligned_highp_u64, 8); + + + /// Default qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uint8, aligned_uint8, 1); + + /// Default qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uint16, aligned_uint16, 2); + + /// Default qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uint32, aligned_uint32, 4); + + /// Default qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uint64, aligned_uint64, 8); + + + /// Default qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uint8_t, aligned_uint8_t, 1); + + /// Default qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uint16_t, aligned_uint16_t, 2); + + /// Default qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uint32_t, aligned_uint32_t, 4); + + /// Default qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uint64_t, aligned_uint64_t, 8); + + + /// Default qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u8, aligned_u8, 1); + + /// Default qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u16, aligned_u16, 2); + + /// Default qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u32, aligned_u32, 4); + + /// Default qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u64, aligned_u64, 8); + + + /// Default qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uvec1, aligned_uvec1, 4); + + /// Default qualifier 32 bit unsigned integer aligned vector of 2 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uvec2, aligned_uvec2, 8); + + /// Default qualifier 32 bit unsigned integer aligned vector of 3 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uvec3, aligned_uvec3, 16); + + /// Default qualifier 32 bit unsigned integer aligned vector of 4 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uvec4, aligned_uvec4, 16); + + + /// Default qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u8vec1, aligned_u8vec1, 1); + + /// Default qualifier 8 bit unsigned integer aligned vector of 2 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u8vec2, aligned_u8vec2, 2); + + /// Default qualifier 8 bit unsigned integer aligned vector of 3 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u8vec3, aligned_u8vec3, 4); + + /// Default qualifier 8 bit unsigned integer aligned vector of 4 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u8vec4, aligned_u8vec4, 4); + + + /// Default qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u16vec1, aligned_u16vec1, 2); + + /// Default qualifier 16 bit unsigned integer aligned vector of 2 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u16vec2, aligned_u16vec2, 4); + + /// Default qualifier 16 bit unsigned integer aligned vector of 3 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u16vec3, aligned_u16vec3, 8); + + /// Default qualifier 16 bit unsigned integer aligned vector of 4 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u16vec4, aligned_u16vec4, 8); + + + /// Default qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u32vec1, aligned_u32vec1, 4); + + /// Default qualifier 32 bit unsigned integer aligned vector of 2 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u32vec2, aligned_u32vec2, 8); + + /// Default qualifier 32 bit unsigned integer aligned vector of 3 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u32vec3, aligned_u32vec3, 16); + + /// Default qualifier 32 bit unsigned integer aligned vector of 4 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u32vec4, aligned_u32vec4, 16); + + + /// Default qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u64vec1, aligned_u64vec1, 8); + + /// Default qualifier 64 bit unsigned integer aligned vector of 2 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u64vec2, aligned_u64vec2, 16); + + /// Default qualifier 64 bit unsigned integer aligned vector of 3 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u64vec3, aligned_u64vec3, 32); + + /// Default qualifier 64 bit unsigned integer aligned vector of 4 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u64vec4, aligned_u64vec4, 32); + + + ////////////////////// + // Float vector types + + /// 32 bit single-qualifier floating-point aligned scalar. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(float32, aligned_float32, 4); + + /// 32 bit single-qualifier floating-point aligned scalar. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(float32_t, aligned_float32_t, 4); + + /// 32 bit single-qualifier floating-point aligned scalar. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(float32, aligned_f32, 4); + +# ifndef GLM_FORCE_SINGLE_ONLY + + /// 64 bit double-qualifier floating-point aligned scalar. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(float64, aligned_float64, 8); + + /// 64 bit double-qualifier floating-point aligned scalar. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(float64_t, aligned_float64_t, 8); + + /// 64 bit double-qualifier floating-point aligned scalar. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(float64, aligned_f64, 8); + +# endif//GLM_FORCE_SINGLE_ONLY + + + /// Single-qualifier floating-point aligned vector of 1 component. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(vec1, aligned_vec1, 4); + + /// Single-qualifier floating-point aligned vector of 2 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(vec2, aligned_vec2, 8); + + /// Single-qualifier floating-point aligned vector of 3 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(vec3, aligned_vec3, 16); + + /// Single-qualifier floating-point aligned vector of 4 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(vec4, aligned_vec4, 16); + + + /// Single-qualifier floating-point aligned vector of 1 component. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fvec1, aligned_fvec1, 4); + + /// Single-qualifier floating-point aligned vector of 2 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fvec2, aligned_fvec2, 8); + + /// Single-qualifier floating-point aligned vector of 3 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fvec3, aligned_fvec3, 16); + + /// Single-qualifier floating-point aligned vector of 4 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fvec4, aligned_fvec4, 16); + + + /// Single-qualifier floating-point aligned vector of 1 component. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32vec1, aligned_f32vec1, 4); + + /// Single-qualifier floating-point aligned vector of 2 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32vec2, aligned_f32vec2, 8); + + /// Single-qualifier floating-point aligned vector of 3 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32vec3, aligned_f32vec3, 16); + + /// Single-qualifier floating-point aligned vector of 4 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32vec4, aligned_f32vec4, 16); + + + /// Double-qualifier floating-point aligned vector of 1 component. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(dvec1, aligned_dvec1, 8); + + /// Double-qualifier floating-point aligned vector of 2 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(dvec2, aligned_dvec2, 16); + + /// Double-qualifier floating-point aligned vector of 3 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(dvec3, aligned_dvec3, 32); + + /// Double-qualifier floating-point aligned vector of 4 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(dvec4, aligned_dvec4, 32); + + +# ifndef GLM_FORCE_SINGLE_ONLY + + /// Double-qualifier floating-point aligned vector of 1 component. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64vec1, aligned_f64vec1, 8); + + /// Double-qualifier floating-point aligned vector of 2 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64vec2, aligned_f64vec2, 16); + + /// Double-qualifier floating-point aligned vector of 3 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64vec3, aligned_f64vec3, 32); + + /// Double-qualifier floating-point aligned vector of 4 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64vec4, aligned_f64vec4, 32); + +# endif//GLM_FORCE_SINGLE_ONLY + + ////////////////////// + // Float matrix types + + /// Single-qualifier floating-point aligned 1x1 matrix. + /// @see gtx_type_aligned + //typedef detail::tmat1 mat1; + + /// Single-qualifier floating-point aligned 2x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mat2, aligned_mat2, 16); + + /// Single-qualifier floating-point aligned 3x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mat3, aligned_mat3, 16); + + /// Single-qualifier floating-point aligned 4x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mat4, aligned_mat4, 16); + + + /// Single-qualifier floating-point aligned 1x1 matrix. + /// @see gtx_type_aligned + //typedef detail::tmat1x1 mat1; + + /// Single-qualifier floating-point aligned 2x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mat2x2, aligned_mat2x2, 16); + + /// Single-qualifier floating-point aligned 3x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mat3x3, aligned_mat3x3, 16); + + /// Single-qualifier floating-point aligned 4x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mat4x4, aligned_mat4x4, 16); + + + /// Single-qualifier floating-point aligned 1x1 matrix. + /// @see gtx_type_aligned + //typedef detail::tmat1x1 fmat1; + + /// Single-qualifier floating-point aligned 2x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat2x2, aligned_fmat2, 16); + + /// Single-qualifier floating-point aligned 3x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat3x3, aligned_fmat3, 16); + + /// Single-qualifier floating-point aligned 4x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat4x4, aligned_fmat4, 16); + + + /// Single-qualifier floating-point aligned 1x1 matrix. + /// @see gtx_type_aligned + //typedef f32 fmat1x1; + + /// Single-qualifier floating-point aligned 2x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat2x2, aligned_fmat2x2, 16); + + /// Single-qualifier floating-point aligned 2x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat2x3, aligned_fmat2x3, 16); + + /// Single-qualifier floating-point aligned 2x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat2x4, aligned_fmat2x4, 16); + + /// Single-qualifier floating-point aligned 3x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat3x2, aligned_fmat3x2, 16); + + /// Single-qualifier floating-point aligned 3x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat3x3, aligned_fmat3x3, 16); + + /// Single-qualifier floating-point aligned 3x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat3x4, aligned_fmat3x4, 16); + + /// Single-qualifier floating-point aligned 4x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat4x2, aligned_fmat4x2, 16); + + /// Single-qualifier floating-point aligned 4x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat4x3, aligned_fmat4x3, 16); + + /// Single-qualifier floating-point aligned 4x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat4x4, aligned_fmat4x4, 16); + + + /// Single-qualifier floating-point aligned 1x1 matrix. + /// @see gtx_type_aligned + //typedef detail::tmat1x1 f32mat1; + + /// Single-qualifier floating-point aligned 2x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat2x2, aligned_f32mat2, 16); + + /// Single-qualifier floating-point aligned 3x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat3x3, aligned_f32mat3, 16); + + /// Single-qualifier floating-point aligned 4x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat4x4, aligned_f32mat4, 16); + + + /// Single-qualifier floating-point aligned 1x1 matrix. + /// @see gtx_type_aligned + //typedef f32 f32mat1x1; + + /// Single-qualifier floating-point aligned 2x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat2x2, aligned_f32mat2x2, 16); + + /// Single-qualifier floating-point aligned 2x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat2x3, aligned_f32mat2x3, 16); + + /// Single-qualifier floating-point aligned 2x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat2x4, aligned_f32mat2x4, 16); + + /// Single-qualifier floating-point aligned 3x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat3x2, aligned_f32mat3x2, 16); + + /// Single-qualifier floating-point aligned 3x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat3x3, aligned_f32mat3x3, 16); + + /// Single-qualifier floating-point aligned 3x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat3x4, aligned_f32mat3x4, 16); + + /// Single-qualifier floating-point aligned 4x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat4x2, aligned_f32mat4x2, 16); + + /// Single-qualifier floating-point aligned 4x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat4x3, aligned_f32mat4x3, 16); + + /// Single-qualifier floating-point aligned 4x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat4x4, aligned_f32mat4x4, 16); + + +# ifndef GLM_FORCE_SINGLE_ONLY + + /// Double-qualifier floating-point aligned 1x1 matrix. + /// @see gtx_type_aligned + //typedef detail::tmat1x1 f64mat1; + + /// Double-qualifier floating-point aligned 2x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat2x2, aligned_f64mat2, 32); + + /// Double-qualifier floating-point aligned 3x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat3x3, aligned_f64mat3, 32); + + /// Double-qualifier floating-point aligned 4x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat4x4, aligned_f64mat4, 32); + + + /// Double-qualifier floating-point aligned 1x1 matrix. + /// @see gtx_type_aligned + //typedef f64 f64mat1x1; + + /// Double-qualifier floating-point aligned 2x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat2x2, aligned_f64mat2x2, 32); + + /// Double-qualifier floating-point aligned 2x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat2x3, aligned_f64mat2x3, 32); + + /// Double-qualifier floating-point aligned 2x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat2x4, aligned_f64mat2x4, 32); + + /// Double-qualifier floating-point aligned 3x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat3x2, aligned_f64mat3x2, 32); + + /// Double-qualifier floating-point aligned 3x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat3x3, aligned_f64mat3x3, 32); + + /// Double-qualifier floating-point aligned 3x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat3x4, aligned_f64mat3x4, 32); + + /// Double-qualifier floating-point aligned 4x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat4x2, aligned_f64mat4x2, 32); + + /// Double-qualifier floating-point aligned 4x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat4x3, aligned_f64mat4x3, 32); + + /// Double-qualifier floating-point aligned 4x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat4x4, aligned_f64mat4x4, 32); + +# endif//GLM_FORCE_SINGLE_ONLY + + + ////////////////////////// + // Quaternion types + + /// Single-qualifier floating-point aligned quaternion. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(quat, aligned_quat, 16); + + /// Single-qualifier floating-point aligned quaternion. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(quat, aligned_fquat, 16); + + /// Double-qualifier floating-point aligned quaternion. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(dquat, aligned_dquat, 32); + + /// Single-qualifier floating-point aligned quaternion. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32quat, aligned_f32quat, 16); + +# ifndef GLM_FORCE_SINGLE_ONLY + + /// Double-qualifier floating-point aligned quaternion. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64quat, aligned_f64quat, 32); + +# endif//GLM_FORCE_SINGLE_ONLY + + /// @} +}//namespace glm + +#include "type_aligned.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/type_aligned.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/type_aligned.inl new file mode 100644 index 0000000000000000000000000000000000000000..54c1b818b64af8a03a2ce5c93853a7fce5093ea1 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/type_aligned.inl @@ -0,0 +1,6 @@ +/// @ref gtc_type_aligned + +namespace glm +{ + +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/type_trait.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/type_trait.hpp new file mode 100644 index 0000000000000000000000000000000000000000..56685c8cb98c1861d9bbc59393b888f62c18f403 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/type_trait.hpp @@ -0,0 +1,85 @@ +/// @ref gtx_type_trait +/// @file glm/gtx/type_trait.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_type_trait GLM_GTX_type_trait +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Defines traits for each type. + +#pragma once + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_type_trait is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_type_trait extension included") +# endif +#endif + +// Dependency: +#include "../detail/qualifier.hpp" +#include "../gtc/quaternion.hpp" +#include "../gtx/dual_quaternion.hpp" + +namespace glm +{ + /// @addtogroup gtx_type_trait + /// @{ + + template + struct type + { + static bool const is_vec = false; + static bool const is_mat = false; + static bool const is_quat = false; + static length_t const components = 0; + static length_t const cols = 0; + static length_t const rows = 0; + }; + + template + struct type > + { + static bool const is_vec = true; + static bool const is_mat = false; + static bool const is_quat = false; + static length_t const components = L; + }; + + template + struct type > + { + static bool const is_vec = false; + static bool const is_mat = true; + static bool const is_quat = false; + static length_t const components = C; + static length_t const cols = C; + static length_t const rows = R; + }; + + template + struct type > + { + static bool const is_vec = false; + static bool const is_mat = false; + static bool const is_quat = true; + static length_t const components = 4; + }; + + template + struct type > + { + static bool const is_vec = false; + static bool const is_mat = false; + static bool const is_quat = true; + static length_t const components = 8; + }; + + /// @} +}//namespace glm + +#include "type_trait.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/type_trait.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/type_trait.inl new file mode 100644 index 0000000000000000000000000000000000000000..045de959cc21dcb60ba5e96424419e9b57824435 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/type_trait.inl @@ -0,0 +1,61 @@ +/// @ref gtx_type_trait + +namespace glm +{ + template + bool const type::is_vec; + template + bool const type::is_mat; + template + bool const type::is_quat; + template + length_t const type::components; + template + length_t const type::cols; + template + length_t const type::rows; + + // vec + template + bool const type >::is_vec; + template + bool const type >::is_mat; + template + bool const type >::is_quat; + template + length_t const type >::components; + + // mat + template + bool const type >::is_vec; + template + bool const type >::is_mat; + template + bool const type >::is_quat; + template + length_t const type >::components; + template + length_t const type >::cols; + template + length_t const type >::rows; + + // tquat + template + bool const type >::is_vec; + template + bool const type >::is_mat; + template + bool const type >::is_quat; + template + length_t const type >::components; + + // tdualquat + template + bool const type >::is_vec; + template + bool const type >::is_mat; + template + bool const type >::is_quat; + template + length_t const type >::components; +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/vec_swizzle.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/vec_swizzle.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f9e36f3e64bcd1efba56f486bd2af28528cff12f --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/vec_swizzle.hpp @@ -0,0 +1,2786 @@ +/// @ref gtx_vec_swizzle +/// @file glm/gtx/vec_swizzle.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_vec_swizzle GLM_GTX_vec_swizzle +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Functions to perform swizzle operation. + +#pragma once + +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_vec_swizzle is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_vec_swizzle extension included") +# endif +#endif + +namespace glm { + /// @addtogroup gtx_vec_swizzle + /// @{ + + // xx + template + GLM_INLINE glm::vec<2, T, Q> xx(const glm::vec<1, T, Q> &v) { + return glm::vec<2, T, Q>(v.x, v.x); + } + + template + GLM_INLINE glm::vec<2, T, Q> xx(const glm::vec<2, T, Q> &v) { + return glm::vec<2, T, Q>(v.x, v.x); + } + + template + GLM_INLINE glm::vec<2, T, Q> xx(const glm::vec<3, T, Q> &v) { + return glm::vec<2, T, Q>(v.x, v.x); + } + + template + GLM_INLINE glm::vec<2, T, Q> xx(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.x, v.x); + } + + // xy + template + GLM_INLINE glm::vec<2, T, Q> xy(const glm::vec<2, T, Q> &v) { + return glm::vec<2, T, Q>(v.x, v.y); + } + + template + GLM_INLINE glm::vec<2, T, Q> xy(const glm::vec<3, T, Q> &v) { + return glm::vec<2, T, Q>(v.x, v.y); + } + + template + GLM_INLINE glm::vec<2, T, Q> xy(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.x, v.y); + } + + // xz + template + GLM_INLINE glm::vec<2, T, Q> xz(const glm::vec<3, T, Q> &v) { + return glm::vec<2, T, Q>(v.x, v.z); + } + + template + GLM_INLINE glm::vec<2, T, Q> xz(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.x, v.z); + } + + // xw + template + GLM_INLINE glm::vec<2, T, Q> xw(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.x, v.w); + } + + // yx + template + GLM_INLINE glm::vec<2, T, Q> yx(const glm::vec<2, T, Q> &v) { + return glm::vec<2, T, Q>(v.y, v.x); + } + + template + GLM_INLINE glm::vec<2, T, Q> yx(const glm::vec<3, T, Q> &v) { + return glm::vec<2, T, Q>(v.y, v.x); + } + + template + GLM_INLINE glm::vec<2, T, Q> yx(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.y, v.x); + } + + // yy + template + GLM_INLINE glm::vec<2, T, Q> yy(const glm::vec<2, T, Q> &v) { + return glm::vec<2, T, Q>(v.y, v.y); + } + + template + GLM_INLINE glm::vec<2, T, Q> yy(const glm::vec<3, T, Q> &v) { + return glm::vec<2, T, Q>(v.y, v.y); + } + + template + GLM_INLINE glm::vec<2, T, Q> yy(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.y, v.y); + } + + // yz + template + GLM_INLINE glm::vec<2, T, Q> yz(const glm::vec<3, T, Q> &v) { + return glm::vec<2, T, Q>(v.y, v.z); + } + + template + GLM_INLINE glm::vec<2, T, Q> yz(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.y, v.z); + } + + // yw + template + GLM_INLINE glm::vec<2, T, Q> yw(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.y, v.w); + } + + // zx + template + GLM_INLINE glm::vec<2, T, Q> zx(const glm::vec<3, T, Q> &v) { + return glm::vec<2, T, Q>(v.z, v.x); + } + + template + GLM_INLINE glm::vec<2, T, Q> zx(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.z, v.x); + } + + // zy + template + GLM_INLINE glm::vec<2, T, Q> zy(const glm::vec<3, T, Q> &v) { + return glm::vec<2, T, Q>(v.z, v.y); + } + + template + GLM_INLINE glm::vec<2, T, Q> zy(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.z, v.y); + } + + // zz + template + GLM_INLINE glm::vec<2, T, Q> zz(const glm::vec<3, T, Q> &v) { + return glm::vec<2, T, Q>(v.z, v.z); + } + + template + GLM_INLINE glm::vec<2, T, Q> zz(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.z, v.z); + } + + // zw + template + GLM_INLINE glm::vec<2, T, Q> zw(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.z, v.w); + } + + // wx + template + GLM_INLINE glm::vec<2, T, Q> wx(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.w, v.x); + } + + // wy + template + GLM_INLINE glm::vec<2, T, Q> wy(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.w, v.y); + } + + // wz + template + GLM_INLINE glm::vec<2, T, Q> wz(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.w, v.z); + } + + // ww + template + GLM_INLINE glm::vec<2, T, Q> ww(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.w, v.w); + } + + // xxx + template + GLM_INLINE glm::vec<3, T, Q> xxx(const glm::vec<1, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.x, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> xxx(const glm::vec<2, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.x, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> xxx(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.x, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> xxx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.x, v.x); + } + + // xxy + template + GLM_INLINE glm::vec<3, T, Q> xxy(const glm::vec<2, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.x, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> xxy(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.x, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> xxy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.x, v.y); + } + + // xxz + template + GLM_INLINE glm::vec<3, T, Q> xxz(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.x, v.z); + } + + template + GLM_INLINE glm::vec<3, T, Q> xxz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.x, v.z); + } + + // xxw + template + GLM_INLINE glm::vec<3, T, Q> xxw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.x, v.w); + } + + // xyx + template + GLM_INLINE glm::vec<3, T, Q> xyx(const glm::vec<2, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.y, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> xyx(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.y, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> xyx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.y, v.x); + } + + // xyy + template + GLM_INLINE glm::vec<3, T, Q> xyy(const glm::vec<2, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.y, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> xyy(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.y, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> xyy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.y, v.y); + } + + // xyz + template + GLM_INLINE glm::vec<3, T, Q> xyz(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.y, v.z); + } + + template + GLM_INLINE glm::vec<3, T, Q> xyz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.y, v.z); + } + + // xyw + template + GLM_INLINE glm::vec<3, T, Q> xyw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.y, v.w); + } + + // xzx + template + GLM_INLINE glm::vec<3, T, Q> xzx(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.z, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> xzx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.z, v.x); + } + + // xzy + template + GLM_INLINE glm::vec<3, T, Q> xzy(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.z, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> xzy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.z, v.y); + } + + // xzz + template + GLM_INLINE glm::vec<3, T, Q> xzz(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.z, v.z); + } + + template + GLM_INLINE glm::vec<3, T, Q> xzz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.z, v.z); + } + + // xzw + template + GLM_INLINE glm::vec<3, T, Q> xzw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.z, v.w); + } + + // xwx + template + GLM_INLINE glm::vec<3, T, Q> xwx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.w, v.x); + } + + // xwy + template + GLM_INLINE glm::vec<3, T, Q> xwy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.w, v.y); + } + + // xwz + template + GLM_INLINE glm::vec<3, T, Q> xwz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.w, v.z); + } + + // xww + template + GLM_INLINE glm::vec<3, T, Q> xww(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.w, v.w); + } + + // yxx + template + GLM_INLINE glm::vec<3, T, Q> yxx(const glm::vec<2, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.x, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> yxx(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.x, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> yxx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.x, v.x); + } + + // yxy + template + GLM_INLINE glm::vec<3, T, Q> yxy(const glm::vec<2, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.x, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> yxy(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.x, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> yxy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.x, v.y); + } + + // yxz + template + GLM_INLINE glm::vec<3, T, Q> yxz(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.x, v.z); + } + + template + GLM_INLINE glm::vec<3, T, Q> yxz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.x, v.z); + } + + // yxw + template + GLM_INLINE glm::vec<3, T, Q> yxw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.x, v.w); + } + + // yyx + template + GLM_INLINE glm::vec<3, T, Q> yyx(const glm::vec<2, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.y, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> yyx(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.y, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> yyx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.y, v.x); + } + + // yyy + template + GLM_INLINE glm::vec<3, T, Q> yyy(const glm::vec<2, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.y, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> yyy(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.y, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> yyy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.y, v.y); + } + + // yyz + template + GLM_INLINE glm::vec<3, T, Q> yyz(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.y, v.z); + } + + template + GLM_INLINE glm::vec<3, T, Q> yyz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.y, v.z); + } + + // yyw + template + GLM_INLINE glm::vec<3, T, Q> yyw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.y, v.w); + } + + // yzx + template + GLM_INLINE glm::vec<3, T, Q> yzx(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.z, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> yzx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.z, v.x); + } + + // yzy + template + GLM_INLINE glm::vec<3, T, Q> yzy(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.z, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> yzy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.z, v.y); + } + + // yzz + template + GLM_INLINE glm::vec<3, T, Q> yzz(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.z, v.z); + } + + template + GLM_INLINE glm::vec<3, T, Q> yzz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.z, v.z); + } + + // yzw + template + GLM_INLINE glm::vec<3, T, Q> yzw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.z, v.w); + } + + // ywx + template + GLM_INLINE glm::vec<3, T, Q> ywx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.w, v.x); + } + + // ywy + template + GLM_INLINE glm::vec<3, T, Q> ywy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.w, v.y); + } + + // ywz + template + GLM_INLINE glm::vec<3, T, Q> ywz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.w, v.z); + } + + // yww + template + GLM_INLINE glm::vec<3, T, Q> yww(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.w, v.w); + } + + // zxx + template + GLM_INLINE glm::vec<3, T, Q> zxx(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.x, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> zxx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.x, v.x); + } + + // zxy + template + GLM_INLINE glm::vec<3, T, Q> zxy(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.x, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> zxy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.x, v.y); + } + + // zxz + template + GLM_INLINE glm::vec<3, T, Q> zxz(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.x, v.z); + } + + template + GLM_INLINE glm::vec<3, T, Q> zxz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.x, v.z); + } + + // zxw + template + GLM_INLINE glm::vec<3, T, Q> zxw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.x, v.w); + } + + // zyx + template + GLM_INLINE glm::vec<3, T, Q> zyx(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.y, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> zyx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.y, v.x); + } + + // zyy + template + GLM_INLINE glm::vec<3, T, Q> zyy(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.y, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> zyy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.y, v.y); + } + + // zyz + template + GLM_INLINE glm::vec<3, T, Q> zyz(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.y, v.z); + } + + template + GLM_INLINE glm::vec<3, T, Q> zyz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.y, v.z); + } + + // zyw + template + GLM_INLINE glm::vec<3, T, Q> zyw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.y, v.w); + } + + // zzx + template + GLM_INLINE glm::vec<3, T, Q> zzx(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.z, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> zzx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.z, v.x); + } + + // zzy + template + GLM_INLINE glm::vec<3, T, Q> zzy(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.z, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> zzy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.z, v.y); + } + + // zzz + template + GLM_INLINE glm::vec<3, T, Q> zzz(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.z, v.z); + } + + template + GLM_INLINE glm::vec<3, T, Q> zzz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.z, v.z); + } + + // zzw + template + GLM_INLINE glm::vec<3, T, Q> zzw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.z, v.w); + } + + // zwx + template + GLM_INLINE glm::vec<3, T, Q> zwx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.w, v.x); + } + + // zwy + template + GLM_INLINE glm::vec<3, T, Q> zwy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.w, v.y); + } + + // zwz + template + GLM_INLINE glm::vec<3, T, Q> zwz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.w, v.z); + } + + // zww + template + GLM_INLINE glm::vec<3, T, Q> zww(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.w, v.w); + } + + // wxx + template + GLM_INLINE glm::vec<3, T, Q> wxx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.x, v.x); + } + + // wxy + template + GLM_INLINE glm::vec<3, T, Q> wxy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.x, v.y); + } + + // wxz + template + GLM_INLINE glm::vec<3, T, Q> wxz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.x, v.z); + } + + // wxw + template + GLM_INLINE glm::vec<3, T, Q> wxw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.x, v.w); + } + + // wyx + template + GLM_INLINE glm::vec<3, T, Q> wyx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.y, v.x); + } + + // wyy + template + GLM_INLINE glm::vec<3, T, Q> wyy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.y, v.y); + } + + // wyz + template + GLM_INLINE glm::vec<3, T, Q> wyz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.y, v.z); + } + + // wyw + template + GLM_INLINE glm::vec<3, T, Q> wyw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.y, v.w); + } + + // wzx + template + GLM_INLINE glm::vec<3, T, Q> wzx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.z, v.x); + } + + // wzy + template + GLM_INLINE glm::vec<3, T, Q> wzy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.z, v.y); + } + + // wzz + template + GLM_INLINE glm::vec<3, T, Q> wzz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.z, v.z); + } + + // wzw + template + GLM_INLINE glm::vec<3, T, Q> wzw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.z, v.w); + } + + // wwx + template + GLM_INLINE glm::vec<3, T, Q> wwx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.w, v.x); + } + + // wwy + template + GLM_INLINE glm::vec<3, T, Q> wwy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.w, v.y); + } + + // wwz + template + GLM_INLINE glm::vec<3, T, Q> wwz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.w, v.z); + } + + // www + template + GLM_INLINE glm::vec<3, T, Q> www(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.w, v.w); + } + + // xxxx + template + GLM_INLINE glm::vec<4, T, Q> xxxx(const glm::vec<1, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxxx(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxxx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.x, v.x); + } + + // xxxy + template + GLM_INLINE glm::vec<4, T, Q> xxxy(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxxy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.x, v.y); + } + + // xxxz + template + GLM_INLINE glm::vec<4, T, Q> xxxz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.x, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.x, v.z); + } + + // xxxw + template + GLM_INLINE glm::vec<4, T, Q> xxxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.x, v.w); + } + + // xxyx + template + GLM_INLINE glm::vec<4, T, Q> xxyx(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxyx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.y, v.x); + } + + // xxyy + template + GLM_INLINE glm::vec<4, T, Q> xxyy(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxyy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.y, v.y); + } + + // xxyz + template + GLM_INLINE glm::vec<4, T, Q> xxyz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.y, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.y, v.z); + } + + // xxyw + template + GLM_INLINE glm::vec<4, T, Q> xxyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.y, v.w); + } + + // xxzx + template + GLM_INLINE glm::vec<4, T, Q> xxzx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.z, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.z, v.x); + } + + // xxzy + template + GLM_INLINE glm::vec<4, T, Q> xxzy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.z, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.z, v.y); + } + + // xxzz + template + GLM_INLINE glm::vec<4, T, Q> xxzz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.z, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.z, v.z); + } + + // xxzw + template + GLM_INLINE glm::vec<4, T, Q> xxzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.z, v.w); + } + + // xxwx + template + GLM_INLINE glm::vec<4, T, Q> xxwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.w, v.x); + } + + // xxwy + template + GLM_INLINE glm::vec<4, T, Q> xxwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.w, v.y); + } + + // xxwz + template + GLM_INLINE glm::vec<4, T, Q> xxwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.w, v.z); + } + + // xxww + template + GLM_INLINE glm::vec<4, T, Q> xxww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.w, v.w); + } + + // xyxx + template + GLM_INLINE glm::vec<4, T, Q> xyxx(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyxx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.x, v.x); + } + + // xyxy + template + GLM_INLINE glm::vec<4, T, Q> xyxy(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyxy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.x, v.y); + } + + // xyxz + template + GLM_INLINE glm::vec<4, T, Q> xyxz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.x, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.x, v.z); + } + + // xyxw + template + GLM_INLINE glm::vec<4, T, Q> xyxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.x, v.w); + } + + // xyyx + template + GLM_INLINE glm::vec<4, T, Q> xyyx(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyyx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.y, v.x); + } + + // xyyy + template + GLM_INLINE glm::vec<4, T, Q> xyyy(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyyy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.y, v.y); + } + + // xyyz + template + GLM_INLINE glm::vec<4, T, Q> xyyz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.y, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.y, v.z); + } + + // xyyw + template + GLM_INLINE glm::vec<4, T, Q> xyyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.y, v.w); + } + + // xyzx + template + GLM_INLINE glm::vec<4, T, Q> xyzx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.z, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.z, v.x); + } + + // xyzy + template + GLM_INLINE glm::vec<4, T, Q> xyzy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.z, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.z, v.y); + } + + // xyzz + template + GLM_INLINE glm::vec<4, T, Q> xyzz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.z, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.z, v.z); + } + + // xyzw + template + GLM_INLINE glm::vec<4, T, Q> xyzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.z, v.w); + } + + // xywx + template + GLM_INLINE glm::vec<4, T, Q> xywx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.w, v.x); + } + + // xywy + template + GLM_INLINE glm::vec<4, T, Q> xywy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.w, v.y); + } + + // xywz + template + GLM_INLINE glm::vec<4, T, Q> xywz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.w, v.z); + } + + // xyww + template + GLM_INLINE glm::vec<4, T, Q> xyww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.w, v.w); + } + + // xzxx + template + GLM_INLINE glm::vec<4, T, Q> xzxx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xzxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.x, v.x); + } + + // xzxy + template + GLM_INLINE glm::vec<4, T, Q> xzxy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xzxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.x, v.y); + } + + // xzxz + template + GLM_INLINE glm::vec<4, T, Q> xzxz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.x, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> xzxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.x, v.z); + } + + // xzxw + template + GLM_INLINE glm::vec<4, T, Q> xzxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.x, v.w); + } + + // xzyx + template + GLM_INLINE glm::vec<4, T, Q> xzyx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xzyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.y, v.x); + } + + // xzyy + template + GLM_INLINE glm::vec<4, T, Q> xzyy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xzyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.y, v.y); + } + + // xzyz + template + GLM_INLINE glm::vec<4, T, Q> xzyz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.y, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> xzyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.y, v.z); + } + + // xzyw + template + GLM_INLINE glm::vec<4, T, Q> xzyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.y, v.w); + } + + // xzzx + template + GLM_INLINE glm::vec<4, T, Q> xzzx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.z, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xzzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.z, v.x); + } + + // xzzy + template + GLM_INLINE glm::vec<4, T, Q> xzzy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.z, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xzzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.z, v.y); + } + + // xzzz + template + GLM_INLINE glm::vec<4, T, Q> xzzz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.z, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> xzzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.z, v.z); + } + + // xzzw + template + GLM_INLINE glm::vec<4, T, Q> xzzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.z, v.w); + } + + // xzwx + template + GLM_INLINE glm::vec<4, T, Q> xzwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.w, v.x); + } + + // xzwy + template + GLM_INLINE glm::vec<4, T, Q> xzwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.w, v.y); + } + + // xzwz + template + GLM_INLINE glm::vec<4, T, Q> xzwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.w, v.z); + } + + // xzww + template + GLM_INLINE glm::vec<4, T, Q> xzww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.w, v.w); + } + + // xwxx + template + GLM_INLINE glm::vec<4, T, Q> xwxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.x, v.x); + } + + // xwxy + template + GLM_INLINE glm::vec<4, T, Q> xwxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.x, v.y); + } + + // xwxz + template + GLM_INLINE glm::vec<4, T, Q> xwxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.x, v.z); + } + + // xwxw + template + GLM_INLINE glm::vec<4, T, Q> xwxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.x, v.w); + } + + // xwyx + template + GLM_INLINE glm::vec<4, T, Q> xwyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.y, v.x); + } + + // xwyy + template + GLM_INLINE glm::vec<4, T, Q> xwyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.y, v.y); + } + + // xwyz + template + GLM_INLINE glm::vec<4, T, Q> xwyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.y, v.z); + } + + // xwyw + template + GLM_INLINE glm::vec<4, T, Q> xwyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.y, v.w); + } + + // xwzx + template + GLM_INLINE glm::vec<4, T, Q> xwzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.z, v.x); + } + + // xwzy + template + GLM_INLINE glm::vec<4, T, Q> xwzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.z, v.y); + } + + // xwzz + template + GLM_INLINE glm::vec<4, T, Q> xwzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.z, v.z); + } + + // xwzw + template + GLM_INLINE glm::vec<4, T, Q> xwzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.z, v.w); + } + + // xwwx + template + GLM_INLINE glm::vec<4, T, Q> xwwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.w, v.x); + } + + // xwwy + template + GLM_INLINE glm::vec<4, T, Q> xwwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.w, v.y); + } + + // xwwz + template + GLM_INLINE glm::vec<4, T, Q> xwwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.w, v.z); + } + + // xwww + template + GLM_INLINE glm::vec<4, T, Q> xwww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.w, v.w); + } + + // yxxx + template + GLM_INLINE glm::vec<4, T, Q> yxxx(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxxx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.x, v.x); + } + + // yxxy + template + GLM_INLINE glm::vec<4, T, Q> yxxy(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxxy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.x, v.y); + } + + // yxxz + template + GLM_INLINE glm::vec<4, T, Q> yxxz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.x, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.x, v.z); + } + + // yxxw + template + GLM_INLINE glm::vec<4, T, Q> yxxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.x, v.w); + } + + // yxyx + template + GLM_INLINE glm::vec<4, T, Q> yxyx(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxyx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.y, v.x); + } + + // yxyy + template + GLM_INLINE glm::vec<4, T, Q> yxyy(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxyy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.y, v.y); + } + + // yxyz + template + GLM_INLINE glm::vec<4, T, Q> yxyz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.y, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.y, v.z); + } + + // yxyw + template + GLM_INLINE glm::vec<4, T, Q> yxyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.y, v.w); + } + + // yxzx + template + GLM_INLINE glm::vec<4, T, Q> yxzx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.z, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.z, v.x); + } + + // yxzy + template + GLM_INLINE glm::vec<4, T, Q> yxzy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.z, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.z, v.y); + } + + // yxzz + template + GLM_INLINE glm::vec<4, T, Q> yxzz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.z, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.z, v.z); + } + + // yxzw + template + GLM_INLINE glm::vec<4, T, Q> yxzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.z, v.w); + } + + // yxwx + template + GLM_INLINE glm::vec<4, T, Q> yxwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.w, v.x); + } + + // yxwy + template + GLM_INLINE glm::vec<4, T, Q> yxwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.w, v.y); + } + + // yxwz + template + GLM_INLINE glm::vec<4, T, Q> yxwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.w, v.z); + } + + // yxww + template + GLM_INLINE glm::vec<4, T, Q> yxww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.w, v.w); + } + + // yyxx + template + GLM_INLINE glm::vec<4, T, Q> yyxx(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyxx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.x, v.x); + } + + // yyxy + template + GLM_INLINE glm::vec<4, T, Q> yyxy(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyxy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.x, v.y); + } + + // yyxz + template + GLM_INLINE glm::vec<4, T, Q> yyxz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.x, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.x, v.z); + } + + // yyxw + template + GLM_INLINE glm::vec<4, T, Q> yyxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.x, v.w); + } + + // yyyx + template + GLM_INLINE glm::vec<4, T, Q> yyyx(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyyx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.y, v.x); + } + + // yyyy + template + GLM_INLINE glm::vec<4, T, Q> yyyy(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyyy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.y, v.y); + } + + // yyyz + template + GLM_INLINE glm::vec<4, T, Q> yyyz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.y, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.y, v.z); + } + + // yyyw + template + GLM_INLINE glm::vec<4, T, Q> yyyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.y, v.w); + } + + // yyzx + template + GLM_INLINE glm::vec<4, T, Q> yyzx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.z, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.z, v.x); + } + + // yyzy + template + GLM_INLINE glm::vec<4, T, Q> yyzy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.z, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.z, v.y); + } + + // yyzz + template + GLM_INLINE glm::vec<4, T, Q> yyzz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.z, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.z, v.z); + } + + // yyzw + template + GLM_INLINE glm::vec<4, T, Q> yyzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.z, v.w); + } + + // yywx + template + GLM_INLINE glm::vec<4, T, Q> yywx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.w, v.x); + } + + // yywy + template + GLM_INLINE glm::vec<4, T, Q> yywy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.w, v.y); + } + + // yywz + template + GLM_INLINE glm::vec<4, T, Q> yywz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.w, v.z); + } + + // yyww + template + GLM_INLINE glm::vec<4, T, Q> yyww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.w, v.w); + } + + // yzxx + template + GLM_INLINE glm::vec<4, T, Q> yzxx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yzxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.x, v.x); + } + + // yzxy + template + GLM_INLINE glm::vec<4, T, Q> yzxy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yzxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.x, v.y); + } + + // yzxz + template + GLM_INLINE glm::vec<4, T, Q> yzxz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.x, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> yzxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.x, v.z); + } + + // yzxw + template + GLM_INLINE glm::vec<4, T, Q> yzxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.x, v.w); + } + + // yzyx + template + GLM_INLINE glm::vec<4, T, Q> yzyx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yzyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.y, v.x); + } + + // yzyy + template + GLM_INLINE glm::vec<4, T, Q> yzyy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yzyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.y, v.y); + } + + // yzyz + template + GLM_INLINE glm::vec<4, T, Q> yzyz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.y, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> yzyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.y, v.z); + } + + // yzyw + template + GLM_INLINE glm::vec<4, T, Q> yzyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.y, v.w); + } + + // yzzx + template + GLM_INLINE glm::vec<4, T, Q> yzzx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.z, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yzzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.z, v.x); + } + + // yzzy + template + GLM_INLINE glm::vec<4, T, Q> yzzy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.z, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yzzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.z, v.y); + } + + // yzzz + template + GLM_INLINE glm::vec<4, T, Q> yzzz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.z, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> yzzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.z, v.z); + } + + // yzzw + template + GLM_INLINE glm::vec<4, T, Q> yzzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.z, v.w); + } + + // yzwx + template + GLM_INLINE glm::vec<4, T, Q> yzwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.w, v.x); + } + + // yzwy + template + GLM_INLINE glm::vec<4, T, Q> yzwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.w, v.y); + } + + // yzwz + template + GLM_INLINE glm::vec<4, T, Q> yzwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.w, v.z); + } + + // yzww + template + GLM_INLINE glm::vec<4, T, Q> yzww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.w, v.w); + } + + // ywxx + template + GLM_INLINE glm::vec<4, T, Q> ywxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.x, v.x); + } + + // ywxy + template + GLM_INLINE glm::vec<4, T, Q> ywxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.x, v.y); + } + + // ywxz + template + GLM_INLINE glm::vec<4, T, Q> ywxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.x, v.z); + } + + // ywxw + template + GLM_INLINE glm::vec<4, T, Q> ywxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.x, v.w); + } + + // ywyx + template + GLM_INLINE glm::vec<4, T, Q> ywyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.y, v.x); + } + + // ywyy + template + GLM_INLINE glm::vec<4, T, Q> ywyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.y, v.y); + } + + // ywyz + template + GLM_INLINE glm::vec<4, T, Q> ywyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.y, v.z); + } + + // ywyw + template + GLM_INLINE glm::vec<4, T, Q> ywyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.y, v.w); + } + + // ywzx + template + GLM_INLINE glm::vec<4, T, Q> ywzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.z, v.x); + } + + // ywzy + template + GLM_INLINE glm::vec<4, T, Q> ywzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.z, v.y); + } + + // ywzz + template + GLM_INLINE glm::vec<4, T, Q> ywzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.z, v.z); + } + + // ywzw + template + GLM_INLINE glm::vec<4, T, Q> ywzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.z, v.w); + } + + // ywwx + template + GLM_INLINE glm::vec<4, T, Q> ywwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.w, v.x); + } + + // ywwy + template + GLM_INLINE glm::vec<4, T, Q> ywwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.w, v.y); + } + + // ywwz + template + GLM_INLINE glm::vec<4, T, Q> ywwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.w, v.z); + } + + // ywww + template + GLM_INLINE glm::vec<4, T, Q> ywww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.w, v.w); + } + + // zxxx + template + GLM_INLINE glm::vec<4, T, Q> zxxx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> zxxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.x, v.x); + } + + // zxxy + template + GLM_INLINE glm::vec<4, T, Q> zxxy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> zxxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.x, v.y); + } + + // zxxz + template + GLM_INLINE glm::vec<4, T, Q> zxxz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.x, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> zxxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.x, v.z); + } + + // zxxw + template + GLM_INLINE glm::vec<4, T, Q> zxxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.x, v.w); + } + + // zxyx + template + GLM_INLINE glm::vec<4, T, Q> zxyx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> zxyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.y, v.x); + } + + // zxyy + template + GLM_INLINE glm::vec<4, T, Q> zxyy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> zxyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.y, v.y); + } + + // zxyz + template + GLM_INLINE glm::vec<4, T, Q> zxyz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.y, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> zxyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.y, v.z); + } + + // zxyw + template + GLM_INLINE glm::vec<4, T, Q> zxyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.y, v.w); + } + + // zxzx + template + GLM_INLINE glm::vec<4, T, Q> zxzx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.z, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> zxzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.z, v.x); + } + + // zxzy + template + GLM_INLINE glm::vec<4, T, Q> zxzy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.z, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> zxzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.z, v.y); + } + + // zxzz + template + GLM_INLINE glm::vec<4, T, Q> zxzz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.z, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> zxzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.z, v.z); + } + + // zxzw + template + GLM_INLINE glm::vec<4, T, Q> zxzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.z, v.w); + } + + // zxwx + template + GLM_INLINE glm::vec<4, T, Q> zxwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.w, v.x); + } + + // zxwy + template + GLM_INLINE glm::vec<4, T, Q> zxwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.w, v.y); + } + + // zxwz + template + GLM_INLINE glm::vec<4, T, Q> zxwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.w, v.z); + } + + // zxww + template + GLM_INLINE glm::vec<4, T, Q> zxww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.w, v.w); + } + + // zyxx + template + GLM_INLINE glm::vec<4, T, Q> zyxx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> zyxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.x, v.x); + } + + // zyxy + template + GLM_INLINE glm::vec<4, T, Q> zyxy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> zyxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.x, v.y); + } + + // zyxz + template + GLM_INLINE glm::vec<4, T, Q> zyxz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.x, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> zyxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.x, v.z); + } + + // zyxw + template + GLM_INLINE glm::vec<4, T, Q> zyxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.x, v.w); + } + + // zyyx + template + GLM_INLINE glm::vec<4, T, Q> zyyx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> zyyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.y, v.x); + } + + // zyyy + template + GLM_INLINE glm::vec<4, T, Q> zyyy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> zyyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.y, v.y); + } + + // zyyz + template + GLM_INLINE glm::vec<4, T, Q> zyyz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.y, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> zyyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.y, v.z); + } + + // zyyw + template + GLM_INLINE glm::vec<4, T, Q> zyyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.y, v.w); + } + + // zyzx + template + GLM_INLINE glm::vec<4, T, Q> zyzx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.z, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> zyzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.z, v.x); + } + + // zyzy + template + GLM_INLINE glm::vec<4, T, Q> zyzy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.z, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> zyzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.z, v.y); + } + + // zyzz + template + GLM_INLINE glm::vec<4, T, Q> zyzz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.z, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> zyzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.z, v.z); + } + + // zyzw + template + GLM_INLINE glm::vec<4, T, Q> zyzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.z, v.w); + } + + // zywx + template + GLM_INLINE glm::vec<4, T, Q> zywx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.w, v.x); + } + + // zywy + template + GLM_INLINE glm::vec<4, T, Q> zywy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.w, v.y); + } + + // zywz + template + GLM_INLINE glm::vec<4, T, Q> zywz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.w, v.z); + } + + // zyww + template + GLM_INLINE glm::vec<4, T, Q> zyww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.w, v.w); + } + + // zzxx + template + GLM_INLINE glm::vec<4, T, Q> zzxx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> zzxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.x, v.x); + } + + // zzxy + template + GLM_INLINE glm::vec<4, T, Q> zzxy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> zzxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.x, v.y); + } + + // zzxz + template + GLM_INLINE glm::vec<4, T, Q> zzxz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.x, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> zzxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.x, v.z); + } + + // zzxw + template + GLM_INLINE glm::vec<4, T, Q> zzxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.x, v.w); + } + + // zzyx + template + GLM_INLINE glm::vec<4, T, Q> zzyx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> zzyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.y, v.x); + } + + // zzyy + template + GLM_INLINE glm::vec<4, T, Q> zzyy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> zzyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.y, v.y); + } + + // zzyz + template + GLM_INLINE glm::vec<4, T, Q> zzyz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.y, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> zzyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.y, v.z); + } + + // zzyw + template + GLM_INLINE glm::vec<4, T, Q> zzyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.y, v.w); + } + + // zzzx + template + GLM_INLINE glm::vec<4, T, Q> zzzx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.z, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> zzzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.z, v.x); + } + + // zzzy + template + GLM_INLINE glm::vec<4, T, Q> zzzy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.z, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> zzzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.z, v.y); + } + + // zzzz + template + GLM_INLINE glm::vec<4, T, Q> zzzz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.z, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> zzzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.z, v.z); + } + + // zzzw + template + GLM_INLINE glm::vec<4, T, Q> zzzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.z, v.w); + } + + // zzwx + template + GLM_INLINE glm::vec<4, T, Q> zzwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.w, v.x); + } + + // zzwy + template + GLM_INLINE glm::vec<4, T, Q> zzwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.w, v.y); + } + + // zzwz + template + GLM_INLINE glm::vec<4, T, Q> zzwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.w, v.z); + } + + // zzww + template + GLM_INLINE glm::vec<4, T, Q> zzww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.w, v.w); + } + + // zwxx + template + GLM_INLINE glm::vec<4, T, Q> zwxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.x, v.x); + } + + // zwxy + template + GLM_INLINE glm::vec<4, T, Q> zwxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.x, v.y); + } + + // zwxz + template + GLM_INLINE glm::vec<4, T, Q> zwxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.x, v.z); + } + + // zwxw + template + GLM_INLINE glm::vec<4, T, Q> zwxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.x, v.w); + } + + // zwyx + template + GLM_INLINE glm::vec<4, T, Q> zwyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.y, v.x); + } + + // zwyy + template + GLM_INLINE glm::vec<4, T, Q> zwyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.y, v.y); + } + + // zwyz + template + GLM_INLINE glm::vec<4, T, Q> zwyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.y, v.z); + } + + // zwyw + template + GLM_INLINE glm::vec<4, T, Q> zwyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.y, v.w); + } + + // zwzx + template + GLM_INLINE glm::vec<4, T, Q> zwzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.z, v.x); + } + + // zwzy + template + GLM_INLINE glm::vec<4, T, Q> zwzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.z, v.y); + } + + // zwzz + template + GLM_INLINE glm::vec<4, T, Q> zwzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.z, v.z); + } + + // zwzw + template + GLM_INLINE glm::vec<4, T, Q> zwzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.z, v.w); + } + + // zwwx + template + GLM_INLINE glm::vec<4, T, Q> zwwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.w, v.x); + } + + // zwwy + template + GLM_INLINE glm::vec<4, T, Q> zwwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.w, v.y); + } + + // zwwz + template + GLM_INLINE glm::vec<4, T, Q> zwwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.w, v.z); + } + + // zwww + template + GLM_INLINE glm::vec<4, T, Q> zwww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.w, v.w); + } + + // wxxx + template + GLM_INLINE glm::vec<4, T, Q> wxxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.x, v.x); + } + + // wxxy + template + GLM_INLINE glm::vec<4, T, Q> wxxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.x, v.y); + } + + // wxxz + template + GLM_INLINE glm::vec<4, T, Q> wxxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.x, v.z); + } + + // wxxw + template + GLM_INLINE glm::vec<4, T, Q> wxxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.x, v.w); + } + + // wxyx + template + GLM_INLINE glm::vec<4, T, Q> wxyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.y, v.x); + } + + // wxyy + template + GLM_INLINE glm::vec<4, T, Q> wxyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.y, v.y); + } + + // wxyz + template + GLM_INLINE glm::vec<4, T, Q> wxyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.y, v.z); + } + + // wxyw + template + GLM_INLINE glm::vec<4, T, Q> wxyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.y, v.w); + } + + // wxzx + template + GLM_INLINE glm::vec<4, T, Q> wxzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.z, v.x); + } + + // wxzy + template + GLM_INLINE glm::vec<4, T, Q> wxzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.z, v.y); + } + + // wxzz + template + GLM_INLINE glm::vec<4, T, Q> wxzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.z, v.z); + } + + // wxzw + template + GLM_INLINE glm::vec<4, T, Q> wxzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.z, v.w); + } + + // wxwx + template + GLM_INLINE glm::vec<4, T, Q> wxwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.w, v.x); + } + + // wxwy + template + GLM_INLINE glm::vec<4, T, Q> wxwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.w, v.y); + } + + // wxwz + template + GLM_INLINE glm::vec<4, T, Q> wxwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.w, v.z); + } + + // wxww + template + GLM_INLINE glm::vec<4, T, Q> wxww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.w, v.w); + } + + // wyxx + template + GLM_INLINE glm::vec<4, T, Q> wyxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.x, v.x); + } + + // wyxy + template + GLM_INLINE glm::vec<4, T, Q> wyxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.x, v.y); + } + + // wyxz + template + GLM_INLINE glm::vec<4, T, Q> wyxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.x, v.z); + } + + // wyxw + template + GLM_INLINE glm::vec<4, T, Q> wyxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.x, v.w); + } + + // wyyx + template + GLM_INLINE glm::vec<4, T, Q> wyyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.y, v.x); + } + + // wyyy + template + GLM_INLINE glm::vec<4, T, Q> wyyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.y, v.y); + } + + // wyyz + template + GLM_INLINE glm::vec<4, T, Q> wyyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.y, v.z); + } + + // wyyw + template + GLM_INLINE glm::vec<4, T, Q> wyyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.y, v.w); + } + + // wyzx + template + GLM_INLINE glm::vec<4, T, Q> wyzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.z, v.x); + } + + // wyzy + template + GLM_INLINE glm::vec<4, T, Q> wyzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.z, v.y); + } + + // wyzz + template + GLM_INLINE glm::vec<4, T, Q> wyzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.z, v.z); + } + + // wyzw + template + GLM_INLINE glm::vec<4, T, Q> wyzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.z, v.w); + } + + // wywx + template + GLM_INLINE glm::vec<4, T, Q> wywx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.w, v.x); + } + + // wywy + template + GLM_INLINE glm::vec<4, T, Q> wywy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.w, v.y); + } + + // wywz + template + GLM_INLINE glm::vec<4, T, Q> wywz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.w, v.z); + } + + // wyww + template + GLM_INLINE glm::vec<4, T, Q> wyww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.w, v.w); + } + + // wzxx + template + GLM_INLINE glm::vec<4, T, Q> wzxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.x, v.x); + } + + // wzxy + template + GLM_INLINE glm::vec<4, T, Q> wzxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.x, v.y); + } + + // wzxz + template + GLM_INLINE glm::vec<4, T, Q> wzxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.x, v.z); + } + + // wzxw + template + GLM_INLINE glm::vec<4, T, Q> wzxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.x, v.w); + } + + // wzyx + template + GLM_INLINE glm::vec<4, T, Q> wzyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.y, v.x); + } + + // wzyy + template + GLM_INLINE glm::vec<4, T, Q> wzyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.y, v.y); + } + + // wzyz + template + GLM_INLINE glm::vec<4, T, Q> wzyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.y, v.z); + } + + // wzyw + template + GLM_INLINE glm::vec<4, T, Q> wzyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.y, v.w); + } + + // wzzx + template + GLM_INLINE glm::vec<4, T, Q> wzzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.z, v.x); + } + + // wzzy + template + GLM_INLINE glm::vec<4, T, Q> wzzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.z, v.y); + } + + // wzzz + template + GLM_INLINE glm::vec<4, T, Q> wzzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.z, v.z); + } + + // wzzw + template + GLM_INLINE glm::vec<4, T, Q> wzzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.z, v.w); + } + + // wzwx + template + GLM_INLINE glm::vec<4, T, Q> wzwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.w, v.x); + } + + // wzwy + template + GLM_INLINE glm::vec<4, T, Q> wzwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.w, v.y); + } + + // wzwz + template + GLM_INLINE glm::vec<4, T, Q> wzwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.w, v.z); + } + + // wzww + template + GLM_INLINE glm::vec<4, T, Q> wzww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.w, v.w); + } + + // wwxx + template + GLM_INLINE glm::vec<4, T, Q> wwxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.x, v.x); + } + + // wwxy + template + GLM_INLINE glm::vec<4, T, Q> wwxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.x, v.y); + } + + // wwxz + template + GLM_INLINE glm::vec<4, T, Q> wwxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.x, v.z); + } + + // wwxw + template + GLM_INLINE glm::vec<4, T, Q> wwxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.x, v.w); + } + + // wwyx + template + GLM_INLINE glm::vec<4, T, Q> wwyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.y, v.x); + } + + // wwyy + template + GLM_INLINE glm::vec<4, T, Q> wwyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.y, v.y); + } + + // wwyz + template + GLM_INLINE glm::vec<4, T, Q> wwyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.y, v.z); + } + + // wwyw + template + GLM_INLINE glm::vec<4, T, Q> wwyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.y, v.w); + } + + // wwzx + template + GLM_INLINE glm::vec<4, T, Q> wwzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.z, v.x); + } + + // wwzy + template + GLM_INLINE glm::vec<4, T, Q> wwzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.z, v.y); + } + + // wwzz + template + GLM_INLINE glm::vec<4, T, Q> wwzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.z, v.z); + } + + // wwzw + template + GLM_INLINE glm::vec<4, T, Q> wwzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.z, v.w); + } + + // wwwx + template + GLM_INLINE glm::vec<4, T, Q> wwwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.w, v.x); + } + + // wwwy + template + GLM_INLINE glm::vec<4, T, Q> wwwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.w, v.y); + } + + // wwwz + template + GLM_INLINE glm::vec<4, T, Q> wwwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.w, v.z); + } + + // wwww + template + GLM_INLINE glm::vec<4, T, Q> wwww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.w, v.w); + } + + /// @} +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/vector_angle.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/vector_angle.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9ae437126b195e637c846f45549adfd8eb7e9965 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/vector_angle.hpp @@ -0,0 +1,57 @@ +/// @ref gtx_vector_angle +/// @file glm/gtx/vector_angle.hpp +/// +/// @see core (dependence) +/// @see gtx_quaternion (dependence) +/// @see gtx_epsilon (dependence) +/// +/// @defgroup gtx_vector_angle GLM_GTX_vector_angle +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Compute angle between vectors + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtc/epsilon.hpp" +#include "../gtx/quaternion.hpp" +#include "../gtx/rotate_vector.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_vector_angle is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_vector_angle extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_vector_angle + /// @{ + + //! Returns the absolute angle between two vectors. + //! Parameters need to be normalized. + /// @see gtx_vector_angle extension. + template + GLM_FUNC_DECL T angle(vec const& x, vec const& y); + + //! Returns the oriented angle between two 2d vectors. + //! Parameters need to be normalized. + /// @see gtx_vector_angle extension. + template + GLM_FUNC_DECL T orientedAngle(vec<2, T, Q> const& x, vec<2, T, Q> const& y); + + //! Returns the oriented angle between two 3d vectors based from a reference axis. + //! Parameters need to be normalized. + /// @see gtx_vector_angle extension. + template + GLM_FUNC_DECL T orientedAngle(vec<3, T, Q> const& x, vec<3, T, Q> const& y, vec<3, T, Q> const& ref); + + /// @} +}// namespace glm + +#include "vector_angle.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/vector_angle.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/vector_angle.inl new file mode 100644 index 0000000000000000000000000000000000000000..878160d9a609a90266a0559671353adce66c883f --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/vector_angle.inl @@ -0,0 +1,45 @@ +/// @ref gtx_vector_angle + +namespace glm +{ + template + GLM_FUNC_QUALIFIER genType angle + ( + genType const& x, + genType const& y + ) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'angle' only accept floating-point inputs"); + return acos(clamp(dot(x, y), genType(-1), genType(1))); + } + + template + GLM_FUNC_QUALIFIER T angle(vec const& x, vec const& y) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'angle' only accept floating-point inputs"); + return acos(clamp(dot(x, y), T(-1), T(1))); + } + + template + GLM_FUNC_QUALIFIER T orientedAngle(vec<2, T, Q> const& x, vec<2, T, Q> const& y) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'orientedAngle' only accept floating-point inputs"); + T const Angle(acos(clamp(dot(x, y), T(-1), T(1)))); + + T const partialCross = x.x * y.y - y.x * x.y; + + if (partialCross > T(0)) + return Angle; + else + return -Angle; + } + + template + GLM_FUNC_QUALIFIER T orientedAngle(vec<3, T, Q> const& x, vec<3, T, Q> const& y, vec<3, T, Q> const& ref) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'orientedAngle' only accept floating-point inputs"); + + T const Angle(acos(clamp(dot(x, y), T(-1), T(1)))); + return mix(Angle, -Angle, dot(ref, cross(x, y)) < T(0)); + } +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/vector_query.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/vector_query.hpp new file mode 100644 index 0000000000000000000000000000000000000000..af1f7b9bd5841de4f1d417cf018972b0e62efbb2 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/vector_query.hpp @@ -0,0 +1,66 @@ +/// @ref gtx_vector_query +/// @file glm/gtx/vector_query.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_vector_query GLM_GTX_vector_query +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Query information of vector types + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_vector_query is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_vector_query extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_vector_query + /// @{ + + //! Check whether two vectors are collinears. + /// @see gtx_vector_query extensions. + template + GLM_FUNC_DECL bool areCollinear(vec const& v0, vec const& v1, T const& epsilon); + + //! Check whether two vectors are orthogonals. + /// @see gtx_vector_query extensions. + template + GLM_FUNC_DECL bool areOrthogonal(vec const& v0, vec const& v1, T const& epsilon); + + //! Check whether a vector is normalized. + /// @see gtx_vector_query extensions. + template + GLM_FUNC_DECL bool isNormalized(vec const& v, T const& epsilon); + + //! Check whether a vector is null. + /// @see gtx_vector_query extensions. + template + GLM_FUNC_DECL bool isNull(vec const& v, T const& epsilon); + + //! Check whether a each component of a vector is null. + /// @see gtx_vector_query extensions. + template + GLM_FUNC_DECL vec isCompNull(vec const& v, T const& epsilon); + + //! Check whether two vectors are orthonormal. + /// @see gtx_vector_query extensions. + template + GLM_FUNC_DECL bool areOrthonormal(vec const& v0, vec const& v1, T const& epsilon); + + /// @} +}// namespace glm + +#include "vector_query.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/vector_query.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/vector_query.inl new file mode 100644 index 0000000000000000000000000000000000000000..d1a5c9be46b1574a80c076d303822261e84e940a --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/vector_query.inl @@ -0,0 +1,154 @@ +/// @ref gtx_vector_query + +#include + +namespace glm{ +namespace detail +{ + template + struct compute_areCollinear{}; + + template + struct compute_areCollinear<2, T, Q> + { + GLM_FUNC_QUALIFIER static bool call(vec<2, T, Q> const& v0, vec<2, T, Q> const& v1, T const& epsilon) + { + return length(cross(vec<3, T, Q>(v0, static_cast(0)), vec<3, T, Q>(v1, static_cast(0)))) < epsilon; + } + }; + + template + struct compute_areCollinear<3, T, Q> + { + GLM_FUNC_QUALIFIER static bool call(vec<3, T, Q> const& v0, vec<3, T, Q> const& v1, T const& epsilon) + { + return length(cross(v0, v1)) < epsilon; + } + }; + + template + struct compute_areCollinear<4, T, Q> + { + GLM_FUNC_QUALIFIER static bool call(vec<4, T, Q> const& v0, vec<4, T, Q> const& v1, T const& epsilon) + { + return length(cross(vec<3, T, Q>(v0), vec<3, T, Q>(v1))) < epsilon; + } + }; + + template + struct compute_isCompNull{}; + + template + struct compute_isCompNull<2, T, Q> + { + GLM_FUNC_QUALIFIER static vec<2, bool, Q> call(vec<2, T, Q> const& v, T const& epsilon) + { + return vec<2, bool, Q>( + (abs(v.x) < epsilon), + (abs(v.y) < epsilon)); + } + }; + + template + struct compute_isCompNull<3, T, Q> + { + GLM_FUNC_QUALIFIER static vec<3, bool, Q> call(vec<3, T, Q> const& v, T const& epsilon) + { + return vec<3, bool, Q>( + (abs(v.x) < epsilon), + (abs(v.y) < epsilon), + (abs(v.z) < epsilon)); + } + }; + + template + struct compute_isCompNull<4, T, Q> + { + GLM_FUNC_QUALIFIER static vec<4, bool, Q> call(vec<4, T, Q> const& v, T const& epsilon) + { + return vec<4, bool, Q>( + (abs(v.x) < epsilon), + (abs(v.y) < epsilon), + (abs(v.z) < epsilon), + (abs(v.w) < epsilon)); + } + }; + +}//namespace detail + + template + GLM_FUNC_QUALIFIER bool areCollinear(vec const& v0, vec const& v1, T const& epsilon) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'areCollinear' only accept floating-point inputs"); + + return detail::compute_areCollinear::call(v0, v1, epsilon); + } + + template + GLM_FUNC_QUALIFIER bool areOrthogonal(vec const& v0, vec const& v1, T const& epsilon) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'areOrthogonal' only accept floating-point inputs"); + + return abs(dot(v0, v1)) <= max( + static_cast(1), + length(v0)) * max(static_cast(1), length(v1)) * epsilon; + } + + template + GLM_FUNC_QUALIFIER bool isNormalized(vec const& v, T const& epsilon) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isNormalized' only accept floating-point inputs"); + + return abs(length(v) - static_cast(1)) <= static_cast(2) * epsilon; + } + + template + GLM_FUNC_QUALIFIER bool isNull(vec const& v, T const& epsilon) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isNull' only accept floating-point inputs"); + + return length(v) <= epsilon; + } + + template + GLM_FUNC_QUALIFIER vec isCompNull(vec const& v, T const& epsilon) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isCompNull' only accept floating-point inputs"); + + return detail::compute_isCompNull::call(v, epsilon); + } + + template + GLM_FUNC_QUALIFIER vec<2, bool, Q> isCompNull(vec<2, T, Q> const& v, T const& epsilon) + { + return vec<2, bool, Q>( + abs(v.x) < epsilon, + abs(v.y) < epsilon); + } + + template + GLM_FUNC_QUALIFIER vec<3, bool, Q> isCompNull(vec<3, T, Q> const& v, T const& epsilon) + { + return vec<3, bool, Q>( + abs(v.x) < epsilon, + abs(v.y) < epsilon, + abs(v.z) < epsilon); + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> isCompNull(vec<4, T, Q> const& v, T const& epsilon) + { + return vec<4, bool, Q>( + abs(v.x) < epsilon, + abs(v.y) < epsilon, + abs(v.z) < epsilon, + abs(v.w) < epsilon); + } + + template + GLM_FUNC_QUALIFIER bool areOrthonormal(vec const& v0, vec const& v1, T const& epsilon) + { + return isNormalized(v0, epsilon) && isNormalized(v1, epsilon) && (abs(dot(v0, v1)) <= epsilon); + } + +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/wrap.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/wrap.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ad4eb3fca740217bf04761eda2e315da1d0125a6 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/wrap.hpp @@ -0,0 +1,37 @@ +/// @ref gtx_wrap +/// @file glm/gtx/wrap.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_wrap GLM_GTX_wrap +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Wrapping mode of texture coordinates. + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../ext/scalar_common.hpp" +#include "../ext/vector_common.hpp" +#include "../gtc/vec1.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_wrap is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_wrap extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_wrap + /// @{ + + /// @} +}// namespace glm + +#include "wrap.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/wrap.inl b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/wrap.inl new file mode 100644 index 0000000000000000000000000000000000000000..4be3b4c38aeeaba444655b2d0ac991806e6da48e --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/gtx/wrap.inl @@ -0,0 +1,6 @@ +/// @ref gtx_wrap + +namespace glm +{ + +}//namespace glm diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/integer.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/integer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8817db3f0a224f6b36a7a0ad75ffc3d895e75aaa --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/integer.hpp @@ -0,0 +1,212 @@ +/// @ref core +/// @file glm/integer.hpp +/// +/// @see GLSL 4.20.8 specification, section 8.8 Integer Functions +/// +/// @defgroup core_func_integer Integer functions +/// @ingroup core +/// +/// Provides GLSL functions on integer types +/// +/// These all operate component-wise. The description is per component. +/// The notation [a, b] means the set of bits from bit-number a through bit-number +/// b, inclusive. The lowest-order bit is bit 0. +/// +/// Include to use these core features. + +#pragma once + +#include "detail/qualifier.hpp" +#include "common.hpp" +#include "vector_relational.hpp" + +namespace glm +{ + /// @addtogroup core_func_integer + /// @{ + + /// Adds 32-bit unsigned integer x and y, returning the sum + /// modulo pow(2, 32). The value carry is set to 0 if the sum was + /// less than pow(2, 32), or to 1 otherwise. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// + /// @see GLSL uaddCarry man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL vec uaddCarry( + vec const& x, + vec const& y, + vec & carry); + + /// Subtracts the 32-bit unsigned integer y from x, returning + /// the difference if non-negative, or pow(2, 32) plus the difference + /// otherwise. The value borrow is set to 0 if x >= y, or to 1 otherwise. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// + /// @see GLSL usubBorrow man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL vec usubBorrow( + vec const& x, + vec const& y, + vec & borrow); + + /// Multiplies 32-bit integers x and y, producing a 64-bit + /// result. The 32 least-significant bits are returned in lsb. + /// The 32 most-significant bits are returned in msb. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// + /// @see GLSL umulExtended man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL void umulExtended( + vec const& x, + vec const& y, + vec & msb, + vec & lsb); + + /// Multiplies 32-bit integers x and y, producing a 64-bit + /// result. The 32 least-significant bits are returned in lsb. + /// The 32 most-significant bits are returned in msb. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// + /// @see GLSL imulExtended man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL void imulExtended( + vec const& x, + vec const& y, + vec & msb, + vec & lsb); + + /// Extracts bits [offset, offset + bits - 1] from value, + /// returning them in the least significant bits of the result. + /// For unsigned data types, the most significant bits of the + /// result will be set to zero. For signed data types, the + /// most significant bits will be set to the value of bit offset + base - 1. + /// + /// If bits is zero, the result will be zero. The result will be + /// undefined if offset or bits is negative, or if the sum of + /// offset and bits is greater than the number of bits used + /// to store the operand. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Signed or unsigned integer scalar types. + /// + /// @see GLSL bitfieldExtract man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL vec bitfieldExtract( + vec const& Value, + int Offset, + int Bits); + + /// Returns the insertion the bits least-significant bits of insert into base. + /// + /// The result will have bits [offset, offset + bits - 1] taken + /// from bits [0, bits - 1] of insert, and all other bits taken + /// directly from the corresponding bits of base. If bits is + /// zero, the result will simply be base. The result will be + /// undefined if offset or bits is negative, or if the sum of + /// offset and bits is greater than the number of bits used to + /// store the operand. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Signed or unsigned integer scalar or vector types. + /// + /// @see GLSL bitfieldInsert man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL vec bitfieldInsert( + vec const& Base, + vec const& Insert, + int Offset, + int Bits); + + /// Returns the reversal of the bits of value. + /// The bit numbered n of the result will be taken from bit (bits - 1) - n of value, + /// where bits is the total number of bits used to represent value. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Signed or unsigned integer scalar or vector types. + /// + /// @see GLSL bitfieldReverse man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL vec bitfieldReverse(vec const& v); + + /// Returns the number of bits set to 1 in the binary representation of value. + /// + /// @tparam genType Signed or unsigned integer scalar or vector types. + /// + /// @see GLSL bitCount man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL int bitCount(genType v); + + /// Returns the number of bits set to 1 in the binary representation of value. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Signed or unsigned integer scalar or vector types. + /// + /// @see GLSL bitCount man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL vec bitCount(vec const& v); + + /// Returns the bit number of the least significant bit set to + /// 1 in the binary representation of value. + /// If value is zero, -1 will be returned. + /// + /// @tparam genIUType Signed or unsigned integer scalar types. + /// + /// @see GLSL findLSB man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL int findLSB(genIUType x); + + /// Returns the bit number of the least significant bit set to + /// 1 in the binary representation of value. + /// If value is zero, -1 will be returned. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Signed or unsigned integer scalar types. + /// + /// @see GLSL findLSB man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL vec findLSB(vec const& v); + + /// Returns the bit number of the most significant bit in the binary representation of value. + /// For positive integers, the result will be the bit number of the most significant bit set to 1. + /// For negative integers, the result will be the bit number of the most significant + /// bit set to 0. For a value of zero or negative one, -1 will be returned. + /// + /// @tparam genIUType Signed or unsigned integer scalar types. + /// + /// @see GLSL findMSB man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL int findMSB(genIUType x); + + /// Returns the bit number of the most significant bit in the binary representation of value. + /// For positive integers, the result will be the bit number of the most significant bit set to 1. + /// For negative integers, the result will be the bit number of the most significant + /// bit set to 0. For a value of zero or negative one, -1 will be returned. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Signed or unsigned integer scalar types. + /// + /// @see GLSL findMSB man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL vec findMSB(vec const& v); + + /// @} +}//namespace glm + +#include "detail/func_integer.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/mat2x2.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/mat2x2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..96bec96b9a63846e577ebbd0e2dd21f65ae8f353 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/mat2x2.hpp @@ -0,0 +1,9 @@ +/// @ref core +/// @file glm/mat2x2.hpp + +#pragma once +#include "./ext/matrix_double2x2.hpp" +#include "./ext/matrix_double2x2_precision.hpp" +#include "./ext/matrix_float2x2.hpp" +#include "./ext/matrix_float2x2_precision.hpp" + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/mat2x3.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/mat2x3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d68dc25eda943a72429732f0cdda9080a38b4829 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/mat2x3.hpp @@ -0,0 +1,9 @@ +/// @ref core +/// @file glm/mat2x3.hpp + +#pragma once +#include "./ext/matrix_double2x3.hpp" +#include "./ext/matrix_double2x3_precision.hpp" +#include "./ext/matrix_float2x3.hpp" +#include "./ext/matrix_float2x3_precision.hpp" + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/mat2x4.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/mat2x4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b04b7387b1a31826ce22ac25d7926586b7b6f14a --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/mat2x4.hpp @@ -0,0 +1,9 @@ +/// @ref core +/// @file glm/mat2x4.hpp + +#pragma once +#include "./ext/matrix_double2x4.hpp" +#include "./ext/matrix_double2x4_precision.hpp" +#include "./ext/matrix_float2x4.hpp" +#include "./ext/matrix_float2x4_precision.hpp" + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/mat3x2.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/mat3x2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c85315372dc02dd2d409a8e214ea587101241a43 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/mat3x2.hpp @@ -0,0 +1,9 @@ +/// @ref core +/// @file glm/mat3x2.hpp + +#pragma once +#include "./ext/matrix_double3x2.hpp" +#include "./ext/matrix_double3x2_precision.hpp" +#include "./ext/matrix_float3x2.hpp" +#include "./ext/matrix_float3x2_precision.hpp" + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/mat3x3.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/mat3x3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..fd4fa31cdee018ed6eaf4a0d5386396010f89c7f --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/mat3x3.hpp @@ -0,0 +1,8 @@ +/// @ref core +/// @file glm/mat3x3.hpp + +#pragma once +#include "./ext/matrix_double3x3.hpp" +#include "./ext/matrix_double3x3_precision.hpp" +#include "./ext/matrix_float3x3.hpp" +#include "./ext/matrix_float3x3_precision.hpp" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/mat3x4.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/mat3x4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6342bf5b992dc97c57b532e25c18b8262d2a2f08 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/mat3x4.hpp @@ -0,0 +1,8 @@ +/// @ref core +/// @file glm/mat3x4.hpp + +#pragma once +#include "./ext/matrix_double3x4.hpp" +#include "./ext/matrix_double3x4_precision.hpp" +#include "./ext/matrix_float3x4.hpp" +#include "./ext/matrix_float3x4_precision.hpp" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/mat4x2.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/mat4x2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e013e46b9c20c136332dd71ecc4f65abf7b51cfb --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/mat4x2.hpp @@ -0,0 +1,9 @@ +/// @ref core +/// @file glm/mat4x2.hpp + +#pragma once +#include "./ext/matrix_double4x2.hpp" +#include "./ext/matrix_double4x2_precision.hpp" +#include "./ext/matrix_float4x2.hpp" +#include "./ext/matrix_float4x2_precision.hpp" + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/mat4x3.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/mat4x3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..205725abd25aa6094e140d80f3158b6a7659ea60 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/mat4x3.hpp @@ -0,0 +1,8 @@ +/// @ref core +/// @file glm/mat4x3.hpp + +#pragma once +#include "./ext/matrix_double4x3.hpp" +#include "./ext/matrix_double4x3_precision.hpp" +#include "./ext/matrix_float4x3.hpp" +#include "./ext/matrix_float4x3_precision.hpp" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/mat4x4.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/mat4x4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..3515f7f370bf105587316498db2459294cd52537 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/mat4x4.hpp @@ -0,0 +1,9 @@ +/// @ref core +/// @file glm/mat4x4.hpp + +#pragma once +#include "./ext/matrix_double4x4.hpp" +#include "./ext/matrix_double4x4_precision.hpp" +#include "./ext/matrix_float4x4.hpp" +#include "./ext/matrix_float4x4_precision.hpp" + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/matrix.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/matrix.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4584c92c3c4ecec7752810234766b06780fa670d --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/matrix.hpp @@ -0,0 +1,161 @@ +/// @ref core +/// @file glm/matrix.hpp +/// +/// @see GLSL 4.20.8 specification, section 8.6 Matrix Functions +/// +/// @defgroup core_func_matrix Matrix functions +/// @ingroup core +/// +/// Provides GLSL matrix functions. +/// +/// Include to use these core features. + +#pragma once + +// Dependencies +#include "detail/qualifier.hpp" +#include "detail/setup.hpp" +#include "vec2.hpp" +#include "vec3.hpp" +#include "vec4.hpp" +#include "mat2x2.hpp" +#include "mat2x3.hpp" +#include "mat2x4.hpp" +#include "mat3x2.hpp" +#include "mat3x3.hpp" +#include "mat3x4.hpp" +#include "mat4x2.hpp" +#include "mat4x3.hpp" +#include "mat4x4.hpp" + +namespace glm { +namespace detail +{ + template + struct outerProduct_trait{}; + + template + struct outerProduct_trait<2, 2, T, Q> + { + typedef mat<2, 2, T, Q> type; + }; + + template + struct outerProduct_trait<2, 3, T, Q> + { + typedef mat<3, 2, T, Q> type; + }; + + template + struct outerProduct_trait<2, 4, T, Q> + { + typedef mat<4, 2, T, Q> type; + }; + + template + struct outerProduct_trait<3, 2, T, Q> + { + typedef mat<2, 3, T, Q> type; + }; + + template + struct outerProduct_trait<3, 3, T, Q> + { + typedef mat<3, 3, T, Q> type; + }; + + template + struct outerProduct_trait<3, 4, T, Q> + { + typedef mat<4, 3, T, Q> type; + }; + + template + struct outerProduct_trait<4, 2, T, Q> + { + typedef mat<2, 4, T, Q> type; + }; + + template + struct outerProduct_trait<4, 3, T, Q> + { + typedef mat<3, 4, T, Q> type; + }; + + template + struct outerProduct_trait<4, 4, T, Q> + { + typedef mat<4, 4, T, Q> type; + }; +}//namespace detail + + /// @addtogroup core_func_matrix + /// @{ + + /// Multiply matrix x by matrix y component-wise, i.e., + /// result[i][j] is the scalar product of x[i][j] and y[i][j]. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number a column + /// @tparam R Integer between 1 and 4 included that qualify the number a row + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL matrixCompMult man page + /// @see GLSL 4.20.8 specification, section 8.6 Matrix Functions + template + GLM_FUNC_DECL mat matrixCompMult(mat const& x, mat const& y); + + /// Treats the first parameter c as a column vector + /// and the second parameter r as a row vector + /// and does a linear algebraic matrix multiply c * r. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number a column + /// @tparam R Integer between 1 and 4 included that qualify the number a row + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL outerProduct man page + /// @see GLSL 4.20.8 specification, section 8.6 Matrix Functions + template + GLM_FUNC_DECL typename detail::outerProduct_trait::type outerProduct(vec const& c, vec const& r); + + /// Returns the transposed matrix of x + /// + /// @tparam C Integer between 1 and 4 included that qualify the number a column + /// @tparam R Integer between 1 and 4 included that qualify the number a row + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL transpose man page + /// @see GLSL 4.20.8 specification, section 8.6 Matrix Functions + template + GLM_FUNC_DECL typename mat::transpose_type transpose(mat const& x); + + /// Return the determinant of a squared matrix. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number a column + /// @tparam R Integer between 1 and 4 included that qualify the number a row + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL determinant man page + /// @see GLSL 4.20.8 specification, section 8.6 Matrix Functions + template + GLM_FUNC_DECL T determinant(mat const& m); + + /// Return the inverse of a squared matrix. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number a column + /// @tparam R Integer between 1 and 4 included that qualify the number a row + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL inverse man page + /// @see GLSL 4.20.8 specification, section 8.6 Matrix Functions + template + GLM_FUNC_DECL mat inverse(mat const& m); + + /// @} +}//namespace glm + +#include "detail/func_matrix.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/packing.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/packing.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ca83ac1dec960d3ddef0127a43f9504d64772fb3 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/packing.hpp @@ -0,0 +1,173 @@ +/// @ref core +/// @file glm/packing.hpp +/// +/// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions +/// @see gtc_packing +/// +/// @defgroup core_func_packing Floating-Point Pack and Unpack Functions +/// @ingroup core +/// +/// Provides GLSL functions to pack and unpack half, single and double-precision floating point values into more compact integer types. +/// +/// These functions do not operate component-wise, rather as described in each case. +/// +/// Include to use these core features. + +#pragma once + +#include "./ext/vector_uint2.hpp" +#include "./ext/vector_float2.hpp" +#include "./ext/vector_float4.hpp" + +namespace glm +{ + /// @addtogroup core_func_packing + /// @{ + + /// First, converts each component of the normalized floating-point value v into 8- or 16-bit integer values. + /// Then, the results are packed into the returned 32-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packUnorm2x16: round(clamp(c, 0, +1) * 65535.0) + /// + /// The first component of the vector will be written to the least significant bits of the output; + /// the last component will be written to the most significant bits. + /// + /// @see GLSL packUnorm2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint packUnorm2x16(vec2 const& v); + + /// First, converts each component of the normalized floating-point value v into 8- or 16-bit integer values. + /// Then, the results are packed into the returned 32-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packSnorm2x16: round(clamp(v, -1, +1) * 32767.0) + /// + /// The first component of the vector will be written to the least significant bits of the output; + /// the last component will be written to the most significant bits. + /// + /// @see GLSL packSnorm2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint packSnorm2x16(vec2 const& v); + + /// First, converts each component of the normalized floating-point value v into 8- or 16-bit integer values. + /// Then, the results are packed into the returned 32-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packUnorm4x8: round(clamp(c, 0, +1) * 255.0) + /// + /// The first component of the vector will be written to the least significant bits of the output; + /// the last component will be written to the most significant bits. + /// + /// @see GLSL packUnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint packUnorm4x8(vec4 const& v); + + /// First, converts each component of the normalized floating-point value v into 8- or 16-bit integer values. + /// Then, the results are packed into the returned 32-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packSnorm4x8: round(clamp(c, -1, +1) * 127.0) + /// + /// The first component of the vector will be written to the least significant bits of the output; + /// the last component will be written to the most significant bits. + /// + /// @see GLSL packSnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint packSnorm4x8(vec4 const& v); + + /// First, unpacks a single 32-bit unsigned integer p into a pair of 16-bit unsigned integers, four 8-bit unsigned integers, or four 8-bit signed integers. + /// Then, each component is converted to a normalized floating-point value to generate the returned two- or four-component vector. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackUnorm2x16: f / 65535.0 + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see GLSL unpackUnorm2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL vec2 unpackUnorm2x16(uint p); + + /// First, unpacks a single 32-bit unsigned integer p into a pair of 16-bit unsigned integers, four 8-bit unsigned integers, or four 8-bit signed integers. + /// Then, each component is converted to a normalized floating-point value to generate the returned two- or four-component vector. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackSnorm2x16: clamp(f / 32767.0, -1, +1) + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see GLSL unpackSnorm2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL vec2 unpackSnorm2x16(uint p); + + /// First, unpacks a single 32-bit unsigned integer p into a pair of 16-bit unsigned integers, four 8-bit unsigned integers, or four 8-bit signed integers. + /// Then, each component is converted to a normalized floating-point value to generate the returned two- or four-component vector. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackUnorm4x8: f / 255.0 + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see GLSL unpackUnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL vec4 unpackUnorm4x8(uint p); + + /// First, unpacks a single 32-bit unsigned integer p into a pair of 16-bit unsigned integers, four 8-bit unsigned integers, or four 8-bit signed integers. + /// Then, each component is converted to a normalized floating-point value to generate the returned two- or four-component vector. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackSnorm4x8: clamp(f / 127.0, -1, +1) + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see GLSL unpackSnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL vec4 unpackSnorm4x8(uint p); + + /// Returns a double-qualifier value obtained by packing the components of v into a 64-bit value. + /// If an IEEE 754 Inf or NaN is created, it will not signal, and the resulting floating point value is unspecified. + /// Otherwise, the bit- level representation of v is preserved. + /// The first vector component specifies the 32 least significant bits; + /// the second component specifies the 32 most significant bits. + /// + /// @see GLSL packDouble2x32 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL double packDouble2x32(uvec2 const& v); + + /// Returns a two-component unsigned integer vector representation of v. + /// The bit-level representation of v is preserved. + /// The first component of the vector contains the 32 least significant bits of the double; + /// the second component consists the 32 most significant bits. + /// + /// @see GLSL unpackDouble2x32 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uvec2 unpackDouble2x32(double v); + + /// Returns an unsigned integer obtained by converting the components of a two-component floating-point vector + /// to the 16-bit floating-point representation found in the OpenGL Specification, + /// and then packing these two 16- bit integers into a 32-bit unsigned integer. + /// The first vector component specifies the 16 least-significant bits of the result; + /// the second component specifies the 16 most-significant bits. + /// + /// @see GLSL packHalf2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint packHalf2x16(vec2 const& v); + + /// Returns a two-component floating-point vector with components obtained by unpacking a 32-bit unsigned integer into a pair of 16-bit values, + /// interpreting those values as 16-bit floating-point numbers according to the OpenGL Specification, + /// and converting them to 32-bit floating-point values. + /// The first component of the vector is obtained from the 16 least-significant bits of v; + /// the second component is obtained from the 16 most-significant bits of v. + /// + /// @see GLSL unpackHalf2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL vec2 unpackHalf2x16(uint v); + + /// @} +}//namespace glm + +#include "detail/func_packing.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/simd/common.h b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/simd/common.h new file mode 100644 index 0000000000000000000000000000000000000000..9b017cb4256e0fc3249c6fdbf6b3cad6c5be5f5a --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/simd/common.h @@ -0,0 +1,240 @@ +/// @ref simd +/// @file glm/simd/common.h + +#pragma once + +#include "platform.h" + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_add(glm_f32vec4 a, glm_f32vec4 b) +{ + return _mm_add_ps(a, b); +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec1_add(glm_f32vec4 a, glm_f32vec4 b) +{ + return _mm_add_ss(a, b); +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_sub(glm_f32vec4 a, glm_f32vec4 b) +{ + return _mm_sub_ps(a, b); +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec1_sub(glm_f32vec4 a, glm_f32vec4 b) +{ + return _mm_sub_ss(a, b); +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_mul(glm_f32vec4 a, glm_f32vec4 b) +{ + return _mm_mul_ps(a, b); +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec1_mul(glm_f32vec4 a, glm_f32vec4 b) +{ + return _mm_mul_ss(a, b); +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_div(glm_f32vec4 a, glm_f32vec4 b) +{ + return _mm_div_ps(a, b); +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec1_div(glm_f32vec4 a, glm_f32vec4 b) +{ + return _mm_div_ss(a, b); +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_div_lowp(glm_f32vec4 a, glm_f32vec4 b) +{ + return glm_vec4_mul(a, _mm_rcp_ps(b)); +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_swizzle_xyzw(glm_f32vec4 a) +{ +# if GLM_ARCH & GLM_ARCH_AVX2_BIT + return _mm_permute_ps(a, _MM_SHUFFLE(3, 2, 1, 0)); +# else + return _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 2, 1, 0)); +# endif +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec1_fma(glm_f32vec4 a, glm_f32vec4 b, glm_f32vec4 c) +{ +# if (GLM_ARCH & GLM_ARCH_AVX2_BIT) && !(GLM_COMPILER & GLM_COMPILER_CLANG) + return _mm_fmadd_ss(a, b, c); +# else + return _mm_add_ss(_mm_mul_ss(a, b), c); +# endif +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_fma(glm_f32vec4 a, glm_f32vec4 b, glm_f32vec4 c) +{ +# if (GLM_ARCH & GLM_ARCH_AVX2_BIT) && !(GLM_COMPILER & GLM_COMPILER_CLANG) + return _mm_fmadd_ps(a, b, c); +# else + return glm_vec4_add(glm_vec4_mul(a, b), c); +# endif +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_abs(glm_f32vec4 x) +{ + return _mm_and_ps(x, _mm_castsi128_ps(_mm_set1_epi32(0x7FFFFFFF))); +} + +GLM_FUNC_QUALIFIER glm_ivec4 glm_ivec4_abs(glm_ivec4 x) +{ +# if GLM_ARCH & GLM_ARCH_SSSE3_BIT + return _mm_sign_epi32(x, x); +# else + glm_ivec4 const sgn0 = _mm_srai_epi32(x, 31); + glm_ivec4 const inv0 = _mm_xor_si128(x, sgn0); + glm_ivec4 const sub0 = _mm_sub_epi32(inv0, sgn0); + return sub0; +# endif +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_sign(glm_vec4 x) +{ + glm_vec4 const zro0 = _mm_setzero_ps(); + glm_vec4 const cmp0 = _mm_cmplt_ps(x, zro0); + glm_vec4 const cmp1 = _mm_cmpgt_ps(x, zro0); + glm_vec4 const and0 = _mm_and_ps(cmp0, _mm_set1_ps(-1.0f)); + glm_vec4 const and1 = _mm_and_ps(cmp1, _mm_set1_ps(1.0f)); + glm_vec4 const or0 = _mm_or_ps(and0, and1); + return or0; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_round(glm_vec4 x) +{ +# if GLM_ARCH & GLM_ARCH_SSE41_BIT + return _mm_round_ps(x, _MM_FROUND_TO_NEAREST_INT); +# else + glm_vec4 const sgn0 = _mm_castsi128_ps(_mm_set1_epi32(int(0x80000000))); + glm_vec4 const and0 = _mm_and_ps(sgn0, x); + glm_vec4 const or0 = _mm_or_ps(and0, _mm_set_ps1(8388608.0f)); + glm_vec4 const add0 = glm_vec4_add(x, or0); + glm_vec4 const sub0 = glm_vec4_sub(add0, or0); + return sub0; +# endif +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_floor(glm_vec4 x) +{ +# if GLM_ARCH & GLM_ARCH_SSE41_BIT + return _mm_floor_ps(x); +# else + glm_vec4 const rnd0 = glm_vec4_round(x); + glm_vec4 const cmp0 = _mm_cmplt_ps(x, rnd0); + glm_vec4 const and0 = _mm_and_ps(cmp0, _mm_set1_ps(1.0f)); + glm_vec4 const sub0 = glm_vec4_sub(rnd0, and0); + return sub0; +# endif +} + +/* trunc TODO +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_trunc(glm_vec4 x) +{ + return glm_vec4(); +} +*/ + +//roundEven +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_roundEven(glm_vec4 x) +{ + glm_vec4 const sgn0 = _mm_castsi128_ps(_mm_set1_epi32(int(0x80000000))); + glm_vec4 const and0 = _mm_and_ps(sgn0, x); + glm_vec4 const or0 = _mm_or_ps(and0, _mm_set_ps1(8388608.0f)); + glm_vec4 const add0 = glm_vec4_add(x, or0); + glm_vec4 const sub0 = glm_vec4_sub(add0, or0); + return sub0; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_ceil(glm_vec4 x) +{ +# if GLM_ARCH & GLM_ARCH_SSE41_BIT + return _mm_ceil_ps(x); +# else + glm_vec4 const rnd0 = glm_vec4_round(x); + glm_vec4 const cmp0 = _mm_cmpgt_ps(x, rnd0); + glm_vec4 const and0 = _mm_and_ps(cmp0, _mm_set1_ps(1.0f)); + glm_vec4 const add0 = glm_vec4_add(rnd0, and0); + return add0; +# endif +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_fract(glm_vec4 x) +{ + glm_vec4 const flr0 = glm_vec4_floor(x); + glm_vec4 const sub0 = glm_vec4_sub(x, flr0); + return sub0; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_mod(glm_vec4 x, glm_vec4 y) +{ + glm_vec4 const div0 = glm_vec4_div(x, y); + glm_vec4 const flr0 = glm_vec4_floor(div0); + glm_vec4 const mul0 = glm_vec4_mul(y, flr0); + glm_vec4 const sub0 = glm_vec4_sub(x, mul0); + return sub0; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_clamp(glm_vec4 v, glm_vec4 minVal, glm_vec4 maxVal) +{ + glm_vec4 const min0 = _mm_min_ps(v, maxVal); + glm_vec4 const max0 = _mm_max_ps(min0, minVal); + return max0; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_mix(glm_vec4 v1, glm_vec4 v2, glm_vec4 a) +{ + glm_vec4 const sub0 = glm_vec4_sub(_mm_set1_ps(1.0f), a); + glm_vec4 const mul0 = glm_vec4_mul(v1, sub0); + glm_vec4 const mad0 = glm_vec4_fma(v2, a, mul0); + return mad0; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_step(glm_vec4 edge, glm_vec4 x) +{ + glm_vec4 const cmp = _mm_cmple_ps(x, edge); + return _mm_movemask_ps(cmp) == 0 ? _mm_set1_ps(1.0f) : _mm_setzero_ps(); +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_smoothstep(glm_vec4 edge0, glm_vec4 edge1, glm_vec4 x) +{ + glm_vec4 const sub0 = glm_vec4_sub(x, edge0); + glm_vec4 const sub1 = glm_vec4_sub(edge1, edge0); + glm_vec4 const div0 = glm_vec4_sub(sub0, sub1); + glm_vec4 const clp0 = glm_vec4_clamp(div0, _mm_setzero_ps(), _mm_set1_ps(1.0f)); + glm_vec4 const mul0 = glm_vec4_mul(_mm_set1_ps(2.0f), clp0); + glm_vec4 const sub2 = glm_vec4_sub(_mm_set1_ps(3.0f), mul0); + glm_vec4 const mul1 = glm_vec4_mul(clp0, clp0); + glm_vec4 const mul2 = glm_vec4_mul(mul1, sub2); + return mul2; +} + +// Agner Fog method +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_nan(glm_vec4 x) +{ + glm_ivec4 const t1 = _mm_castps_si128(x); // reinterpret as 32-bit integer + glm_ivec4 const t2 = _mm_sll_epi32(t1, _mm_cvtsi32_si128(1)); // shift out sign bit + glm_ivec4 const t3 = _mm_set1_epi32(int(0xFF000000)); // exponent mask + glm_ivec4 const t4 = _mm_and_si128(t2, t3); // exponent + glm_ivec4 const t5 = _mm_andnot_si128(t3, t2); // fraction + glm_ivec4 const Equal = _mm_cmpeq_epi32(t3, t4); + glm_ivec4 const Nequal = _mm_cmpeq_epi32(t5, _mm_setzero_si128()); + glm_ivec4 const And = _mm_and_si128(Equal, Nequal); + return _mm_castsi128_ps(And); // exponent = all 1s and fraction != 0 +} + +// Agner Fog method +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_inf(glm_vec4 x) +{ + glm_ivec4 const t1 = _mm_castps_si128(x); // reinterpret as 32-bit integer + glm_ivec4 const t2 = _mm_sll_epi32(t1, _mm_cvtsi32_si128(1)); // shift out sign bit + return _mm_castsi128_ps(_mm_cmpeq_epi32(t2, _mm_set1_epi32(int(0xFF000000)))); // exponent is all 1s, fraction is 0 +} + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/simd/exponential.h b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/simd/exponential.h new file mode 100644 index 0000000000000000000000000000000000000000..bc351d0119b9a8a2513a23eb02a0dee5f9c03d2d --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/simd/exponential.h @@ -0,0 +1,20 @@ +/// @ref simd +/// @file glm/simd/experimental.h + +#pragma once + +#include "platform.h" + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec1_sqrt_lowp(glm_f32vec4 x) +{ + return _mm_mul_ss(_mm_rsqrt_ss(x), x); +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_sqrt_lowp(glm_f32vec4 x) +{ + return _mm_mul_ps(_mm_rsqrt_ps(x), x); +} + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/simd/geometric.h b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/simd/geometric.h new file mode 100644 index 0000000000000000000000000000000000000000..07d7cbcc425f2910e2dc50bcb35fe0cd7a0d9609 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/simd/geometric.h @@ -0,0 +1,124 @@ +/// @ref simd +/// @file glm/simd/geometric.h + +#pragma once + +#include "common.h" + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +GLM_FUNC_DECL glm_vec4 glm_vec4_dot(glm_vec4 v1, glm_vec4 v2); +GLM_FUNC_DECL glm_vec4 glm_vec1_dot(glm_vec4 v1, glm_vec4 v2); + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_length(glm_vec4 x) +{ + glm_vec4 const dot0 = glm_vec4_dot(x, x); + glm_vec4 const sqt0 = _mm_sqrt_ps(dot0); + return sqt0; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_distance(glm_vec4 p0, glm_vec4 p1) +{ + glm_vec4 const sub0 = _mm_sub_ps(p0, p1); + glm_vec4 const len0 = glm_vec4_length(sub0); + return len0; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_dot(glm_vec4 v1, glm_vec4 v2) +{ +# if GLM_ARCH & GLM_ARCH_AVX_BIT + return _mm_dp_ps(v1, v2, 0xff); +# elif GLM_ARCH & GLM_ARCH_SSE3_BIT + glm_vec4 const mul0 = _mm_mul_ps(v1, v2); + glm_vec4 const hadd0 = _mm_hadd_ps(mul0, mul0); + glm_vec4 const hadd1 = _mm_hadd_ps(hadd0, hadd0); + return hadd1; +# else + glm_vec4 const mul0 = _mm_mul_ps(v1, v2); + glm_vec4 const swp0 = _mm_shuffle_ps(mul0, mul0, _MM_SHUFFLE(2, 3, 0, 1)); + glm_vec4 const add0 = _mm_add_ps(mul0, swp0); + glm_vec4 const swp1 = _mm_shuffle_ps(add0, add0, _MM_SHUFFLE(0, 1, 2, 3)); + glm_vec4 const add1 = _mm_add_ps(add0, swp1); + return add1; +# endif +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec1_dot(glm_vec4 v1, glm_vec4 v2) +{ +# if GLM_ARCH & GLM_ARCH_AVX_BIT + return _mm_dp_ps(v1, v2, 0xff); +# elif GLM_ARCH & GLM_ARCH_SSE3_BIT + glm_vec4 const mul0 = _mm_mul_ps(v1, v2); + glm_vec4 const had0 = _mm_hadd_ps(mul0, mul0); + glm_vec4 const had1 = _mm_hadd_ps(had0, had0); + return had1; +# else + glm_vec4 const mul0 = _mm_mul_ps(v1, v2); + glm_vec4 const mov0 = _mm_movehl_ps(mul0, mul0); + glm_vec4 const add0 = _mm_add_ps(mov0, mul0); + glm_vec4 const swp1 = _mm_shuffle_ps(add0, add0, 1); + glm_vec4 const add1 = _mm_add_ss(add0, swp1); + return add1; +# endif +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_cross(glm_vec4 v1, glm_vec4 v2) +{ + glm_vec4 const swp0 = _mm_shuffle_ps(v1, v1, _MM_SHUFFLE(3, 0, 2, 1)); + glm_vec4 const swp1 = _mm_shuffle_ps(v1, v1, _MM_SHUFFLE(3, 1, 0, 2)); + glm_vec4 const swp2 = _mm_shuffle_ps(v2, v2, _MM_SHUFFLE(3, 0, 2, 1)); + glm_vec4 const swp3 = _mm_shuffle_ps(v2, v2, _MM_SHUFFLE(3, 1, 0, 2)); + glm_vec4 const mul0 = _mm_mul_ps(swp0, swp3); + glm_vec4 const mul1 = _mm_mul_ps(swp1, swp2); + glm_vec4 const sub0 = _mm_sub_ps(mul0, mul1); + return sub0; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_normalize(glm_vec4 v) +{ + glm_vec4 const dot0 = glm_vec4_dot(v, v); + glm_vec4 const isr0 = _mm_rsqrt_ps(dot0); + glm_vec4 const mul0 = _mm_mul_ps(v, isr0); + return mul0; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_faceforward(glm_vec4 N, glm_vec4 I, glm_vec4 Nref) +{ + glm_vec4 const dot0 = glm_vec4_dot(Nref, I); + glm_vec4 const sgn0 = glm_vec4_sign(dot0); + glm_vec4 const mul0 = _mm_mul_ps(sgn0, _mm_set1_ps(-1.0f)); + glm_vec4 const mul1 = _mm_mul_ps(N, mul0); + return mul1; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_reflect(glm_vec4 I, glm_vec4 N) +{ + glm_vec4 const dot0 = glm_vec4_dot(N, I); + glm_vec4 const mul0 = _mm_mul_ps(N, dot0); + glm_vec4 const mul1 = _mm_mul_ps(mul0, _mm_set1_ps(2.0f)); + glm_vec4 const sub0 = _mm_sub_ps(I, mul1); + return sub0; +} + +GLM_FUNC_QUALIFIER __m128 glm_vec4_refract(glm_vec4 I, glm_vec4 N, glm_vec4 eta) +{ + glm_vec4 const dot0 = glm_vec4_dot(N, I); + glm_vec4 const mul0 = _mm_mul_ps(eta, eta); + glm_vec4 const mul1 = _mm_mul_ps(dot0, dot0); + glm_vec4 const sub0 = _mm_sub_ps(_mm_set1_ps(1.0f), mul0); + glm_vec4 const sub1 = _mm_sub_ps(_mm_set1_ps(1.0f), mul1); + glm_vec4 const mul2 = _mm_mul_ps(sub0, sub1); + + if(_mm_movemask_ps(_mm_cmplt_ss(mul2, _mm_set1_ps(0.0f))) == 0) + return _mm_set1_ps(0.0f); + + glm_vec4 const sqt0 = _mm_sqrt_ps(mul2); + glm_vec4 const mad0 = glm_vec4_fma(eta, dot0, sqt0); + glm_vec4 const mul4 = _mm_mul_ps(mad0, N); + glm_vec4 const mul5 = _mm_mul_ps(eta, I); + glm_vec4 const sub2 = _mm_sub_ps(mul5, mul4); + + return sub2; +} + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/simd/integer.h b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/simd/integer.h new file mode 100644 index 0000000000000000000000000000000000000000..93814183fe027ab62e3532062de1abbb0ffe8c9e --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/simd/integer.h @@ -0,0 +1,115 @@ +/// @ref simd +/// @file glm/simd/integer.h + +#pragma once + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +GLM_FUNC_QUALIFIER glm_uvec4 glm_i128_interleave(glm_uvec4 x) +{ + glm_uvec4 const Mask4 = _mm_set1_epi32(0x0000FFFF); + glm_uvec4 const Mask3 = _mm_set1_epi32(0x00FF00FF); + glm_uvec4 const Mask2 = _mm_set1_epi32(0x0F0F0F0F); + glm_uvec4 const Mask1 = _mm_set1_epi32(0x33333333); + glm_uvec4 const Mask0 = _mm_set1_epi32(0x55555555); + + glm_uvec4 Reg1; + glm_uvec4 Reg2; + + // REG1 = x; + // REG2 = y; + //Reg1 = _mm_unpacklo_epi64(x, y); + Reg1 = x; + + //REG1 = ((REG1 << 16) | REG1) & glm::uint64(0x0000FFFF0000FFFF); + //REG2 = ((REG2 << 16) | REG2) & glm::uint64(0x0000FFFF0000FFFF); + Reg2 = _mm_slli_si128(Reg1, 2); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask4); + + //REG1 = ((REG1 << 8) | REG1) & glm::uint64(0x00FF00FF00FF00FF); + //REG2 = ((REG2 << 8) | REG2) & glm::uint64(0x00FF00FF00FF00FF); + Reg2 = _mm_slli_si128(Reg1, 1); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask3); + + //REG1 = ((REG1 << 4) | REG1) & glm::uint64(0x0F0F0F0F0F0F0F0F); + //REG2 = ((REG2 << 4) | REG2) & glm::uint64(0x0F0F0F0F0F0F0F0F); + Reg2 = _mm_slli_epi32(Reg1, 4); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask2); + + //REG1 = ((REG1 << 2) | REG1) & glm::uint64(0x3333333333333333); + //REG2 = ((REG2 << 2) | REG2) & glm::uint64(0x3333333333333333); + Reg2 = _mm_slli_epi32(Reg1, 2); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask1); + + //REG1 = ((REG1 << 1) | REG1) & glm::uint64(0x5555555555555555); + //REG2 = ((REG2 << 1) | REG2) & glm::uint64(0x5555555555555555); + Reg2 = _mm_slli_epi32(Reg1, 1); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask0); + + //return REG1 | (REG2 << 1); + Reg2 = _mm_slli_epi32(Reg1, 1); + Reg2 = _mm_srli_si128(Reg2, 8); + Reg1 = _mm_or_si128(Reg1, Reg2); + + return Reg1; +} + +GLM_FUNC_QUALIFIER glm_uvec4 glm_i128_interleave2(glm_uvec4 x, glm_uvec4 y) +{ + glm_uvec4 const Mask4 = _mm_set1_epi32(0x0000FFFF); + glm_uvec4 const Mask3 = _mm_set1_epi32(0x00FF00FF); + glm_uvec4 const Mask2 = _mm_set1_epi32(0x0F0F0F0F); + glm_uvec4 const Mask1 = _mm_set1_epi32(0x33333333); + glm_uvec4 const Mask0 = _mm_set1_epi32(0x55555555); + + glm_uvec4 Reg1; + glm_uvec4 Reg2; + + // REG1 = x; + // REG2 = y; + Reg1 = _mm_unpacklo_epi64(x, y); + + //REG1 = ((REG1 << 16) | REG1) & glm::uint64(0x0000FFFF0000FFFF); + //REG2 = ((REG2 << 16) | REG2) & glm::uint64(0x0000FFFF0000FFFF); + Reg2 = _mm_slli_si128(Reg1, 2); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask4); + + //REG1 = ((REG1 << 8) | REG1) & glm::uint64(0x00FF00FF00FF00FF); + //REG2 = ((REG2 << 8) | REG2) & glm::uint64(0x00FF00FF00FF00FF); + Reg2 = _mm_slli_si128(Reg1, 1); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask3); + + //REG1 = ((REG1 << 4) | REG1) & glm::uint64(0x0F0F0F0F0F0F0F0F); + //REG2 = ((REG2 << 4) | REG2) & glm::uint64(0x0F0F0F0F0F0F0F0F); + Reg2 = _mm_slli_epi32(Reg1, 4); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask2); + + //REG1 = ((REG1 << 2) | REG1) & glm::uint64(0x3333333333333333); + //REG2 = ((REG2 << 2) | REG2) & glm::uint64(0x3333333333333333); + Reg2 = _mm_slli_epi32(Reg1, 2); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask1); + + //REG1 = ((REG1 << 1) | REG1) & glm::uint64(0x5555555555555555); + //REG2 = ((REG2 << 1) | REG2) & glm::uint64(0x5555555555555555); + Reg2 = _mm_slli_epi32(Reg1, 1); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask0); + + //return REG1 | (REG2 << 1); + Reg2 = _mm_slli_epi32(Reg1, 1); + Reg2 = _mm_srli_si128(Reg2, 8); + Reg1 = _mm_or_si128(Reg1, Reg2); + + return Reg1; +} + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/simd/matrix.h b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/simd/matrix.h new file mode 100644 index 0000000000000000000000000000000000000000..b6c42ea4c17cff134a492d057309a131489ef51a --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/simd/matrix.h @@ -0,0 +1,1028 @@ +/// @ref simd +/// @file glm/simd/matrix.h + +#pragma once + +#include "geometric.h" + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +GLM_FUNC_QUALIFIER void glm_mat4_matrixCompMult(glm_vec4 const in1[4], glm_vec4 const in2[4], glm_vec4 out[4]) +{ + out[0] = _mm_mul_ps(in1[0], in2[0]); + out[1] = _mm_mul_ps(in1[1], in2[1]); + out[2] = _mm_mul_ps(in1[2], in2[2]); + out[3] = _mm_mul_ps(in1[3], in2[3]); +} + +GLM_FUNC_QUALIFIER void glm_mat4_add(glm_vec4 const in1[4], glm_vec4 const in2[4], glm_vec4 out[4]) +{ + out[0] = _mm_add_ps(in1[0], in2[0]); + out[1] = _mm_add_ps(in1[1], in2[1]); + out[2] = _mm_add_ps(in1[2], in2[2]); + out[3] = _mm_add_ps(in1[3], in2[3]); +} + +GLM_FUNC_QUALIFIER void glm_mat4_sub(glm_vec4 const in1[4], glm_vec4 const in2[4], glm_vec4 out[4]) +{ + out[0] = _mm_sub_ps(in1[0], in2[0]); + out[1] = _mm_sub_ps(in1[1], in2[1]); + out[2] = _mm_sub_ps(in1[2], in2[2]); + out[3] = _mm_sub_ps(in1[3], in2[3]); +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_mat4_mul_vec4(glm_vec4 const m[4], glm_vec4 v) +{ + __m128 v0 = _mm_shuffle_ps(v, v, _MM_SHUFFLE(0, 0, 0, 0)); + __m128 v1 = _mm_shuffle_ps(v, v, _MM_SHUFFLE(1, 1, 1, 1)); + __m128 v2 = _mm_shuffle_ps(v, v, _MM_SHUFFLE(2, 2, 2, 2)); + __m128 v3 = _mm_shuffle_ps(v, v, _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 m0 = _mm_mul_ps(m[0], v0); + __m128 m1 = _mm_mul_ps(m[1], v1); + __m128 m2 = _mm_mul_ps(m[2], v2); + __m128 m3 = _mm_mul_ps(m[3], v3); + + __m128 a0 = _mm_add_ps(m0, m1); + __m128 a1 = _mm_add_ps(m2, m3); + __m128 a2 = _mm_add_ps(a0, a1); + + return a2; +} + +GLM_FUNC_QUALIFIER __m128 glm_vec4_mul_mat4(glm_vec4 v, glm_vec4 const m[4]) +{ + __m128 i0 = m[0]; + __m128 i1 = m[1]; + __m128 i2 = m[2]; + __m128 i3 = m[3]; + + __m128 m0 = _mm_mul_ps(v, i0); + __m128 m1 = _mm_mul_ps(v, i1); + __m128 m2 = _mm_mul_ps(v, i2); + __m128 m3 = _mm_mul_ps(v, i3); + + __m128 u0 = _mm_unpacklo_ps(m0, m1); + __m128 u1 = _mm_unpackhi_ps(m0, m1); + __m128 a0 = _mm_add_ps(u0, u1); + + __m128 u2 = _mm_unpacklo_ps(m2, m3); + __m128 u3 = _mm_unpackhi_ps(m2, m3); + __m128 a1 = _mm_add_ps(u2, u3); + + __m128 f0 = _mm_movelh_ps(a0, a1); + __m128 f1 = _mm_movehl_ps(a1, a0); + __m128 f2 = _mm_add_ps(f0, f1); + + return f2; +} + +GLM_FUNC_QUALIFIER void glm_mat4_mul(glm_vec4 const in1[4], glm_vec4 const in2[4], glm_vec4 out[4]) +{ + { + __m128 e0 = _mm_shuffle_ps(in2[0], in2[0], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 e1 = _mm_shuffle_ps(in2[0], in2[0], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 e2 = _mm_shuffle_ps(in2[0], in2[0], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 e3 = _mm_shuffle_ps(in2[0], in2[0], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 m0 = _mm_mul_ps(in1[0], e0); + __m128 m1 = _mm_mul_ps(in1[1], e1); + __m128 m2 = _mm_mul_ps(in1[2], e2); + __m128 m3 = _mm_mul_ps(in1[3], e3); + + __m128 a0 = _mm_add_ps(m0, m1); + __m128 a1 = _mm_add_ps(m2, m3); + __m128 a2 = _mm_add_ps(a0, a1); + + out[0] = a2; + } + + { + __m128 e0 = _mm_shuffle_ps(in2[1], in2[1], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 e1 = _mm_shuffle_ps(in2[1], in2[1], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 e2 = _mm_shuffle_ps(in2[1], in2[1], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 e3 = _mm_shuffle_ps(in2[1], in2[1], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 m0 = _mm_mul_ps(in1[0], e0); + __m128 m1 = _mm_mul_ps(in1[1], e1); + __m128 m2 = _mm_mul_ps(in1[2], e2); + __m128 m3 = _mm_mul_ps(in1[3], e3); + + __m128 a0 = _mm_add_ps(m0, m1); + __m128 a1 = _mm_add_ps(m2, m3); + __m128 a2 = _mm_add_ps(a0, a1); + + out[1] = a2; + } + + { + __m128 e0 = _mm_shuffle_ps(in2[2], in2[2], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 e1 = _mm_shuffle_ps(in2[2], in2[2], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 e2 = _mm_shuffle_ps(in2[2], in2[2], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 e3 = _mm_shuffle_ps(in2[2], in2[2], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 m0 = _mm_mul_ps(in1[0], e0); + __m128 m1 = _mm_mul_ps(in1[1], e1); + __m128 m2 = _mm_mul_ps(in1[2], e2); + __m128 m3 = _mm_mul_ps(in1[3], e3); + + __m128 a0 = _mm_add_ps(m0, m1); + __m128 a1 = _mm_add_ps(m2, m3); + __m128 a2 = _mm_add_ps(a0, a1); + + out[2] = a2; + } + + { + //(__m128&)_mm_shuffle_epi32(__m128i&)in2[0], _MM_SHUFFLE(3, 3, 3, 3)) + __m128 e0 = _mm_shuffle_ps(in2[3], in2[3], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 e1 = _mm_shuffle_ps(in2[3], in2[3], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 e2 = _mm_shuffle_ps(in2[3], in2[3], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 e3 = _mm_shuffle_ps(in2[3], in2[3], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 m0 = _mm_mul_ps(in1[0], e0); + __m128 m1 = _mm_mul_ps(in1[1], e1); + __m128 m2 = _mm_mul_ps(in1[2], e2); + __m128 m3 = _mm_mul_ps(in1[3], e3); + + __m128 a0 = _mm_add_ps(m0, m1); + __m128 a1 = _mm_add_ps(m2, m3); + __m128 a2 = _mm_add_ps(a0, a1); + + out[3] = a2; + } +} + +GLM_FUNC_QUALIFIER void glm_mat4_transpose(glm_vec4 const in[4], glm_vec4 out[4]) +{ + __m128 tmp0 = _mm_shuffle_ps(in[0], in[1], 0x44); + __m128 tmp2 = _mm_shuffle_ps(in[0], in[1], 0xEE); + __m128 tmp1 = _mm_shuffle_ps(in[2], in[3], 0x44); + __m128 tmp3 = _mm_shuffle_ps(in[2], in[3], 0xEE); + + out[0] = _mm_shuffle_ps(tmp0, tmp1, 0x88); + out[1] = _mm_shuffle_ps(tmp0, tmp1, 0xDD); + out[2] = _mm_shuffle_ps(tmp2, tmp3, 0x88); + out[3] = _mm_shuffle_ps(tmp2, tmp3, 0xDD); +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_mat4_determinant_highp(glm_vec4 const in[4]) +{ + __m128 Fac0; + { + // valType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + // valType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + // valType SubFactor06 = m[1][2] * m[3][3] - m[3][2] * m[1][3]; + // valType SubFactor13 = m[1][2] * m[2][3] - m[2][2] * m[1][3]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac0 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac1; + { + // valType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + // valType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + // valType SubFactor07 = m[1][1] * m[3][3] - m[3][1] * m[1][3]; + // valType SubFactor14 = m[1][1] * m[2][3] - m[2][1] * m[1][3]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac1 = _mm_sub_ps(Mul00, Mul01); + } + + + __m128 Fac2; + { + // valType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + // valType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + // valType SubFactor08 = m[1][1] * m[3][2] - m[3][1] * m[1][2]; + // valType SubFactor15 = m[1][1] * m[2][2] - m[2][1] * m[1][2]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac2 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac3; + { + // valType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + // valType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + // valType SubFactor09 = m[1][0] * m[3][3] - m[3][0] * m[1][3]; + // valType SubFactor16 = m[1][0] * m[2][3] - m[2][0] * m[1][3]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac3 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac4; + { + // valType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + // valType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + // valType SubFactor10 = m[1][0] * m[3][2] - m[3][0] * m[1][2]; + // valType SubFactor17 = m[1][0] * m[2][2] - m[2][0] * m[1][2]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac4 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac5; + { + // valType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + // valType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + // valType SubFactor12 = m[1][0] * m[3][1] - m[3][0] * m[1][1]; + // valType SubFactor18 = m[1][0] * m[2][1] - m[2][0] * m[1][1]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac5 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 SignA = _mm_set_ps( 1.0f,-1.0f, 1.0f,-1.0f); + __m128 SignB = _mm_set_ps(-1.0f, 1.0f,-1.0f, 1.0f); + + // m[1][0] + // m[0][0] + // m[0][0] + // m[0][0] + __m128 Temp0 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Vec0 = _mm_shuffle_ps(Temp0, Temp0, _MM_SHUFFLE(2, 2, 2, 0)); + + // m[1][1] + // m[0][1] + // m[0][1] + // m[0][1] + __m128 Temp1 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Vec1 = _mm_shuffle_ps(Temp1, Temp1, _MM_SHUFFLE(2, 2, 2, 0)); + + // m[1][2] + // m[0][2] + // m[0][2] + // m[0][2] + __m128 Temp2 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Vec2 = _mm_shuffle_ps(Temp2, Temp2, _MM_SHUFFLE(2, 2, 2, 0)); + + // m[1][3] + // m[0][3] + // m[0][3] + // m[0][3] + __m128 Temp3 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Vec3 = _mm_shuffle_ps(Temp3, Temp3, _MM_SHUFFLE(2, 2, 2, 0)); + + // col0 + // + (Vec1[0] * Fac0[0] - Vec2[0] * Fac1[0] + Vec3[0] * Fac2[0]), + // - (Vec1[1] * Fac0[1] - Vec2[1] * Fac1[1] + Vec3[1] * Fac2[1]), + // + (Vec1[2] * Fac0[2] - Vec2[2] * Fac1[2] + Vec3[2] * Fac2[2]), + // - (Vec1[3] * Fac0[3] - Vec2[3] * Fac1[3] + Vec3[3] * Fac2[3]), + __m128 Mul00 = _mm_mul_ps(Vec1, Fac0); + __m128 Mul01 = _mm_mul_ps(Vec2, Fac1); + __m128 Mul02 = _mm_mul_ps(Vec3, Fac2); + __m128 Sub00 = _mm_sub_ps(Mul00, Mul01); + __m128 Add00 = _mm_add_ps(Sub00, Mul02); + __m128 Inv0 = _mm_mul_ps(SignB, Add00); + + // col1 + // - (Vec0[0] * Fac0[0] - Vec2[0] * Fac3[0] + Vec3[0] * Fac4[0]), + // + (Vec0[0] * Fac0[1] - Vec2[1] * Fac3[1] + Vec3[1] * Fac4[1]), + // - (Vec0[0] * Fac0[2] - Vec2[2] * Fac3[2] + Vec3[2] * Fac4[2]), + // + (Vec0[0] * Fac0[3] - Vec2[3] * Fac3[3] + Vec3[3] * Fac4[3]), + __m128 Mul03 = _mm_mul_ps(Vec0, Fac0); + __m128 Mul04 = _mm_mul_ps(Vec2, Fac3); + __m128 Mul05 = _mm_mul_ps(Vec3, Fac4); + __m128 Sub01 = _mm_sub_ps(Mul03, Mul04); + __m128 Add01 = _mm_add_ps(Sub01, Mul05); + __m128 Inv1 = _mm_mul_ps(SignA, Add01); + + // col2 + // + (Vec0[0] * Fac1[0] - Vec1[0] * Fac3[0] + Vec3[0] * Fac5[0]), + // - (Vec0[0] * Fac1[1] - Vec1[1] * Fac3[1] + Vec3[1] * Fac5[1]), + // + (Vec0[0] * Fac1[2] - Vec1[2] * Fac3[2] + Vec3[2] * Fac5[2]), + // - (Vec0[0] * Fac1[3] - Vec1[3] * Fac3[3] + Vec3[3] * Fac5[3]), + __m128 Mul06 = _mm_mul_ps(Vec0, Fac1); + __m128 Mul07 = _mm_mul_ps(Vec1, Fac3); + __m128 Mul08 = _mm_mul_ps(Vec3, Fac5); + __m128 Sub02 = _mm_sub_ps(Mul06, Mul07); + __m128 Add02 = _mm_add_ps(Sub02, Mul08); + __m128 Inv2 = _mm_mul_ps(SignB, Add02); + + // col3 + // - (Vec1[0] * Fac2[0] - Vec1[0] * Fac4[0] + Vec2[0] * Fac5[0]), + // + (Vec1[0] * Fac2[1] - Vec1[1] * Fac4[1] + Vec2[1] * Fac5[1]), + // - (Vec1[0] * Fac2[2] - Vec1[2] * Fac4[2] + Vec2[2] * Fac5[2]), + // + (Vec1[0] * Fac2[3] - Vec1[3] * Fac4[3] + Vec2[3] * Fac5[3])); + __m128 Mul09 = _mm_mul_ps(Vec0, Fac2); + __m128 Mul10 = _mm_mul_ps(Vec1, Fac4); + __m128 Mul11 = _mm_mul_ps(Vec2, Fac5); + __m128 Sub03 = _mm_sub_ps(Mul09, Mul10); + __m128 Add03 = _mm_add_ps(Sub03, Mul11); + __m128 Inv3 = _mm_mul_ps(SignA, Add03); + + __m128 Row0 = _mm_shuffle_ps(Inv0, Inv1, _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Row1 = _mm_shuffle_ps(Inv2, Inv3, _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Row2 = _mm_shuffle_ps(Row0, Row1, _MM_SHUFFLE(2, 0, 2, 0)); + + // valType Determinant = m[0][0] * Inverse[0][0] + // + m[0][1] * Inverse[1][0] + // + m[0][2] * Inverse[2][0] + // + m[0][3] * Inverse[3][0]; + __m128 Det0 = glm_vec4_dot(in[0], Row2); + return Det0; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_mat4_determinant_lowp(glm_vec4 const m[4]) +{ + // _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128( + + //T SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + //T SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + //T SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + //T SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + //T SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + //T SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + + // First 2 columns + __m128 Swp2A = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[2]), _MM_SHUFFLE(0, 1, 1, 2))); + __m128 Swp3A = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[3]), _MM_SHUFFLE(3, 2, 3, 3))); + __m128 MulA = _mm_mul_ps(Swp2A, Swp3A); + + // Second 2 columns + __m128 Swp2B = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[2]), _MM_SHUFFLE(3, 2, 3, 3))); + __m128 Swp3B = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[3]), _MM_SHUFFLE(0, 1, 1, 2))); + __m128 MulB = _mm_mul_ps(Swp2B, Swp3B); + + // Columns subtraction + __m128 SubE = _mm_sub_ps(MulA, MulB); + + // Last 2 rows + __m128 Swp2C = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[2]), _MM_SHUFFLE(0, 0, 1, 2))); + __m128 Swp3C = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[3]), _MM_SHUFFLE(1, 2, 0, 0))); + __m128 MulC = _mm_mul_ps(Swp2C, Swp3C); + __m128 SubF = _mm_sub_ps(_mm_movehl_ps(MulC, MulC), MulC); + + //vec<4, T, Q> DetCof( + // + (m[1][1] * SubFactor00 - m[1][2] * SubFactor01 + m[1][3] * SubFactor02), + // - (m[1][0] * SubFactor00 - m[1][2] * SubFactor03 + m[1][3] * SubFactor04), + // + (m[1][0] * SubFactor01 - m[1][1] * SubFactor03 + m[1][3] * SubFactor05), + // - (m[1][0] * SubFactor02 - m[1][1] * SubFactor04 + m[1][2] * SubFactor05)); + + __m128 SubFacA = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(SubE), _MM_SHUFFLE(2, 1, 0, 0))); + __m128 SwpFacA = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[1]), _MM_SHUFFLE(0, 0, 0, 1))); + __m128 MulFacA = _mm_mul_ps(SwpFacA, SubFacA); + + __m128 SubTmpB = _mm_shuffle_ps(SubE, SubF, _MM_SHUFFLE(0, 0, 3, 1)); + __m128 SubFacB = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(SubTmpB), _MM_SHUFFLE(3, 1, 1, 0)));//SubF[0], SubE[3], SubE[3], SubE[1]; + __m128 SwpFacB = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[1]), _MM_SHUFFLE(1, 1, 2, 2))); + __m128 MulFacB = _mm_mul_ps(SwpFacB, SubFacB); + + __m128 SubRes = _mm_sub_ps(MulFacA, MulFacB); + + __m128 SubTmpC = _mm_shuffle_ps(SubE, SubF, _MM_SHUFFLE(1, 0, 2, 2)); + __m128 SubFacC = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(SubTmpC), _MM_SHUFFLE(3, 3, 2, 0))); + __m128 SwpFacC = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[1]), _MM_SHUFFLE(2, 3, 3, 3))); + __m128 MulFacC = _mm_mul_ps(SwpFacC, SubFacC); + + __m128 AddRes = _mm_add_ps(SubRes, MulFacC); + __m128 DetCof = _mm_mul_ps(AddRes, _mm_setr_ps( 1.0f,-1.0f, 1.0f,-1.0f)); + + //return m[0][0] * DetCof[0] + // + m[0][1] * DetCof[1] + // + m[0][2] * DetCof[2] + // + m[0][3] * DetCof[3]; + + return glm_vec4_dot(m[0], DetCof); +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_mat4_determinant(glm_vec4 const m[4]) +{ + // _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(add) + + //T SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + //T SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + //T SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + //T SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + //T SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + //T SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + + // First 2 columns + __m128 Swp2A = _mm_shuffle_ps(m[2], m[2], _MM_SHUFFLE(0, 1, 1, 2)); + __m128 Swp3A = _mm_shuffle_ps(m[3], m[3], _MM_SHUFFLE(3, 2, 3, 3)); + __m128 MulA = _mm_mul_ps(Swp2A, Swp3A); + + // Second 2 columns + __m128 Swp2B = _mm_shuffle_ps(m[2], m[2], _MM_SHUFFLE(3, 2, 3, 3)); + __m128 Swp3B = _mm_shuffle_ps(m[3], m[3], _MM_SHUFFLE(0, 1, 1, 2)); + __m128 MulB = _mm_mul_ps(Swp2B, Swp3B); + + // Columns subtraction + __m128 SubE = _mm_sub_ps(MulA, MulB); + + // Last 2 rows + __m128 Swp2C = _mm_shuffle_ps(m[2], m[2], _MM_SHUFFLE(0, 0, 1, 2)); + __m128 Swp3C = _mm_shuffle_ps(m[3], m[3], _MM_SHUFFLE(1, 2, 0, 0)); + __m128 MulC = _mm_mul_ps(Swp2C, Swp3C); + __m128 SubF = _mm_sub_ps(_mm_movehl_ps(MulC, MulC), MulC); + + //vec<4, T, Q> DetCof( + // + (m[1][1] * SubFactor00 - m[1][2] * SubFactor01 + m[1][3] * SubFactor02), + // - (m[1][0] * SubFactor00 - m[1][2] * SubFactor03 + m[1][3] * SubFactor04), + // + (m[1][0] * SubFactor01 - m[1][1] * SubFactor03 + m[1][3] * SubFactor05), + // - (m[1][0] * SubFactor02 - m[1][1] * SubFactor04 + m[1][2] * SubFactor05)); + + __m128 SubFacA = _mm_shuffle_ps(SubE, SubE, _MM_SHUFFLE(2, 1, 0, 0)); + __m128 SwpFacA = _mm_shuffle_ps(m[1], m[1], _MM_SHUFFLE(0, 0, 0, 1)); + __m128 MulFacA = _mm_mul_ps(SwpFacA, SubFacA); + + __m128 SubTmpB = _mm_shuffle_ps(SubE, SubF, _MM_SHUFFLE(0, 0, 3, 1)); + __m128 SubFacB = _mm_shuffle_ps(SubTmpB, SubTmpB, _MM_SHUFFLE(3, 1, 1, 0));//SubF[0], SubE[3], SubE[3], SubE[1]; + __m128 SwpFacB = _mm_shuffle_ps(m[1], m[1], _MM_SHUFFLE(1, 1, 2, 2)); + __m128 MulFacB = _mm_mul_ps(SwpFacB, SubFacB); + + __m128 SubRes = _mm_sub_ps(MulFacA, MulFacB); + + __m128 SubTmpC = _mm_shuffle_ps(SubE, SubF, _MM_SHUFFLE(1, 0, 2, 2)); + __m128 SubFacC = _mm_shuffle_ps(SubTmpC, SubTmpC, _MM_SHUFFLE(3, 3, 2, 0)); + __m128 SwpFacC = _mm_shuffle_ps(m[1], m[1], _MM_SHUFFLE(2, 3, 3, 3)); + __m128 MulFacC = _mm_mul_ps(SwpFacC, SubFacC); + + __m128 AddRes = _mm_add_ps(SubRes, MulFacC); + __m128 DetCof = _mm_mul_ps(AddRes, _mm_setr_ps( 1.0f,-1.0f, 1.0f,-1.0f)); + + //return m[0][0] * DetCof[0] + // + m[0][1] * DetCof[1] + // + m[0][2] * DetCof[2] + // + m[0][3] * DetCof[3]; + + return glm_vec4_dot(m[0], DetCof); +} + +GLM_FUNC_QUALIFIER void glm_mat4_inverse(glm_vec4 const in[4], glm_vec4 out[4]) +{ + __m128 Fac0; + { + // valType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + // valType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + // valType SubFactor06 = m[1][2] * m[3][3] - m[3][2] * m[1][3]; + // valType SubFactor13 = m[1][2] * m[2][3] - m[2][2] * m[1][3]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac0 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac1; + { + // valType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + // valType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + // valType SubFactor07 = m[1][1] * m[3][3] - m[3][1] * m[1][3]; + // valType SubFactor14 = m[1][1] * m[2][3] - m[2][1] * m[1][3]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac1 = _mm_sub_ps(Mul00, Mul01); + } + + + __m128 Fac2; + { + // valType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + // valType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + // valType SubFactor08 = m[1][1] * m[3][2] - m[3][1] * m[1][2]; + // valType SubFactor15 = m[1][1] * m[2][2] - m[2][1] * m[1][2]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac2 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac3; + { + // valType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + // valType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + // valType SubFactor09 = m[1][0] * m[3][3] - m[3][0] * m[1][3]; + // valType SubFactor16 = m[1][0] * m[2][3] - m[2][0] * m[1][3]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac3 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac4; + { + // valType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + // valType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + // valType SubFactor10 = m[1][0] * m[3][2] - m[3][0] * m[1][2]; + // valType SubFactor17 = m[1][0] * m[2][2] - m[2][0] * m[1][2]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac4 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac5; + { + // valType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + // valType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + // valType SubFactor12 = m[1][0] * m[3][1] - m[3][0] * m[1][1]; + // valType SubFactor18 = m[1][0] * m[2][1] - m[2][0] * m[1][1]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac5 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 SignA = _mm_set_ps( 1.0f,-1.0f, 1.0f,-1.0f); + __m128 SignB = _mm_set_ps(-1.0f, 1.0f,-1.0f, 1.0f); + + // m[1][0] + // m[0][0] + // m[0][0] + // m[0][0] + __m128 Temp0 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Vec0 = _mm_shuffle_ps(Temp0, Temp0, _MM_SHUFFLE(2, 2, 2, 0)); + + // m[1][1] + // m[0][1] + // m[0][1] + // m[0][1] + __m128 Temp1 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Vec1 = _mm_shuffle_ps(Temp1, Temp1, _MM_SHUFFLE(2, 2, 2, 0)); + + // m[1][2] + // m[0][2] + // m[0][2] + // m[0][2] + __m128 Temp2 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Vec2 = _mm_shuffle_ps(Temp2, Temp2, _MM_SHUFFLE(2, 2, 2, 0)); + + // m[1][3] + // m[0][3] + // m[0][3] + // m[0][3] + __m128 Temp3 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Vec3 = _mm_shuffle_ps(Temp3, Temp3, _MM_SHUFFLE(2, 2, 2, 0)); + + // col0 + // + (Vec1[0] * Fac0[0] - Vec2[0] * Fac1[0] + Vec3[0] * Fac2[0]), + // - (Vec1[1] * Fac0[1] - Vec2[1] * Fac1[1] + Vec3[1] * Fac2[1]), + // + (Vec1[2] * Fac0[2] - Vec2[2] * Fac1[2] + Vec3[2] * Fac2[2]), + // - (Vec1[3] * Fac0[3] - Vec2[3] * Fac1[3] + Vec3[3] * Fac2[3]), + __m128 Mul00 = _mm_mul_ps(Vec1, Fac0); + __m128 Mul01 = _mm_mul_ps(Vec2, Fac1); + __m128 Mul02 = _mm_mul_ps(Vec3, Fac2); + __m128 Sub00 = _mm_sub_ps(Mul00, Mul01); + __m128 Add00 = _mm_add_ps(Sub00, Mul02); + __m128 Inv0 = _mm_mul_ps(SignB, Add00); + + // col1 + // - (Vec0[0] * Fac0[0] - Vec2[0] * Fac3[0] + Vec3[0] * Fac4[0]), + // + (Vec0[0] * Fac0[1] - Vec2[1] * Fac3[1] + Vec3[1] * Fac4[1]), + // - (Vec0[0] * Fac0[2] - Vec2[2] * Fac3[2] + Vec3[2] * Fac4[2]), + // + (Vec0[0] * Fac0[3] - Vec2[3] * Fac3[3] + Vec3[3] * Fac4[3]), + __m128 Mul03 = _mm_mul_ps(Vec0, Fac0); + __m128 Mul04 = _mm_mul_ps(Vec2, Fac3); + __m128 Mul05 = _mm_mul_ps(Vec3, Fac4); + __m128 Sub01 = _mm_sub_ps(Mul03, Mul04); + __m128 Add01 = _mm_add_ps(Sub01, Mul05); + __m128 Inv1 = _mm_mul_ps(SignA, Add01); + + // col2 + // + (Vec0[0] * Fac1[0] - Vec1[0] * Fac3[0] + Vec3[0] * Fac5[0]), + // - (Vec0[0] * Fac1[1] - Vec1[1] * Fac3[1] + Vec3[1] * Fac5[1]), + // + (Vec0[0] * Fac1[2] - Vec1[2] * Fac3[2] + Vec3[2] * Fac5[2]), + // - (Vec0[0] * Fac1[3] - Vec1[3] * Fac3[3] + Vec3[3] * Fac5[3]), + __m128 Mul06 = _mm_mul_ps(Vec0, Fac1); + __m128 Mul07 = _mm_mul_ps(Vec1, Fac3); + __m128 Mul08 = _mm_mul_ps(Vec3, Fac5); + __m128 Sub02 = _mm_sub_ps(Mul06, Mul07); + __m128 Add02 = _mm_add_ps(Sub02, Mul08); + __m128 Inv2 = _mm_mul_ps(SignB, Add02); + + // col3 + // - (Vec1[0] * Fac2[0] - Vec1[0] * Fac4[0] + Vec2[0] * Fac5[0]), + // + (Vec1[0] * Fac2[1] - Vec1[1] * Fac4[1] + Vec2[1] * Fac5[1]), + // - (Vec1[0] * Fac2[2] - Vec1[2] * Fac4[2] + Vec2[2] * Fac5[2]), + // + (Vec1[0] * Fac2[3] - Vec1[3] * Fac4[3] + Vec2[3] * Fac5[3])); + __m128 Mul09 = _mm_mul_ps(Vec0, Fac2); + __m128 Mul10 = _mm_mul_ps(Vec1, Fac4); + __m128 Mul11 = _mm_mul_ps(Vec2, Fac5); + __m128 Sub03 = _mm_sub_ps(Mul09, Mul10); + __m128 Add03 = _mm_add_ps(Sub03, Mul11); + __m128 Inv3 = _mm_mul_ps(SignA, Add03); + + __m128 Row0 = _mm_shuffle_ps(Inv0, Inv1, _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Row1 = _mm_shuffle_ps(Inv2, Inv3, _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Row2 = _mm_shuffle_ps(Row0, Row1, _MM_SHUFFLE(2, 0, 2, 0)); + + // valType Determinant = m[0][0] * Inverse[0][0] + // + m[0][1] * Inverse[1][0] + // + m[0][2] * Inverse[2][0] + // + m[0][3] * Inverse[3][0]; + __m128 Det0 = glm_vec4_dot(in[0], Row2); + __m128 Rcp0 = _mm_div_ps(_mm_set1_ps(1.0f), Det0); + //__m128 Rcp0 = _mm_rcp_ps(Det0); + + // Inverse /= Determinant; + out[0] = _mm_mul_ps(Inv0, Rcp0); + out[1] = _mm_mul_ps(Inv1, Rcp0); + out[2] = _mm_mul_ps(Inv2, Rcp0); + out[3] = _mm_mul_ps(Inv3, Rcp0); +} + +GLM_FUNC_QUALIFIER void glm_mat4_inverse_lowp(glm_vec4 const in[4], glm_vec4 out[4]) +{ + __m128 Fac0; + { + // valType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + // valType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + // valType SubFactor06 = m[1][2] * m[3][3] - m[3][2] * m[1][3]; + // valType SubFactor13 = m[1][2] * m[2][3] - m[2][2] * m[1][3]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac0 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac1; + { + // valType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + // valType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + // valType SubFactor07 = m[1][1] * m[3][3] - m[3][1] * m[1][3]; + // valType SubFactor14 = m[1][1] * m[2][3] - m[2][1] * m[1][3]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac1 = _mm_sub_ps(Mul00, Mul01); + } + + + __m128 Fac2; + { + // valType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + // valType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + // valType SubFactor08 = m[1][1] * m[3][2] - m[3][1] * m[1][2]; + // valType SubFactor15 = m[1][1] * m[2][2] - m[2][1] * m[1][2]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac2 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac3; + { + // valType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + // valType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + // valType SubFactor09 = m[1][0] * m[3][3] - m[3][0] * m[1][3]; + // valType SubFactor16 = m[1][0] * m[2][3] - m[2][0] * m[1][3]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac3 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac4; + { + // valType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + // valType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + // valType SubFactor10 = m[1][0] * m[3][2] - m[3][0] * m[1][2]; + // valType SubFactor17 = m[1][0] * m[2][2] - m[2][0] * m[1][2]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac4 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac5; + { + // valType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + // valType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + // valType SubFactor12 = m[1][0] * m[3][1] - m[3][0] * m[1][1]; + // valType SubFactor18 = m[1][0] * m[2][1] - m[2][0] * m[1][1]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac5 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 SignA = _mm_set_ps( 1.0f,-1.0f, 1.0f,-1.0f); + __m128 SignB = _mm_set_ps(-1.0f, 1.0f,-1.0f, 1.0f); + + // m[1][0] + // m[0][0] + // m[0][0] + // m[0][0] + __m128 Temp0 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Vec0 = _mm_shuffle_ps(Temp0, Temp0, _MM_SHUFFLE(2, 2, 2, 0)); + + // m[1][1] + // m[0][1] + // m[0][1] + // m[0][1] + __m128 Temp1 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Vec1 = _mm_shuffle_ps(Temp1, Temp1, _MM_SHUFFLE(2, 2, 2, 0)); + + // m[1][2] + // m[0][2] + // m[0][2] + // m[0][2] + __m128 Temp2 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Vec2 = _mm_shuffle_ps(Temp2, Temp2, _MM_SHUFFLE(2, 2, 2, 0)); + + // m[1][3] + // m[0][3] + // m[0][3] + // m[0][3] + __m128 Temp3 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Vec3 = _mm_shuffle_ps(Temp3, Temp3, _MM_SHUFFLE(2, 2, 2, 0)); + + // col0 + // + (Vec1[0] * Fac0[0] - Vec2[0] * Fac1[0] + Vec3[0] * Fac2[0]), + // - (Vec1[1] * Fac0[1] - Vec2[1] * Fac1[1] + Vec3[1] * Fac2[1]), + // + (Vec1[2] * Fac0[2] - Vec2[2] * Fac1[2] + Vec3[2] * Fac2[2]), + // - (Vec1[3] * Fac0[3] - Vec2[3] * Fac1[3] + Vec3[3] * Fac2[3]), + __m128 Mul00 = _mm_mul_ps(Vec1, Fac0); + __m128 Mul01 = _mm_mul_ps(Vec2, Fac1); + __m128 Mul02 = _mm_mul_ps(Vec3, Fac2); + __m128 Sub00 = _mm_sub_ps(Mul00, Mul01); + __m128 Add00 = _mm_add_ps(Sub00, Mul02); + __m128 Inv0 = _mm_mul_ps(SignB, Add00); + + // col1 + // - (Vec0[0] * Fac0[0] - Vec2[0] * Fac3[0] + Vec3[0] * Fac4[0]), + // + (Vec0[0] * Fac0[1] - Vec2[1] * Fac3[1] + Vec3[1] * Fac4[1]), + // - (Vec0[0] * Fac0[2] - Vec2[2] * Fac3[2] + Vec3[2] * Fac4[2]), + // + (Vec0[0] * Fac0[3] - Vec2[3] * Fac3[3] + Vec3[3] * Fac4[3]), + __m128 Mul03 = _mm_mul_ps(Vec0, Fac0); + __m128 Mul04 = _mm_mul_ps(Vec2, Fac3); + __m128 Mul05 = _mm_mul_ps(Vec3, Fac4); + __m128 Sub01 = _mm_sub_ps(Mul03, Mul04); + __m128 Add01 = _mm_add_ps(Sub01, Mul05); + __m128 Inv1 = _mm_mul_ps(SignA, Add01); + + // col2 + // + (Vec0[0] * Fac1[0] - Vec1[0] * Fac3[0] + Vec3[0] * Fac5[0]), + // - (Vec0[0] * Fac1[1] - Vec1[1] * Fac3[1] + Vec3[1] * Fac5[1]), + // + (Vec0[0] * Fac1[2] - Vec1[2] * Fac3[2] + Vec3[2] * Fac5[2]), + // - (Vec0[0] * Fac1[3] - Vec1[3] * Fac3[3] + Vec3[3] * Fac5[3]), + __m128 Mul06 = _mm_mul_ps(Vec0, Fac1); + __m128 Mul07 = _mm_mul_ps(Vec1, Fac3); + __m128 Mul08 = _mm_mul_ps(Vec3, Fac5); + __m128 Sub02 = _mm_sub_ps(Mul06, Mul07); + __m128 Add02 = _mm_add_ps(Sub02, Mul08); + __m128 Inv2 = _mm_mul_ps(SignB, Add02); + + // col3 + // - (Vec1[0] * Fac2[0] - Vec1[0] * Fac4[0] + Vec2[0] * Fac5[0]), + // + (Vec1[0] * Fac2[1] - Vec1[1] * Fac4[1] + Vec2[1] * Fac5[1]), + // - (Vec1[0] * Fac2[2] - Vec1[2] * Fac4[2] + Vec2[2] * Fac5[2]), + // + (Vec1[0] * Fac2[3] - Vec1[3] * Fac4[3] + Vec2[3] * Fac5[3])); + __m128 Mul09 = _mm_mul_ps(Vec0, Fac2); + __m128 Mul10 = _mm_mul_ps(Vec1, Fac4); + __m128 Mul11 = _mm_mul_ps(Vec2, Fac5); + __m128 Sub03 = _mm_sub_ps(Mul09, Mul10); + __m128 Add03 = _mm_add_ps(Sub03, Mul11); + __m128 Inv3 = _mm_mul_ps(SignA, Add03); + + __m128 Row0 = _mm_shuffle_ps(Inv0, Inv1, _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Row1 = _mm_shuffle_ps(Inv2, Inv3, _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Row2 = _mm_shuffle_ps(Row0, Row1, _MM_SHUFFLE(2, 0, 2, 0)); + + // valType Determinant = m[0][0] * Inverse[0][0] + // + m[0][1] * Inverse[1][0] + // + m[0][2] * Inverse[2][0] + // + m[0][3] * Inverse[3][0]; + __m128 Det0 = glm_vec4_dot(in[0], Row2); + __m128 Rcp0 = _mm_rcp_ps(Det0); + //__m128 Rcp0 = _mm_div_ps(one, Det0); + // Inverse /= Determinant; + out[0] = _mm_mul_ps(Inv0, Rcp0); + out[1] = _mm_mul_ps(Inv1, Rcp0); + out[2] = _mm_mul_ps(Inv2, Rcp0); + out[3] = _mm_mul_ps(Inv3, Rcp0); +} +/* +GLM_FUNC_QUALIFIER void glm_mat4_rotate(__m128 const in[4], float Angle, float const v[3], __m128 out[4]) +{ + float a = glm::radians(Angle); + float c = cos(a); + float s = sin(a); + + glm::vec4 AxisA(v[0], v[1], v[2], float(0)); + __m128 AxisB = _mm_set_ps(AxisA.w, AxisA.z, AxisA.y, AxisA.x); + __m128 AxisC = detail::sse_nrm_ps(AxisB); + + __m128 Cos0 = _mm_set_ss(c); + __m128 CosA = _mm_shuffle_ps(Cos0, Cos0, _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Sin0 = _mm_set_ss(s); + __m128 SinA = _mm_shuffle_ps(Sin0, Sin0, _MM_SHUFFLE(0, 0, 0, 0)); + + // vec<3, T, Q> temp = (valType(1) - c) * axis; + __m128 Temp0 = _mm_sub_ps(one, CosA); + __m128 Temp1 = _mm_mul_ps(Temp0, AxisC); + + //Rotate[0][0] = c + temp[0] * axis[0]; + //Rotate[0][1] = 0 + temp[0] * axis[1] + s * axis[2]; + //Rotate[0][2] = 0 + temp[0] * axis[2] - s * axis[1]; + __m128 Axis0 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(0, 0, 0, 0)); + __m128 TmpA0 = _mm_mul_ps(Axis0, AxisC); + __m128 CosA0 = _mm_shuffle_ps(Cos0, Cos0, _MM_SHUFFLE(1, 1, 1, 0)); + __m128 TmpA1 = _mm_add_ps(CosA0, TmpA0); + __m128 SinA0 = SinA;//_mm_set_ps(0.0f, s, -s, 0.0f); + __m128 TmpA2 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(3, 1, 2, 3)); + __m128 TmpA3 = _mm_mul_ps(SinA0, TmpA2); + __m128 TmpA4 = _mm_add_ps(TmpA1, TmpA3); + + //Rotate[1][0] = 0 + temp[1] * axis[0] - s * axis[2]; + //Rotate[1][1] = c + temp[1] * axis[1]; + //Rotate[1][2] = 0 + temp[1] * axis[2] + s * axis[0]; + __m128 Axis1 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(1, 1, 1, 1)); + __m128 TmpB0 = _mm_mul_ps(Axis1, AxisC); + __m128 CosA1 = _mm_shuffle_ps(Cos0, Cos0, _MM_SHUFFLE(1, 1, 0, 1)); + __m128 TmpB1 = _mm_add_ps(CosA1, TmpB0); + __m128 SinB0 = SinA;//_mm_set_ps(-s, 0.0f, s, 0.0f); + __m128 TmpB2 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(3, 0, 3, 2)); + __m128 TmpB3 = _mm_mul_ps(SinA0, TmpB2); + __m128 TmpB4 = _mm_add_ps(TmpB1, TmpB3); + + //Rotate[2][0] = 0 + temp[2] * axis[0] + s * axis[1]; + //Rotate[2][1] = 0 + temp[2] * axis[1] - s * axis[0]; + //Rotate[2][2] = c + temp[2] * axis[2]; + __m128 Axis2 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(2, 2, 2, 2)); + __m128 TmpC0 = _mm_mul_ps(Axis2, AxisC); + __m128 CosA2 = _mm_shuffle_ps(Cos0, Cos0, _MM_SHUFFLE(1, 0, 1, 1)); + __m128 TmpC1 = _mm_add_ps(CosA2, TmpC0); + __m128 SinC0 = SinA;//_mm_set_ps(s, -s, 0.0f, 0.0f); + __m128 TmpC2 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(3, 3, 0, 1)); + __m128 TmpC3 = _mm_mul_ps(SinA0, TmpC2); + __m128 TmpC4 = _mm_add_ps(TmpC1, TmpC3); + + __m128 Result[4]; + Result[0] = TmpA4; + Result[1] = TmpB4; + Result[2] = TmpC4; + Result[3] = _mm_set_ps(1, 0, 0, 0); + + //mat<4, 4, valType> Result; + //Result[0] = m[0] * Rotate[0][0] + m[1] * Rotate[0][1] + m[2] * Rotate[0][2]; + //Result[1] = m[0] * Rotate[1][0] + m[1] * Rotate[1][1] + m[2] * Rotate[1][2]; + //Result[2] = m[0] * Rotate[2][0] + m[1] * Rotate[2][1] + m[2] * Rotate[2][2]; + //Result[3] = m[3]; + //return Result; + sse_mul_ps(in, Result, out); +} +*/ +GLM_FUNC_QUALIFIER void glm_mat4_outerProduct(__m128 const& c, __m128 const& r, __m128 out[4]) +{ + out[0] = _mm_mul_ps(c, _mm_shuffle_ps(r, r, _MM_SHUFFLE(0, 0, 0, 0))); + out[1] = _mm_mul_ps(c, _mm_shuffle_ps(r, r, _MM_SHUFFLE(1, 1, 1, 1))); + out[2] = _mm_mul_ps(c, _mm_shuffle_ps(r, r, _MM_SHUFFLE(2, 2, 2, 2))); + out[3] = _mm_mul_ps(c, _mm_shuffle_ps(r, r, _MM_SHUFFLE(3, 3, 3, 3))); +} + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/simd/neon.h b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/simd/neon.h new file mode 100644 index 0000000000000000000000000000000000000000..f85947f5c19a2b196e13287bce05fb97c2b4c99b --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/simd/neon.h @@ -0,0 +1,155 @@ +/// @ref simd_neon +/// @file glm/simd/neon.h + +#pragma once + +#if GLM_ARCH & GLM_ARCH_NEON_BIT +#include + +namespace glm { + namespace neon { + static inline float32x4_t dupq_lane(float32x4_t vsrc, int lane) { + switch(lane) { +#if GLM_ARCH & GLM_ARCH_ARMV8_BIT + case 0: return vdupq_laneq_f32(vsrc, 0); + case 1: return vdupq_laneq_f32(vsrc, 1); + case 2: return vdupq_laneq_f32(vsrc, 2); + case 3: return vdupq_laneq_f32(vsrc, 3); +#else + case 0: return vdupq_n_f32(vgetq_lane_f32(vsrc, 0)); + case 1: return vdupq_n_f32(vgetq_lane_f32(vsrc, 1)); + case 2: return vdupq_n_f32(vgetq_lane_f32(vsrc, 2)); + case 3: return vdupq_n_f32(vgetq_lane_f32(vsrc, 3)); +#endif + } + assert(!"Unreachable code executed!"); + return vdupq_n_f32(0.0f); + } + + static inline float32x2_t dup_lane(float32x4_t vsrc, int lane) { + switch(lane) { +#if GLM_ARCH & GLM_ARCH_ARMV8_BIT + case 0: return vdup_laneq_f32(vsrc, 0); + case 1: return vdup_laneq_f32(vsrc, 1); + case 2: return vdup_laneq_f32(vsrc, 2); + case 3: return vdup_laneq_f32(vsrc, 3); +#else + case 0: return vdup_n_f32(vgetq_lane_f32(vsrc, 0)); + case 1: return vdup_n_f32(vgetq_lane_f32(vsrc, 1)); + case 2: return vdup_n_f32(vgetq_lane_f32(vsrc, 2)); + case 3: return vdup_n_f32(vgetq_lane_f32(vsrc, 3)); +#endif + } + assert(!"Unreachable code executed!"); + return vdup_n_f32(0.0f); + } + + static inline float32x4_t copy_lane(float32x4_t vdst, int dlane, float32x4_t vsrc, int slane) { +#if GLM_ARCH & GLM_ARCH_ARMV8_BIT + switch(dlane) { + case 0: + switch(slane) { + case 0: return vcopyq_laneq_f32(vdst, 0, vsrc, 0); + case 1: return vcopyq_laneq_f32(vdst, 0, vsrc, 1); + case 2: return vcopyq_laneq_f32(vdst, 0, vsrc, 2); + case 3: return vcopyq_laneq_f32(vdst, 0, vsrc, 3); + } + assert(!"Unreachable code executed!"); + case 1: + switch(slane) { + case 0: return vcopyq_laneq_f32(vdst, 1, vsrc, 0); + case 1: return vcopyq_laneq_f32(vdst, 1, vsrc, 1); + case 2: return vcopyq_laneq_f32(vdst, 1, vsrc, 2); + case 3: return vcopyq_laneq_f32(vdst, 1, vsrc, 3); + } + assert(!"Unreachable code executed!"); + case 2: + switch(slane) { + case 0: return vcopyq_laneq_f32(vdst, 2, vsrc, 0); + case 1: return vcopyq_laneq_f32(vdst, 2, vsrc, 1); + case 2: return vcopyq_laneq_f32(vdst, 2, vsrc, 2); + case 3: return vcopyq_laneq_f32(vdst, 2, vsrc, 3); + } + assert(!"Unreachable code executed!"); + case 3: + switch(slane) { + case 0: return vcopyq_laneq_f32(vdst, 3, vsrc, 0); + case 1: return vcopyq_laneq_f32(vdst, 3, vsrc, 1); + case 2: return vcopyq_laneq_f32(vdst, 3, vsrc, 2); + case 3: return vcopyq_laneq_f32(vdst, 3, vsrc, 3); + } + assert(!"Unreachable code executed!"); + } +#else + + float l; + switch(slane) { + case 0: l = vgetq_lane_f32(vsrc, 0); break; + case 1: l = vgetq_lane_f32(vsrc, 1); break; + case 2: l = vgetq_lane_f32(vsrc, 2); break; + case 3: l = vgetq_lane_f32(vsrc, 3); break; + default: + assert(!"Unreachable code executed!"); + } + switch(dlane) { + case 0: return vsetq_lane_f32(l, vdst, 0); + case 1: return vsetq_lane_f32(l, vdst, 1); + case 2: return vsetq_lane_f32(l, vdst, 2); + case 3: return vsetq_lane_f32(l, vdst, 3); + } +#endif + assert(!"Unreachable code executed!"); + return vdupq_n_f32(0.0f); + } + + static inline float32x4_t mul_lane(float32x4_t v, float32x4_t vlane, int lane) { +#if GLM_ARCH & GLM_ARCH_ARMV8_BIT + switch(lane) { + case 0: return vmulq_laneq_f32(v, vlane, 0); break; + case 1: return vmulq_laneq_f32(v, vlane, 1); break; + case 2: return vmulq_laneq_f32(v, vlane, 2); break; + case 3: return vmulq_laneq_f32(v, vlane, 3); break; + default: + assert(!"Unreachable code executed!"); + } + assert(!"Unreachable code executed!"); + return vdupq_n_f32(0.0f); +#else + return vmulq_f32(v, dupq_lane(vlane, lane)); +#endif + } + + static inline float32x4_t madd_lane(float32x4_t acc, float32x4_t v, float32x4_t vlane, int lane) { +#if GLM_ARCH & GLM_ARCH_ARMV8_BIT +#ifdef GLM_CONFIG_FORCE_FMA +# define FMADD_LANE(acc, x, y, L) do { asm volatile ("fmla %0.4s, %1.4s, %2.4s" : "+w"(acc) : "w"(x), "w"(dup_lane(y, L))); } while(0) +#else +# define FMADD_LANE(acc, x, y, L) do { acc = vmlaq_laneq_f32(acc, x, y, L); } while(0) +#endif + + switch(lane) { + case 0: + FMADD_LANE(acc, v, vlane, 0); + return acc; + case 1: + FMADD_LANE(acc, v, vlane, 1); + return acc; + case 2: + FMADD_LANE(acc, v, vlane, 2); + return acc; + case 3: + FMADD_LANE(acc, v, vlane, 3); + return acc; + default: + assert(!"Unreachable code executed!"); + } + assert(!"Unreachable code executed!"); + return vdupq_n_f32(0.0f); +# undef FMADD_LANE +#else + return vaddq_f32(acc, vmulq_f32(v, dupq_lane(vlane, lane))); +#endif + } + } //namespace neon +} // namespace glm +#endif // GLM_ARCH & GLM_ARCH_NEON_BIT diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/simd/packing.h b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/simd/packing.h new file mode 100644 index 0000000000000000000000000000000000000000..609163eb0d77aaccd0f165fab215a703d70f91c8 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/simd/packing.h @@ -0,0 +1,8 @@ +/// @ref simd +/// @file glm/simd/packing.h + +#pragma once + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/simd/platform.h b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/simd/platform.h new file mode 100644 index 0000000000000000000000000000000000000000..4fe0900db541d3486a6cb9833fddea84b07a823f --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/simd/platform.h @@ -0,0 +1,409 @@ +#pragma once + +/////////////////////////////////////////////////////////////////////////////////// +// Platform + +#define GLM_PLATFORM_UNKNOWN 0x00000000 +#define GLM_PLATFORM_WINDOWS 0x00010000 +#define GLM_PLATFORM_LINUX 0x00020000 +#define GLM_PLATFORM_APPLE 0x00040000 +//#define GLM_PLATFORM_IOS 0x00080000 +#define GLM_PLATFORM_ANDROID 0x00100000 +#define GLM_PLATFORM_CHROME_NACL 0x00200000 +#define GLM_PLATFORM_UNIX 0x00400000 +#define GLM_PLATFORM_QNXNTO 0x00800000 +#define GLM_PLATFORM_WINCE 0x01000000 +#define GLM_PLATFORM_CYGWIN 0x02000000 + +#ifdef GLM_FORCE_PLATFORM_UNKNOWN +# define GLM_PLATFORM GLM_PLATFORM_UNKNOWN +#elif defined(__CYGWIN__) +# define GLM_PLATFORM GLM_PLATFORM_CYGWIN +#elif defined(__QNXNTO__) +# define GLM_PLATFORM GLM_PLATFORM_QNXNTO +#elif defined(__APPLE__) +# define GLM_PLATFORM GLM_PLATFORM_APPLE +#elif defined(WINCE) +# define GLM_PLATFORM GLM_PLATFORM_WINCE +#elif defined(_WIN32) +# define GLM_PLATFORM GLM_PLATFORM_WINDOWS +#elif defined(__native_client__) +# define GLM_PLATFORM GLM_PLATFORM_CHROME_NACL +#elif defined(__ANDROID__) +# define GLM_PLATFORM GLM_PLATFORM_ANDROID +#elif defined(__linux) +# define GLM_PLATFORM GLM_PLATFORM_LINUX +#elif defined(__unix) +# define GLM_PLATFORM GLM_PLATFORM_UNIX +#else +# define GLM_PLATFORM GLM_PLATFORM_UNKNOWN +#endif// + +/////////////////////////////////////////////////////////////////////////////////// +// Compiler + +#define GLM_COMPILER_UNKNOWN 0x00000000 + +// Intel +#define GLM_COMPILER_INTEL 0x00100000 +#define GLM_COMPILER_INTEL14 0x00100040 +#define GLM_COMPILER_INTEL15 0x00100050 +#define GLM_COMPILER_INTEL16 0x00100060 +#define GLM_COMPILER_INTEL17 0x00100070 + +// Visual C++ defines +#define GLM_COMPILER_VC 0x01000000 +#define GLM_COMPILER_VC12 0x01000001 +#define GLM_COMPILER_VC14 0x01000002 +#define GLM_COMPILER_VC15 0x01000003 +#define GLM_COMPILER_VC15_3 0x01000004 +#define GLM_COMPILER_VC15_5 0x01000005 +#define GLM_COMPILER_VC15_6 0x01000006 +#define GLM_COMPILER_VC15_7 0x01000007 +#define GLM_COMPILER_VC15_8 0x01000008 +#define GLM_COMPILER_VC15_9 0x01000009 +#define GLM_COMPILER_VC16 0x0100000A + +// GCC defines +#define GLM_COMPILER_GCC 0x02000000 +#define GLM_COMPILER_GCC46 0x020000D0 +#define GLM_COMPILER_GCC47 0x020000E0 +#define GLM_COMPILER_GCC48 0x020000F0 +#define GLM_COMPILER_GCC49 0x02000100 +#define GLM_COMPILER_GCC5 0x02000200 +#define GLM_COMPILER_GCC6 0x02000300 +#define GLM_COMPILER_GCC61 0x02000800 +#define GLM_COMPILER_GCC7 0x02000400 +#define GLM_COMPILER_GCC8 0x02000500 + +// CUDA +#define GLM_COMPILER_CUDA 0x10000000 +#define GLM_COMPILER_CUDA75 0x10000001 +#define GLM_COMPILER_CUDA80 0x10000002 +#define GLM_COMPILER_CUDA90 0x10000004 +#define GLM_COMPILER_CUDA_RTC 0x10000100 + +// SYCL +#define GLM_COMPILER_SYCL 0x00300000 + +// Clang +#define GLM_COMPILER_CLANG 0x20000000 +#define GLM_COMPILER_CLANG34 0x20000050 +#define GLM_COMPILER_CLANG35 0x20000060 +#define GLM_COMPILER_CLANG36 0x20000070 +#define GLM_COMPILER_CLANG37 0x20000080 +#define GLM_COMPILER_CLANG38 0x20000090 +#define GLM_COMPILER_CLANG39 0x200000A0 +#define GLM_COMPILER_CLANG40 0x200000B0 +#define GLM_COMPILER_CLANG41 0x200000C0 +#define GLM_COMPILER_CLANG42 0x200000D0 + +// HIP +#define GLM_COMPILER_HIP 0x40000000 + +// Build model +#define GLM_MODEL_32 0x00000010 +#define GLM_MODEL_64 0x00000020 + +// Force generic C++ compiler +#ifdef GLM_FORCE_COMPILER_UNKNOWN +# define GLM_COMPILER GLM_COMPILER_UNKNOWN + +#elif defined(__INTEL_COMPILER) +# if __INTEL_COMPILER >= 1700 +# define GLM_COMPILER GLM_COMPILER_INTEL17 +# elif __INTEL_COMPILER >= 1600 +# define GLM_COMPILER GLM_COMPILER_INTEL16 +# elif __INTEL_COMPILER >= 1500 +# define GLM_COMPILER GLM_COMPILER_INTEL15 +# elif __INTEL_COMPILER >= 1400 +# define GLM_COMPILER GLM_COMPILER_INTEL14 +# elif __INTEL_COMPILER < 1400 +# error "GLM requires ICC 2013 SP1 or newer" +# endif + +// CUDA +#elif defined(__CUDACC__) +# if !defined(CUDA_VERSION) && !defined(GLM_FORCE_CUDA) +# include // make sure version is defined since nvcc does not define it itself! +# endif +# if defined(__CUDACC_RTC__) +# define GLM_COMPILER GLM_COMPILER_CUDA_RTC +# elif CUDA_VERSION >= 8000 +# define GLM_COMPILER GLM_COMPILER_CUDA80 +# elif CUDA_VERSION >= 7500 +# define GLM_COMPILER GLM_COMPILER_CUDA75 +# elif CUDA_VERSION >= 7000 +# define GLM_COMPILER GLM_COMPILER_CUDA70 +# elif CUDA_VERSION < 7000 +# error "GLM requires CUDA 7.0 or higher" +# endif + +// HIP +#elif defined(__HIP__) +# define GLM_COMPILER GLM_COMPILER_HIP + +// SYCL +#elif defined(__SYCL_DEVICE_ONLY__) +# define GLM_COMPILER GLM_COMPILER_SYCL + +// Clang +#elif defined(__clang__) +# if defined(__apple_build_version__) +# if (__clang_major__ < 6) +# error "GLM requires Clang 3.4 / Apple Clang 6.0 or higher" +# elif __clang_major__ == 6 && __clang_minor__ == 0 +# define GLM_COMPILER GLM_COMPILER_CLANG35 +# elif __clang_major__ == 6 && __clang_minor__ >= 1 +# define GLM_COMPILER GLM_COMPILER_CLANG36 +# elif __clang_major__ >= 7 +# define GLM_COMPILER GLM_COMPILER_CLANG37 +# endif +# else +# if ((__clang_major__ == 3) && (__clang_minor__ < 4)) || (__clang_major__ < 3) +# error "GLM requires Clang 3.4 or higher" +# elif __clang_major__ == 3 && __clang_minor__ == 4 +# define GLM_COMPILER GLM_COMPILER_CLANG34 +# elif __clang_major__ == 3 && __clang_minor__ == 5 +# define GLM_COMPILER GLM_COMPILER_CLANG35 +# elif __clang_major__ == 3 && __clang_minor__ == 6 +# define GLM_COMPILER GLM_COMPILER_CLANG36 +# elif __clang_major__ == 3 && __clang_minor__ == 7 +# define GLM_COMPILER GLM_COMPILER_CLANG37 +# elif __clang_major__ == 3 && __clang_minor__ == 8 +# define GLM_COMPILER GLM_COMPILER_CLANG38 +# elif __clang_major__ == 3 && __clang_minor__ >= 9 +# define GLM_COMPILER GLM_COMPILER_CLANG39 +# elif __clang_major__ == 4 && __clang_minor__ == 0 +# define GLM_COMPILER GLM_COMPILER_CLANG40 +# elif __clang_major__ == 4 && __clang_minor__ == 1 +# define GLM_COMPILER GLM_COMPILER_CLANG41 +# elif __clang_major__ == 4 && __clang_minor__ >= 2 +# define GLM_COMPILER GLM_COMPILER_CLANG42 +# elif __clang_major__ >= 4 +# define GLM_COMPILER GLM_COMPILER_CLANG42 +# endif +# endif + +// Visual C++ +#elif defined(_MSC_VER) +# if _MSC_VER >= 1920 +# define GLM_COMPILER GLM_COMPILER_VC16 +# elif _MSC_VER >= 1916 +# define GLM_COMPILER GLM_COMPILER_VC15_9 +# elif _MSC_VER >= 1915 +# define GLM_COMPILER GLM_COMPILER_VC15_8 +# elif _MSC_VER >= 1914 +# define GLM_COMPILER GLM_COMPILER_VC15_7 +# elif _MSC_VER >= 1913 +# define GLM_COMPILER GLM_COMPILER_VC15_6 +# elif _MSC_VER >= 1912 +# define GLM_COMPILER GLM_COMPILER_VC15_5 +# elif _MSC_VER >= 1911 +# define GLM_COMPILER GLM_COMPILER_VC15_3 +# elif _MSC_VER >= 1910 +# define GLM_COMPILER GLM_COMPILER_VC15 +# elif _MSC_VER >= 1900 +# define GLM_COMPILER GLM_COMPILER_VC14 +# elif _MSC_VER >= 1800 +# define GLM_COMPILER GLM_COMPILER_VC12 +# elif _MSC_VER < 1800 +# error "GLM requires Visual C++ 12 - 2013 or higher" +# endif//_MSC_VER + +// G++ +#elif defined(__GNUC__) || defined(__MINGW32__) +# if __GNUC__ >= 8 +# define GLM_COMPILER GLM_COMPILER_GCC8 +# elif __GNUC__ >= 7 +# define GLM_COMPILER GLM_COMPILER_GCC7 +# elif __GNUC__ >= 6 +# define GLM_COMPILER GLM_COMPILER_GCC6 +# elif __GNUC__ >= 5 +# define GLM_COMPILER GLM_COMPILER_GCC5 +# elif __GNUC__ == 4 && __GNUC_MINOR__ >= 9 +# define GLM_COMPILER GLM_COMPILER_GCC49 +# elif __GNUC__ == 4 && __GNUC_MINOR__ >= 8 +# define GLM_COMPILER GLM_COMPILER_GCC48 +# elif __GNUC__ == 4 && __GNUC_MINOR__ >= 7 +# define GLM_COMPILER GLM_COMPILER_GCC47 +# elif __GNUC__ == 4 && __GNUC_MINOR__ >= 6 +# define GLM_COMPILER GLM_COMPILER_GCC46 +# elif ((__GNUC__ == 4) && (__GNUC_MINOR__ < 6)) || (__GNUC__ < 4) +# error "GLM requires GCC 4.6 or higher" +# endif + +#else +# define GLM_COMPILER GLM_COMPILER_UNKNOWN +#endif + +#ifndef GLM_COMPILER +# error "GLM_COMPILER undefined, your compiler may not be supported by GLM. Add #define GLM_COMPILER 0 to ignore this message." +#endif//GLM_COMPILER + +/////////////////////////////////////////////////////////////////////////////////// +// Instruction sets + +// User defines: GLM_FORCE_PURE GLM_FORCE_INTRINSICS GLM_FORCE_SSE2 GLM_FORCE_SSE3 GLM_FORCE_AVX GLM_FORCE_AVX2 GLM_FORCE_AVX2 + +#define GLM_ARCH_MIPS_BIT (0x10000000) +#define GLM_ARCH_PPC_BIT (0x20000000) +#define GLM_ARCH_ARM_BIT (0x40000000) +#define GLM_ARCH_ARMV8_BIT (0x01000000) +#define GLM_ARCH_X86_BIT (0x80000000) + +#define GLM_ARCH_SIMD_BIT (0x00001000) + +#define GLM_ARCH_NEON_BIT (0x00000001) +#define GLM_ARCH_SSE_BIT (0x00000002) +#define GLM_ARCH_SSE2_BIT (0x00000004) +#define GLM_ARCH_SSE3_BIT (0x00000008) +#define GLM_ARCH_SSSE3_BIT (0x00000010) +#define GLM_ARCH_SSE41_BIT (0x00000020) +#define GLM_ARCH_SSE42_BIT (0x00000040) +#define GLM_ARCH_AVX_BIT (0x00000080) +#define GLM_ARCH_AVX2_BIT (0x00000100) + +#define GLM_ARCH_UNKNOWN (0) +#define GLM_ARCH_X86 (GLM_ARCH_X86_BIT) +#define GLM_ARCH_SSE (GLM_ARCH_SSE_BIT | GLM_ARCH_SIMD_BIT | GLM_ARCH_X86) +#define GLM_ARCH_SSE2 (GLM_ARCH_SSE2_BIT | GLM_ARCH_SSE) +#define GLM_ARCH_SSE3 (GLM_ARCH_SSE3_BIT | GLM_ARCH_SSE2) +#define GLM_ARCH_SSSE3 (GLM_ARCH_SSSE3_BIT | GLM_ARCH_SSE3) +#define GLM_ARCH_SSE41 (GLM_ARCH_SSE41_BIT | GLM_ARCH_SSSE3) +#define GLM_ARCH_SSE42 (GLM_ARCH_SSE42_BIT | GLM_ARCH_SSE41) +#define GLM_ARCH_AVX (GLM_ARCH_AVX_BIT | GLM_ARCH_SSE42) +#define GLM_ARCH_AVX2 (GLM_ARCH_AVX2_BIT | GLM_ARCH_AVX) +#define GLM_ARCH_ARM (GLM_ARCH_ARM_BIT) +#define GLM_ARCH_ARMV8 (GLM_ARCH_NEON_BIT | GLM_ARCH_SIMD_BIT | GLM_ARCH_ARM | GLM_ARCH_ARMV8_BIT) +#define GLM_ARCH_NEON (GLM_ARCH_NEON_BIT | GLM_ARCH_SIMD_BIT | GLM_ARCH_ARM) +#define GLM_ARCH_MIPS (GLM_ARCH_MIPS_BIT) +#define GLM_ARCH_PPC (GLM_ARCH_PPC_BIT) + +#if defined(GLM_FORCE_ARCH_UNKNOWN) || defined(GLM_FORCE_PURE) +# define GLM_ARCH GLM_ARCH_UNKNOWN +#elif defined(GLM_FORCE_NEON) +# if __ARM_ARCH >= 8 +# define GLM_ARCH (GLM_ARCH_ARMV8) +# else +# define GLM_ARCH (GLM_ARCH_NEON) +# endif +# define GLM_FORCE_INTRINSICS +#elif defined(GLM_FORCE_AVX2) +# define GLM_ARCH (GLM_ARCH_AVX2) +# define GLM_FORCE_INTRINSICS +#elif defined(GLM_FORCE_AVX) +# define GLM_ARCH (GLM_ARCH_AVX) +# define GLM_FORCE_INTRINSICS +#elif defined(GLM_FORCE_SSE42) +# define GLM_ARCH (GLM_ARCH_SSE42) +# define GLM_FORCE_INTRINSICS +#elif defined(GLM_FORCE_SSE41) +# define GLM_ARCH (GLM_ARCH_SSE41) +# define GLM_FORCE_INTRINSICS +#elif defined(GLM_FORCE_SSSE3) +# define GLM_ARCH (GLM_ARCH_SSSE3) +# define GLM_FORCE_INTRINSICS +#elif defined(GLM_FORCE_SSE3) +# define GLM_ARCH (GLM_ARCH_SSE3) +# define GLM_FORCE_INTRINSICS +#elif defined(GLM_FORCE_SSE2) +# define GLM_ARCH (GLM_ARCH_SSE2) +# define GLM_FORCE_INTRINSICS +#elif defined(GLM_FORCE_SSE) +# define GLM_ARCH (GLM_ARCH_SSE) +# define GLM_FORCE_INTRINSICS +#elif defined(GLM_FORCE_INTRINSICS) && !defined(GLM_FORCE_XYZW_ONLY) +# if defined(__AVX2__) +# define GLM_ARCH (GLM_ARCH_AVX2) +# elif defined(__AVX__) +# define GLM_ARCH (GLM_ARCH_AVX) +# elif defined(__SSE4_2__) +# define GLM_ARCH (GLM_ARCH_SSE42) +# elif defined(__SSE4_1__) +# define GLM_ARCH (GLM_ARCH_SSE41) +# elif defined(__SSSE3__) +# define GLM_ARCH (GLM_ARCH_SSSE3) +# elif defined(__SSE3__) +# define GLM_ARCH (GLM_ARCH_SSE3) +# elif defined(__SSE2__) || defined(__x86_64__) || defined(_M_X64) || defined(_M_IX86_FP) +# define GLM_ARCH (GLM_ARCH_SSE2) +# elif defined(__i386__) +# define GLM_ARCH (GLM_ARCH_X86) +# elif defined(__ARM_ARCH) && (__ARM_ARCH >= 8) +# define GLM_ARCH (GLM_ARCH_ARMV8) +# elif defined(__ARM_NEON) +# define GLM_ARCH (GLM_ARCH_ARM | GLM_ARCH_NEON) +# elif defined(__arm__ ) || defined(_M_ARM) +# define GLM_ARCH (GLM_ARCH_ARM) +# elif defined(__mips__ ) +# define GLM_ARCH (GLM_ARCH_MIPS) +# elif defined(__powerpc__ ) || defined(_M_PPC) +# define GLM_ARCH (GLM_ARCH_PPC) +# else +# define GLM_ARCH (GLM_ARCH_UNKNOWN) +# endif +#else +# if defined(__x86_64__) || defined(_M_X64) || defined(_M_IX86) || defined(__i386__) +# define GLM_ARCH (GLM_ARCH_X86) +# elif defined(__arm__) || defined(_M_ARM) +# define GLM_ARCH (GLM_ARCH_ARM) +# elif defined(__powerpc__) || defined(_M_PPC) +# define GLM_ARCH (GLM_ARCH_PPC) +# elif defined(__mips__) +# define GLM_ARCH (GLM_ARCH_MIPS) +# else +# define GLM_ARCH (GLM_ARCH_UNKNOWN) +# endif +#endif + +#if GLM_ARCH & GLM_ARCH_AVX2_BIT +# include +#elif GLM_ARCH & GLM_ARCH_AVX_BIT +# include +#elif GLM_ARCH & GLM_ARCH_SSE42_BIT +# if GLM_COMPILER & GLM_COMPILER_CLANG +# include +# endif +# include +#elif GLM_ARCH & GLM_ARCH_SSE41_BIT +# include +#elif GLM_ARCH & GLM_ARCH_SSSE3_BIT +# include +#elif GLM_ARCH & GLM_ARCH_SSE3_BIT +# include +#elif GLM_ARCH & GLM_ARCH_SSE2_BIT +# include +#elif GLM_ARCH & GLM_ARCH_NEON_BIT +# include "neon.h" +#endif//GLM_ARCH + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + typedef __m128 glm_f32vec4; + typedef __m128i glm_i32vec4; + typedef __m128i glm_u32vec4; + typedef __m128d glm_f64vec2; + typedef __m128i glm_i64vec2; + typedef __m128i glm_u64vec2; + + typedef glm_f32vec4 glm_vec4; + typedef glm_i32vec4 glm_ivec4; + typedef glm_u32vec4 glm_uvec4; + typedef glm_f64vec2 glm_dvec2; +#endif + +#if GLM_ARCH & GLM_ARCH_AVX_BIT + typedef __m256d glm_f64vec4; + typedef glm_f64vec4 glm_dvec4; +#endif + +#if GLM_ARCH & GLM_ARCH_AVX2_BIT + typedef __m256i glm_i64vec4; + typedef __m256i glm_u64vec4; +#endif + +#if GLM_ARCH & GLM_ARCH_NEON_BIT + typedef float32x4_t glm_f32vec4; + typedef int32x4_t glm_i32vec4; + typedef uint32x4_t glm_u32vec4; +#endif diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/simd/trigonometric.h b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/simd/trigonometric.h new file mode 100644 index 0000000000000000000000000000000000000000..739b796e7e45c86f07dbe5d508ed46dd9a9c6fd4 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/simd/trigonometric.h @@ -0,0 +1,9 @@ +/// @ref simd +/// @file glm/simd/trigonometric.h + +#pragma once + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/simd/vector_relational.h b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/simd/vector_relational.h new file mode 100644 index 0000000000000000000000000000000000000000..f7385e9747363cf64be22d5b0b5e061983a36a12 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/simd/vector_relational.h @@ -0,0 +1,8 @@ +/// @ref simd +/// @file glm/simd/vector_relational.h + +#pragma once + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/trigonometric.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/trigonometric.hpp new file mode 100644 index 0000000000000000000000000000000000000000..51d49c132bb5fcd34af76222e332be9d45564eb2 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/trigonometric.hpp @@ -0,0 +1,210 @@ +/// @ref core +/// @file glm/trigonometric.hpp +/// +/// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions +/// +/// @defgroup core_func_trigonometric Angle and Trigonometry Functions +/// @ingroup core +/// +/// Function parameters specified as angle are assumed to be in units of radians. +/// In no case will any of these functions result in a divide by zero error. If +/// the divisor of a ratio is 0, then results will be undefined. +/// +/// These all operate component-wise. The description is per component. +/// +/// Include to use these core features. +/// +/// @see ext_vector_trigonometric + +#pragma once + +#include "detail/setup.hpp" +#include "detail/qualifier.hpp" + +namespace glm +{ + /// @addtogroup core_func_trigonometric + /// @{ + + /// Converts degrees to radians and returns the result. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL radians man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec radians(vec const& degrees); + + /// Converts radians to degrees and returns the result. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL degrees man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec degrees(vec const& radians); + + /// The standard trigonometric sine function. + /// The values returned by this function will range from [-1, 1]. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL sin man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec sin(vec const& angle); + + /// The standard trigonometric cosine function. + /// The values returned by this function will range from [-1, 1]. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL cos man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec cos(vec const& angle); + + /// The standard trigonometric tangent function. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL tan man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec tan(vec const& angle); + + /// Arc sine. Returns an angle whose sine is x. + /// The range of values returned by this function is [-PI/2, PI/2]. + /// Results are undefined if |x| > 1. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL asin man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec asin(vec const& x); + + /// Arc cosine. Returns an angle whose cosine is x. + /// The range of values returned by this function is [0, PI]. + /// Results are undefined if |x| > 1. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL acos man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec acos(vec const& x); + + /// Arc tangent. Returns an angle whose tangent is y/x. + /// The signs of x and y are used to determine what + /// quadrant the angle is in. The range of values returned + /// by this function is [-PI, PI]. Results are undefined + /// if x and y are both 0. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL atan man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec atan(vec const& y, vec const& x); + + /// Arc tangent. Returns an angle whose tangent is y_over_x. + /// The range of values returned by this function is [-PI/2, PI/2]. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL atan man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec atan(vec const& y_over_x); + + /// Returns the hyperbolic sine function, (exp(x) - exp(-x)) / 2 + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL sinh man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec sinh(vec const& angle); + + /// Returns the hyperbolic cosine function, (exp(x) + exp(-x)) / 2 + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL cosh man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec cosh(vec const& angle); + + /// Returns the hyperbolic tangent function, sinh(angle) / cosh(angle) + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL tanh man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec tanh(vec const& angle); + + /// Arc hyperbolic sine; returns the inverse of sinh. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL asinh man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec asinh(vec const& x); + + /// Arc hyperbolic cosine; returns the non-negative inverse + /// of cosh. Results are undefined if x < 1. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL acosh man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec acosh(vec const& x); + + /// Arc hyperbolic tangent; returns the inverse of tanh. + /// Results are undefined if abs(x) >= 1. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL atanh man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec atanh(vec const& x); + + /// @} +}//namespace glm + +#include "detail/func_trigonometric.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/vec2.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/vec2.hpp new file mode 100644 index 0000000000000000000000000000000000000000..cd4e0708e109cfa2c35bff6ea146dbdd2167104b --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/vec2.hpp @@ -0,0 +1,14 @@ +/// @ref core +/// @file glm/vec2.hpp + +#pragma once +#include "./ext/vector_bool2.hpp" +#include "./ext/vector_bool2_precision.hpp" +#include "./ext/vector_float2.hpp" +#include "./ext/vector_float2_precision.hpp" +#include "./ext/vector_double2.hpp" +#include "./ext/vector_double2_precision.hpp" +#include "./ext/vector_int2.hpp" +#include "./ext/vector_int2_sized.hpp" +#include "./ext/vector_uint2.hpp" +#include "./ext/vector_uint2_sized.hpp" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/vec3.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/vec3.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f5a927dbe4c577736c88b86638454c095e1eb9bb --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/vec3.hpp @@ -0,0 +1,14 @@ +/// @ref core +/// @file glm/vec3.hpp + +#pragma once +#include "./ext/vector_bool3.hpp" +#include "./ext/vector_bool3_precision.hpp" +#include "./ext/vector_float3.hpp" +#include "./ext/vector_float3_precision.hpp" +#include "./ext/vector_double3.hpp" +#include "./ext/vector_double3_precision.hpp" +#include "./ext/vector_int3.hpp" +#include "./ext/vector_int3_sized.hpp" +#include "./ext/vector_uint3.hpp" +#include "./ext/vector_uint3_sized.hpp" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/vec4.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/vec4.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c6ea9f1ff4c51cd9cfaee865e7413f928e354b71 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/vec4.hpp @@ -0,0 +1,15 @@ +/// @ref core +/// @file glm/vec4.hpp + +#pragma once +#include "./ext/vector_bool4.hpp" +#include "./ext/vector_bool4_precision.hpp" +#include "./ext/vector_float4.hpp" +#include "./ext/vector_float4_precision.hpp" +#include "./ext/vector_double4.hpp" +#include "./ext/vector_double4_precision.hpp" +#include "./ext/vector_int4.hpp" +#include "./ext/vector_int4_sized.hpp" +#include "./ext/vector_uint4.hpp" +#include "./ext/vector_uint4_sized.hpp" + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/vector_relational.hpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/vector_relational.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a0fe17eb707a4e5ba3590fe16d2704cecc3bd8ef --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/glm/vector_relational.hpp @@ -0,0 +1,121 @@ +/// @ref core +/// @file glm/vector_relational.hpp +/// +/// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions +/// +/// @defgroup core_func_vector_relational Vector Relational Functions +/// @ingroup core +/// +/// Relational and equality operators (<, <=, >, >=, ==, !=) are defined to +/// operate on scalars and produce scalar Boolean results. For vector results, +/// use the following built-in functions. +/// +/// In all cases, the sizes of all the input and return vectors for any particular +/// call must match. +/// +/// Include to use these core features. +/// +/// @see ext_vector_relational + +#pragma once + +#include "detail/qualifier.hpp" +#include "detail/setup.hpp" + +namespace glm +{ + /// @addtogroup core_func_vector_relational + /// @{ + + /// Returns the component-wise comparison result of x < y. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T A floating-point or integer scalar type. + /// + /// @see GLSL lessThan man page + /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec lessThan(vec const& x, vec const& y); + + /// Returns the component-wise comparison of result x <= y. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T A floating-point or integer scalar type. + /// + /// @see GLSL lessThanEqual man page + /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec lessThanEqual(vec const& x, vec const& y); + + /// Returns the component-wise comparison of result x > y. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T A floating-point or integer scalar type. + /// + /// @see GLSL greaterThan man page + /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec greaterThan(vec const& x, vec const& y); + + /// Returns the component-wise comparison of result x >= y. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T A floating-point or integer scalar type. + /// + /// @see GLSL greaterThanEqual man page + /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec greaterThanEqual(vec const& x, vec const& y); + + /// Returns the component-wise comparison of result x == y. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T A floating-point, integer or bool scalar type. + /// + /// @see GLSL equal man page + /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec equal(vec const& x, vec const& y); + + /// Returns the component-wise comparison of result x != y. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T A floating-point, integer or bool scalar type. + /// + /// @see GLSL notEqual man page + /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y); + + /// Returns true if any component of x is true. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// + /// @see GLSL any man page + /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR bool any(vec const& v); + + /// Returns true if all components of x are true. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// + /// @see GLSL all man page + /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR bool all(vec const& v); + + /// Returns the component-wise logical complement of x. + /// /!\ Because of language incompatibilities between C++ and GLSL, GLM defines the function not but not_ instead. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// + /// @see GLSL not man page + /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec not_(vec const& v); + + /// @} +}//namespace glm + +#include "detail/func_vector_relational.inl" diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/manual.md b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/manual.md new file mode 100644 index 0000000000000000000000000000000000000000..654bdbb113f53691ca4ae6d20087503a797b8bb7 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/manual.md @@ -0,0 +1,2448 @@ +![Alt](./doc/manual/logo-mini.png "GLM Logo") + +# GLM 0.9.9 Manual + +![Alt](./doc/manual/g-truc.png "G-Truc Logo") + +--- +
+ +## Table of Contents + ++ [0. Licenses](#section0) ++ [1. Getting started](#section1) ++ [1.1. Using global headers](#section1_1) ++ [1.2. Using separated headers](#section1_2) ++ [1.3. Using extension headers](#section1_3) ++ [1.4. Dependencies](#section1_4) ++ [1.5. Finding GLM with CMake](#section1_5) ++ [2. Preprocessor configurations](#section2) ++ [2.1. GLM\_FORCE\_MESSAGES: Platform auto detection and default configuration](#section2_1) ++ [2.2. GLM\_FORCE\_PLATFORM\_UNKNOWN: Force GLM to no detect the build platform](#section2_2) ++ [2.3. GLM\_FORCE\_COMPILER\_UNKNOWN: Force GLM to no detect the C++ compiler](#section2_3) ++ [2.4. GLM\_FORCE\_ARCH\_UNKNOWN: Force GLM to no detect the build architecture](#section2_4) ++ [2.5. GLM\_FORCE\_CXX\_UNKNOWN: Force GLM to no detect the C++ standard](#section2_5) ++ [2.6. GLM\_FORCE\_CXX**: C++ language detection](#section2_6) ++ [2.7. GLM\_FORCE\_EXPLICIT\_CTOR: Requiring explicit conversions](#section2_7) ++ [2.8. GLM\_FORCE\_INLINE: Force inline](#section2_8) ++ [2.9. GLM\_FORCE\_ALIGNED\_GENTYPES: Force GLM to enable aligned types](#section2_9) ++ [2.10. GLM\_FORCE\_DEFAULT\_ALIGNED\_GENTYPES: Force GLM to use aligned types by default](#section2_10) ++ [2.11. GLM\_FORCE\_INTRINSICS: Using SIMD optimizations](#section2_11) ++ [2.12. GLM\_FORCE\_PRECISION\_**: Default precision](#section2_12) ++ [2.13. GLM\_FORCE\_SINGLE\_ONLY: Removed explicit 64-bits floating point types](#section2_13) ++ [2.14. GLM\_FORCE\_SWIZZLE: Enable swizzle operators](#section2_14) ++ [2.15. GLM\_FORCE\_XYZW\_ONLY: Only exposes x, y, z and w components](#section2_15) ++ [2.16. GLM\_FORCE\_LEFT\_HANDED: Force left handed coordinate system](#section2_16) ++ [2.17. GLM\_FORCE\_DEPTH\_ZERO\_TO\_ONE: Force the use of a clip space between 0 to 1](#section2_17) ++ [2.18. GLM\_FORCE\_SIZE\_T\_LENGTH: Vector and matrix static size type](#section2_18) ++ [2.19. GLM\_FORCE\_UNRESTRICTED\_GENTYPE: Removing genType restriction](#section2_19) ++ [2.20. GLM\_FORCE\_SILENT\_WARNINGS: Silent C++ warnings from language extensions](#section2_20) ++ [2.21. GLM\_FORCE\_QUAT\_DATA\_WXYZ: Force GLM to store quat data as w,x,y,z instead of x,y,z,w](#section2_21) ++ [3. Stable extensions](#section3) ++ [3.1. Scalar types](#section3_1) ++ [3.2. Scalar functions](#section3_2) ++ [3.3. Vector types](#section3_3) ++ [3.4. Vector types with precision qualifiers](#section3_4) ++ [3.5. Vector functions](#section3_5) ++ [3.6. Matrix types](#section3_6) ++ [3.7. Matrix types with precision qualifiers](#section3_7) ++ [3.8. Matrix functions](#section3_8) ++ [3.9. Quaternion types](#section3_9) ++ [3.10. Quaternion types with precision qualifiers](#section3_10) ++ [3.11. Quaternion functions](#section3_11) ++ [4. Recommended extensions](#section4) ++ [4.1. GLM_GTC_bitfield](#section4_1) ++ [4.2. GLM_GTC_color_space](#section4_2) ++ [4.3. GLM_GTC_constants](#section4_3) ++ [4.4. GLM_GTC_epsilon](#section4_4) ++ [4.5. GLM_GTC_integer](#section4_5) ++ [4.6. GLM_GTC_matrix_access](#section4_6) ++ [4.7. GLM_GTC_matrix_integer](#section4_7) ++ [4.8. GLM_GTC_matrix_inverse](#section4_8) ++ [4.9. GLM_GTC_matrix_transform](#section4_9) ++ [4.10. GLM_GTC_noise](#section4_10) ++ [4.11. GLM_GTC_packing](#section4_11) ++ [4.12. GLM_GTC_quaternion](#section4_12) ++ [4.13. GLM_GTC_random](#section4_13) ++ [4.14. GLM_GTC_reciprocal](#section4_14) ++ [4.15. GLM_GTC_round](#section4_15) ++ [4.16. GLM_GTC_type_alignment](#section4_16) ++ [4.17. GLM_GTC_type_precision](#section4_17) ++ [4.18. GLM_GTC_type_ptr](#section4_18) ++ [4.19. GLM_GTC_ulp](#section4_19) ++ [4.20. GLM_GTC_vec1](#section4_20) ++ [5. OpenGL interoperability](#section5) ++ [5.1. GLM Replacements for deprecated OpenGL functions](#section5_1) ++ [5.2. GLM Replacements for GLU functions](#section5_2) ++ [6. Known issues](#section6) ++ [6.1. Not function](#section6_1) ++ [6.2. Precision qualifiers support](#section6_2) ++ [7. FAQ](#section7) ++ [7.1 Why GLM follows GLSL specification and conventions?](#section7_1) ++ [7.2. Does GLM run GLSL programs?](#section7_2) ++ [7.3. Does a GLSL compiler build GLM codes?](#section7_3) ++ [7.4. Should I use β€˜GTX’ extensions?](#section7_4) ++ [7.5. Where can I ask my questions?](#section7_5) ++ [7.6. Where can I find the documentation of extensions?](#section7_6) ++ [7.7. Should I use 'using namespace glm;'?](#section7_7) ++ [7.8. Is GLM fast?](#section7_8) ++ [7.9. When I build with Visual C++ with /w4 warning level, I have warnings...](#section7_9) ++ [7.10. Why some GLM functions can crash because of division by zero?](#section7_10) ++ [7.11. What unit for angles us used in GLM?](#section7_11) ++ [7.12. Windows headers cause build errors...](#section7_12) ++ [7.13. Constant expressions support](#section7_13) ++ [8. Code samples](#section8) ++ [8.1. Compute a triangle normal](#section8_1) ++ [8.2. Matrix transform](#section8_2) ++ [8.3. Vector types](#section8_3) ++ [8.4. Lighting](#section8_4) ++ [9. Contributing to GLM](#section9) ++ [9.1. Submitting bug reports](#section9_1) ++ [9.2. Contributing to GLM with pull request](#section9_2) ++ [9.3. Coding style](#section9_3) ++ [10. References](#section10) ++ [10.1. OpenGL specifications](#section10_1) ++ [10.2. External links](#section10_2) ++ [10.3. Projects using GLM](#section10_3) ++ [10.4. Tutorials using GLM](#section10_4) ++ [10.5. Equivalent for other languages](#section10_5) ++ [10.6. Alternatives to GLM](#section10_6) ++ [10.7. Acknowledgements](#section10_7) + +--- +
+ +## Licenses + +### The Happy Bunny License (Modified MIT License) + +Copyright (c) 2005 - G-Truc Creation + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +Restrictions: By making use of the Software for military purposes, you +choose to make a Bunny unhappy. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +![](./doc/manual/frontpage1.png) + +### The MIT License + +Copyright (c) 2005 - G-Truc Creation + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +![](./doc/manual/frontpage2.png) + +--- +
+ +## 1. Getting started + +### 1.1. Using global headers + +GLM is a header-only library, and thus does not need to be compiled. We can use GLM's implementation of GLSL's mathematics functionality by including the `` header: + +```cpp +#include +``` + +To extend the feature set supported by GLM and keeping the library as close to GLSL as possible, new features are implemented as extensions that can be included thought a separated header: + +```cpp +// Include all GLM core / GLSL features +#include // vec2, vec3, mat4, radians + +// Include all GLM extensions +#include // perspective, translate, rotate + +glm::mat4 transform(glm::vec2 const& Orientation, glm::vec3 const& Translate, glm::vec3 const& Up) +{ + glm::mat4 Proj = glm::perspective(glm::radians(45.f), 1.33f, 0.1f, 10.f); + glm::mat4 ViewTranslate = glm::translate(glm::mat4(1.f), Translate); + glm::mat4 ViewRotateX = glm::rotate(ViewTranslate, Orientation.y, Up); + glm::mat4 View = glm::rotate(ViewRotateX, Orientation.x, Up); + glm::mat4 Model = glm::mat4(1.0f); + return Proj * View * Model; +} +``` + +*Note: Including `` and `` is convenient but pull a lot of code which will significantly increase build time, particularly if these files are included in all source files. We may prefer to use the approaches describe in the two following sections to keep the project build fast.* + +### 1.2. Using separated headers + +GLM relies on C++ templates heavily, and may significantly increase compilation times for projects that use it. Hence, user projects could only include the features they actually use. Following is the list of all the core features, based on GLSL specification, headers: + +```cpp +#include // vec2, bvec2, dvec2, ivec2 and uvec2 +#include // vec3, bvec3, dvec3, ivec3 and uvec3 +#include // vec4, bvec4, dvec4, ivec4 and uvec4 +#include // mat2, dmat2 +#include // mat2x3, dmat2x3 +#include // mat2x4, dmat2x4 +#include // mat3x2, dmat3x2 +#include // mat3, dmat3 +#include // mat3x4, dmat2 +#include // mat4x2, dmat4x2 +#include // mat4x3, dmat4x3 +#include // mat4, dmat4 +#include // all the GLSL common functions: abs, min, mix, isnan, fma, etc. +#include // all the GLSL exponential functions: pow, log, exp2, sqrt, etc. +#include // all the GLSL geometry functions: dot, cross, reflect, etc. +#include // all the GLSL integer functions: findMSB, bitfieldExtract, etc. +#include // all the GLSL matrix functions: transpose, inverse, etc. +#include // all the GLSL packing functions: packUnorm4x8, unpackHalf2x16, etc. +#include // all the GLSL trigonometric functions: radians, cos, asin, etc. +#include // all the GLSL vector relational functions: equal, less, etc. +``` + +The following is a code sample using separated core headers and an extension: + +```cpp +// Include GLM core features +#include // vec2 +#include // vec3 +#include // mat4 +#include //radians + +// Include GLM extension +#include // perspective, translate, rotate + +glm::mat4 transform(glm::vec2 const& Orientation, glm::vec3 const& Translate, glm::vec3 const& Up) +{ + glm::mat4 Proj = glm::perspective(glm::radians(45.f), 1.33f, 0.1f, 10.f); + glm::mat4 ViewTranslate = glm::translate(glm::mat4(1.f), Translate); + glm::mat4 ViewRotateX = glm::rotate(ViewTranslate, Orientation.y, Up); + glm::mat4 View = glm::rotate(ViewRotateX, Orientation.x, Up); + glm::mat4 Model = glm::mat4(1.0f); + return Proj * View * Model; +} +``` + +### 1.3. Using extension headers + +Using GLM through split headers to minimize the project build time: + +```cpp +// Include GLM vector extensions: +#include // vec2 +#include // vec3 +#include // radians + +// Include GLM matrix extensions: +#include // mat4 +#include // perspective, translate, rotate + +glm::mat4 transform(glm::vec2 const& Orientation, glm::vec3 const& Translate, glm::vec3 const& Up) +{ + glm::mat4 Proj = glm::perspective(glm::radians(45.f), 1.33f, 0.1f, 10.f); + glm::mat4 ViewTranslate = glm::translate(glm::mat4(1.f), Translate); + glm::mat4 ViewRotateX = glm::rotate(ViewTranslate, Orientation.y, Up); + glm::mat4 View = glm::rotate(ViewRotateX, Orientation.x, Up); + glm::mat4 Model = glm::mat4(1.0f); + return Proj * View * Model; +} +``` + +### 1.4. Dependencies + +GLM does not depend on external libraries or headers such as ``, [``](http://www.opengl.org/registry/api/GL/glcorearb.h), ``, ``, or ``. + +### 1.5. Finding GLM with CMake + +When installed, GLM provides the CMake package configuration files `glmConfig.cmake` and `glmConfigVersion.cmake`. + +To use these configurations files, you may need to set the `glm_DIR` variable to the directory containing the configuration files `/lib/cmake/glm/`. + +Use the `find_package` CMake command to load the configurations into your project. Lastly, either link your executable against the `glm::glm` target or add `${GLM_INCLUDE_DIRS}` to your target's include directories: + +```cmake +set(glm_DIR /lib/cmake/glm) # if necessary +find_package(glm REQUIRED) +target_link_libraries( glm::glm) +``` + +To use GLM as a submodule in a project instead, use `add_subdirectory` to expose the same target, or add the directory to your target's + +```cmake +add_subdirectory(glm) +target_link_libraries( glm::glm) +# or +target_include_directories( glm) +``` + +--- +
+ +## 2. Preprocessor configurations + +### 2.1. GLM\_FORCE\_MESSAGES: Platform auto detection and default configuration + +When included, GLM will first automatically detect the compiler used, the C++ standard supported, the compiler arguments used to configure itself matching the build environment. + +For example, if the compiler arguments request AVX code generation, GLM will rely on its code path providing AVX optimizations when available. + +We can change GLM configuration using specific C++ preprocessor defines that must be declared before including any GLM headers. + +Using `GLM_FORCE_MESSAGES`, GLM will report the configuration as part of the build log. + +```cpp +#define GLM_FORCE_MESSAGES // Or defined when building (e.g. -DGLM_FORCE_SWIZZLE) +#include +``` + +Example of configuration log generated by `GLM_FORCE_MESSAGES`: + +```plaintext +GLM: version 0.9.9.1 +GLM: C++ 17 with extensions +GLM: Clang compiler detected +GLM: x86 64 bits with AVX instruction set build target +GLM: Linux platform detected +GLM: GLM_FORCE_SWIZZLE is undefined. swizzling functions or operators are disabled. +GLM: GLM_FORCE_SIZE_T_LENGTH is undefined. .length() returns a glm::length_t, a typedef of int following GLSL. +GLM: GLM_FORCE_UNRESTRICTED_GENTYPE is undefined. Follows strictly GLSL on valid function genTypes. +GLM: GLM_FORCE_DEPTH_ZERO_TO_ONE is undefined. Using negative one to one depth clip space. +GLM: GLM_FORCE_LEFT_HANDED is undefined. Using right handed coordinate system. +``` + +The following subsections describe each configurations and defines. + +### 2.2. GLM\_FORCE\_PLATFORM\_UNKNOWN: Force GLM to no detect the build platform + +`GLM_FORCE_PLATFORM_UNKNOWN` prevents GLM from detecting the build platform. + +### 2.3. GLM\_FORCE\_COMPILER\_UNKNOWN: Force GLM to no detect the C++ compiler + +`GLM_FORCE_COMPILER_UNKNOWN` prevents GLM from detecting the C++ compiler. + +### 2.4. GLM\_FORCE\_ARCH\_UNKNOWN: Force GLM to no detect the build architecture + +`GLM_FORCE_ARCH_UNKNOWN` prevents GLM from detecting the build target architecture. + +### 2.5. GLM\_FORCE\_CXX\_UNKNOWN: Force GLM to no detect the C++ standard + +`GLM_FORCE_CSS_UNKNOWN` prevents GLM from detecting the C++ compiler standard support. + +### 2.6. GLM\_FORCE\_CXX**: C++ language detection + +GLM will automatically take advantage of compilers’ language extensions when enabled. To increase cross platform compatibility and to avoid compiler extensions, a programmer can define `GLM_FORCE_CXX98` before +any inclusion of `` to restrict the language feature set C++98: + +```cpp +#define GLM_FORCE_CXX98 +#include +``` + +For C++11, C++14, and C++17 equivalent defines are available: + +* `GLM_FORCE_CXX11` +* `GLM_FORCE_CXX14` +* `GLM_FORCE_CXX17` + +```cpp +#define GLM_FORCE_CXX11 +#include + +// If the compiler doesn’t support C++11, compiler errors will happen. +``` + +`GLM_FORCE_CXX17` overrides `GLM_FORCE_CXX14`; `GLM_FORCE_CXX14` overrides `GLM_FORCE_CXX11`; and `GLM_FORCE_CXX11` overrides `GLM_FORCE_CXX98` defines. + +### 2.7. GLM\_FORCE\_EXPLICIT\_CTOR: Requiring explicit conversions + +GLSL supports implicit conversions of vector and matrix types. For example, an ivec4 can be implicitly converted into `vec4`. + +Often, this behaviour is not desirable but following the spirit of the library, this is the default behavior in GLM. However, GLM 0.9.6 introduced the define `GLM_FORCE_EXPLICIT_CTOR` to require explicit conversion for GLM types. + +```cpp +#include + +void foo() +{ + glm::ivec4 a; + ... + + glm::vec4 b(a); // Explicit conversion, OK + glm::vec4 c = a; // Implicit conversion, OK + ... +} +``` + +With `GLM_FORCE_EXPLICIT_CTOR` define, implicit conversions are not allowed: + +```cpp +#define GLM_FORCE_EXPLICIT_CTOR +#include + +void foo() +{ + glm::ivec4 a; + { + glm::vec4 b(a); // Explicit conversion, OK + glm::vec4 c = a; // Implicit conversion, ERROR + ... +} +``` + +### 2.8. GLM\_FORCE\_INLINE: Force inline + +To push further the software performance, a programmer can define `GLM_FORCE_INLINE` before any inclusion of `` to force the compiler to inline GLM code. + +```cpp +#define GLM_FORCE_INLINE +#include +``` + +### 2.9. GLM\_FORCE\_ALIGNED\_GENTYPES: Force GLM to enable aligned types + +Every object type has the property called alignment requirement, which is an integer value (of type `std::size_t`, always a power of 2) representing the number of bytes between successive addresses at which objects of this type can be allocated. The alignment requirement of a type can be queried with alignof or `std::alignment_of`. The pointer alignment function `std::align` can be used to obtain a suitably-aligned pointer within some buffer, and `std::aligned_storage` can be used to obtain suitably-aligned storage. + +Each object type imposes its alignment requirement on every object of that type; stricter alignment (with larger alignment requirement) can be requested using C++11 `alignas`. + +In order to satisfy alignment requirements of all non-static members of a class, padding may be inserted after some of its members. + +GLM supports both packed and aligned types. Packed types allow filling data structure without inserting extra padding. Aligned GLM types align addresses based on the size of the value type of a GLM type. + +```cpp +#define GLM_FORCE_ALIGNED_GENTYPES +#include +#include + +typedef glm::aligned_vec4 vec4a; +typedef glm::packed_vec4 vec4p; +``` + +### 2.10. GLM\_FORCE\_DEFAULT\_ALIGNED\_GENTYPES: Force GLM to use aligned types by default + +GLM allows using aligned types by default for vector types using `GLM_FORCE_DEFAULT_ALIGNED_GENTYPES`: + +```cpp +#define GLM_FORCE_DEFAULT_ALIGNED_GENTYPES +#include + +struct MyStruct +{ + glm::vec4 a; + float b; + glm::vec3 c; +}; + +void foo() +{ + printf("MyStruct requires memory padding: %d bytes\n", sizeof(MyStruct)); +} + +>>> MyStruct requires memory padding: 48 bytes +``` + +```cpp +#include + +struct MyStruct +{ + glm::vec4 a; + float b; + glm::vec3 c; +}; + +void foo() +{ + printf("MyStruct is tightly packed: %d bytes\n", sizeof(MyStruct)); +} + +>>> MyStruct is tightly packed: 32 bytes +``` + +*Note: GLM SIMD optimizations require the use of aligned types* + +### 2.11. GLM\_FORCE\_INTRINSICS: Using SIMD optimizations + +GLM provides some SIMD optimizations based on [compiler intrinsics](https://msdn.microsoft.com/en-us/library/26td21ds.aspx). +These optimizations will be automatically thanks to compiler arguments when `GLM_FORCE_INTRINSICS` is defined before including GLM files. +For example, if a program is compiled with Visual Studio using `/arch:AVX`, GLM will detect this argument and generate code using AVX instructions automatically when available. + +It’s possible to avoid the instruction set detection by forcing the use of a specific instruction set with one of the fallowing define: +`GLM_FORCE_SSE2`, `GLM_FORCE_SSE3`, `GLM_FORCE_SSSE3`, `GLM_FORCE_SSE41`, `GLM_FORCE_SSE42`, `GLM_FORCE_AVX`, `GLM_FORCE_AVX2` or `GLM_FORCE_AVX512`. + +The use of intrinsic functions by GLM implementation can be avoided using the define `GLM_FORCE_PURE` before any inclusion of GLM headers. This can be particularly useful if we want to rely on C++14 `constexpr`. + +```cpp +#define GLM_FORCE_PURE +#include + +static_assert(glm::vec4::length() == 4, "Using GLM C++ 14 constexpr support for compile time tests"); + +// GLM code will be compiled using pure C++ code without any intrinsics +``` + +```cpp +#define GLM_FORCE_SIMD_AVX2 +#include + +// If the compiler doesn’t support AVX2 instrinsics, compiler errors will happen. +``` + +Additionally, GLM provides a low level SIMD API in glm/simd directory for users who are really interested in writing fast algorithms. + +### 2.12. GLM\_FORCE\_PRECISION\_**: Default precision + +C++ does not provide a way to implement GLSL default precision selection (as defined in GLSL 4.10 specification section 4.5.3) with GLSL-like syntax. + +```glsl +precision mediump int; +precision highp float; +``` + +To use the default precision functionality, GLM provides some defines that need to added before any include of `glm.hpp`: + +```cpp +#define GLM_FORCE_PRECISION_MEDIUMP_INT +#define GLM_FORCE_PRECISION_HIGHP_FLOAT +#include +``` + +Available defines for floating point types (`glm::vec\*`, `glm::mat\*`): + +* `GLM_FORCE_PRECISION_LOWP_FLOAT`: Low precision +* `GLM_FORCE_PRECISION_MEDIUMP_FLOAT`: Medium precision +* `GLM_FORCE_PRECISION_HIGHP_FLOAT`: High precision (default) + +Available defines for floating point types (`glm::dvec\*`, `glm::dmat\*`): + +* `GLM_FORCE_PRECISION_LOWP_DOUBLE`: Low precision +* `GLM_FORCE_PRECISION_MEDIUMP_DOUBLE`: Medium precision +* `GLM_FORCE_PRECISION_HIGHP_DOUBLE`: High precision (default) + +Available defines for signed integer types (`glm::ivec\*`): + +* `GLM_FORCE_PRECISION_LOWP_INT`: Low precision +* `GLM_FORCE_PRECISION_MEDIUMP_INT`: Medium precision +* `GLM_FORCE_PRECISION_HIGHP_INT`: High precision (default) + +Available defines for unsigned integer types (`glm::uvec\*`): + +* `GLM_FORCE_PRECISION_LOWP_UINT`: Low precision +* `GLM_FORCE_PRECISION_MEDIUMP_UINT`: Medium precision +* `GLM_FORCE_PRECISION_HIGHP_UINT`: High precision (default) + +### 2.13. GLM\_FORCE\_SINGLE\_ONLY: Removed explicit 64-bits floating point types + +Some platforms (Dreamcast) doesn't support double precision floating point values. To compile on such platforms, GCC has the `--m4-single-only` build argument. When defining `GLM_FORCE_SINGLE_ONLY` before including GLM headers, GLM releases the requirement of double precision floating point values support. Effectivement, all the float64 types are no longer defined and double behaves like float. + +### 2.14. GLM\_FORCE\_SWIZZLE: Enable swizzle operators + +Shader languages like GLSL often feature so-called swizzle expressions, which may be used to freely select and arrange a vector's components. For example, `variable.x`, `variable.xzy` and `variable.zxyy` respectively form a scalar, a 3D vector and a 4D vector. The result of a swizzle expression in GLSL can be either an R-value or an L-value. Swizzle expressions can be written with characters from exactly one of `xyzw` (usually for positions), `rgba` (usually for colors), and `stpq` (usually for texture coordinates). + +```glsl +vec4 A; +vec2 B; + +B.yx = A.wy; +B = A.xx; +vec3 C = A.bgr; +vec3 D = B.rsz; // Invalid, won't compile +``` + +GLM supports some of this functionality. Swizzling can be enabled by defining `GLM_FORCE_SWIZZLE`. + +*Note: Enabling swizzle expressions will massively increase the size of your binaries and the time it takes to compile them!* + +GLM has two levels of swizzling support described in the following subsections. + +#### 2.14.1. Swizzle functions for standard C++ 98 + +When compiling GLM as C++98, R-value swizzle expressions are simulated through member functions of each vector type. + +```cpp +#define GLM_FORCE_SWIZZLE // Or defined when building (e.g. -DGLM_FORCE_SWIZZLE) +#include + +void foo() +{ + glm::vec4 const ColorRGBA = glm::vec4(1.0f, 0.5f, 0.0f, 1.0f); + glm::vec3 const ColorBGR = ColorRGBA.bgr(); + + glm::vec3 const PositionA = glm::vec3(1.0f, 0.5f, 0.0f); + glm::vec3 const PositionB = PositionXYZ.xyz() * 2.0f; + + glm::vec2 const TexcoordST = glm::vec2(1.0f, 0.5f); + glm::vec4 const TexcoordSTPQ = TexcoordST.stst(); +} +``` + +Swizzle operators return a **copy** of the component values, and thus *can't* be used as L-values to change a vector's values. + +```cpp +#define GLM_FORCE_SWIZZLE +#include + +void foo() +{ + glm::vec3 const A = glm::vec3(1.0f, 0.5f, 0.0f); + + // No compiler error, but A is not modified. + // An anonymous copy is being modified (and then discarded). + A.bgr() = glm::vec3(2.0f, 1.5f, 1.0f); // A is not modified! +} +``` + +#### 2.14.2. Swizzle operations for C++ 98 with language extensions + +Visual C++, GCC and Clang support, as a _non-standard language extension_, anonymous `struct`s as `union` members. This permits a powerful swizzling implementation that both allows L-value swizzle expressions and GLSL-like syntax. To use this feature, the language extension must be enabled by a supporting compiler and `GLM_FORCE_SWIZZLE` must be `#define`d. + +```cpp +#define GLM_FORCE_SWIZZLE +#include + +// Only guaranteed to work with Visual C++! +// Some compilers that support Microsoft extensions may compile this. +void foo() +{ + glm::vec4 ColorRGBA = glm::vec4(1.0f, 0.5f, 0.0f, 1.0f); + + // l-value: + glm::vec4 ColorBGRA = ColorRGBA.bgra; + + // r-value: + ColorRGBA.bgra = ColorRGBA; + + // Both l-value and r-value + ColorRGBA.bgra = ColorRGBA.rgba; +} +``` + +This version returns implementation-specific objects that _implicitly convert_ to their respective vector types. As a consequence of this design, these extra types **can't be directly used** as C++ function arguments; they must be converted through constructors or `operator()`. + +```cpp +#define GLM_FORCE_SWIZZLE +#include + +using namespace glm; + +void foo() +{ + vec4 Color = vec4(1.0f, 0.5f, 0.0f, 1.0f); + + // Generates compiler errors. Color.rgba is not a vector type. + vec4 ClampedA = clamp(Color.rgba, 0.f, 1.f); // ERROR + + // Explicit conversion through a constructor + vec4 ClampedB = clamp(vec4(Color.rgba), 0.f, 1.f); // OK + + // Explicit conversion through operator() + vec4 ClampedC = clamp(Color.rgba(), 0.f, 1.f); // OK +} +``` + +*Note: The implementation has a caveat: Swizzle operator types must be different on both size of the equal operator or the operation will fail. There is no known fix for this issue to date* + +### 2.15. GLM\_FORCE\_XYZW\_ONLY: Only exposes x, y, z and w components + +Following GLSL specifications, GLM supports three sets of components to access vector types member: x, y, z, w; r, g, b, a; and s, t, p, q. +Also, this is making vector component very expressive in the code, it may make debugging vector types a little cubersom as the debuggers will typically display three time the values for each compoenents due to the existence of the three sets. + +To simplify vector types, GLM allows exposing only x, y, z and w components thanks to `GLM_FORCE_XYZW_ONLY` define. + +### 2.16. GLM\_FORCE\_LEFT\_HANDED: Force left handed coordinate system + +By default, OpenGL is using a right handed coordinate system. However, others APIs such as Direct3D have done different choice and relies on the left handed coordinate system. + +GLM allows switching the coordinate system to left handed by defining `GLM_FORCE_LEFT_HANDED`. + +### 2.17. GLM\_FORCE\_DEPTH\_ZERO\_TO\_ONE: Force the use of a clip space between 0 to 1 + +By default, OpenGL is using a -1 to 1 clip space in Z-axis. However, others APIs such as Direct3D relies on a clip space between 0 to 1 in Z-axis. + +GLM allows switching the clip space in Z-axis to 0 to 1 by defining `GLM_FORCE_DEPTH_ZERO_TO_ONE`. + +### 2.18. GLM\_FORCE\_SIZE\_T\_LENGTH: Vector and matrix static size + +GLSL supports the member function .length() for all vector and matrix types. + +```cpp +#include + +void foo(vec4 const& v) +{ + int Length = v.length(); + ... +} +``` + +This function returns an `int` however this function typically interacts with STL `size_t` based code. GLM provides `GLM_FORCE_SIZE_T_LENGTH` pre-processor configuration so that member functions `length()` return a `size_t`. + +Additionally, GLM defines the type `glm::length_t` to identify `length()` returned type, independently from `GLM_FORCE_SIZE_T_LENGTH`. + +```cpp +#define GLM_FORCE_SIZE_T_LENGTH +#include + +void foo(vec4 const& v) +{ + glm::length_t Length = v.length(); + ... +} +``` + +### 2.19. GLM\_FORCE\_UNRESTRICTED\_GENTYPE: Removing genType restriction + +GLSL has restrictions on types supported by certain functions that may appear excessive. +By default, GLM follows the GLSL specification as accurately as possible however it's possible to relax these rules using `GLM_FORCE_UNRESTRICTED_GENTYPE` define. + +```cpp +#include + +float average(float const A, float const B) +{ + return glm::mix(A, B, 0.5f); // By default glm::mix only supports floating-point types +} +``` + +By defining GLM\_FORCE\_UNRESTRICTED\_GENTYPE, we allow using integer types: + +```cpp +#define GLM_FORCE_UNRESTRICTED_GENTYPE +#include + +int average(int const A, int const B) +{ + return glm::mix(A, B, 0.5f); // integers are ok thanks to GLM_FORCE_UNRESTRICTED_GENTYPE +} +``` + +### 2.20. GLM\_FORCE\_SILENT\_WARNINGS: Silent C++ warnings from language extensions + +When using /W4 on Visual C++ or -Wpedantic on GCC, for example, the compilers will generate warnings for using C++ language extensions (/Za with Visual C++) such as anonymous struct. +GLM relies on anonymous structs for swizzle operators and aligned vector types. To silent those warnings define `GLM_FORCE_SILENT_WARNINGS` before including GLM headers. + +### 2.21. GLM\_FORCE\_QUAT\_DATA\_WXYZ: Force GLM to store quat data as w,x,y,z instead of x,y,z,w + +By default GLM store quaternion components with the x, y, z, w order. `GLM_FORCE_QUAT_DATA_WXYZ` allows switching the quaternion data storage to the w, x, y, z order. + +--- +
+ +## 3. Stable extensions + +### 3.1. Scalar types + +#### 3.1.1. GLM_EXT_scalar_int_sized + +This extension exposes sized and signed integer types. + +Include `` to use these features. + +#### 3.1.2. GLM_EXT_scalar_uint_sized + +This extension exposes sized and unsigned integer types. + +```cpp +#include + +glm::uint64 pack(glm::uint32 A, glm::uint16 B, glm::uint8 C, glm::uint8 D) +{ + glm::uint64 ShiftA = 0; + glm::uint64 ShiftB = sizeof(glm::uint32) * 8; + glm::uint64 ShiftC = (sizeof(glm::uint32) + sizeof(glm::uint16)) * 8; + glm::uint64 ShiftD = (sizeof(glm::uint32) + sizeof(glm::uint16) + sizeof(glm::uint8)) * 8; + return (glm::uint64(A) << ShiftA) | (glm::uint64(B) << ShiftB) | (glm::uint64(C) << ShiftC) | (glm::uint64(D) << ShiftD); +} +``` + +Include `` to use these features. + +### 3.2. Scalar functions + +#### 3.2.1. GLM_EXT_scalar_common + +This extension exposes support for `min` and `max` functions taking more than two scalar arguments. Also, it adds `fmin` and `fmax` variants which prevents `NaN` propagation. + +```cpp +#include + +float positiveMax(float const a, float const b) +{ + return glm::fmax(a, b, 0.0f); +} +``` + +Include `` to use these features. + +#### 3.2.2. GLM_EXT_scalar_relational + +This extension exposes `equal` and `notEqual` scalar variants which takes an epsilon argument. + +```cpp +#include + +bool epsilonEqual(float const a, float const b) +{ + float const CustomEpsilon = 0.0001f; + return glm::equal(a, b, CustomEpsilon); +} +``` + +Include `` to use these features. + +#### 3.2.3. GLM_EXT_scalar_constants + +This extension exposes useful constants such as `epsilon` and `pi`. + +```cpp +#include + +float circumference(float const Diameter) +{ + return glm::pi() * Diameter; +} +``` + +```cpp +#include // abs +#include // epsilon + +bool equalULP1(float const a, float const b) +{ + return glm::abs(a - b) <= glm::epsilon(); +} +``` + +Include `` to use these features. + +#### 3.2.4. GLM_EXT_scalar_ulp + +This extension exposes function that measure of accuracy in numeric calculations. + +```cpp +#include + +bool test_ulp(float x) +{ + float const a = glm::next_float(x); // return a float a ULP away from the float argument. + return float_distance(a, x) == 1; // check both float are a single ULP away. +} +``` + +Include `` to use these features. + +### 3.3. Vector types + +#### 3.3.1. GLM_EXT_vector_float1 + +This extension exposes single-precision floating point vector with 1 component: `vec1`. + +Include `` to use these features. + +#### 3.3.2. GLM_EXT_vector_float2 + +This extension exposes single-precision floating point vector with 2 components: `vec2`. + +Include `` to use these features. + +#### 3.3.3. GLM_EXT_vector_float3 + +This extension exposes single-precision floating point vector with 3 components: `vec3`. + +Include `` to use these features. + +#### 3.3.4. GLM_EXT_vector_float4 + +This extension exposes single-precision floating point vector with 4 components: `vec4`. + +Include `` to use these features. + +#### 3.3.5. GLM_EXT_vector_double1 + +This extension exposes double-precision floating point vector with 1 component: `dvec1`. + +Include `` to use these features. + +#### 3.3.6. GLM_EXT_vector_double2 + +This extension exposes double-precision floating point vector with 2 components: `dvec2`. + +Include `` to use these features. + +#### 3.3.7. GLM_EXT_vector_double3 + +This extension exposes double-precision floating point vector with 3 components: `dvec3`. + +Include `` to use these features. + +#### 3.3.8. GLM_EXT_vector_double4 + +This extension exposes double-precision floating point vector with 4 components: `dvec4`. + +Include `` to use these features. + +#### 3.3.9. GLM_EXT_vector_int1 + +This extension exposes signed integer vector with 1 component: `ivec1`. + +Include `` to use these features. + +#### 3.3.10. GLM_EXT_vector_int2 + +This extension exposes signed integer vector with 2 components: `ivec2`. + +Include `` to use these features. + +#### 3.3.11. GLM_EXT_vector_int3 + +This extension exposes signed integer vector with 3 components: `ivec3`. + +Include `` to use these features. + +#### 3.3.12. GLM_EXT_vector_int4 + +This extension exposes signed integer vector with 4 components: `ivec4`. + +Include `` to use these features. + +#### 3.3.13. GLM_EXT_vector_int1 + +This extension exposes unsigned integer vector with 1 component: `uvec1`. + +Include `` to use these features. + +#### 3.3.14. GLM_EXT_vector_uint2 + +This extension exposes unsigned integer vector with 2 components: `uvec2`. + +Include `` to use these features. + +#### 3.3.15. GLM_EXT_vector_uint3 + +This extension exposes unsigned integer vector with 3 components: `uvec3`. + +Include `` to use these features. + +#### 3.3.16. GLM_EXT_vector_uint4 + +This extension exposes unsigned integer vector with 4 components: `uvec4`. + +Include `` to use these features. + +#### 3.3.17. GLM_EXT_vector_bool1 + +This extension exposes boolean vector with 1 component: `bvec1`. + +Include `` to use these features. + +#### 3.3.18. GLM_EXT_vector_bool2 + +This extension exposes boolean vector with 2 components: `bvec2`. + +Include `` to use these features. + +#### 3.3.19. GLM_EXT_vector_bool3 + +This extension exposes boolean vector with 3 components: `bvec3`. + +Include `` to use these features. + +#### 3.3.20. GLM_EXT_vector_bool4 + +This extension exposes boolean vector with 4 components: `bvec4`. + +Include `` to use these features. + +### 3.4. Vector types with precision qualifiers + +#### 3.4.1. GLM_EXT_vector_float1_precision + +This extension exposes single-precision floating point vector with 1 component using various precision in term of ULPs: `lowp_vec1`, `mediump_vec1` and `highp_vec1`. + +Include `` to use these features. + +#### 3.4.2. GLM_EXT_vector_float2_precision + +This extension exposes single-precision floating point vector with 2 components using various precision in term of ULPs: `lowp_vec2`, `mediump_vec2` and `highp_vec2`. + +Include `` to use these features. + +#### 3.4.3. GLM_EXT_vector_float3_precision + +This extension exposes single-precision floating point vector with 3 components using various precision in term of ULPs: `lowp_vec3`, `mediump_vec3` and `highp_vec3`. + +Include `` to use these features. + +#### 3.4.4. GLM_EXT_vector_float4_precision + +This extension exposes single-precision floating point vector with 4 components using various precision in term of ULPs: `lowp_vec4`, `mediump_vec4` and `highp_vec4`. + +Include `` to use these features. + +#### 3.4.5. GLM_EXT_vector_double1_precision + +This extension exposes double-precision floating point vector with 1 component using various precision in term of ULPs: `lowp_dvec1`, `mediump_dvec1` and `highp_dvec1`. + +Include `` to use these features. + +#### 3.4.6. GLM_EXT_vector_double2_precision + +This extension exposes double-precision floating point vector with 2 components using various precision in term of ULPs: `lowp_dvec2`, `mediump_dvec2` and `highp_dvec2`. + +Include `` to use these features. + +#### 3.4.7. GLM_EXT_vector_double3_precision + +This extension exposes double-precision floating point vector with 3 components using various precision in term of ULPs: `lowp_dvec3`, `mediump_dvec3` and `highp_dvec3`. + +Include `` to use these features. + +#### 3.4.8. GLM_EXT_vector_double4_precision + +This extension exposes double-precision floating point vector with 4 components using various precision in term of ULPs: `lowp_dvec4`, `mediump_dvec4` and `highp_dvec4`. + +Include `` to use these features. + +### 3.5. Vector functions + +#### 3.5.1. GLM_EXT_vector_common + +This extension exposes support for `min` and `max` functions taking more than two vector arguments. Also, it adds `fmin` and `fmax` variants which prevents `NaN` propagation. + +```cpp +#include // vec2 +#include // fmax + +float positiveMax(float const a, float const b) +{ + return glm::fmax(a, b, 0.0f); +} +``` + +Include `` to use these features. + +#### 3.5.2. GLM_EXT_vector_relational + +This extension exposes `equal` and `notEqual` vector variants which takes an epsilon argument. + +```cpp +#include // vec2 +#include // equal, all + +bool epsilonEqual(glm::vec2 const& A, glm::vec2 const& B) +{ + float const CustomEpsilon = 0.0001f; + return glm::all(glm::equal(A, B, CustomEpsilon)); +} +``` + +Include `` to use these features. + +#### 3.5.3. GLM_EXT_vector_ulp + +This extension exposes function that measure of accuracy in numeric calculations. + +```cpp +#include +#include +#include + +bool test_ulp(glm::vec4 const& x) +{ + glm::vec4 const a = glm::next_float(x); // return a float a ULP away from the float argument. + return glm::all(float_distance(a, x) == glm::ivec4(1)); // check both float are a single ULP away. +} +``` + +Include `` to use these features. + +### 3.6. Matrix types + +#### 3.6.1. GLM_EXT_matrix_float2x2 + +This extension exposes single-precision floating point vector with 2 columns by 2 rows: `mat2x2`. + +Include `` to use these features. + +#### 3.6.2. GLM_EXT_matrix_float2x3 + +This extension exposes single-precision floating point vector with 2 columns by 3 rows: `mat2x3`. + +Include `` to use these features. + +#### 3.6.3. GLM_EXT_matrix_float2x4 + +This extension exposes single-precision floating point vector with 2 columns by 4 rows: `mat2x4`. + +Include `` to use these features. + +#### 3.6.4. GLM_EXT_matrix_float3x2 + +This extension exposes single-precision floating point vector with 3 columns by 2 rows: `mat3x2`. + +Include `` to use these features. + +#### 3.6.5. GLM_EXT_matrix_float3x3 + +This extension exposes single-precision floating point vector with 3 columns by 3 rows: `mat3x3`. + +Include `` to use these features. + +#### 3.6.6. GLM_EXT_matrix_float3x4 + +This extension exposes single-precision floating point vector with 3 columns by 4 rows: `mat3x4`. + +Include `` to use these features. + +#### 3.6.7. GLM_EXT_matrix_float4x2 + +This extension exposes single-precision floating point vector with 4 columns by 2 rows: `mat4x2`. + +Include `` to use these features. + +#### 3.6.8. GLM_EXT_matrix_float4x3 + +This extension exposes single-precision floating point vector with 4 columns by 3 rows: `mat4x3`. + +Include `` to use these features. + +#### 3.6.9. GLM_EXT_matrix_float4x4 + +This extension exposes single-precision floating point vector with 4 columns by 4 rows: `mat4x4`. + +Include `` to use these features. + +#### 3.6.10. GLM_EXT_matrix_double2x2 + +This extension exposes double-precision floating point vector with 2 columns by 2 rows: `dmat2x2`. + +Include `` to use these features. + +#### 3.6.11. GLM_EXT_matrix_double2x3 + +This extension exposes double-precision floating point vector with 2 columns by 3 rows: `dmat2x3`. + +Include `` to use these features. + +#### 3.6.12. GLM_EXT_matrix_double2x4 + +This extension exposes double-precision floating point vector with 2 columns by 4 rows: `dmat2x4`. + +Include `` to use these features. + +#### 3.6.13. GLM_EXT_matrix_double3x2 + +This extension exposes double-precision floating point vector with 3 columns by 2 rows: `dmat3x2`. + +Include `` to use these features. + +#### 3.6.14. GLM_EXT_matrix_double3x3 + +This extension exposes double-precision floating point vector with 3 columns by 3 rows: `dmat3x3`. + +Include `` to use these features. + +#### 3.6.15. GLM_EXT_matrix_double3x4 + +This extension exposes double-precision floating point vector with 3 columns by 4 rows: `dmat3x4`. + +Include `` to use these features. + +#### 3.6.16. GLM_EXT_matrix_double4x2 + +This extension exposes double-precision floating point vector with 4 columns by 2 rows: `dmat4x2`. + +Include `` to use these features. + +#### 3.6.17. GLM_EXT_matrix_double4x3 + +This extension exposes double-precision floating point vector with 4 columns by 3 rows: `dmat4x3`. + +Include `` to use these features. + +#### 3.6.18. GLM_EXT_matrix_double4x4 + +This extension exposes double-precision floating point vector with 4 columns by 4 rows: `dmat4x4`. + +Include `` to use these features. + +### 3.7. Matrix types with precision qualifiers + +#### 3.7.1. GLM_EXT_matrix_float2x2_precision + +This extension exposes single-precision floating point vector with 2 columns by 2 rows using various precision in term of ULPs: `lowp_mat2x2`, `mediump_mat2x2` and `highp_mat2x2`. + +Include `` to use these features. + +#### 3.7.2. GLM_EXT_matrix_float2x3_precision + +This extension exposes single-precision floating point vector with 2 columns by 3 rows using various precision in term of ULPs: `lowp_mat2x3`, `mediump_mat2x3` and `highp_mat2x3`. + +Include `` to use these features. + +#### 3.7.3. GLM_EXT_matrix_float2x4_precision + +This extension exposes single-precision floating point vector with 2 columns by 4 rows using various precision in term of ULPs: `lowp_mat2x4`, `mediump_mat2x4` and `highp_mat2x4`. + +Include `` to use these features. + +#### 3.7.4. GLM_EXT_matrix_float3x2_precision + +This extension exposes single-precision floating point vector with 3 columns by 2 rows using various precision in term of ULPs: `lowp_mat3x2`, `mediump_mat3x2` and `highp_mat3x2`. + +Include `` to use these features. + +#### 3.7.5. GLM_EXT_matrix_float3x3_precision + +This extension exposes single-precision floating point vector with 3 columns by 3 rows using various precision in term of ULPs: `lowp_mat3x3`, `mediump_mat3x3` and `highp_mat3x3`. + +Include `` to use these features. + +#### 3.7.6. GLM_EXT_matrix_float3x4_precision + +This extension exposes single-precision floating point vector with 3 columns by 4 rows using various precision in term of ULPs: `lowp_mat3x4`, `mediump_mat3x4` and `highp_mat3x4`. + +Include `` to use these features. + +#### 3.7.7. GLM_EXT_matrix_float4x2_precision + +This extension exposes single-precision floating point vector with 4 columns by 2 rows using various precision in term of ULPs: `lowp_mat4x2`, `mediump_mat4x2` and `highp_mat4x2`. + +Include `` to use these features. + +#### 3.7.8. GLM_EXT_matrix_float4x3_precision + +This extension exposes single-precision floating point vector with 4 columns by 3 rows using various precision in term of ULPs: `lowp_mat4x3`, `mediump_mat4x3` and `highp_mat4x3`. + +Include `` to use these features. + +#### 3.7.9. GLM_EXT_matrix_float4x4_precision + +This extension exposes single-precision floating point vector with 4 columns by 4 rows using various precision in term of ULPs: `lowp_mat4x4`, `mediump_mat4x4` and `highp_mat4x4`. + +Include `` to use these features. + +#### 3.7.10. GLM_EXT_matrix_double2x2_precision + +This extension exposes double-precision floating point vector with 2 columns by 2 rows using various precision in term of ULPs: `lowp_dmat2x2`, `mediump_dmat2x2` and `highp_dmat2x2`. + +Include `` to use these features. + +#### 3.7.11. GLM_EXT_matrix_double2x3_precision + +This extension exposes double-precision floating point vector with 2 columns by 3 rows using various precision in term of ULPs: `lowp_dmat2x3`, `mediump_dmat2x3` and `highp_dmat2x3`. + +Include `` to use these features. + +#### 3.7.12. GLM_EXT_matrix_double2x4_precision + +This extension exposes double-precision floating point vector with 2 columns by 4 rows using various precision in term of ULPs: `lowp_dmat2x4`, `mediump_dmat2x4` and `highp_dmat2x4`. + +Include `` to use these features. + +#### 3.7.13. GLM_EXT_matrix_double3x2_precision + +This extension exposes double-precision floating point vector with 3 columns by 2 rows using various precision in term of ULPs: `lowp_dmat3x2`, `mediump_dmat3x2` and `highp_dmat3x2`. + +Include `` to use these features. + +#### 3.7.14. GLM_EXT_matrix_double3x3_precision + +This extension exposes double-precision floating point vector with 3 columns by 3 rows using various precision in term of ULPs: `lowp_dmat3x3`, `mediump_dmat3x3` and `highp_dmat3x3`. + +Include `` to use these features. + +#### 3.7.15. GLM_EXT_matrix_double3x4_precision + +This extension exposes double-precision floating point vector with 3 columns by 4 rows using various precision in term of ULPs: `lowp_dmat3x4`, `mediump_dmat3x4` and `highp_dmat3x4`. + +Include `` to use these features. + +#### 3.7.16. GLM_EXT_matrix_double4x2_precision + +This extension exposes double-precision floating point vector with 4 columns by 2 rows using various precision in term of ULPs: `lowp_dmat4x2`, `mediump_dmat4x2` and `highp_dmat4x2`. + +Include `` to use these features. + +#### 3.7.17. GLM_EXT_matrix_double4x3_precision + +This extension exposes double-precision floating point vector with 4 columns by 3 rows using various precision in term of ULPs: `lowp_dmat4x3`, `mediump_dmat4x3` and `highp_dmat4x3`. + +Include `` to use these features. + +#### 3.7.18. GLM_EXT_matrix_double4x4_precision + +This extension exposes double-precision floating point vector with 4 columns by 4 rows using various precision in term of ULPs: `lowp_dmat4x4`, `mediump_dmat4x4` and `highp_dmat4x4`. + +Include `` to use these features. + +### 3.8. Matrix functions + +#### 3.8.1. GLM_EXT_matrix_relational + +This extension exposes `equal` and `notEqual` matrix variants which takes an optional epsilon argument. + +```cpp +#include // bvec4 +#include // mat4 +#include // equal, all + +bool epsilonEqual(glm::mat4 const& A, glm::mat4 const& B) +{ + float const CustomEpsilon = 0.0001f; + glm::bvec4 const ColumnEqual = glm::equal(A, B, CustomEpsilon); // Evaluation per column + return glm::all(ColumnEqual); +} +``` + +Include `` to use these features. + +#### 3.8.2. GLM_EXT_matrix_transform + +This extension exposes matrix transformation functions: `translate`, `rotate` and `scale`. + +```cpp +#include // vec2 +#include // vec3 +#include // mat4x4 +#include // translate, rotate, scale, identity + +glm::mat4 computeModelViewMatrix(float Translate, glm::vec2 const & Rotate) +{ + glm::mat4 View = glm::translate(glm::identity(), glm::vec3(0.0f, 0.0f, -Translate)); + View = glm::rotate(View, Rotate.y, glm::vec3(-1.0f, 0.0f, 0.0f)); + View = glm::rotate(View, Rotate.x, glm::vec3(0.0f, 1.0f, 0.0f)); + glm::mat4 Model = glm::scale(glm::identity(), glm::vec3(0.5f)); + return View * Model; +} +``` + +Include `` to use these features. + +#### 3.8.3. GLM_EXT_matrix_clip_space + +This extension exposes functions to transform scenes into the clip space. + +```cpp +#include // mat4x4 +#include // perspective +#include // radians + +glm::mat4 computeProjection(float Width, float Height) +{ + return glm::perspective(glm::radians(45.0f), Width / Height, 0.1f, 100.f); +} +``` + +Include `` to use these features. + +#### 3.8.4. GLM_EXT_matrix_projection + +This extension exposes functions to map object coordinates into window coordinates and reverse + +Include `` to use these features. + +### 3.9. Quaternion types + +#### 3.9.1. GLM_EXT_quaternion_float + +This extension exposes single-precision floating point quaternion: `quat`. + +Include `` to use these features. + +#### 3.9.2. GLM_EXT_quaternion_double + +This extension exposes double-precision floating point quaternion: `dquat`. + +Include `` to use these features. + +### 3.10. Quaternion types with precision qualifiers + +#### 3.10.1. GLM_EXT_quaternion_float_precision + +This extension exposes single-precision floating point quaternion using various precision in term of ULPs: `lowp_quat`, `mediump_quat` and `highp_quat`. + +Include `` to use these features. + +#### 3.10.2. GLM_EXT_quaternion_double_precision + +This extension exposes double-precision floating point quaternion using various precision in term of ULPs: `lowp_dquat`, `mediump_dquat` and `highp_dquat`. + +Include `` to use these features. + +### 3.11. Quaternion functions + +#### 3.11.1. GLM_EXT_quaternion_common + +This extension exposes common quaternion functions such as `slerp`, `conjugate` and `inverse`. + +Include `` to use these features. + +#### 3.11.2. GLM_EXT_quaternion_geometric + +This extension exposes geometric quaternion functions such as `length`, `normalize`, `dot` and `cross`. + +Include `` to use these features. + +#### 3.11.3. GLM_EXT_quaternion_trigonometric + +This extension exposes trigonometric quaternion functions such as `angle` and `axis`. + +Include `` to use these features. + +#### 3.11.4. GLM_EXT_quaternion_exponential + +This extensions expose exponential functions for quaternions such as `exp`, `log`, `pow` and `sqrt`. + +Include `` to use these features. + +#### 3.11.5. GLM_EXT_quaternion_relational + +This extension exposes relational functions to compare quaternions. + +Include `` to use these features. + +#### 3.11.6. GLM_EXT_quaternion_transform + +This extension exposes functions to transform objects. + +Include `` to use these features. + +--- +
+ +## 4. Recommended extensions + +GLM extends the core GLSL feature set with extensions. These extensions include: quaternion, transformation, spline, matrix inverse, color spaces, etc. + +To include an extension, we only need to include the dedicated header file. Once included, the features are added to the GLM namespace. + +```cpp +#include +#include + +int foo() +{ + glm::vec4 Position = glm::vec4(glm:: vec3(0.0f), 1.0f); + glm::mat4 Model = glm::translate(glm::mat4(1.0f), glm::vec3(1.0f)); + + glm::vec4 Transformed = Model * Position; + ... + + return 0; +} +``` + +When an extension is included, all the dependent core functionalities and extensions will be included as well. + +### 4.1. GLM_GTC_bitfield + +Fast bitfield operations on scalar and vector variables. + +`` need to be included to use these features. + +### 4.2. GLM_GTC_color_space + +Conversion between linear RGB and sRGB color spaces. + +`` need to be included to use these features. + +### 4.3. GLM_GTC_constants + +Provide a list of built-in constants. + +`` need to be included to use these features. + +### 4.4. GLM\_GTC\_epsilon + +Approximate equality comparisons for floating-point numbers, possibly with a user-defined epsilon. + +`` need to be included to use these features. + +### 4.5. GLM\_GTC\_integer + +Integer variants of core GLM functions. + +`` need to be included to use these features. + +### 4.6. GLM\_GTC\_matrix\_access + +Functions to conveniently access the individual rows or columns of a matrix. + +`` need to be included to use these features. + +### 4.7. GLM\_GTC\_matrix\_integer + +Integer matrix types similar to the core floating-point matrices. Some operations (such as inverse and determinant) are not supported. + +`` need to be included to use these features. + +### 4.8. GLM\_GTC\_matrix\_inverse + +Additional matrix inverse functions. + +`` need to be included to use these features. + +### 4.9. GLM\_GTC\_matrix\_transform + +Matrix transformation functions that follow the OpenGL fixed-function conventions. + +For example, the `lookAt` function generates a transformation matrix that projects world coordinates into eye coordinates suitable for projection matrices (e.g. `perspective`, `ortho`). See the OpenGL compatibility specifications for more information about the layout of these generated matrices. + +The matrices generated by this extension use standard OpenGL fixed-function conventions. For example, the `lookAt` function generates a transform from world space into the specific eye space that the +projective matrix functions (`perspective`, `ortho`, etc) are designed to expect. The OpenGL compatibility specifications define the particular layout of this eye space. + +`` need to be included to use these features. + +### 4.10. GLM\_GTC\_noise + +Define 2D, 3D and 4D procedural noise functions. + +`` need to be included to use these features. + +![](./doc/manual/noise-simplex1.jpg) + +Figure 4.10.1: glm::simplex(glm::vec2(x / 16.f, y / 16.f)); + +![](./doc/manual/noise-simplex2.jpg) + +Figure 4.10.2: glm::simplex(glm::vec3(x / 16.f, y / 16.f, 0.5f)); + +![](./doc/manual/noise-simplex3.jpg) + +Figure 4.10.3: glm::simplex(glm::vec4(x / 16.f, y / 16.f, 0.5f, 0.5f)); + +![](./doc/manual/noise-perlin1.jpg) + +Figure 4.10.4: glm::perlin(glm::vec2(x / 16.f, y / 16.f)); + +![](./doc/manual/noise-perlin2.jpg) + +Figure 4.10.5: glm::perlin(glm::vec3(x / 16.f, y / 16.f, 0.5f)); + +![](./doc/manual/noise-perlin3.jpg) + +Figure 4.10.6: glm::perlin(glm::vec4(x / 16.f, y / 16.f, 0.5f, 0.5f))); + +![](./doc/manual/noise-perlin4.png) + +Figure 4.10.7: glm::perlin(glm::vec2(x / 16.f, y / 16.f), glm::vec2(2.0f)); + +![](./doc/manual/noise-perlin5.png) + +Figure 4.10.8: glm::perlin(glm::vec3(x / 16.f, y / 16.f, 0.5f), glm::vec3(2.0f)); + +![](./doc/manual/noise-perlin6.png) + +Figure 4.10.9: glm::perlin(glm::vec4(x / 16.f, y / 16.f, glm::vec2(0.5f)), glm::vec4(2.0f)); + +### 4.11. GLM\_GTC\_packing + +Convert scalar and vector types to and from packed formats, saving space at the cost of precision. However, packing a value into a format that it was previously unpacked from is guaranteed to be lossless. + +`` need to be included to use these features. + +### 4.12. GLM\_GTC\_quaternion + +Quaternions and operations upon thereof. + +`` need to be included to use these features. + +### 4.13. GLM\_GTC\_random + +Probability distributions in up to four dimensions. + +`` need to be included to use these features. + +![](./doc/manual/random-linearrand.png) + +Figure 4.13.1: glm::vec4(glm::linearRand(glm::vec2(-1), glm::vec2(1)), 0, 1); + +![](./doc/manual/random-circularrand.png) + +Figure 4.13.2: glm::vec4(glm::circularRand(1.0f), 0, 1); + +![](./doc/manual/random-sphericalrand.png) + +Figure 4.13.3: glm::vec4(glm::sphericalRand(1.0f), 1); + +![](./doc/manual/random-diskrand.png) + +Figure 4.13.4: glm::vec4(glm::diskRand(1.0f), 0, 1); + +![](./doc/manual/random-ballrand.png) + +Figure 4.13.5: glm::vec4(glm::ballRand(1.0f), 1); + +![](./doc/manual/random-gaussrand.png) + +Figure 4.13.6: glm::vec4(glm::gaussRand(glm::vec3(0), glm::vec3(1)), 1); + +### 4.14. GLM\_GTC\_reciprocal + +Reciprocal trigonometric functions (e.g. secant, cosecant, tangent). + +`` need to be included to use the features of this extension. + +### 4.15. GLM\_GTC\_round + +Various rounding operations and common special cases thereof. + +`` need to be included to use the features of this extension. + +### 4.16. GLM\_GTC\_type\_aligned + +Aligned vector types. + +`` need to be included to use the features of this extension. + +### 4.17. GLM\_GTC\_type\_precision + +Vector and matrix types with defined precisions, e.g. `i8vec4`, which is a 4D vector of signed 8-bit integers. + +`` need to be included to use the features of this extension. + +### 4.18. GLM\_GTC\_type\_ptr + +Facilitate interactions between pointers to basic types (e.g. `float*`) and GLM types (e.g. `mat4`). + +This extension defines an overloaded function, `glm::value_ptr`, which returns a pointer to the memory layout of any GLM vector or matrix (`vec3`, `mat4`, etc.). Matrix types store their values in column-major order. This is useful for uploading data to matrices or for copying data to buffer objects. + +```cpp +// GLM_GTC_type_ptr provides a safe solution: +#include +#include + +void foo() +{ + glm::vec4 v(0.0f); + glm::mat4 m(1.0f); + ... + glVertex3fv(glm::value_ptr(v)) + glLoadMatrixfv(glm::value_ptr(m)); +} + +// Another solution, this one inspired by the STL: +#include + +void foo() +{ + glm::vec4 v(0.0f); + glm::mat4 m(1.0f); + ... + glVertex3fv(&v[0]); + glLoadMatrixfv(&m[0][0]); +} +``` + +*Note: It would be possible to implement [`glVertex3fv`](http://www.opengl.org/sdk/docs/man2/xhtml/glVertex.xml)(glm::vec3(0)) in C++ with the appropriate cast operator that would result as an +implicit cast in this example. However cast operators may produce programs running with unexpected behaviours without build error or any form of notification.* + +`` need to be included to use these features. + +### 4.19. GLM\_GTC\_ulp + +Measure a function's accuracy given a reference implementation of it. This extension works on floating-point data and provides results in [ULP](http://ljk.imag.fr/membres/Carine.Lucas/TPScilab/JMMuller/ulp-toms.pdf). + +`` need to be included to use these features. + +### 4.20. GLM\_GTC\_vec1 + +Add \*vec1 types. + +`` need to be included to use these features. + +--- +
+ +## 5. OpenGL interoperability + +### 5.1. GLM replacements for deprecated OpenGL functions + +OpenGL 3.1 specification has deprecated some features that have been removed from OpenGL 3.2 core profile specification. GLM provides some replacement functions. + +[***glRotate{f, d}:***](https://www.opengl.org/sdk/docs/man2/xhtml/glRotate.xml) + +```cpp +glm::mat4 glm::rotate(glm::mat4 const& m, float angle, glm::vec3 const& axis); +glm::dmat4 glm::rotate(glm::dmat4 const& m, double angle, glm::dvec3 const& axis); +``` + +From `GLM_GTC_matrix_transform` extension: <glm/gtc/matrix\_transform.hpp> + +[***glScale{f, d}:***](http://www.opengl.org/sdk/docs/man2/xhtml/glScale.xml) + +```cpp +glm::mat4 glm::scale(glm::mat4 const& m, glm::vec3 const& factors); +glm::dmat4 glm::scale(glm::dmat4 const& m, glm::dvec3 const& factors); +``` + +From `GLM_GTC_matrix_transform` extension: <glm/gtc/matrix\_transform.hpp> + +[***glTranslate{f, d}:***](https://www.opengl.org/sdk/docs/man2/xhtml/glTranslate.xml) + +```cpp +glm::mat4 glm::translate(glm::mat4 const& m, glm::vec3 const& translation); +glm::dmat4 glm::translate(glm::dmat4 const& m, glm::dvec3 const& translation); +``` + +From `GLM_GTC_matrix_transform` extension: <glm/gtc/matrix\_transform.hpp> + +[***glLoadIdentity:***](https://www.opengl.org/sdk/docs/man2/xhtml/glLoadIdentity.xml) + +```cpp +glm::mat4(1.0) or glm::mat4(); +glm::dmat4(1.0) or glm::dmat4(); +``` + +From GLM core library: `` + +[***glMultMatrix{f, d}:***](https://www.opengl.org/sdk/docs/man2/xhtml/glMultMatrix.xml) + +```cpp +glm::mat4() * glm::mat4(); +glm::dmat4() * glm::dmat4(); +``` + +From GLM core library: `` + +[***glLoadTransposeMatrix{f, d}:***](https://www.opengl.org/sdk/docs/man2/xhtml/glLoadTransposeMatrix.xml) + +```cpp +glm::transpose(glm::mat4()); +glm::transpose(glm::dmat4()); +``` + +From GLM core library: `` + +[***glMultTransposeMatrix{f, d}:***](https://www.opengl.org/sdk/docs/man2/xhtml/glMultTransposeMatrix.xml) + +```cpp +glm::mat4() * glm::transpose(glm::mat4()); +glm::dmat4() * glm::transpose(glm::dmat4()); +``` + +From GLM core library: `` + +[***glFrustum:***](http://www.opengl.org/sdk/docs/man2/xhtml/glFrustum.xml) + +```cpp +glm::mat4 glm::frustum(float left, float right, float bottom, float top, float zNear, float zFar); +glm::dmat4 glm::frustum(double left, double right, double bottom, double top, double zNear, double zFar); +``` + +From `GLM_GTC_matrix_transform` extension: `` + +[***glOrtho:***](https://www.opengl.org/sdk/docs/man2/xhtml/glOrtho.xml) + +```cpp +glm::mat4 glm::ortho(float left, float right, float bottom, float top, float zNear, float zFar); +glm::dmat4 glm::ortho(double left, double right, double bottom, double top, double zNear, double zFar); +``` + +From `GLM_GTC_matrix_transform` extension: `` + +### 5.2. GLM replacements for GLU functions + +[***gluLookAt:***](https://www.opengl.org/sdk/docs/man2/xhtml/gluLookAt.xml) + +```cpp +glm::mat4 glm::lookAt(glm::vec3 const& eye, glm::vec3 const& center, glm::vec3 const& up); +glm::dmat4 glm::lookAt(glm::dvec3 const& eye, glm::dvec3 const& center, glm::dvec3 const& up); +``` + +From `GLM_GTC_matrix_transform` extension: `` + +[***gluOrtho2D:***](https://www.opengl.org/sdk/docs/man2/xhtml/gluOrtho2D.xml) + +```cpp +glm::mat4 glm::ortho(float left, float right, float bottom, float top); +glm::dmat4 glm::ortho(double left, double right, double bottom, double top); +``` + +From `GLM_GTC_matrix_transform` extension: `` + +[***gluPerspective:***](https://www.opengl.org/sdk/docs/man2/xhtml/gluPerspective.xml) + +```cpp +glm::mat4 perspective(float fovy, float aspect, float zNear, float zFar); +glm::dmat4 perspective(double fovy, double aspect, double zNear, double zFar); +``` + +Note that in GLM, fovy is expressed in radians, not degrees. + +From `GLM_GTC_matrix_transform` extension: `` + +[***gluPickMatrix:***](https://www.opengl.org/sdk/docs/man2/xhtml/gluPickMatrix.xml) + +```cpp +glm::mat4 pickMatrix(glm::vec2 const& center, glm::vec2 const& delta, glm::ivec4 const& viewport); +glm::dmat4 pickMatrix(glm::dvec2 const& center, glm::dvec2 const& delta, glm::ivec4 const& viewport); +``` + +From `GLM_GTC_matrix_transform` extension: `` + +[***gluProject:***](http://www.opengl.org/sdk/docs/man2/xhtml/gluProject.xml) + +```cpp +glm::vec3 project(glm::vec3 const& obj, glm::mat4 const& model, glm::mat4 const& proj, glm::ivec4 const& viewport); +glm::dvec3 project(glm::dvec3 const& obj, glm::dmat4 const& model, glm::dmat4 const& proj, glm::ivec4 const& viewport); +``` + +From `GLM_GTC_matrix_transform` extension: `` + +[***gluUnProject:***](https://www.opengl.org/sdk/docs/man2/xhtml/gluUnProject.xml) + +```cpp +glm::vec3 unProject(glm::vec3 const& win, glm::mat4 const& model, glm::mat4 const& proj, glm::ivec4 const& viewport); +glm::dvec3 unProject(glm::dvec3 const& win, glm::dmat4 const& model, glm::dmat4 const& proj, glm::ivec4 const& viewport); +``` + +From `GLM_GTC_matrix_transform` extension: `` + +--- +
+ +## 6. Known issues + +This section reports GLSL features that GLM can't accurately emulate due to language restrictions. + +### 6.1. not function + +The GLSL function 'not' is a keyword in C++. To prevent name collisions and ensure a consistent API, the name `not\_` (note the underscore) is used instead. + +### 6.2. Precision qualifiers support + +GLM supports GLSL precision qualifiers through prefixes instead of qualifiers. For example, GLM exposes \verb|lowp_vec4|, \verb|mediump_vec4| and \verb|highp_vec4| as variations of \verb|vec4|. + +Similarly to GLSL, GLM precision qualifiers are used to trade precision of operations in term of [ULPs](http://en.wikipedia.org/wiki/Unit_in_the_last_place) for better performance. By default, all the types use high precision. + +```cpp +// Using precision qualifier in GLSL: + +ivec3 foo(in vec4 v) +{ + highp vec4 a = v; + mediump vec4 b = a; + lowp ivec3 c = ivec3(b); + returnΒ c; +} + +// Using precision qualifier in GLM: + +#include + +ivec3 foo(const vec4 & v) +{ + highp_vec4 a = v; + medium_vec4 b = a; + lowp_ivec3 c = glm::ivec3(b); + returnΒ c; +} +``` + +--- +
+ +## 7. FAQ + +### 7.1 Why GLM follows GLSL specification and conventions? + +Following GLSL conventions is a really strict policy of GLM. It has been designed following the idea that everyone does its own math library with his own conventions. The idea is that brilliant developers (the OpenGL ARB) worked together and agreed to make GLSL. Following GLSL conventions +is a way to find consensus. Moreover, basically when a developer knows GLSL, he knows GLM. + +### 7.2. Does GLM run GLSL program? + +No, GLM is a C++ implementation of a subset of GLSL. + +### 7.3. Does a GLSL compiler build GLM codes? + +No, this is not what GLM attends to do. + +### 7.4. Should I use β€˜GTX’ extensions? + +GTX extensions are qualified to be experimental extensions. In GLM this means that these extensions might change from version to version without any restriction. In practice, it doesn’t really change except time to +time. GTC extensions are stabled, tested and perfectly reliable in time. Many GTX extensions extend GTC extensions and provide a way to explore features and implementations and APIs and then are promoted to GTC +extensions. This is fairly the way OpenGL features are developed; through extensions. + +Stating with GLM 0.9.9, to use experimental extensions, an application must define GLM_ENABLE_EXPERIMENTAL. + +### 7.5. Where can I ask my questions? + +A good place is [stackoverflow](http://stackoverflow.com/search?q=GLM) using the GLM tag. + +### 7.6. Where can I find the documentation of extensions? + +The Doxygen generated documentation includes a complete list of all extensions available. Explore this [*API documentation*](http://glm.g-truc.net/html/index.html) to get a complete +view of all GLM capabilities! + +### 7.7. Should I use β€˜using namespace glm;’? + +NO! Chances are that if using namespace glm; is called, especially in a header file, name collisions will happen as GLM is based on GLSL which uses common tokens for types and functions. Avoiding using namespace +glm; will a higher compatibility with third party library and SDKs. + +### 7.8. Is GLM fast? + +GLM is mainly designed to be convenient and that's why it is written against the GLSL specification. + +Following the Pareto principle where 20% of the code consumes 80% of the execution time, GLM operates perfectly on the 80% of the code that consumes 20% of the performances. Furthermore, thanks to the lowp, +mediump and highp qualifiers, GLM provides approximations which trade precision for performance. Finally, GLM can automatically produce SIMD optimized code for functions of its implementation. + +However, on performance critical code paths, we should expect that dedicated algorithms should be written to reach peak performance. + +### 7.9. When I build with Visual C++ with /W4 warning level, I have warnings... + +You should not have any warnings even in `/W4` mode. However, if you expect such level for your code, then you should ask for the same level to the compiler by at least disabling the Visual C++ language extensions +(`/Za`) which generates warnings when used. If these extensions are enabled, then GLM will take advantage of them and the compiler will generate warnings. + +### 7.10. Why some GLM functions can crash because of division by zero? + +GLM functions crashing is the result of a domain error. Such behavior follows the precedent set by C and C++'s standard library. For example, it’s a domain error to pass a null vector (all zeroes) to glm::normalize function, or to pass a negative number into std::sqrt. + +### 7.11. What unit for angles is used in GLM? + +GLSL is using radians but GLU is using degrees to express angles. This has caused GLM to use inconsistent units for angles. Starting with GLM 0.9.6, all GLM functions are using radians. For more information, follow +the [link](http://www.g-truc.net/post-0693.html#menu). + +### 7.12. Windows headers cause build errors... + +Some Windows headers define min and max as macros which may cause compatibility with third party libraries such as GLM. +It is highly recommended to [`define NOMINMAX`](http://stackoverflow.com/questions/4913922/possible-problems-with-nominmax-on-visual-c) before including Windows headers to workaround this issue. +To workaround the incompatibility with these macros, GLM will systematically undef these macros if they are defined. + +### 7.13. Constant expressions support + +GLM has some C++ [constant expressions](http://en.cppreference.com/w/cpp/language/constexpr) support. However, GLM automatically detects the use of SIMD instruction sets through compiler arguments to populate its implementation with SIMD intrinsics. +Unfortunately, GCC and Clang doesn't support SIMD instrinsics as constant expressions. To allow constant expressions on all vectors and matrices types, define `GLM_FORCE_PURE` before including GLM headers. + +--- +
+ +## 8. Code samples + +This series of samples only shows various GLM features without consideration of any sort. + +### 8.1. Compute a triangle normal + +```cpp +#include // vec3 normalize cross + +glm::vec3 computeNormal(glm::vec3 const& a, glm::vec3 const& b, glm::vec3 const& c) +{ + return glm::normalize(glm::cross(c - a, b - a)); +} + +// A much faster but less accurate alternative: +#include // vec3 cross +#include // fastNormalize + +glm::vec3 computeNormal(glm::vec3 const& a, glm::vec3 const& b, glm::vec3 const& c) +{ + return glm::fastNormalize(glm::cross(c - a, b - a)); +} +``` + +### 8.2. Matrix transform + +```cpp +#include // vec3, vec4, ivec4, mat4 +#include // translate, rotate, scale, perspective +#include // value_ptr + +void setUniformMVP(GLuint Location, glm::vec3 const& Translate, glm::vec3 const& Rotate) +{ + glm::mat4 Projection = glm::perspective(45.0f, 4.0f / 3.0f, 0.1f, 100.f); + glm::mat4 ViewTranslate = glm::translate( + glm::mat4(1.0f), Translate); + glm::mat4 ViewRotateX = glm::rotate( + ViewTranslate, Rotate.y, glm::vec3(-1.0f, 0.0f, 0.0f)); + glm::mat4 View = glm::rotate(ViewRotateX, + Rotate.x, glm::vec3(0.0f, 1.0f, 0.0f)); + glm::mat4 Model = glm::scale( + glm::mat4(1.0f), glm::vec3(0.5f)); + glm::mat4 MVP = Projection * View * Model; + glUniformMatrix4fv(Location, 1, GL_FALSE, glm::value_ptr(MVP)); +} +``` + +### 8.3. Vector types + +```cpp +#include // vec2 +#include // hvec2, i8vec2, i32vec2 + +std::size_t const VertexCount = 4; + +// Float quad geometry +std::size_t const PositionSizeF32 = VertexCount * sizeof(glm::vec2); +glm::vec2 const PositionDataF32[VertexCount] = +{ + glm::vec2(-1.0f,-1.0f), + glm::vec2( 1.0f,-1.0f), + glm::vec2( 1.0f, 1.0f), + glm::vec2(-1.0f, 1.0f) +}; + +// Half-float quad geometry +std::size_t const PositionSizeF16 = VertexCount * sizeof(glm::hvec2); +glm::hvec2 const PositionDataF16[VertexCount] = +{ + glm::hvec2(-1.0f, -1.0f), + glm::hvec2( 1.0f, -1.0f), + glm::hvec2( 1.0f, 1.0f), + glm::hvec2(-1.0f, 1.0f) +}; + +// 8 bits signed integer quad geometry +std::size_t const PositionSizeI8 = VertexCount * sizeof(glm::i8vec2); +glm::i8vec2 const PositionDataI8[VertexCount] = +{ + glm::i8vec2(-1,-1), + glm::i8vec2( 1,-1), + glm::i8vec2( 1, 1), + glm::i8vec2(-1, 1) +}; + +// 32 bits signed integer quad geometry +std::size_t const PositionSizeI32 = VertexCount * sizeof(glm::i32vec2); +glm::i32vec2 const PositionDataI32[VertexCount] = +{ + glm::i32vec2(-1,-1), + glm::i32vec2( 1,-1), + glm::i32vec2( 1, 1), + glm::i32vec2(-1, 1) +}; +``` + +### 8.4. Lighting + +```cpp +#include // vec3 normalize reflect dot pow +#include // ballRand + +// vecRand3, generate a random and equiprobable normalized vec3 +glm::vec3 lighting(intersection const& Intersection, material const& Material, light const& Light, glm::vec3 const& View) +{ + glm::vec3 Color = glm::vec3(0.0f); + glm::vec3 LightVertor = glm::normalize( + Light.position() - Intersection.globalPosition() + + glm::ballRand(0.0f, Light.inaccuracy()); + + if(!shadow(Intersection.globalPosition(), Light.position(), LightVertor)) + { + float Diffuse = glm::dot(Intersection.normal(), LightVector); + if(Diffuse <= 0.0f) + return Color; + + if(Material.isDiffuse()) + Color += Light.color() * Material.diffuse() * Diffuse; + + if(Material.isSpecular()) + { + glm::vec3 Reflect = glm::reflect(-LightVector, Intersection.normal()); + float Dot = glm::dot(Reflect, View); + float Base = Dot > 0.0f ? Dot : 0.0f; + float Specular = glm::pow(Base, Material.exponent()); + Color += Material.specular() \* Specular; + } + } + + return Color; +} +``` + +--- +
+ +## 9. Contributing to GLM + +### 9.1. Submitting bug reports + +Bug should be reported on Github using the [issue page](https://github.com/g-truc/glm/issues). + +A minimal code to reproduce the issue will help. + +Additional, bugs can be configuration specific. We can report the configuration by defining `GLM_FORCE_MESSAGES` before including GLM headers then build and copy paste the build messages GLM will output. + +```cpp +#define GLM_FORCE_MESSAGES +#include +``` + +An example of build messages generated by GLM: + +```plaintext +GLM: 0.9.9.1 +GLM: C++ 17 with extensions +GLM: GCC compiler detected" +GLM: x86 64 bits with AVX instruction set build target +GLM: Linux platform detected +GLM: GLM_FORCE_SWIZZLE is undefined. swizzling functions or operators are disabled. +GLM: GLM_FORCE_SIZE_T_LENGTH is undefined. .length() returns a glm::length_t, a typedef of int following GLSL. +GLM: GLM_FORCE_UNRESTRICTED_GENTYPE is undefined. Follows strictly GLSL on valid function genTypes. +GLM: GLM_FORCE_DEPTH_ZERO_TO_ONE is undefined. Using negative one to one depth clip space. +GLM: GLM_FORCE_LEFT_HANDED is undefined. Using right handed coordinate system. +``` + +### 9.2. Contributing to GLM with pull request + +This tutorial will show us how to successfully contribute a bug-fix to GLM using GitHub's Pull Request workflow. + +We will be typing git commands in the Terminal. Mac and Linux users may have git pre-installed. You can download git from [here](http://git-scm.com/downloads). + +The tutorial assumes you have some basic understanding of git concepts - repositories, branches, commits, etc. Explaining it all from scratch is beyond the scope of this tutorial. Some good links to learn git basics are: [Link 1](http://git-scm.com/book/en/Getting-Started-Git-Basics), [Link 2](https://www.atlassian.com/git/tutorial/git-basics) + +#### Step 1: Setup our GLM Fork + +We will make our changes in our own copy of the GLM sitory. On the GLM GitHub repo and we press the Fork button. +We need to download a copy of our fork to our local machine. In the terminal, type: + +```plaintext +>>> git clone +``` + +This will clone our fork repository into the current folder. + +We can find our repository git url on the Github reposotory page. The url looks like this: `https://github.com//.git` + +#### Step 2: Synchronizing our fork + +We can use the following command to add `upstream` (original project repository) as a remote repository so that we can fetch the latest GLM commits into our branch and keep our forked copy is synchronized. + +```plaintext +>>> git remote add upstream https://github.com/processing/processing.git +``` + +To synchronize our fork to the latest commit in the GLM repository, we can use the following command: + +```plaintext +>>> git fetch upstream +``` + +Then, we can merge the remote master branch to our current branch: + +```plaintext +>>> git merge upstream/master +``` + +Now our local copy of our fork has been synchronized. However, the fork's copy is not updated on GitHub's servers yet. To do that, use: + +```plaintext +>>> git push origin master +``` + +#### Step 3: Modifying our GLM Fork + +Our fork is now setup and we are ready to modify GLM to fix a bug. + +It's a good practice to make changes in our fork in a separate branch than the master branch because we can submit only one pull request per branch. + +Before creating a new branch, it's best to synchronize our fork and then create a new branch from the latest master branch. + +If we are not on the master branch, we should switch to it using: + +```plaintext +>>> git checkout master +``` + +To create a new branch called `bugifx`, we use: + +```plaintext +git branch bugfix +``` + +Once the code changes for the fix is done, we need to commit the changes: + +```plaintext +>>> git commit -m "Resolve the issue that caused problem with a specific fix #432" +``` + +The commit message should be as specific as possible and finished by the bug number in the [GLM GitHub issue page](https://github.com/g-truc/glm/issues) + +Finally, we need to push our changes in our branch to our GitHub fork using: + +```plaintext +>>> git push origin bugfix +``` + +Some things to keep in mind for a pull request: + +* Keep it minimal: Try to make the minimum required changes to fix the issue. If we have added any debugging code, we should remove it. +* A fix at a time: The pull request should deal with one issue at a time only, unless two issue are so interlinked they must be fixed together. +* Write a test: GLM is largely unit tests. Unit tests are in `glm/test` directory. We should also add tests for the fixes we provide to ensure future regression doesn't happen. +* No whitespace changes: Avoid unnecessary formatting or whitespace changes in other parts of the code. Be careful with auto-format options in the code editor which can cause wide scale formatting changes. +* Follow [GLM Code Style](#section9_3) for consistency. +* Tests passes: Make sure GLM build and tests don't fail because of the changes. + +#### Step 4: Submitting a Pull Request + +We need to submit a pull request from the `bugfix` branch to GLM's master branch. + +On the fork github page, we can click on the *Pull Request* button. Then we can describe our pull request. Finally we press *Send Pull Request*. + +Please be patient and give them some time to go through it. + +The pull request review may suggest additional changes. So we can make those changes in our branch, and push those changes to our fork repository. Our pull request will always include the latest changes in our branch on GitHub, so we don't need to resubmit the pull request. + +Once your changes have been accepted, a project maintainer will merge our pull request. + +We are grateful to the users for their time and effort in contributing fixes. + +### 9.3. Coding style + +#### Indentation + +Always tabs. Never spaces. + +#### Spacing + +No space after if. Use if(blah) not if (blah). Example if/else block: + +```cpp +if(blah) +{ + // yes like this +} +else +{ + // something besides +} +``` + +Single line if blocks: + +```cpp +if(blah) + // yes like this +else + // something besides +``` + +No spaces inside parens: + +```cpp +if (blah) // No +if( blah ) // No +if ( blah ) // No +if(blah) // Yes +``` + +Use spaces before/after commas: + +```cpp +someFunction(apple,bear,cat); // No +someFunction(apple, bear, cat); // Yes +``` + +Use spaces before/after use of `+, -, *, /, %, >>, <<, |, &, ^, ||, &&` operators: + +```cpp +vec4 v = a + b; +``` + +#### Blank lines + +One blank line after the function blocks. + +#### Comments + +Always one space after the // in single line comments + +One space before // at the end of a line (that has code as well) + +Try to use // comments inside functions, to make it easier to remove a whole block via /\* \*/ + +#### Cases + +```cpp +#define GLM_MY_DEFINE 76 + +class myClass +{}; + +myClass const MyClass; + +namespace glm{ // glm namespace is for public code +namespace detail // glm::detail namespace is for implementation detail +{ + float myFunction(vec2 const& V) + { + return V.x + V.y; + } + + float myFunction(vec2 const* const V) + { + return V->x + V->y; + } +}//namespace detail +}//namespace glm +``` + +--- +
+ +## 10. References + +### 10.1. OpenGL specifications + +* OpenGL 4.3 core specification +* [GLSL 4.30 specification](http://www.opengl.org/registry/doc/GLSLangSpec.4.30.7.diff.pdf) +![](media/image21.png){width="2.859722222222222in" height="1.6083333333333334in"}- [*GLU 1.3 specification*](http://www.opengl.org/documentation/specs/glu/glu1_3.pdf) + +### 10.2. External links + +* [GLM on stackoverflow](http://stackoverflow.com/search?q=GLM) + +### 10.3. Projects using GLM + +***[Leo’s Fortune](http://www.leosfortune.com/)*** + +Leo’s Fortune is a platform adventure game where you hunt down the cunning and mysterious thief that stole your gold. Available on PS4, Xbox One, PC, Mac, iOS and Android. + +Beautifully hand-crafted levels bring the story of Leo to life in this epic adventure. + +β€œI just returned home to find all my gold has been stolen! For some devious purpose, the thief has dropped pieces of my gold like breadcrumbs through the woods.” + +β€œDespite this pickle of a trap, I am left with no choice but to follow the trail.” + +β€œWhatever lies ahead, I must recover my fortune.” -Leopold + +![](./doc/manual/references-leosfortune.jpeg) + +![](./doc/manual/references-leosfortune2.jpg) + +[***OpenGL 4.0 Shading Language Cookbook***](http://www.packtpub.com/opengl-4-0-shading-language-cookbook/book?tag=rk/opengl4-abr1/0811) + +A set of recipes that demonstrates a wide of techniques for producing high-quality, real-time 3D graphics with GLSL 4.0, such as: + +* Using GLSL 4.0 to implement lighting and shading techniques. +* Using the new features of GLSL 4.0 including tessellation and geometry shaders. +* Using textures in GLSL as part of a wide variety of techniques from basic texture mapping to deferred shading. + +Simple, easy-to-follow examples with GLSL source code are provided, as well as a basic description of the theory behind each technique. + +![](./doc/manual/references-glsl4book.jpg) + +[***Outerra***](http://outerra.com/) + +A 3D planetary engine for seamless planet rendering from space down to the surface. Can use arbitrary resolution of elevation data, refining it to centimetre resolution using fractal algorithms. + +![](./doc/manual/references-outerra1.jpg) + +![](./doc/manual/references-outerra2.jpg) + +![](./doc/manual/references-outerra3.jpg) + +![](./doc/manual/references-outerra4.jpg) + +[***Falcor***](https://github.com/NVIDIA/Falcor) + +Real-time rendering research framework by NVIDIA. + +[***Cinder***](https://libcinder.org/) + +Cinder is a free and open source library for professional-quality creative coding in C++. + +Cinder is a C++ libraryΒ for programming with aesthetic intent - the sort of development often calledΒ creative coding. This includes domains like graphics, audio, video, and computational geometry. Cinder is cross-platform, with official support forΒ OS X, Windows, iOS, and WinRT. + +Cinder is production-proven, powerful enough to be the primary tool for professionals, but still suitable for learning and experimentation. Cinder is released under theΒ [2-Clause BSD License](http://opensource.org/licenses/BSD-2-Clause). + +![](./doc/manual/references-cinder.png) + +[***opencloth***](https://github.com/mmmovania/opencloth/) + +A collection of source codes implementing cloth simulation algorithms in OpenGL. + +Simple, easy-to-follow examples with GLSL source code, as well as a basic description of the theory behind each technique. + +![](./doc/manual/references-opencloth1.png) + +![](./doc/manual/references-opencloth3.png) + +[***LibreOffice***](https://www.libreoffice.org/) + +LibreOffice includes several applications that make it the most powerful Free and Open Source office suite on the market. + +[***Are you using GLM in a project?***](mailto:glm@g-truc.net) + +### 10.4. Tutorials using GLM + +* [Sascha Willems' Vulkan examples](https://github.com/SaschaWillems/Vulkan), Examples and demos for the new Vulkan API +* [VKTS](https://github.com/McNopper/Vulkan) Vulkan examples using VulKan ToolS (VKTS) +* [*The OpenGL Samples Pack*](http://www.g-truc.net/project-0026.html#menu), samples that show how to set up all the different new features +* [*Learning Modern 3D Graphics programming*](http://www.arcsynthesis.org/gltut/), a great OpenGL tutorial using GLM by Jason L. McKesson +* [*Morten Nobel-JΓΈrgensen’s*](http://blog.nobel-joergensen.com/2011/04/02/glm-brilliant-math-library-for-opengl/) review and use an [*OpenGL renderer*](https://github.com/mortennobel/RenderE) +* [*Swiftless’ OpenGL tutorial*](http://www.swiftless.com/opengltuts.html) using GLM by Donald Urquhart +* [*Rastergrid*](http://rastergrid.com/blog/), many technical articles with companion programs using GLM by Daniel RΓ‘kos\ +* [*OpenGL Tutorial*](http://www.opengl-tutorial.org), tutorials for OpenGL 3.1 and later +* [*OpenGL Programming on Wikibooks*](http://en.wikibooks.org/wiki/OpenGL_Programming): For beginners who are discovering OpenGL. +* [*3D Game Engine Programming*](http://3dgep.com/): Learning the latest 3D Game Engine Programming techniques. +* [Game Tutorials](http://www.gametutorials.com/opengl-4-matrices-and-glm/), graphics and game programming. +* [open.gl](https://open.gl/), OpenGL tutorial +* [c-jump](http://www.c-jump.com/bcc/common/Talk3/Math/GLM/GLM.html), GLM tutorial +* [Learn OpenGL](http://learnopengl.com/), OpenGL tutorial +* [***Are you using GLM in a tutorial?***](mailto:glm@g-truc.net) + +### 10.5. Equivalent for other languages + +* [*cglm*](https://github.com/recp/cglm): OpenGL Mathematics (glm) for C. +* [*GlmSharp*](https://github.com/Philip-Trettner/GlmSharp): Open-source semi-generated GLM-flavored math library for .NET/C\#. +* [glm-js](https://github.com/humbletim/glm-js): JavaScript adaptation of the OpenGL Mathematics (GLM) C++ library interfaces +* [JVM OpenGL Mathematics (GLM)](https://github.com/kotlin-graphics/glm): written in Kotlin, Java compatible +* [JGLM](https://github.com/jroyalty/jglm) - Java OpenGL Mathematics Library +* [SwiftGL Math Library](https://github.com/SwiftGL/Math/blob/master/Sources/glm.swift) GLM for Swift +* [glm-go](https://github.com/jbowtie/glm-go): Simple linear algebra library similar in spirit to GLM +* [openll](https://github.com/Polkm/openll): Lua bindings for OpenGL, GLM, GLFW, OpenAL, SOIL and PhysicsFS +* [glm-rs](https://github.com/dche/glm-rs): GLSL mathematics for Rust programming language +* [glmpython](https://github.com/Queatz/glmpython): GLM math library for Python + +### 10.6. Alternatives to GLM + +* [*CML*](http://cmldev.net/): The CML (Configurable Math Library) is a free C++ math library for games and graphics. +* [*Eigen*](http://eigen.tuxfamily.org/): A more heavy weight math library for general linear algebra in C++. +* [*glhlib*](http://glhlib.sourceforge.net/): A much more than glu C library. +* Are you using or developing an alternative library to GLM? + +### 10.7. Acknowledgements + +GLM is developed and maintained by [*Christophe Riccio*](http://www.g-truc.net) but many contributors have made this project what it is. + +Special thanks to: + +* Ashima Arts and Stefan Gustavson for their work on [*webgl-noise*](https://github.com/ashima/webgl-noise) which has been used for GLM noises implementation. +* [*Arthur Winters*](http://athile.net/library/wiki/index.php?title=Athile_Technologies) for the C++11 and Visual C++ swizzle operators implementation and tests. +* Joshua Smith and Christoph Schied for the discussions and the experiments around the swizzle operators implementation issues. +* Guillaume Chevallereau for providing and maintaining the [*nightlight build system*](http://my.cdash.org/index.php?project=GLM). +* Ghenadii Ursachi for GLM\_GTX\_matrix\_interpolation implementation. +* Mathieu Roumillac for providing some implementation ideas. +* [*Grant James*](http://www.zeuscmd.com/) for the implementation of all combination of none-squared matrix products. +* Jesse Talavera-Greenberg for his work on the manual amount other things. +* All the GLM users that have report bugs and hence help GLM to become a great library! diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/readme.md b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..dd47f459f811d1e638809dfa4074a9b43b8f2742 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/readme.md @@ -0,0 +1,1231 @@ +![glm](/doc/manual/logo-mini.png) + +[OpenGL Mathematics](http://glm.g-truc.net/) (*GLM*) is a header only C++ mathematics library for graphics software based on the [OpenGL Shading Language (GLSL) specifications](https://www.opengl.org/registry/doc/GLSLangSpec.4.50.diff.pdf). + +*GLM* provides classes and functions designed and implemented with the same naming conventions and functionality than *GLSL* so that anyone who knows *GLSL*, can use *GLM* as well in C++. + +This project isn't limited to *GLSL* features. An extension system, based on the *GLSL* extension conventions, provides extended capabilities: matrix transformations, quaternions, data packing, random numbers, noise, etc... + +This library works perfectly with *[OpenGL](https://www.opengl.org)* but it also ensures interoperability with other third party libraries and SDK. It is a good candidate for software rendering (raytracing / rasterisation), image processing, physics simulations and any development context that requires a simple and convenient mathematics library. + +*GLM* is written in C++98 but can take advantage of C++11 when supported by the compiler. It is a platform independent library with no dependence and it officially supports the following compilers: +- [*GCC*](http://gcc.gnu.org/) 4.7 and higher +- [*Intel C++ Compose*](https://software.intel.com/en-us/intel-compilers) XE 2013 and higher +- [*Clang*](http://llvm.org/) 3.4 and higher +- [*Apple Clang 6.0*](https://developer.apple.com/library/mac/documentation/CompilerTools/Conceptual/LLVMCompilerOverview/index.html) and higher +- [*Visual C++*](http://www.visualstudio.com/) 2013 and higher +- [*CUDA*](https://developer.nvidia.com/about-cuda) 9.0 and higher (experimental) +- [*SYCL*](https://www.khronos.org/sycl/) (experimental: only [ComputeCpp](https://codeplay.com/products/computesuite/computecpp) implementation has been tested). +- Any C++11 compiler + +For more information about *GLM*, please have a look at the [manual](manual.md) and the [API reference documentation](http://glm.g-truc.net/0.9.8/api/index.html). +The source code and the documentation are licensed under either the [Happy Bunny License (Modified MIT) or the MIT License](manual.md#section0). + +Thanks for contributing to the project by [submitting pull requests](https://github.com/g-truc/glm/pulls). + +```cpp +#include // glm::vec3 +#include // glm::vec4 +#include // glm::mat4 +#include // glm::translate, glm::rotate, glm::scale +#include // glm::perspective +#include // glm::pi + +glm::mat4 camera(float Translate, glm::vec2 const& Rotate) +{ + glm::mat4 Projection = glm::perspective(glm::pi() * 0.25f, 4.0f / 3.0f, 0.1f, 100.f); + glm::mat4 View = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -Translate)); + View = glm::rotate(View, Rotate.y, glm::vec3(-1.0f, 0.0f, 0.0f)); + View = glm::rotate(View, Rotate.x, glm::vec3(0.0f, 1.0f, 0.0f)); + glm::mat4 Model = glm::scale(glm::mat4(1.0f), glm::vec3(0.5f)); + return Projection * View * Model; +} +``` + +## [Lastest release](https://github.com/g-truc/glm/releases/latest) + +## Project Health + +| Service | System | Compiler | Status | +| ------- | ------ | -------- | ------ | +| [Travis CI](https://travis-ci.org/g-truc/glm)| MacOSX, Linux 64 bits | Clang 3.6, Clang 5.0, GCC 4.9, GCC 7.3 | [![Travis CI](https://travis-ci.org/g-truc/glm.svg?branch=master)](https://travis-ci.org/g-truc/glm) +| [AppVeyor](https://ci.appveyor.com/project/Groovounet/glm)| Windows 32 and 64 | Visual Studio 2013, Visual Studio 2015, Visual Studio 2017 | [![AppVeyor](https://ci.appveyor.com/api/projects/status/32r7s2skrgm9ubva?svg=true)](https://ci.appveyor.com/project/Groovounet/glm) + +## Release notes + +### [GLM 0.9.9.9](https://github.com/g-truc/glm/releases/tag/0.9.9.9) - 2020-XX-XX +#### Features: +- Added *GLM_EXT_scalar_reciprocal* with tests +- Added *GLM_EXT_vector_reciprocal* with tests +- Added `glm::iround` and `glm::uround` to *GLM_EXT_scalar_common* and *GLM_EXT_vector_common* +- Added *GLM_EXT_matrix_integer* with tests + +#### Improvements: +- Added `constexpr` qualifier for `cross` product #1040 +- Added `constexpr` qualifier for `dot` product #1040 + +#### Fixes: +- Fixed incorrect assertion for `glm::min` and `glm::max` #1009 +- Fixed quaternion orientation in `glm::decompose` #1012 +- Fixed singularity in quaternion to euler angle roll conversion #1019 +- Fixed `quat` `glm::pow` handling of small magnitude quaternions #1022 +- Fixed `glm::fastNormalize` build error #1033 +- Fixed `glm::isMultiple` build error #1034 +- Fixed `glm::adjugate` calculation #1035 +- Fixed `glm::angle` discards the sign of result for angles in range (2*pi-1, 2*pi) #1038 +- Removed ban on using `glm::string_cast` with *CUDA* host code #1041 + +### [GLM 0.9.9.8](https://github.com/g-truc/glm/releases/tag/0.9.9.8) - 2020-04-13 +#### Features: +- Added *GLM_EXT_vector_intX* and *GLM_EXT_vector_uintX* extensions +- Added *GLM_EXT_matrix_intX* and *GLM_EXT_matrix_uintX* extensions + +#### Improvements: +- Added `glm::clamp`, `glm::repeat`, `glm::mirrorClamp` and `glm::mirrorRepeat` function to `GLM_EXT_scalar_commond` and `GLM_EXT_vector_commond` extensions with tests + +#### Fixes: +- Fixed unnecessary warnings from `matrix_projection.inl` #995 +- Fixed quaternion `glm::slerp` overload which interpolates with extra spins #996 +- Fixed for `glm::length` using arch64 #992 +- Fixed singularity check for `glm::quatLookAt` #770 + +### [GLM 0.9.9.7](https://github.com/g-truc/glm/releases/tag/0.9.9.7) - 2020-01-05 +#### Improvements: +- Improved *Neon* support with more functions optimized #950 +- Added *CMake* *GLM* interface #963 +- Added `glm::fma` implementation based on `std::fma` #969 +- Added missing quat constexpr #955 +- Added `GLM_FORCE_QUAT_DATA_WXYZ` to store quat data as w,x,y,z instead of x,y,z,w #983 + +#### Fixes: +- Fixed equal *ULP* variation when using negative sign #965 +- Fixed for intersection ray/plane and added related tests #953 +- Fixed ARM 64bit detection #949 +- Fixed *GLM_EXT_matrix_clip_space* warnings #980 +- Fixed Wimplicit-int-float-conversion warnings with clang 10+ #986 +- Fixed *GLM_EXT_matrix_clip_space* `perspectiveFov` + +### [GLM 0.9.9.6](https://github.com/g-truc/glm/releases/tag/0.9.9.6) - 2019-09-08 +#### Features: +- Added *Neon* support #945 +- Added *SYCL* support #914 +- Added *GLM_EXT_scalar_integer* extension with power of two and multiple scalar functions +- Added *GLM_EXT_vector_integer* extension with power of two and multiple vector functions + +#### Improvements: +- Added *Visual C++ 2019* detection +- Added *Visual C++ 2017* 15.8 and 15.9 detection +- Added missing genType check for `glm::bitCount` and `glm::bitfieldReverse` #893 + +#### Fixes: +- Fixed for g++6 where -std=c++1z sets __cplusplus to 201500 instead of 201402 #921 +- Fixed hash hashes qua instead of tquat #919 +- Fixed `.natvis` as structs renamed #915 +- Fixed `glm::ldexp` and `glm::frexp` declaration #895 +- Fixed missing const to quaternion conversion operators #890 +- Fixed *GLM_EXT_scalar_ulp* and *GLM_EXT_vector_ulp* API coding style +- Fixed quaternion componant order: `w, {x, y, z}` #916 +- Fixed `GLM_HAS_CXX11_STL` broken on Clang with Linux #926 +- Fixed *Clang* or *GCC* build due to wrong `GLM_HAS_IF_CONSTEXPR` definition #907 +- Fixed *CUDA* 9 build #910 + +#### Deprecation: + - Removed CMake install and uninstall scripts + +### [GLM 0.9.9.5](https://github.com/g-truc/glm/releases/tag/0.9.9.5) - 2019-04-01 +#### Fixes: +- Fixed build errors when defining `GLM_ENABLE_EXPERIMENTAL` #884 #883 +- Fixed `if constexpr` warning #887 +- Fixed missing declarations for `glm::frexp` and `glm::ldexp` #886 + +### [GLM 0.9.9.4](https://github.com/g-truc/glm/releases/tag/0.9.9.4) - 2019-03-19 +#### Features: +- Added `glm::mix` implementation for matrices in *GLM_EXT_matrix_common/ #842 +- Added *CMake* `BUILD_SHARED_LIBS` and `BUILD_STATIC_LIBS` build options #871 + +#### Improvements: +- Added GLM_FORCE_INTRINSICS to enable SIMD instruction code path. By default, it's disabled allowing constexpr support by default. #865 +- Optimized inverseTransform #867 + +#### Fixes: +- Fixed in `glm::mat4x3` conversion #829 +- Fixed `constexpr` issue on GCC #832 #865 +- Fixed `glm::mix` implementation to improve GLSL conformance #866 +- Fixed `glm::int8` being defined as unsigned char with some compiler #839 +- Fixed `glm::vec1` include #856 +- Ignore `.vscode` #848 + +### [GLM 0.9.9.3](https://github.com/g-truc/glm/releases/tag/0.9.9.3) - 2018-10-31 +#### Features: +- Added `glm::equal` and `glm::notEqual` overload with max ULPs parameters for scalar numbers #121 +- Added `GLM_FORCE_SILENT_WARNINGS` to silent *GLM* warnings when using language extensions but using W4 or Wpedantic warnings #814 #775 +- Added adjugate functions to `GLM_GTX_matrix_operation` #151 +- Added `GLM_FORCE_ALIGNED_GENTYPES` to enable aligned types and SIMD instruction are not enabled. This disable `constexpr` #816 + +#### Improvements: +- Added constant time ULP distance between float #121 +- Added `GLM_FORCE_SILENT_WARNINGS` to suppress *GLM* warnings #822 + +#### Fixes: +- Fixed `glm::simplex` noise build with double #734 +- Fixed `glm::bitfieldInsert` according to GLSL spec #818 +- Fixed `glm::refract` for negative 'k' #808 + +### [GLM 0.9.9.2](https://github.com/g-truc/glm/releases/tag/0.9.9.2) - 2018-09-14 +#### Fixes: +- Fixed `GLM_FORCE_CXX**` section in the manual +- Fixed default initialization with vector and quaternion types using `GLM_FORCE_CTOR_INIT` #812 + +### [GLM 0.9.9.1](https://github.com/g-truc/glm/releases/tag/0.9.9.1) - 2018-09-03 +#### Features: +- Added `bitfieldDeinterleave` to *GLM_GTC_bitfield* +- Added missing `glm::equal` and `glm::notEqual` with epsilon for quaternion types to *GLM_GTC_quaternion* +- Added *GLM_EXT_matrix_relational*: `glm::equal` and `glm::notEqual` with epsilon for matrix types +- Added missing aligned matrix types to *GLM_GTC_type_aligned* +- Added C++17 detection +- Added *Visual C++* language standard version detection +- Added PDF manual build from markdown + +#### Improvements: +- Added a section to the manual for contributing to *GLM* +- Refactor manual, lists all configuration defines +- Added missing `glm::vec1` based constructors +- Redesigned constexpr support which excludes both SIMD and `constexpr` #783 +- Added detection of *Visual C++ 2017* toolsets +- Added identity functions #765 +- Splitted headers into EXT extensions to improve compilation time #670 +- Added separated performance tests +- Clarified refract valid range of the indices of refraction, between -1 and 1 inclusively #806 + +#### Fixes: +- Fixed SIMD detection on *Clang* and *GCC* +- Fixed build problems due to `std::printf` and `std::clock_t` #778 +- Fixed int mod +- Anonymous unions require C++ language extensions +- Fixed `glm::ortho` #790 +- Fixed *Visual C++* 2013 warnings in vector relational code #782 +- Fixed *ICC* build errors with constexpr #704 +- Fixed defaulted operator= and constructors #791 +- Fixed invalid conversion from int scalar with vec4 constructor when using SSE instruction +- Fixed infinite loop in random functions when using negative radius values using an assert #739 + +### [GLM 0.9.9.0](https://github.com/g-truc/glm/releases/tag/0.9.9.0) - 2018-05-22 +#### Features: +- Added *RGBM* encoding in *GLM_GTC_packing* #420 +- Added *GLM_GTX_color_encoding* extension +- Added *GLM_GTX_vec_swizzle*, faster compile time swizzling then swizzle operator #558 +- Added *GLM_GTX_exterior_product* with a `vec2` `glm::cross` implementation #621 +- Added *GLM_GTX_matrix_factorisation* to factor matrices in various forms #654 +- Added [`GLM_ENABLE_EXPERIMENTAL`](manual.md#section7_4) to enable experimental features. +- Added packing functions for integer vectors #639 +- Added conan packaging configuration #643 #641 +- Added `glm::quatLookAt` to *GLM_GTX_quaternion* #659 +- Added `glm::fmin`, `glm::fmax` and `glm::fclamp` to *GLM_GTX_extended_min_max* #372 +- Added *GLM_EXT_vector_relational*: extend `glm::equal` and `glm::notEqual` to take an epsilon argument +- Added *GLM_EXT_vector_relational*: `glm::openBounded` and `glm::closeBounded` +- Added *GLM_EXT_vec1*: `*vec1` types +- Added *GLM_GTX_texture*: `levels` function +- Added spearate functions to use both nagative one and zero near clip plans #680 +- Added `GLM_FORCE_SINGLE_ONLY` to use *GLM* on platforms that don't support double #627 +- Added *GLM_GTX_easing* for interpolation functions #761 + +#### Improvements: +- No more default initialization of vector, matrix and quaternion types +- Added lowp variant of GTC_color_space convertLinearToSRGB #419 +- Replaced the manual by a markdown version #458 +- Improved API documentation #668 +- Optimized GTC_packing implementation +- Optimized GTC_noise functions +- Optimized GTC_color_space HSV to RGB conversions +- Optimised GTX_color_space_YCoCg YCoCgR conversions +- Optimized GTX_matrix_interpolation axisAngle function +- Added FAQ 12: Windows headers cause build errors... #557 +- Removed GCC shadow warnings #595 +- Added error for including of different versions of GLM #619 +- Added GLM_FORCE_IGNORE_VERSION to ignore error caused by including different version of GLM #619 +- Reduced warnings when using very strict compilation flags #646 +- length() member functions are constexpr #657 +- Added support of -Weverything with Clang #646 +- Improved exponential function test coverage +- Enabled warnings as error with Clang unit tests +- Conan package is an external repository: https://github.com/bincrafters/conan-glm +- Clarify quat_cast documentation, applying on pure rotation matrices #759 + +#### Fixes: +- Removed doxygen references to *GLM_GTC_half_float* which was removed in 0.9.4 +- Fixed `glm::decompose` #448 +- Fixed `glm::intersectRayTriangle` #6 +- Fixed dual quaternion != operator #629 +- Fixed usused variable warning in *GLM_GTX_spline* #618 +- Fixed references to `GLM_FORCE_RADIANS` which was removed #642 +- Fixed `glm::fastInverseSqrt` to use fast inverse square #640 +- Fixed `glm::axisAngle` NaN #638 +- Fixed integer pow from *GLM_GTX_integer* with null exponent #658 +- Fixed `quat` `normalize` build error #656 +- Fixed *Visual C++ 2017.2* warning regarding `__has_feature` definision #655 +- Fixed documentation warnings +- Fixed `GLM_HAS_OPENMP` when *OpenMP* is not enabled +- Fixed Better follow GLSL `min` and `max` specification #372 +- Fixed quaternion constructor from two vectors special cases #469 +- Fixed `glm::to_string` on quaternions wrong components order #681 +- Fixed `glm::acsch` #698 +- Fixed `glm::isnan` on *CUDA* #727 + +#### Deprecation: +- Requires *Visual Studio 2013*, *GCC 4.7*, *Clang 3.4*, *Cuda 7*, *ICC 2013* or a C++11 compiler +- Removed *GLM_GTX_simd_vec4* extension +- Removed *GLM_GTX_simd_mat4* extension +- Removed *GLM_GTX_simd_quat* extension +- Removed `GLM_SWIZZLE`, use `GLM_FORCE_SWIZZLE` instead +- Removed `GLM_MESSAGES`, use `GLM_FORCE_MESSAGES` instead +- Removed `GLM_DEPTH_ZERO_TO_ONE`, use `GLM_FORCE_DEPTH_ZERO_TO_ONE` instead +- Removed `GLM_LEFT_HANDED`, use `GLM_FORCE_LEFT_HANDED` instead +- Removed `GLM_FORCE_NO_CTOR_INIT` +- Removed `glm::uninitialize` + +--- +### [GLM 0.9.8.5](https://github.com/g-truc/glm/releases/tag/0.9.8.5) - 2017-08-16 +#### Features: +- Added *Conan* package support #647 + +#### Fixes: +- Fixed *Clang* version detection from source #608 +- Fixed `glm::packF3x9_E1x5` exponent packing #614 +- Fixed build error `min` and `max` specializations with integer #616 +- Fixed `simd_mat4` build error #652 + +--- +### [GLM 0.9.8.4](https://github.com/g-truc/glm/releases/tag/0.9.8.4) - 2017-01-22 +#### Fixes: +- Fixed *GLM_GTC_packing* test failing on *GCC* x86 due to denorms #212 #577 +- Fixed `POPCNT` optimization build in *Clang* #512 +- Fixed `glm::intersectRayPlane` returns true in parallel case #578 +- Fixed *GCC* 6.2 compiler warnings #580 +- Fixed *GLM_GTX_matrix_decompose* `glm::decompose` #582 #448 +- Fixed *GCC* 4.5 and older build #566 +- Fixed *Visual C++* internal error when declaring a global vec type with siwzzle expression enabled #594 +- Fixed `GLM_FORCE_CXX11` with Clang and libstlc++ which wasn't using C++11 STL features. #604 + +--- +### [GLM 0.9.8.3](https://github.com/g-truc/glm/releases/tag/0.9.8.3) - 2016-11-12 +#### Improvements: +- Broader support of `GLM_FORCE_UNRESTRICTED_GENTYPE` #378 + +#### Fixes: +- Fixed Android build error with C++11 compiler but C++98 STL #284 #564 +- Fixed *GLM_GTX_transform2* shear* functions #403 +- Fixed interaction between `GLM_FORCE_UNRESTRICTED_GENTYPE` and `glm::ortho` function #568 +- Fixed `glm::bitCount` with AVX on 32 bit builds #567 +- Fixed *CMake* `find_package` with version specification #572 #573 + +--- +### [GLM 0.9.8.2](https://github.com/g-truc/glm/releases/tag/0.9.8.2) - 2016-11-01 +#### Improvements: +- Added *Visual C++* 15 detection +- Added *Clang* 4.0 detection +- Added warning messages when using `GLM_FORCE_CXX**` but the compiler + is known to not fully support the requested C++ version #555 +- Refactored `GLM_COMPILER_VC` values +- Made quat, vec, mat type component `length()` static #565 + +#### Fixes: +- Fixed *Visual C++* `constexpr` build error #555, #556 + +--- +### [GLM 0.9.8.1](https://github.com/g-truc/glm/releases/tag/0.9.8.1) - 2016-09-25 +#### Improvements: +- Optimized quaternion `glm::log` function #554 + +#### Fixes: +- Fixed *GCC* warning filtering, replaced -pedantic by -Wpedantic +- Fixed SIMD faceforward bug. #549 +- Fixed *GCC* 4.8 with C++11 compilation option #550 +- Fixed *Visual Studio* aligned type W4 warning #548 +- Fixed packing/unpacking function fixed for 5_6_5 and 5_5_5_1 #552 + +--- +### [GLM 0.9.8.0](https://github.com/g-truc/glm/releases/tag/0.9.8.0) - 2016-09-11 +#### Features: +- Added right and left handed projection and clip control support #447 #415 #119 +- Added `glm::compNormalize` and `glm::compScale` functions to *GLM_GTX_component_wise* +- Added `glm::packF3x9_E1x5` and `glm::unpackF3x9_E1x5` to *GLM_GTC_packing* for RGB9E5 #416 +- Added `(un)packHalf` to *GLM_GTC_packing* +- Added `(un)packUnorm` and `(un)packSnorm` to *GLM_GTC_packing* +- Added 16bit pack and unpack to *GLM_GTC_packing* +- Added 8bit pack and unpack to *GLM_GTC_packing* +- Added missing `bvec*` && and || operators +- Added `glm::iround` and `glm::uround` to *GLM_GTC_integer*, fast round on positive values +- Added raw SIMD API +- Added 'aligned' qualifiers +- Added *GLM_GTC_type_aligned* with aligned *vec* types +- Added *GLM_GTC_functions* extension +- Added quaternion version of `glm::isnan` and `glm::isinf` #521 +- Added `glm::lowestBitValue` to *GLM_GTX_bit* #536 +- Added `GLM_FORCE_UNRESTRICTED_GENTYPE` allowing non basic `genType` #543 + +#### Improvements: +- Improved SIMD and swizzle operators interactions with *GCC* and *Clang* #474 +- Improved *GLM_GTC_random* `linearRand` documentation +- Improved *GLM_GTC_reciprocal* documentation +- Improved `GLM_FORCE_EXPLICIT_CTOR` coverage #481 +- Improved *OpenMP* support detection for *Clang*, *GCC*, *ICC* and *VC* +- Improved *GLM_GTX_wrap* for SIMD friendliness +- Added `constexpr` for `*vec*`, `*mat*`, `*quat*` and `*dual_quat*` types #493 +- Added *NEON* instruction set detection +- Added *MIPS* CPUs detection +- Added *PowerPC* CPUs detection +- Use *Cuda* built-in function for abs function implementation with Cuda compiler +- Factorized `GLM_COMPILER_LLVM` and `GLM_COMPILER_APPLE_CLANG` into `GLM_COMPILER_CLANG` +- No more warnings for use of long long +- Added more information to build messages + +#### Fixes: +- Fixed *GLM_GTX_extended_min_max* filename typo #386 +- Fixed `glm::intersectRayTriangle` to not do any unintentional backface culling +- Fixed long long warnings when using C++98 on *GCC* and *Clang* #482 +- Fixed sign with signed integer function on non-x86 architecture +- Fixed strict aliasing warnings #473 +- Fixed missing `glm::vec1` overload to `glm::length2` and `glm::distance2` functions #431 +- Fixed *GLM* test '/fp:fast' and '/Za' command-line options are incompatible +- Fixed quaterion to mat3 cast function `glm::mat3_cast` from *GLM_GTC_quaternion* #542 +- Fixed *GLM_GTX_io* for *Cuda* #547 #546 + +#### Deprecation: +- Removed `GLM_FORCE_SIZE_FUNC` define +- Deprecated *GLM_GTX_simd_vec4* extension +- Deprecated *GLM_GTX_simd_mat4* extension +- Deprecated *GLM_GTX_simd_quat* extension +- Deprecated `GLM_SWIZZLE`, use `GLM_FORCE_SWIZZLE` instead +- Deprecated `GLM_MESSAGES`, use `GLM_FORCE_MESSAGES` instead + +--- +### [GLM 0.9.7.6](https://github.com/g-truc/glm/releases/tag/0.9.7.6) - 2016-07-16 +#### Improvements: +- Added pkg-config file #509 +- Updated list of compiler versions detected +- Improved C++ 11 STL detection #523 + +#### Fixes: +- Fixed STL for C++11 detection on ICC #510 +- Fixed missing vec1 overload to length2 and distance2 functions #431 +- Fixed long long warnings when using C++98 on GCC and Clang #482 +- Fixed scalar reciprocal functions (GTC_reciprocal) #520 + +--- +### [GLM 0.9.7.5](https://github.com/g-truc/glm/releases/tag/0.9.7.5) - 2016-05-24 +#### Improvements: +- Added Visual C++ Clang toolset detection + +#### Fixes: +- Fixed uaddCarry warning #497 +- Fixed roundPowerOfTwo and floorPowerOfTwo #503 +- Fixed Visual C++ SIMD instruction set automatic detection in 64 bits +- Fixed to_string when used with GLM_FORCE_INLINE #506 +- Fixed GLM_FORCE_INLINE with binary vec4 operators +- Fixed GTX_extended_min_max filename typo #386 +- Fixed intersectRayTriangle to not do any unintentional backface culling + +--- +### [GLM 0.9.7.4](https://github.com/g-truc/glm/releases/tag/0.9.7.4) - 2016-03-19 +#### Fixes: +- Fixed asinh and atanh warning with C++98 STL #484 +- Fixed polar coordinates function latitude #485 +- Fixed outerProduct defintions and operator signatures for mat2x4 and vec4 #475 +- Fixed eulerAngles precision error, returns NaN #451 +- Fixed undefined reference errors #489 +- Fixed missing GLM_PLATFORM_CYGWIN declaration #495 +- Fixed various undefined reference errors #490 + +--- +### [GLM 0.9.7.3](https://github.com/g-truc/glm/releases/tag/0.9.7.3) - 2016-02-21 +#### Improvements: +- Added AVX512 detection + +#### Fixes: +- Fixed CMake policy warning +- Fixed GCC 6.0 detection #477 +- Fixed Clang build on Windows #479 +- Fixed 64 bits constants warnings on GCC #463 + +--- +### [GLM 0.9.7.2](https://github.com/g-truc/glm/releases/tag/0.9.7.2) - 2016-01-03 +#### Fixes: +- Fixed GTC_round floorMultiple/ceilMultiple #412 +- Fixed GTC_packing unpackUnorm3x10_1x2 #414 +- Fixed GTC_matrix_inverse affineInverse #192 +- Fixed ICC on Linux build errors #449 +- Fixed ldexp and frexp compilation errors +- Fixed "Declaration shadows a field" warning #468 +- Fixed 'GLM_COMPILER_VC2005 is not defined' warning #468 +- Fixed various 'X is not defined' warnings #468 +- Fixed missing unary + operator #435 +- Fixed Cygwin build errors when using C++11 #405 + +--- +### [GLM 0.9.7.1](https://github.com/g-truc/glm/releases/tag/0.9.7.1) - 2015-09-07 +#### Improvements: +- Improved constexpr for constant functions coverage #198 +- Added to_string for quat and dual_quat in GTX_string_cast #375 +- Improved overall execution time of unit tests #396 + +#### Fixes: +- Fixed strict alignment warnings #235 #370 +- Fixed link errors on compilers not supported default function #377 +- Fixed compilation warnings in vec4 +- Fixed non-identity quaternions for equal vectors #234 +- Fixed excessive GTX_fast_trigonometry execution time #396 +- Fixed Visual Studio 2015 'hides class member' warnings #394 +- Fixed builtin bitscan never being used #392 +- Removed unused func_noise.* files #398 + +--- +### [GLM 0.9.7.0](https://github.com/g-truc/glm/releases/tag/0.9.7.0) - 2015-08-02 +#### Features: +- Added GTC_color_space: convertLinearToSRGB and convertSRGBToLinear functions +- Added 'fmod' overload to GTX_common with tests #308 +- Left handed perspective and lookAt functions #314 +- Added functions eulerAngleXYZ and extractEulerAngleXYZ #311 +- Added to perform std::hash on GLM types #320 #367 +- Added for texcoord wrapping +- Added static components and precision members to all vector and quat types #350 +- Added .gitignore #349 +- Added support of defaulted functions to GLM types, to use them in unions #366 + +#### Improvements: +- Changed usage of __has_include to support Intel compiler #307 +- Specialized integer implementation of YCoCg-R #310 +- Don't show status message in 'FindGLM' if 'QUIET' option is set. #317 +- Added master branch continuous integration service on Linux 64 #332 +- Clarified manual regarding angle unit in GLM, added FAQ 11 #326 +- Updated list of compiler versions + +#### Fixes: +- Fixed default precision for quat and dual_quat type #312 +- Fixed (u)int64 MSB/LSB handling on BE archs #306 +- Fixed multi-line comment warning in g++. #315 +- Fixed specifier removal by 'std::make_pair<>' #333 +- Fixed perspective fovy argument documentation #327 +- Removed -m64 causing build issues on Linux 32 #331 +- Fixed isfinite with C++98 compilers #343 +- Fixed Intel compiler build error on Linux #354 +- Fixed use of libstdc++ with Clang #351 +- Fixed quaternion pow #346 +- Fixed decompose warnings #373 +- Fixed matrix conversions #371 + +#### Deprecation: +- Removed integer specification for 'mod' in GTC_integer #308 +- Removed GTX_multiple, replaced by GTC_round + +--- +### [GLM 0.9.6.3](https://github.com/g-truc/glm/releases/tag/0.9.6.3) - 2015-02-15 +- Fixed Android doesn't have C++ 11 STL #284 + +--- +### [GLM 0.9.6.2](https://github.com/g-truc/glm/releases/tag/0.9.6.2) - 2015-02-15 +#### Features: +- Added display of GLM version with other GLM_MESSAGES +- Added ARM instruction set detection + +#### Improvements: +- Removed assert for perspective with zFar < zNear #298 +- Added Visual Studio natvis support for vec1, quat and dualqual types +- Cleaned up C++11 feature detections +- Clarify GLM licensing + +#### Fixes: +- Fixed faceforward build #289 +- Fixed conflict with Xlib #define True 1 #293 +- Fixed decompose function VS2010 templating issues #294 +- Fixed mat4x3 = mat2x3 * mat4x2 operator #297 +- Fixed warnings in F2x11_1x10 packing function in GTC_packing #295 +- Fixed Visual Studio natvis support for vec4 #288 +- Fixed GTC_packing *pack*norm*x* build and added tests #292 +- Disabled GTX_scalar_multiplication for GCC, failing to build tests #242 +- Fixed Visual C++ 2015 constexpr errors: Disabled only partial support +- Fixed functions not inlined with Clang #302 +- Fixed memory corruption (undefined behaviour) #303 + +--- +### [GLM 0.9.6.1](https://github.com/g-truc/glm/releases/tag/0.9.6.1) - 2014-12-10 +#### Features: +- Added GLM_LANG_CXX14_FLAG and GLM_LANG_CXX1Z_FLAG language feature flags +- Added C++14 detection + +#### Improvements: +- Clean up GLM_MESSAGES compilation log to report only detected capabilities + +#### Fixes: +- Fixed scalar uaddCarry build error with Cuda #276 +- Fixed C++11 explicit conversion operators detection #282 +- Fixed missing explicit conversion when using integer log2 with *vec1 types +- Fixed 64 bits integer GTX_string_cast to_string on VC 32 bit compiler +- Fixed Android build issue, STL C++11 is not supported by the NDK #284 +- Fixed unsupported _BitScanForward64 and _BitScanReverse64 in VC10 +- Fixed Visual C++ 32 bit build #283 +- Fixed GLM_FORCE_SIZE_FUNC pragma message +- Fixed C++98 only build +- Fixed conflict between GTX_compatibility and GTC_quaternion #286 +- Fixed C++ language restriction using GLM_FORCE_CXX** + +--- +### [GLM 0.9.6.0](https://github.com/g-truc/glm/releases/tag/0.9.6.0) - 2014-11-30 +#### Features: +- Exposed template vector and matrix types in 'glm' namespace #239, #244 +- Added GTX_scalar_multiplication for C++ 11 compiler only #242 +- Added GTX_range for C++ 11 compiler only #240 +- Added closestPointOnLine function for tvec2 to GTX_closest_point #238 +- Added GTC_vec1 extension, *vec1 support to *vec* types +- Updated GTX_associated_min_max with vec1 support +- Added support of precision and integers to linearRand #230 +- Added Integer types support to GTX_string_cast #249 +- Added vec3 slerp #237 +- Added GTX_common with isdenomal #223 +- Added GLM_FORCE_SIZE_FUNC to replace .length() by .size() #245 +- Added GLM_FORCE_NO_CTOR_INIT +- Added 'uninitialize' to explicitly not initialize a GLM type +- Added GTC_bitfield extension, promoted GTX_bit +- Added GTC_integer extension, promoted GTX_bit and GTX_integer +- Added GTC_round extension, promoted GTX_bit +- Added GLM_FORCE_EXPLICIT_CTOR to require explicit type conversions #269 +- Added GTX_type_aligned for aligned vector, matrix and quaternion types + +#### Improvements: +- Rely on C++11 to implement isinf and isnan +- Removed GLM_FORCE_CUDA, Cuda is implicitly detected +- Separated Apple Clang and LLVM compiler detection +- Used pragma once +- Undetected C++ compiler automatically compile with GLM_FORCE_CXX98 and + GLM_FORCE_PURE +- Added not function (from GLSL specification) on VC12 +- Optimized bitfieldReverse and bitCount functions +- Optimized findLSB and findMSB functions. +- Optimized matrix-vector multiple performance with Cuda #257, #258 +- Reduced integer type redifinitions #233 +- Rewrited of GTX_fast_trigonometry #264 #265 +- Made types trivially copyable #263 +- Removed in GLM tests +- Used std features within GLM without redeclaring +- Optimized cot function #272 +- Optimized sign function #272 +- Added explicit cast from quat to mat3 and mat4 #275 + +#### Fixes: +- Fixed std::nextafter not supported with C++11 on Android #217 +- Fixed missing value_type for dual quaternion +- Fixed return type of dual quaternion length +- Fixed infinite loop in isfinite function with GCC #221 +- Fixed Visual Studio 14 compiler warnings +- Fixed implicit conversion from another tvec2 type to another tvec2 #241 +- Fixed lack of consistency of quat and dualquat constructors +- Fixed uaddCarray #253 +- Fixed float comparison warnings #270 + +#### Deprecation: +- Requires Visual Studio 2010, GCC 4.2, Apple Clang 4.0, LLVM 3.0, Cuda 4, ICC 2013 or a C++98 compiler +- Removed degrees for function parameters +- Removed GLM_FORCE_RADIANS, active by default +- Removed VC 2005 / 8 and 2008 / 9 support +- Removed GCC 3.4 to 4.3 support +- Removed LLVM GCC support +- Removed LLVM 2.6 to 3.1 support +- Removed CUDA 3.0 to 3.2 support + +--- +### [GLM 0.9.5.4 - 2014-06-21](https://github.com/g-truc/glm/releases/tag/0.9.5.4) +- Fixed non-utf8 character #196 +- Added FindGLM install for CMake #189 +- Fixed GTX_color_space - saturation #195 +- Fixed glm::isinf and glm::isnan for with Android NDK 9d #191 +- Fixed builtin GLM_ARCH_SSE4 #204 +- Optimized Quaternion vector rotation #205 +- Fixed missing doxygen @endcond tag #211 +- Fixed instruction set detection with Clang #158 +- Fixed orientate3 function #207 +- Fixed lerp when cosTheta is close to 1 in quaternion slerp #210 +- Added GTX_io for io with #144 +- Fixed fastDistance ambiguity #215 +- Fixed tweakedInfinitePerspective #208 and added user-defined epsilon to + tweakedInfinitePerspective +- Fixed std::copy and std::vector with GLM types #214 +- Fixed strict aliasing issues #212, #152 +- Fixed std::nextafter not supported with C++11 on Android #213 +- Fixed corner cases in exp and log functions for quaternions #199 + +--- +### GLM 0.9.5.3 - 2014-04-02 +- Added instruction set auto detection with Visual C++ using _M_IX86_FP - /arch + compiler argument +- Fixed GTX_raw_data code dependency +- Fixed GCC instruction set detection +- Added GLM_GTX_matrix_transform_2d extension (#178, #176) +- Fixed CUDA issues (#169, #168, #183, #182) +- Added support for all extensions but GTX_string_cast to CUDA +- Fixed strict aliasing warnings in GCC 4.8.1 / Android NDK 9c (#152) +- Fixed missing bitfieldInterleave definisions +- Fixed usubBorrow (#171) +- Fixed eulerAngle*** not consistent for right-handed coordinate system (#173) +- Added full tests for eulerAngle*** functions (#173) +- Added workaround for a CUDA compiler bug (#186, #185) + +--- +### GLM 0.9.5.2 - 2014-02-08 +- Fixed initializer list ambiguity (#159, #160) +- Fixed warnings with the Android NDK 9c +- Fixed non power of two matrix products +- Fixed mix function link error +- Fixed SSE code included in GLM tests on "pure" platforms +- Fixed undefined reference to fastInverseSqrt (#161) +- Fixed GLM_FORCE_RADIANS with build error (#165) +- Fix dot product clamp range for vector angle functions. (#163) +- Tentative fix for strict aliasing warning in GCC 4.8.1 / Android NDK 9c (#152) +- Fixed GLM_GTC_constants description brief (#162) + +--- +### GLM 0.9.5.1 - 2014-01-11 +- Fixed angle and orientedAngle that sometimes return NaN values (#145) +- Deprecated degrees for function parameters and display a message +- Added possible static_cast conversion of GLM types (#72) +- Fixed error 'inverse' is not a member of 'glm' from glm::unProject (#146) +- Fixed mismatch between some declarations and definitions +- Fixed inverse link error when using namespace glm; (#147) +- Optimized matrix inverse and division code (#149) +- Added intersectRayPlane function (#153) +- Fixed outerProduct return type (#155) + +--- +### GLM 0.9.5.0 - 2013-12-25 +- Added forward declarations (glm/fwd.hpp) for faster compilations +- Added per feature headers +- Minimized GLM internal dependencies +- Improved Intel Compiler detection +- Added bitfieldInterleave and _mm_bit_interleave_si128 functions +- Added GTX_scalar_relational +- Added GTX_dual_quaternion +- Added rotation function to GTX_quaternion (#22) +- Added precision variation of each type +- Added quaternion comparison functions +- Fixed GTX_multiple for negative value +- Removed GTX_ocl_type extension +- Fixed post increment and decrement operators +- Fixed perspective with zNear == 0 (#71) +- Removed l-value swizzle operators +- Cleaned up compiler detection code for unsupported compilers +- Replaced C cast by C++ casts +- Fixed .length() that should return a int and not a size_t +- Added GLM_FORCE_SIZE_T_LENGTH and glm::length_t +- Removed unnecessary conversions +- Optimized packing and unpacking functions +- Removed the normalization of the up argument of lookAt function (#114) +- Added low precision specializations of inversesqrt +- Fixed ldexp and frexp implementations +- Increased assert coverage +- Increased static_assert coverage +- Replaced GLM traits by STL traits when possible +- Allowed including individual core feature +- Increased unit tests completeness +- Added creating of a quaternion from two vectors +- Added C++11 initializer lists +- Fixed umulExtended and imulExtended implementations for vector types (#76) +- Fixed CUDA coverage for GTC extensions +- Added GTX_io extension +- Improved GLM messages enabled when defining GLM_MESSAGES +- Hidden matrix_inverse function implementation detail into private section + +--- +### [GLM 0.9.4.6](https://github.com/g-truc/glm/releases/tag/0.9.4.6) - 2013-09-20 +- Fixed detection to select the last known compiler if newer version #106 +- Fixed is_int and is_uint code duplication with GCC and C++11 #107 +- Fixed test suite build while using Clang in C++11 mode +- Added c++1y mode support in CMake test suite +- Removed ms extension mode to CMake when no using Visual C++ +- Added pedantic mode to CMake test suite for Clang and GCC +- Added use of GCC frontend on Unix for ICC and Visual C++ fronted on Windows + for ICC +- Added compilation errors for unsupported compiler versions +- Fixed glm::orientation with GLM_FORCE_RADIANS defined #112 +- Fixed const ref issue on assignment operator taking a scalar parameter #116 +- Fixed glm::eulerAngleY implementation #117 + +--- +### GLM 0.9.4.5 - 2013-08-12 +- Fixed CUDA support +- Fixed inclusion of intrinsics in "pure" mode #92 +- Fixed language detection on GCC when the C++0x mode isn't enabled #95 +- Fixed issue #97: register is deprecated in C++11 +- Fixed issue #96: CUDA issues +- Added Windows CE detection #92 +- Added missing value_ptr for quaternions #99 + +--- +### GLM 0.9.4.4 - 2013-05-29 +- Fixed slerp when costheta is close to 1 #65 +- Fixed mat4x2 value_type constructor #70 +- Fixed glm.natvis for Visual C++ 12 #82 +- Added assert in inversesqrt to detect division by zero #61 +- Fixed missing swizzle operators #86 +- Fixed CUDA warnings #86 +- Fixed GLM natvis for VC11 #82 +- Fixed GLM_GTX_multiple with negative values #79 +- Fixed glm::perspective when zNear is zero #71 + +--- +### GLM 0.9.4.3 - 2013-03-20 +- Detected qualifier for Clang +- Fixed C++11 mode for GCC, couldn't be enabled without MS extensions +- Fixed squad, intermediate and exp quaternion functions +- Fixed GTX_polar_coordinates euclidean function, takes a vec2 instead of a vec3 +- Clarify the license applying on the manual +- Added a docx copy of the manual +- Fixed GLM_GTX_matrix_interpolation +- Fixed isnan and isinf on Android with Clang +- Autodetected C++ version using __cplusplus value +- Fixed mix for bool and bvec* third parameter + +--- +### GLM 0.9.4.2 - 2013-02-14 +- Fixed compAdd from GTX_component_wise +- Fixed SIMD support for Intel compiler on Windows +- Fixed isnan and isinf for CUDA compiler +- Fixed GLM_FORCE_RADIANS on glm::perspective +- Fixed GCC warnings +- Fixed packDouble2x32 on Xcode +- Fixed mix for vec4 SSE implementation +- Fixed 0x2013 dash character in comments that cause issue in Windows + Japanese mode +- Fixed documentation warnings +- Fixed CUDA warnings + +--- +### GLM 0.9.4.1 - 2012-12-22 +- Improved half support: -0.0 case and implicit conversions +- Fixed Intel Composer Compiler support on Linux +- Fixed interaction between quaternion and euler angles +- Fixed GTC_constants build +- Fixed GTX_multiple +- Fixed quat slerp using mix function when cosTheta close to 1 +- Improved fvec4SIMD and fmat4x4SIMD implementations +- Fixed assert messages +- Added slerp and lerp quaternion functions and tests + +--- +### GLM 0.9.4.0 - 2012-11-18 +- Added Intel Composer Compiler support +- Promoted GTC_espilon extension +- Promoted GTC_ulp extension +- Removed GLM website from the source repository +- Added GLM_FORCE_RADIANS so that all functions takes radians for arguments +- Fixed detection of Clang and LLVM GCC on MacOS X +- Added debugger visualizers for Visual C++ 2012 +- Requires Visual Studio 2005, GCC 4.2, Clang 2.6, Cuda 3, ICC 2013 or a C++98 compiler + +--- +### [GLM 0.9.3.4](https://github.com/g-truc/glm/releases/tag/0.9.3.4) - 2012-06-30 +- Added SSE4 and AVX2 detection. +- Removed VIRTREV_xstream and the incompatibility generated with GCC +- Fixed C++11 compiler option for GCC +- Removed MS language extension option for GCC (not fonctionnal) +- Fixed bitfieldExtract for vector types +- Fixed warnings +- Fixed SSE includes + +--- +### GLM 0.9.3.3 - 2012-05-10 +- Fixed isinf and isnan +- Improved compatibility with Intel compiler +- Added CMake test build options: SIMD, C++11, fast math and MS land ext +- Fixed SIMD mat4 test on GCC +- Fixed perspectiveFov implementation +- Fixed matrixCompMult for none-square matrices +- Fixed namespace issue on stream operators +- Fixed various warnings +- Added VC11 support + +--- +### GLM 0.9.3.2 - 2012-03-15 +- Fixed doxygen documentation +- Fixed Clang version detection +- Fixed simd mat4 /= operator + +--- +### GLM 0.9.3.1 - 2012-01-25 +- Fixed platform detection +- Fixed warnings +- Removed detail code from Doxygen doc + +--- +### GLM 0.9.3.0 - 2012-01-09 +- Added CPP Check project +- Fixed conflict with Windows headers +- Fixed isinf implementation +- Fixed Boost conflict +- Fixed warnings + +--- +### GLM 0.9.3.B - 2011-12-12 +- Added support for Chrone Native Client +- Added epsilon constant +- Removed value_size function from vector types +- Fixed roundEven on GCC +- Improved API documentation +- Fixed modf implementation +- Fixed step function accuracy +- Fixed outerProduct + +--- +### GLM 0.9.3.A - 2011-11-11 +- Improved doxygen documentation +- Added new swizzle operators for C++11 compilers +- Added new swizzle operators declared as functions +- Added GLSL 4.20 length for vector and matrix types +- Promoted GLM_GTC_noise extension: simplex, perlin, periodic noise functions +- Promoted GLM_GTC_random extension: linear, gaussian and various random number +generation distribution +- Added GLM_GTX_constants: provides useful constants +- Added extension versioning +- Removed many unused namespaces +- Fixed half based type contructors +- Added GLSL core noise functions + +--- +### [GLM 0.9.2.7](https://github.com/g-truc/glm/releases/tag/0.9.2.7) - 2011-10-24 +- Added more swizzling constructors +- Added missing non-squared matrix products + +--- +### [GLM 0.9.2.6](https://github.com/g-truc/glm/releases/tag/0.9.2.6) - 2011-10-01 +- Fixed half based type build on old GCC +- Fixed /W4 warnings on Visual C++ +- Fixed some missing l-value swizzle operators + +--- +### GLM 0.9.2.5 - 2011-09-20 +- Fixed floatBitToXint functions +- Fixed pack and unpack functions +- Fixed round functions + +--- +### GLM 0.9.2.4 - 2011-09-03 +- Fixed extensions bugs + +--- +### GLM 0.9.2.3 - 2011-06-08 +- Fixed build issues + +--- +### GLM 0.9.2.2 - 2011-06-02 +- Expend matrix constructors flexibility +- Improved quaternion implementation +- Fixed many warnings across platforms and compilers + +--- +### GLM 0.9.2.1 - 2011-05-24 +- Automatically detect CUDA support +- Improved compiler detection +- Fixed errors and warnings in VC with C++ extensions disabled +- Fixed and tested GLM_GTX_vector_angle +- Fixed and tested GLM_GTX_rotate_vector + +--- +### GLM 0.9.2.0 - 2011-05-09 +- Added CUDA support +- Added CTest test suite +- Added GLM_GTX_ulp extension +- Added GLM_GTX_noise extension +- Added GLM_GTX_matrix_interpolation extension +- Updated quaternion slerp interpolation + +--- +### [GLM 0.9.1.3](https://github.com/g-truc/glm/releases/tag/0.9.1.3) - 2011-05-07 +- Fixed bugs + +--- +### GLM 0.9.1.2 - 2011-04-15 +- Fixed bugs + +--- +### GLM 0.9.1.1 - 2011-03-17 +- Fixed bugs + +--- +### GLM 0.9.1.0 - 2011-03-03 +- Fixed bugs + +--- +### GLM 0.9.1.B - 2011-02-13 +- Updated API documentation +- Improved SIMD implementation +- Fixed Linux build + +--- +### [GLM 0.9.0.8](https://github.com/g-truc/glm/releases/tag/0.9.0.8) - 2011-02-13 +- Added quaternion product operator. +- Clarify that GLM is a header only library. + +--- +### GLM 0.9.1.A - 2011-01-31 +- Added SIMD support +- Added new swizzle functions +- Improved static assert error message with C++0x static_assert +- New setup system +- Reduced branching +- Fixed trunc implementation + +--- +### [GLM 0.9.0.7](https://github.com/g-truc/glm/releases/tag/0.9.0.7) - 2011-01-30 +- Added GLSL 4.10 packing functions +- Added == and != operators for every types. + +--- +### GLM 0.9.0.6 - 2010-12-21 +- Many matrices bugs fixed + +--- +### GLM 0.9.0.5 - 2010-11-01 +- Improved Clang support +- Fixed bugs + +--- +### GLM 0.9.0.4 - 2010-10-04 +- Added autoexp for GLM +- Fixed bugs + +--- +### GLM 0.9.0.3 - 2010-08-26 +- Fixed non-squared matrix operators + +--- +### GLM 0.9.0.2 - 2010-07-08 +- Added GLM_GTX_int_10_10_10_2 +- Fixed bugs + +--- +### GLM 0.9.0.1 - 2010-06-21 +- Fixed extensions errors + +--- +### GLM 0.9.0.0 - 2010-05-25 +- Objective-C support +- Fixed warnings +- Updated documentation + +--- +### GLM 0.9.B.2 - 2010-04-30 +- Git transition +- Removed experimental code from releases +- Fixed bugs + +--- +### GLM 0.9.B.1 - 2010-04-03 +- Based on GLSL 4.00 specification +- Added the new core functions +- Added some implicit conversion support + +--- +### GLM 0.9.A.2 - 2010-02-20 +- Improved some possible errors messages +- Improved declarations and definitions match + +--- +### GLM 0.9.A.1 - 2010-02-09 +- Removed deprecated features +- Internal redesign + +--- +### GLM 0.8.4.4 final - 2010-01-25 +- Fixed warnings + +--- +### GLM 0.8.4.3 final - 2009-11-16 +- Fixed Half float arithmetic +- Fixed setup defines + +--- +### GLM 0.8.4.2 final - 2009-10-19 +- Fixed Half float adds + +--- +### GLM 0.8.4.1 final - 2009-10-05 +- Updated documentation +- Fixed MacOS X build + +--- +### GLM 0.8.4.0 final - 2009-09-16 +- Added GCC 4.4 and VC2010 support +- Added matrix optimizations + +--- +### GLM 0.8.3.5 final - 2009-08-11 +- Fixed bugs + +--- +### GLM 0.8.3.4 final - 2009-08-10 +- Updated GLM according GLSL 1.5 spec +- Fixed bugs + +--- +### GLM 0.8.3.3 final - 2009-06-25 +- Fixed bugs + +--- +### GLM 0.8.3.2 final - 2009-06-04 +- Added GLM_GTC_quaternion +- Added GLM_GTC_type_precision + +--- +### GLM 0.8.3.1 final - 2009-05-21 +- Fixed old extension system. + +--- +### GLM 0.8.3.0 final - 2009-05-06 +- Added stable extensions. +- Added new extension system. + +--- +### GLM 0.8.2.3 final - 2009-04-01 +- Fixed bugs. + +--- +### GLM 0.8.2.2 final - 2009-02-24 +- Fixed bugs. + +--- +### GLM 0.8.2.1 final - 2009-02-13 +- Fixed bugs. + +--- +### GLM 0.8.2 final - 2009-01-21 +- Fixed bugs. + +--- +### GLM 0.8.1 final - 2008-10-30 +- Fixed bugs. + +--- +### GLM 0.8.0 final - 2008-10-23 +- New method to use extension. + +--- +### GLM 0.8.0 beta3 - 2008-10-10 +- Added CMake support for GLM tests. + +--- +### GLM 0.8.0 beta2 - 2008-10-04 +- Improved half scalars and vectors support. + +--- +### GLM 0.8.0 beta1 - 2008-09-26 +- Improved GLSL conformance +- Added GLSL 1.30 support +- Improved API documentation + +--- +### GLM 0.7.6 final - 2008-08-08 +- Improved C++ standard comformance +- Added Static assert for types checking + +--- +### GLM 0.7.5 final - 2008-07-05 +- Added build message system with Visual Studio +- Pedantic build with GCC + +--- +### GLM 0.7.4 final - 2008-06-01 +- Added external dependencies system. + +--- +### GLM 0.7.3 final - 2008-05-24 +- Fixed bugs +- Added new extension group + +--- +### GLM 0.7.2 final - 2008-04-27 +- Updated documentation +- Added preprocessor options + +--- +### GLM 0.7.1 final - 2008-03-24 +- Disabled half on GCC +- Fixed extensions + +--- +### GLM 0.7.0 final - 2008-03-22 +- Changed to MIT license +- Added new documentation + +--- +### GLM 0.6.4 - 2007-12-10 +- Fixed swizzle operators + +--- +### GLM 0.6.3 - 2007-11-05 +- Fixed type data accesses +- Fixed 3DSMax sdk conflict + +--- +### GLM 0.6.2 - 2007-10-08 +- Fixed extension + +--- +### GLM 0.6.1 - 2007-10-07 +- Fixed a namespace error +- Added extensions + +--- +### GLM 0.6.0 : 2007-09-16 +- Added new extension namespace mecanium +- Added Automatic compiler detection + +--- +### GLM 0.5.1 - 2007-02-19 +- Fixed swizzle operators + +--- +### GLM 0.5.0 - 2007-01-06 +- Upgrated to GLSL 1.2 +- Added swizzle operators +- Added setup settings + +--- +### GLM 0.4.1 - 2006-05-22 +- Added OpenGL examples + +--- +### GLM 0.4.0 - 2006-05-17 +- Added missing operators to vec* and mat* +- Added first GLSL 1.2 features +- Fixed windows.h before glm.h when windows.h required + +--- +### GLM 0.3.2 - 2006-04-21 +- Fixed texcoord components access. +- Fixed mat4 and imat4 division operators. + +--- +### GLM 0.3.1 - 2006-03-28 +- Added GCC 4.0 support under MacOS X. +- Added GCC 4.0 and 4.1 support under Linux. +- Added code optimisations. + +--- +### GLM 0.3 - 2006-02-19 +- Improved GLSL type conversion and construction compliance. +- Added experimental extensions. +- Added Doxygen Documentation. +- Added code optimisations. +- Fixed bugs. + +--- +### GLM 0.2 - 2005-05-05 +- Improve adaptative from GLSL. +- Add experimental extensions based on OpenGL extension process. +- Fixed bugs. + +--- +### GLM 0.1 - 2005-02-21 +- Add vec2, vec3, vec4 GLSL types +- Add ivec2, ivec3, ivec4 GLSL types +- Add bvec2, bvec3, bvec4 GLSL types +- Add mat2, mat3, mat4 GLSL types +- Add almost all functions + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/CMakeLists.txt b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..e7f85f19f8e08e8c33055937708811d4557ed750 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/CMakeLists.txt @@ -0,0 +1,246 @@ +option(GLM_QUIET "No CMake Message" OFF) +option(BUILD_SHARED_LIBS "Build shared library" ON) +option(BUILD_STATIC_LIBS "Build static library" ON) +option(GLM_TEST_ENABLE_CXX_98 "Enable C++ 98" OFF) +option(GLM_TEST_ENABLE_CXX_11 "Enable C++ 11" OFF) +option(GLM_TEST_ENABLE_CXX_14 "Enable C++ 14" OFF) +option(GLM_TEST_ENABLE_CXX_17 "Enable C++ 17" OFF) +option(GLM_TEST_ENABLE_CXX_20 "Enable C++ 20" OFF) + +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +if(GLM_TEST_ENABLE_CXX_20) + set(CMAKE_CXX_STANDARD 20) + add_definitions(-DGLM_FORCE_CXX2A) + if(NOT GLM_QUIET) + message(STATUS "GLM: Build with C++20 features") + endif() + +elseif(GLM_TEST_ENABLE_CXX_17) + set(CMAKE_CXX_STANDARD 17) + add_definitions(-DGLM_FORCE_CXX17) + if(NOT GLM_QUIET) + message(STATUS "GLM: Build with C++17 features") + endif() + +elseif(GLM_TEST_ENABLE_CXX_14) + set(CMAKE_CXX_STANDARD 14) + add_definitions(-DGLM_FORCE_CXX14) + if(NOT GLM_QUIET) + message(STATUS "GLM: Build with C++14 features") + endif() + +elseif(GLM_TEST_ENABLE_CXX_11) + set(CMAKE_CXX_STANDARD 11) + add_definitions(-DGLM_FORCE_CXX11) + if(NOT GLM_QUIET) + message(STATUS "GLM: Build with C++11 features") + endif() + +elseif(GLM_TEST_ENABLE_CXX_98) + set(CMAKE_CXX_STANDARD 98) + add_definitions(-DGLM_FORCE_CXX98) + if(NOT GLM_QUIET) + message(STATUS "GLM: Build with C++98 features") + endif() +endif() + +option(GLM_TEST_ENABLE_LANG_EXTENSIONS "Enable language extensions" OFF) + +option(GLM_DISABLE_AUTO_DETECTION "Enable language extensions" OFF) + +if(GLM_DISABLE_AUTO_DETECTION) + add_definitions(-DGLM_FORCE_PLATFORM_UNKNOWN -DGLM_FORCE_COMPILER_UNKNOWN -DGLM_FORCE_ARCH_UNKNOWN -DGLM_FORCE_CXX_UNKNOWN) +endif() + +if(GLM_TEST_ENABLE_LANG_EXTENSIONS) + set(CMAKE_CXX_EXTENSIONS ON) + if((CMAKE_CXX_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "GNU")) + add_compile_options(-fms-extensions) + endif() + message(STATUS "GLM: Build with C++ language extensions") +else() + set(CMAKE_CXX_EXTENSIONS OFF) + if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + add_compile_options(/Za) + if(MSVC15) + add_compile_options(/permissive-) + endif() + endif() +endif() + +option(GLM_TEST_ENABLE_FAST_MATH "Enable fast math optimizations" OFF) +if(GLM_TEST_ENABLE_FAST_MATH) + if(NOT GLM_QUIET) + message(STATUS "GLM: Build with fast math optimizations") + endif() + + if((CMAKE_CXX_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "GNU")) + add_compile_options(-ffast-math) + + elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + add_compile_options(/fp:fast) + endif() +else() + if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + add_compile_options(/fp:precise) + endif() +endif() + +option(GLM_TEST_ENABLE "Build unit tests" ON) +option(GLM_TEST_ENABLE_SIMD_SSE2 "Enable SSE2 optimizations" OFF) +option(GLM_TEST_ENABLE_SIMD_SSE3 "Enable SSE3 optimizations" OFF) +option(GLM_TEST_ENABLE_SIMD_SSSE3 "Enable SSSE3 optimizations" OFF) +option(GLM_TEST_ENABLE_SIMD_SSE4_1 "Enable SSE 4.1 optimizations" OFF) +option(GLM_TEST_ENABLE_SIMD_SSE4_2 "Enable SSE 4.2 optimizations" OFF) +option(GLM_TEST_ENABLE_SIMD_AVX "Enable AVX optimizations" OFF) +option(GLM_TEST_ENABLE_SIMD_AVX2 "Enable AVX2 optimizations" OFF) +option(GLM_TEST_FORCE_PURE "Force 'pure' instructions" OFF) + +if(GLM_TEST_FORCE_PURE) + add_definitions(-DGLM_FORCE_PURE) + + if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") + add_compile_options(-mfpmath=387) + endif() + message(STATUS "GLM: No SIMD instruction set") + +elseif(GLM_TEST_ENABLE_SIMD_AVX2) + add_definitions(-DGLM_FORCE_INTRINSICS) + + if((CMAKE_CXX_COMPILER_ID MATCHES "GNU") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) + add_compile_options(-mavx2) + elseif(CMAKE_CXX_COMPILER_ID MATCHES "Intel") + add_compile_options(/QxAVX2) + elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + add_compile_options(/arch:AVX2) + endif() + message(STATUS "GLM: AVX2 instruction set") + +elseif(GLM_TEST_ENABLE_SIMD_AVX) + add_definitions(-DGLM_FORCE_INTRINSICS) + + if((CMAKE_CXX_COMPILER_ID MATCHES "GNU") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) + add_compile_options(-mavx) + elseif(CMAKE_CXX_COMPILER_ID MATCHES "Intel") + add_compile_options(/QxAVX) + elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + add_compile_options(/arch:AVX) + endif() + message(STATUS "GLM: AVX instruction set") + +elseif(GLM_TEST_ENABLE_SIMD_SSE4_2) + add_definitions(-DGLM_FORCE_INTRINSICS) + + if((CMAKE_CXX_COMPILER_ID MATCHES "GNU") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) + add_compile_options(-msse4.2) + elseif(CMAKE_CXX_COMPILER_ID MATCHES "Intel") + add_compile_options(/QxSSE4.2) + elseif((CMAKE_CXX_COMPILER_ID MATCHES "MSVC") AND NOT CMAKE_CL_64) + add_compile_options(/arch:SSE2) # VC doesn't support SSE4.2 + endif() + message(STATUS "GLM: SSE4.2 instruction set") + +elseif(GLM_TEST_ENABLE_SIMD_SSE4_1) + add_definitions(-DGLM_FORCE_INTRINSICS) + + if((CMAKE_CXX_COMPILER_ID MATCHES "GNU") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) + add_compile_options(-msse4.1) + elseif(CMAKE_CXX_COMPILER_ID MATCHES "Intel") + add_compile_options(/QxSSE4.1) + elseif((CMAKE_CXX_COMPILER_ID MATCHES "MSVC") AND NOT CMAKE_CL_64) + add_compile_options(/arch:SSE2) # VC doesn't support SSE4.1 + endif() + message(STATUS "GLM: SSE4.1 instruction set") + +elseif(GLM_TEST_ENABLE_SIMD_SSSE3) + add_definitions(-DGLM_FORCE_INTRINSICS) + + if((CMAKE_CXX_COMPILER_ID MATCHES "GNU") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) + add_compile_options(-mssse3) + elseif(CMAKE_CXX_COMPILER_ID MATCHES "Intel") + add_compile_options(/QxSSSE3) + elseif((CMAKE_CXX_COMPILER_ID MATCHES "MSVC") AND NOT CMAKE_CL_64) + add_compile_options(/arch:SSE2) # VC doesn't support SSSE3 + endif() + message(STATUS "GLM: SSSE3 instruction set") + +elseif(GLM_TEST_ENABLE_SIMD_SSE3) + add_definitions(-DGLM_FORCE_INTRINSICS) + + if((CMAKE_CXX_COMPILER_ID MATCHES "GNU") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) + add_compile_options(-msse3) + elseif(CMAKE_CXX_COMPILER_ID MATCHES "Intel") + add_compile_options(/QxSSE3) + elseif((CMAKE_CXX_COMPILER_ID MATCHES "MSVC") AND NOT CMAKE_CL_64) + add_compile_options(/arch:SSE2) # VC doesn't support SSE3 + endif() + message(STATUS "GLM: SSE3 instruction set") + +elseif(GLM_TEST_ENABLE_SIMD_SSE2) + add_definitions(-DGLM_FORCE_INTRINSICS) + + if((CMAKE_CXX_COMPILER_ID MATCHES "GNU") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) + add_compile_options(-msse2) + elseif(CMAKE_CXX_COMPILER_ID MATCHES "Intel") + add_compile_options(/QxSSE2) + elseif((CMAKE_CXX_COMPILER_ID MATCHES "MSVC") AND NOT CMAKE_CL_64) + add_compile_options(/arch:SSE2) + endif() + message(STATUS "GLM: SSE2 instruction set") +endif() + +# Compiler and default options + +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + if(NOT GLM_QUIET) + message("GLM: Clang - ${CMAKE_CXX_COMPILER_ID} compiler") + endif() + + add_compile_options(-Werror -Weverything) + add_compile_options(-Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-c++11-long-long -Wno-padded -Wno-gnu-anonymous-struct -Wno-nested-anon-types) + add_compile_options(-Wno-undefined-reinterpret-cast -Wno-sign-conversion -Wno-unused-variable -Wno-missing-prototypes -Wno-unreachable-code -Wno-missing-variable-declarations -Wno-sign-compare -Wno-global-constructors -Wno-unused-macros -Wno-format-nonliteral) + +elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU") + if(NOT GLM_QUIET) + message("GLM: GCC - ${CMAKE_CXX_COMPILER_ID} compiler") + endif() + + add_compile_options(-O2) + add_compile_options(-Wno-long-long) + +elseif(CMAKE_CXX_COMPILER_ID MATCHES "Intel") + if(NOT GLM_QUIET) + message("GLM: Intel - ${CMAKE_CXX_COMPILER_ID} compiler") + endif() + +elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + if(NOT GLM_QUIET) + message("GLM: Visual C++ - ${CMAKE_CXX_COMPILER_ID} compiler") + endif() + + add_compile_options(/W4 /WX) + add_compile_options(/wd4309 /wd4324 /wd4389 /wd4127 /wd4267 /wd4146 /wd4201 /wd4464 /wd4514 /wd4701 /wd4820 /wd4365) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) +endif() + +function(glmCreateTestGTC NAME) + set(SAMPLE_NAME test-${NAME}) + add_executable(${SAMPLE_NAME} ${NAME}.cpp) + + add_test( + NAME ${SAMPLE_NAME} + COMMAND $ ) + target_link_libraries(${SAMPLE_NAME} PRIVATE glm::glm) +endfunction() + +if(GLM_TEST_ENABLE) + add_subdirectory(bug) + add_subdirectory(core) + add_subdirectory(ext) + add_subdirectory(gtc) + add_subdirectory(gtx) + add_subdirectory(perf) +endif() + + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/bug/CMakeLists.txt b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/bug/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..26e8569429f190180afc3744d48d9023f67c469e --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/bug/CMakeLists.txt @@ -0,0 +1 @@ +glmCreateTestGTC(bug_ms_vec_static) diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/bug/bug_ms_vec_static.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/bug/bug_ms_vec_static.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7f44e409a7bc30ce3fb8e0d175caff25e24b0b32 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/bug/bug_ms_vec_static.cpp @@ -0,0 +1,31 @@ +#include + +#if GLM_CONFIG_ANONYMOUS_STRUCT == GLM_ENABLE +struct vec2; + +struct _swizzle +{ + char _buffer[1]; +}; + +struct vec2 +{ + GLM_CONSTEXPR vec2() : + x(0), y(0) + {} + + union + { + struct { float x, y; }; + struct { _swizzle xx; }; + }; +}; +#endif + +// Visual C++ has a bug generating the error: fatal error C1001: An internal error has occurred in the compiler. +// vec2 Bar; + +int main() +{ + return 0; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/cmake/CMakeLists.txt b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/cmake/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..5bc11ef4efd741f7bb87ceae765f5d87eca1fb5f --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/cmake/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.2 FATAL_ERROR) +project(test_find_glm) + +find_package(glm REQUIRED) + +add_executable(test_find_glm test_find_glm.cpp) +target_link_libraries(test_find_glm glm::glm) + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/cmake/test_find_glm.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/cmake/test_find_glm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..361b97779681dd07d0a69b844b69d90ba87f0faf --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/cmake/test_find_glm.cpp @@ -0,0 +1,22 @@ +#include +#include +#include + +glm::mat4 camera(float Translate, glm::vec2 const& Rotate) +{ + glm::mat4 Projection = glm::perspective(glm::pi() * 0.25f, 4.0f / 3.0f, 0.1f, 100.f); + glm::mat4 View = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -Translate)); + View = glm::rotate(View, Rotate.y, glm::vec3(-1.0f, 0.0f, 0.0f)); + View = glm::rotate(View, Rotate.x, glm::vec3(0.0f, 1.0f, 0.0f)); + glm::mat4 Model = glm::scale(glm::mat4(1.0f), glm::vec3(0.5f)); + return Projection * View * Model; +} + +int main() +{ + const glm::mat4 m = camera(1.f, glm::vec2(1.f, 0.5f)); + std::cout << "matrix diagonal: " << m[0][0] << ", " + << m[1][1] << ", " << m[2][2] << ", " << m[3][3] << "\n"; + return 0; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/CMakeLists.txt b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..6cd57b18c8389cc6826d43e9cd1f33176a6b7cc6 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/CMakeLists.txt @@ -0,0 +1,52 @@ +glmCreateTestGTC(core_cpp_constexpr) +glmCreateTestGTC(core_cpp_defaulted_ctor) +glmCreateTestGTC(core_force_aligned_gentypes) +glmCreateTestGTC(core_force_ctor_init) +glmCreateTestGTC(core_force_cxx03) +glmCreateTestGTC(core_force_cxx98) +glmCreateTestGTC(core_force_arch_unknown) +glmCreateTestGTC(core_force_compiler_unknown) +glmCreateTestGTC(core_force_cxx_unknown) +glmCreateTestGTC(core_force_explicit_ctor) +glmCreateTestGTC(core_force_inline) +glmCreateTestGTC(core_force_platform_unknown) +glmCreateTestGTC(core_force_pure) +glmCreateTestGTC(core_force_unrestricted_gentype) +glmCreateTestGTC(core_force_xyzw_only) +glmCreateTestGTC(core_force_quat_xyzw) +glmCreateTestGTC(core_type_aligned) +glmCreateTestGTC(core_type_cast) +glmCreateTestGTC(core_type_ctor) +glmCreateTestGTC(core_type_int) +glmCreateTestGTC(core_type_length) +glmCreateTestGTC(core_type_mat2x2) +glmCreateTestGTC(core_type_mat2x3) +glmCreateTestGTC(core_type_mat2x4) +glmCreateTestGTC(core_type_mat3x2) +glmCreateTestGTC(core_type_mat3x3) +glmCreateTestGTC(core_type_mat3x4) +glmCreateTestGTC(core_type_mat4x2) +glmCreateTestGTC(core_type_mat4x3) +glmCreateTestGTC(core_type_mat4x4) +glmCreateTestGTC(core_type_vec1) +glmCreateTestGTC(core_type_vec2) +glmCreateTestGTC(core_type_vec3) +glmCreateTestGTC(core_type_vec4) +glmCreateTestGTC(core_func_common) +glmCreateTestGTC(core_func_exponential) +glmCreateTestGTC(core_func_geometric) +glmCreateTestGTC(core_func_integer) +glmCreateTestGTC(core_func_integer_bit_count) +glmCreateTestGTC(core_func_integer_find_lsb) +glmCreateTestGTC(core_func_integer_find_msb) +glmCreateTestGTC(core_func_matrix) +glmCreateTestGTC(core_func_noise) +glmCreateTestGTC(core_func_packing) +glmCreateTestGTC(core_func_trigonometric) +glmCreateTestGTC(core_func_vector_relational) +glmCreateTestGTC(core_func_swizzle) +glmCreateTestGTC(core_setup_force_cxx98) +glmCreateTestGTC(core_setup_force_size_t_length) +glmCreateTestGTC(core_setup_message) +glmCreateTestGTC(core_setup_platform_unknown) +glmCreateTestGTC(core_setup_precision) diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_cpp_constexpr.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_cpp_constexpr.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3dc0a92bfb8245c9b5f4b4d8f7616956fb82bd7f --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_cpp_constexpr.cpp @@ -0,0 +1,750 @@ +#include + +#if GLM_CONFIG_CONSTEXP == GLM_ENABLE + +#include +#include +#include +#include +#include +#include +#include +#include + +static int test_vec1() +{ + int Error = 0; + + { + constexpr glm::bvec1 B(true); + constexpr bool A = glm::all(B); + static_assert(A, "GLM: Failed constexpr"); + + constexpr glm::bvec1 D(true); + constexpr bool C = glm::any(D); + static_assert(C, "GLM: Failed constexpr"); + } + + { + constexpr glm::bvec2 C(true); + constexpr glm::bvec2 B(true); + static_assert(glm::any(glm::equal(C, B)), "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec1 O(glm::ivec1(1)); + static_assert(glm::ivec1(1) == O, "GLM: Failed constexpr"); + + constexpr glm::ivec1 P(1); + static_assert(glm::ivec1(1) == P, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec1 L(glm::ivec2(1, 2)); + static_assert(glm::ivec1(1) == L, "GLM: Failed constexpr"); + + constexpr glm::ivec1 M(glm::ivec3(1, 2, 3)); + static_assert(glm::ivec1(1) == M, "GLM: Failed constexpr"); + + constexpr glm::ivec1 N(glm::ivec4(1, 2, 3, 4)); + static_assert(glm::ivec1(1) == N, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec1 A(1); + static_assert(A[0] == 1, "GLM: Failed constexpr"); + static_assert(glm::vec1(1.0f).x > 0.0f, "GLM: Failed constexpr"); + static_assert(glm::vec1::length() == 1, "GLM: Failed constexpr"); + } + + { + constexpr glm::bvec1 A1(true); + constexpr glm::bvec1 A2(true); + constexpr glm::bvec1 B1(false); + constexpr glm::bvec1 B2(false); + static_assert(A1 == A2 && B1 == B2, "GLM: Failed constexpr"); + static_assert(A1 == A2 || B1 == B2, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec1 A(1); + constexpr glm::ivec1 B = A + 1; + constexpr glm::ivec1 C(3); + static_assert(A + B == C, "GLM: Failed constexpr"); + + constexpr glm::ivec1 D = +A; + static_assert(D == A, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec1 A(3); + constexpr glm::ivec1 B = A - 1; + constexpr glm::ivec1 C(1); + static_assert(A - B == C, "GLM: Failed constexpr"); + + constexpr glm::ivec1 D = -A; + static_assert(-D == A, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec1 A(3); + constexpr glm::ivec1 B = A * 1; + static_assert(A == B, "GLM: Failed constexpr"); + + constexpr glm::ivec1 C(1); + static_assert(B * C == A, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec1 A(3); + constexpr glm::ivec1 B = A / 1; + static_assert(A == B, "GLM: Failed constexpr"); + + constexpr glm::ivec1 C(1); + static_assert(B / C == A, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec1 A(3); + constexpr glm::ivec1 B = A % 2; + constexpr glm::ivec1 C(1); + static_assert(B == C, "GLM: Failed constexpr"); + + constexpr glm::ivec1 D(2); + static_assert(A % D == C, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec1 A(1); + constexpr glm::ivec1 B = A & 1; + static_assert(A == B, "GLM: Failed constexpr"); + + constexpr glm::ivec1 C(1); + static_assert(A == (A & C), "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec1 A(1); + constexpr glm::ivec1 B = A | 1; + static_assert(A == B, "GLM: Failed constexpr"); + + constexpr glm::ivec1 C(1); + static_assert(A == (A | C), "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec1 A(1); + constexpr glm::ivec1 B = A ^ 0; + static_assert(A == B, "GLM: Failed constexpr"); + + constexpr glm::ivec1 C(0); + static_assert(A == (A ^ C), "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec1 A(1); + constexpr glm::ivec1 B = A << 1; + static_assert(B == glm::ivec1(2), "GLM: Failed constexpr"); + + constexpr glm::ivec1 C(1); + static_assert(B == (A << C), "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec1 A(2); + constexpr glm::ivec1 B = A >> 1; + static_assert(B == glm::ivec1(1), "GLM: Failed constexpr"); + + constexpr glm::ivec1 C(1); + static_assert(B == A >> C, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec1 A(~0); + constexpr glm::ivec1 B = ~A; + static_assert(A == ~B, "GLM: Failed constexpr"); + } + + return Error; +} + +static int test_vec2() +{ + int Error = 0; + + { + constexpr glm::bvec2 B(true); + constexpr bool A = glm::all(B); + static_assert(A, "GLM: Failed constexpr"); + + constexpr glm::bvec2 D(true, false); + constexpr bool C = glm::any(D); + static_assert(C, "GLM: Failed constexpr"); + } + + { + constexpr glm::bvec2 C(true); + constexpr glm::bvec2 B(true, false); + static_assert(glm::any(glm::equal(C, B)), "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec2 O(glm::ivec1(1)); + static_assert(glm::ivec2(1) == O, "GLM: Failed constexpr"); + + constexpr glm::ivec2 A(1); + static_assert(glm::ivec2(1) == A, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec2 F(glm::ivec1(1), glm::ivec1(2)); + static_assert(glm::ivec2(1, 2) == F, "GLM: Failed constexpr"); + + constexpr glm::ivec2 G(1, glm::ivec1(2)); + static_assert(glm::ivec2(1, 2) == G, "GLM: Failed constexpr"); + + constexpr glm::ivec2 H(glm::ivec1(1), 2); + static_assert(glm::ivec2(1, 2) == H, "GLM: Failed constexpr"); + + constexpr glm::ivec2 I(1, 2); + static_assert(glm::ivec2(1, 2) == I, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec2 L(glm::ivec2(1, 2)); + static_assert(glm::ivec2(1, 2) == L, "GLM: Failed constexpr"); + + constexpr glm::ivec2 M(glm::ivec3(1, 2, 3)); + static_assert(glm::ivec2(1, 2) == M, "GLM: Failed constexpr"); + + constexpr glm::ivec2 N(glm::ivec4(1, 2, 3, 4)); + static_assert(glm::ivec2(1, 2) == N, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec2 A(1); + static_assert(A[0] == 1, "GLM: Failed constexpr"); + static_assert(glm::vec2(1.0f).x > 0.0f, "GLM: Failed constexpr"); + static_assert(glm::vec2(1.0f, -1.0f).x > 0.0f, "GLM: Failed constexpr"); + static_assert(glm::vec2(1.0f, -1.0f).y < 0.0f, "GLM: Failed constexpr"); + static_assert(glm::vec2::length() == 2, "GLM: Failed constexpr"); + } + + { + constexpr glm::bvec2 A1(true); + constexpr glm::bvec2 A2(true); + constexpr glm::bvec2 B1(false); + constexpr glm::bvec2 B2(false); + static_assert(A1 == A2 && B1 == B2, "GLM: Failed constexpr"); + static_assert(A1 == A2 || B1 == B2, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec2 A(1); + constexpr glm::ivec2 B = A + 1; + constexpr glm::ivec2 C(3); + static_assert(A + B == C, "GLM: Failed constexpr"); + + constexpr glm::ivec2 D = +A; + static_assert(D == A, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec2 A(3); + constexpr glm::ivec2 B = A - 1; + constexpr glm::ivec2 C(1); + static_assert(A - B == C, "GLM: Failed constexpr"); + + constexpr glm::ivec2 D = -A; + static_assert(-D == A, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec2 A(3); + constexpr glm::ivec2 B = A * 1; + static_assert(A == B, "GLM: Failed constexpr"); + + constexpr glm::ivec2 C(1); + static_assert(B * C == A, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec2 A(3); + constexpr glm::ivec2 B = A / 1; + static_assert(A == B, "GLM: Failed constexpr"); + + constexpr glm::ivec2 C(1); + static_assert(B / C == A, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec2 A(3); + constexpr glm::ivec2 B = A % 2; + constexpr glm::ivec2 C(1); + static_assert(B == C, "GLM: Failed constexpr"); + + constexpr glm::ivec1 D(2); + static_assert(A % D == C, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec2 A(1); + constexpr glm::ivec2 B = A & 1; + static_assert(A == B, "GLM: Failed constexpr"); + + constexpr glm::ivec1 C(1); + static_assert(A == (A & C), "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec2 A(1); + constexpr glm::ivec2 B = A | 1; + static_assert(A == B, "GLM: Failed constexpr"); + + constexpr glm::ivec1 C(1); + static_assert(A == (A | C), "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec2 A(1); + constexpr glm::ivec2 B = A ^ 0; + static_assert(A == B, "GLM: Failed constexpr"); + + constexpr glm::ivec1 C(0); + static_assert(A == (A ^ C), "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec2 A(1); + constexpr glm::ivec2 B = A << 1; + static_assert(B == glm::ivec2(2), "GLM: Failed constexpr"); + + constexpr glm::ivec1 C(1); + static_assert(B == (A << C), "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec2 A(2); + constexpr glm::ivec2 B = A >> 1; + static_assert(B == glm::ivec2(1), "GLM: Failed constexpr"); + + constexpr glm::ivec1 C(1); + static_assert(B == A >> C, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec2 A(~0); + constexpr glm::ivec2 B = ~A; + static_assert(A == ~B, "GLM: Failed constexpr"); + } + + return Error; +} + +static int test_vec3() +{ + int Error = 0; + + { + constexpr glm::bvec3 B(true); + constexpr bool A = glm::all(B); + static_assert(A, "GLM: Failed constexpr"); + + constexpr glm::bvec3 D(true, false, true); + constexpr bool C = glm::any(D); + static_assert(C, "GLM: Failed constexpr"); + } + + { + constexpr glm::bvec3 C(true); + constexpr glm::bvec3 B(true, false, true); + static_assert(glm::any(glm::equal(C, B)), "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec3 O(glm::ivec1(1)); + static_assert(glm::ivec3(1) == O, "GLM: Failed constexpr"); + + constexpr glm::ivec3 A(1); + static_assert(glm::ivec3(1) == A, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec3 B(glm::ivec2(1, 2), 3); + static_assert(glm::ivec3(1, 2, 3) == B, "GLM: Failed constexpr"); + + constexpr glm::ivec3 C(1, glm::ivec2(2, 3)); + static_assert(glm::ivec3(1, 2, 3) == C, "GLM: Failed constexpr"); + + constexpr glm::ivec3 D(glm::ivec1(1), glm::ivec2(2, 3)); + static_assert(glm::ivec3(1, 2, 3) == D, "GLM: Failed constexpr"); + + constexpr glm::ivec3 E(glm::ivec2(1, 2), glm::ivec1(3)); + static_assert(glm::ivec3(1, 2, 3) == E, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec3 F(glm::ivec1(1), glm::ivec1(2), glm::ivec1(3)); + static_assert(glm::ivec3(1, 2, 3) == F, "GLM: Failed constexpr"); + + constexpr glm::ivec3 G(1, glm::ivec1(2), glm::ivec1(3)); + static_assert(glm::ivec3(1, 2, 3) == G, "GLM: Failed constexpr"); + + constexpr glm::ivec3 H(glm::ivec1(1), 2, glm::ivec1(3)); + static_assert(glm::ivec3(1, 2, 3) == H, "GLM: Failed constexpr"); + + constexpr glm::ivec3 I(1, 2, glm::ivec1(3)); + static_assert(glm::ivec3(1, 2, 3) == I, "GLM: Failed constexpr"); + + constexpr glm::ivec3 J(glm::ivec1(1), glm::ivec1(2), 3); + static_assert(glm::ivec3(1, 2, 3) == J, "GLM: Failed constexpr"); + + constexpr glm::ivec3 K(1, glm::ivec1(2), 3); + static_assert(glm::ivec3(1, 2, 3) == K, "GLM: Failed constexpr"); + + constexpr glm::ivec3 L(glm::ivec1(1), 2, 3); + static_assert(glm::ivec3(1, 2, 3) == L, "GLM: Failed constexpr"); + + constexpr glm::ivec3 M(1, 2, 3); + static_assert(glm::ivec3(1, 2, 3) == M, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec3 N(glm::ivec4(1, 2, 3, 4)); + static_assert(glm::ivec3(1, 2, 3) == N, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec3 const A(1); + static_assert(A[0] == 1, "GLM: Failed constexpr"); + static_assert(glm::vec3(1.0f).x > 0.0f, "GLM: Failed constexpr"); + static_assert(glm::vec3(1.0f, -1.0f, -1.0f).x > 0.0f, "GLM: Failed constexpr"); + static_assert(glm::vec3(1.0f, -1.0f, -1.0f).y < 0.0f, "GLM: Failed constexpr"); + static_assert(glm::vec3::length() == 3, "GLM: Failed constexpr"); + } + + { + constexpr glm::bvec3 A1(true); + constexpr glm::bvec3 A2(true); + constexpr glm::bvec3 B1(false); + constexpr glm::bvec3 B2(false); + static_assert(A1 == A2 && B1 == B2, "GLM: Failed constexpr"); + static_assert(A1 == A2 || B1 == B2, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec3 A(1); + constexpr glm::ivec3 B = A + 1; + constexpr glm::ivec3 C(3); + static_assert(A + B == C, "GLM: Failed constexpr"); + + constexpr glm::ivec3 D = +A; + static_assert(D == A, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec3 A(3); + constexpr glm::ivec3 B = A - 1; + constexpr glm::ivec3 C(1); + static_assert(A - B == C, "GLM: Failed constexpr"); + + constexpr glm::ivec3 D = -A; + static_assert(-D == A, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec3 A(3); + constexpr glm::ivec3 B = A * 1; + static_assert(A == B, "GLM: Failed constexpr"); + + constexpr glm::ivec3 C(1); + static_assert(B * C == A, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec3 A(3); + constexpr glm::ivec3 B = A / 1; + static_assert(A == B, "GLM: Failed constexpr"); + + constexpr glm::ivec3 C(1); + static_assert(B / C == A, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec3 A(3); + constexpr glm::ivec3 B = A % 2; + constexpr glm::ivec3 C(1); + static_assert(B == C, "GLM: Failed constexpr"); + + constexpr glm::ivec1 D(2); + static_assert(A % D == C, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec3 A(1); + constexpr glm::ivec3 B = A & 1; + static_assert(A == B, "GLM: Failed constexpr"); + + constexpr glm::ivec1 C(1); + static_assert(A == (A & C), "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec3 A(1); + constexpr glm::ivec3 B = A | 1; + static_assert(A == B, "GLM: Failed constexpr"); + + constexpr glm::ivec1 C(1); + static_assert(A == (A | C), "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec3 A(1); + constexpr glm::ivec3 B = A ^ 0; + static_assert(A == B, "GLM: Failed constexpr"); + + constexpr glm::ivec1 C(0); + static_assert(A == (A ^ C), "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec3 A(1); + constexpr glm::ivec3 B = A << 1; + static_assert(B == glm::ivec3(2), "GLM: Failed constexpr"); + + constexpr glm::ivec1 C(1); + static_assert(B == (A << C), "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec3 A(2); + constexpr glm::ivec3 B = A >> 1; + static_assert(B == glm::ivec3(1), "GLM: Failed constexpr"); + + constexpr glm::ivec1 C(1); + static_assert(B == A >> C, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec3 A(~0); + constexpr glm::ivec3 B = ~A; + static_assert(A == ~B, "GLM: Failed constexpr"); + } + + return Error; +} + +static int test_vec4() +{ + int Error = 0; + + { + constexpr glm::bvec4 B(true); + constexpr bool A = glm::all(B); + static_assert(A, "GLM: Failed constexpr"); + + constexpr glm::bvec4 D(true, false, true, false); + constexpr bool C = glm::any(D); + static_assert(C, "GLM: Failed constexpr"); + } + + { + constexpr glm::bvec4 C(true); + constexpr glm::bvec4 B(true, false, true, false); + static_assert(glm::any(glm::equal(C, B)), "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec4 O(glm::ivec4(1)); + static_assert(glm::ivec4(1) == O, "GLM: Failed constexpr"); + + constexpr glm::ivec4 A(1); + static_assert(glm::ivec4(1) == A, "GLM: Failed constexpr"); + + constexpr glm::ivec4 N(glm::ivec4(1, 2, 3, 4)); + static_assert(glm::ivec4(1, 2, 3, 4) == N, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec4 A(glm::ivec3(1, 2, 3), 4); + static_assert(glm::ivec4(1, 2, 3, 4) == A, "GLM: Failed constexpr"); + + constexpr glm::ivec4 B(glm::ivec2(1, 2), glm::ivec2(3, 4)); + static_assert(glm::ivec4(1, 2, 3, 4) == B, "GLM: Failed constexpr"); + + constexpr glm::ivec4 C(1, glm::ivec3(2, 3, 4)); + static_assert(glm::ivec4(1, 2, 3, 4) == C, "GLM: Failed constexpr"); + + constexpr glm::ivec4 D(glm::ivec1(1), glm::ivec2(2, 3), glm::ivec1(4)); + static_assert(glm::ivec4(1, 2, 3, 4) == D, "GLM: Failed constexpr"); + + constexpr glm::ivec4 E(glm::ivec2(1, 2), glm::ivec1(3), glm::ivec1(4)); + static_assert(glm::ivec4(1, 2, 3, 4) == E, "GLM: Failed constexpr"); + + constexpr glm::ivec4 F(glm::ivec1(1), glm::ivec1(2), glm::ivec2(3, 4)); + static_assert(glm::ivec4(1, 2, 3, 4) == F, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec4 A(1); + static_assert(A[0] == 1, "GLM: Failed constexpr"); + static_assert(glm::ivec4(1).x > 0, "GLM: Failed constexpr"); + static_assert(glm::ivec4(1.0f, -1.0f, -1.0f, 1.0f).x > 0, "GLM: Failed constexpr"); + static_assert(glm::ivec4(1.0f, -1.0f, -1.0f, 1.0f).y < 0, "GLM: Failed constexpr"); + static_assert(glm::ivec4::length() == 4, "GLM: Failed constexpr"); + } + + { + constexpr glm::bvec4 A1(true); + constexpr glm::bvec4 A2(true); + constexpr glm::bvec4 B1(false); + constexpr glm::bvec4 B2(false); + static_assert(A1 == A2 && B1 == B2, "GLM: Failed constexpr"); + static_assert(A1 == A2 || B1 == B2, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec4 A(1); + constexpr glm::ivec4 B = A + 1; + constexpr glm::ivec4 C(3); + static_assert(A + B == C, "GLM: Failed constexpr"); + + constexpr glm::ivec4 D = +A; + static_assert(D == A, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec4 A(3); + constexpr glm::ivec4 B = A - 1; + constexpr glm::ivec4 C(1); + static_assert(A - B == C, "GLM: Failed constexpr"); + + constexpr glm::ivec4 D = -A; + static_assert(-D == A, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec4 A(3); + constexpr glm::ivec4 B = A * 1; + static_assert(A == B, "GLM: Failed constexpr"); + + constexpr glm::ivec4 C(1); + static_assert(B * C == A, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec4 A(3); + constexpr glm::ivec4 B = A / 1; + static_assert(A == B, "GLM: Failed constexpr"); + + constexpr glm::ivec4 C(1); + static_assert(B / C == A, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec4 A(3); + constexpr glm::ivec4 B = A % 2; + constexpr glm::ivec4 C(1); + static_assert(B == C, "GLM: Failed constexpr"); + + constexpr glm::ivec1 D(2); + static_assert(A % D == C, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec4 A(1); + constexpr glm::ivec4 B = A & 1; + static_assert(A == B, "GLM: Failed constexpr"); + + constexpr glm::ivec1 C(1); + static_assert(A == (A & C), "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec4 A(1); + constexpr glm::ivec4 B = A | 1; + static_assert(A == B, "GLM: Failed constexpr"); + + constexpr glm::ivec1 C(1); + static_assert(A == (A | C), "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec4 A(1); + constexpr glm::ivec4 B = A ^ 0; + static_assert(A == B, "GLM: Failed constexpr"); + + constexpr glm::ivec1 C(0); + static_assert(A == (A ^ C), "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec4 A(1); + constexpr glm::ivec4 B = A << 1; + static_assert(B == glm::ivec4(2), "GLM: Failed constexpr"); + + constexpr glm::ivec1 C(1); + static_assert(B == (A << C), "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec4 A(2); + constexpr glm::ivec4 B = A >> 1; + static_assert(B == glm::ivec4(1), "GLM: Failed constexpr"); + + constexpr glm::ivec1 C(1); + static_assert(B == A >> C, "GLM: Failed constexpr"); + } + + { + constexpr glm::ivec4 A(~0); + constexpr glm::ivec4 B = ~A; + static_assert(A == ~B, "GLM: Failed constexpr"); + } + + return Error; +} + +static int test_quat() +{ + int Error = 0; + + { + static_assert(glm::quat::length() == 4, "GLM: Failed constexpr"); + static_assert(glm::quat(1.0f, glm::vec3(0.0f)).w > 0.0f, "GLM: Failed constexpr"); + static_assert(glm::quat(1.0f, 0.0f, 0.0f, 0.0f).w > 0.0f, "GLM: Failed constexpr"); + + glm::quat constexpr Q = glm::identity(); + static_assert(Q.x - glm::quat(1.0f, glm::vec3(0.0f)).x <= glm::epsilon(), "GLM: Failed constexpr"); + } + + return Error; +} + +static int test_mat2x2() +{ + int Error = 0; + + static_assert(glm::mat2x2::length() == 2, "GLM: Failed constexpr"); + + return Error; +} + +#endif//GLM_CONFIG_CONSTEXP == GLM_ENABLE + +int main() +{ + int Error = 0; + +# if GLM_CONFIG_CONSTEXP == GLM_ENABLE + Error += test_vec1(); + Error += test_vec2(); + Error += test_vec3(); + Error += test_vec4(); + Error += test_quat(); + Error += test_mat2x2(); +# endif//GLM_CONFIG_CONSTEXP == GLM_ENABLE + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_cpp_defaulted_ctor.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_cpp_defaulted_ctor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..07afd9cd559399d7d501b61f5c565ef8e48a57d6 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_cpp_defaulted_ctor.cpp @@ -0,0 +1,145 @@ +#include + +#if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_ENABLE + +#include +#include +#include +#include +#include +#include + +static int test_vec_memcpy() +{ + int Error = 0; + + { + glm::ivec1 const A = glm::ivec1(76); + glm::ivec1 B; + std::memcpy(&B, &A, sizeof(glm::ivec1)); + Error += B == A ? 0 : 1; + } + + { + glm::ivec2 const A = glm::ivec2(76); + glm::ivec2 B; + std::memcpy(&B, &A, sizeof(glm::ivec2)); + Error += B == A ? 0 : 1; + } + + { + glm::ivec3 const A = glm::ivec3(76); + glm::ivec3 B; + std::memcpy(&B, &A, sizeof(glm::ivec3)); + Error += B == A ? 0 : 1; + } + + { + glm::ivec4 const A = glm::ivec4(76); + glm::ivec4 B; + std::memcpy(&B, &A, sizeof(glm::ivec4)); + Error += B == A ? 0 : 1; + } + + return Error; +} + +static int test_mat_memcpy() +{ + int Error = 0; + + { + glm::mat2x2 const A = glm::mat2x2(76); + glm::mat2x2 B; + std::memcpy(&B, &A, sizeof(glm::mat2x2)); + Error += glm::all(glm::equal(B, A, glm::epsilon())) ? 0 : 1; + } + + { + glm::mat2x3 const A = glm::mat2x3(76); + glm::mat2x3 B; + std::memcpy(&B, &A, sizeof(glm::mat2x3)); + Error += glm::all(glm::equal(B, A, glm::epsilon())) ? 0 : 1; + } + + { + glm::mat2x4 const A = glm::mat2x4(76); + glm::mat2x4 B; + std::memcpy(&B, &A, sizeof(glm::mat2x4)); + Error += glm::all(glm::equal(B, A, glm::epsilon())) ? 0 : 1; + } + + { + glm::mat3x2 const A = glm::mat3x2(76); + glm::mat3x2 B; + std::memcpy(&B, &A, sizeof(glm::mat3x2)); + Error += glm::all(glm::equal(B, A, glm::epsilon())) ? 0 : 1; + } + + { + glm::mat3x3 const A = glm::mat3x3(76); + glm::mat3x3 B; + std::memcpy(&B, &A, sizeof(glm::mat3x3)); + Error += glm::all(glm::equal(B, A, glm::epsilon())) ? 0 : 1; + } + + { + glm::mat3x4 const A = glm::mat3x4(76); + glm::mat3x4 B; + std::memcpy(&B, &A, sizeof(glm::mat3x4)); + Error += glm::all(glm::equal(B, A, glm::epsilon())) ? 0 : 1; + } + + { + glm::mat4x2 const A = glm::mat4x2(76); + glm::mat4x2 B; + std::memcpy(&B, &A, sizeof(glm::mat4x2)); + Error += glm::all(glm::equal(B, A, glm::epsilon())) ? 0 : 1; + } + + { + glm::mat4x3 const A = glm::mat4x3(76); + glm::mat4x3 B; + std::memcpy(&B, &A, sizeof(glm::mat4x3)); + Error += glm::all(glm::equal(B, A, glm::epsilon())) ? 0 : 1; + } + + { + glm::mat4x4 const A = glm::mat4x4(76); + glm::mat4x4 B; + std::memcpy(&B, &A, sizeof(glm::mat4x4)); + Error += glm::all(glm::equal(B, A, glm::epsilon())) ? 0 : 1; + } + + return Error; +} + +static int test_quat_memcpy() +{ + int Error = 0; + + { + glm::quat const A = glm::quat(1, 0, 0, 0); + glm::quat B; + std::memcpy(&B, &A, sizeof(glm::quat)); + Error += glm::all(glm::equal(B, A, glm::epsilon())) ? 0 : 1; + } + + return Error; +} + +#endif//GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_ENABLE + +int main() +{ + int Error = 0; + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_ENABLE + Error += test_vec_memcpy(); + Error += test_mat_memcpy(); + Error += test_quat_memcpy(); +# endif//GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_ENABLE + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_aligned_gentypes.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_aligned_gentypes.cpp new file mode 100644 index 0000000000000000000000000000000000000000..70713c4b19f63be1fa82f7dedf2849f2f7c26a60 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_aligned_gentypes.cpp @@ -0,0 +1,10 @@ +#include +#include + +int main() +{ + int Error = 0; + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_arch_unknown.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_arch_unknown.cpp new file mode 100644 index 0000000000000000000000000000000000000000..45b51bf00cad9b98243f310f910e7d4d6d9b9b9a --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_arch_unknown.cpp @@ -0,0 +1,14 @@ +#ifndef GLM_FORCE_ARCH_UNKNOWN +# define GLM_FORCE_ARCH_UNKNOWN +#endif + +#include +#include + +int main() +{ + int Error = 0; + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_compiler_unknown.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_compiler_unknown.cpp new file mode 100644 index 0000000000000000000000000000000000000000..44d7fc336559e9f4b91eaed3d7edf41c9726ec6e --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_compiler_unknown.cpp @@ -0,0 +1,14 @@ +#ifndef GLM_FORCE_COMPILER_UNKNOWN +# define GLM_FORCE_COMPILER_UNKNOWN +#endif + +#include +#include + +int main() +{ + int Error = 0; + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_ctor_init.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_ctor_init.cpp new file mode 100644 index 0000000000000000000000000000000000000000..298b7edc71948199d8ba01b7ad13b9c533ce389b --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_ctor_init.cpp @@ -0,0 +1,139 @@ +#define GLM_FORCE_CTOR_INIT + +#include +#include + +static int test_vec() +{ + int Error = 0; + + glm::vec1 V1; + Error += glm::all(glm::equal(V1, glm::vec1(0), glm::epsilon())) ? 0 : 1; + + glm::dvec1 U1; + Error += glm::all(glm::equal(U1, glm::dvec1(0), glm::epsilon())) ? 0 : 1; + + glm::vec2 V2; + Error += glm::all(glm::equal(V2, glm::vec2(0, 0), glm::epsilon())) ? 0 : 1; + + glm::dvec2 U2; + Error += glm::all(glm::equal(U2, glm::dvec2(0, 0), glm::epsilon())) ? 0 : 1; + + glm::vec3 V3; + Error += glm::all(glm::equal(V3, glm::vec3(0, 0, 0), glm::epsilon())) ? 0 : 1; + + glm::dvec3 U3; + Error += glm::all(glm::equal(U3, glm::dvec3(0, 0, 0), glm::epsilon())) ? 0 : 1; + + glm::vec4 V4; + Error += glm::all(glm::equal(V4, glm::vec4(0, 0, 0, 0), glm::epsilon())) ? 0 : 1; + + glm::dvec4 U4; + Error += glm::all(glm::equal(U4, glm::dvec4(0, 0, 0, 0), glm::epsilon())) ? 0 : 1; + + return Error; +} + +static int test_mat() +{ + int Error = 0; + + { + glm::mat2x2 F; + Error += glm::all(glm::equal(F, glm::mat2x2(1), glm::epsilon())) ? 0 : 1; + + glm::dmat2x2 D; + Error += glm::all(glm::equal(D, glm::dmat2x2(1), glm::epsilon())) ? 0 : 1; + } + + { + glm::mat2x3 F; + Error += glm::all(glm::equal(F, glm::mat2x3(1), glm::epsilon())) ? 0 : 1; + + glm::dmat2x3 D; + Error += glm::all(glm::equal(D, glm::dmat2x3(1), glm::epsilon())) ? 0 : 1; + } + + { + glm::mat2x4 F; + Error += glm::all(glm::equal(F, glm::mat2x4(1), glm::epsilon())) ? 0 : 1; + + glm::dmat2x4 D; + Error += glm::all(glm::equal(D, glm::dmat2x4(1), glm::epsilon())) ? 0 : 1; + } + + { + glm::mat3x2 F; + Error += glm::all(glm::equal(F, glm::mat3x2(1), glm::epsilon())) ? 0 : 1; + + glm::dmat3x2 D; + Error += glm::all(glm::equal(D, glm::dmat3x2(1), glm::epsilon())) ? 0 : 1; + } + + { + glm::mat3x3 F; + Error += glm::all(glm::equal(F, glm::mat3x3(1), glm::epsilon())) ? 0 : 1; + + glm::dmat3x3 D; + Error += glm::all(glm::equal(D, glm::dmat3x3(1), glm::epsilon())) ? 0 : 1; + } + + { + glm::mat3x4 F; + Error += glm::all(glm::equal(F, glm::mat3x4(1), glm::epsilon())) ? 0 : 1; + + glm::dmat3x4 D; + Error += glm::all(glm::equal(D, glm::dmat3x4(1), glm::epsilon())) ? 0 : 1; + } + + { + glm::mat4x2 F; + Error += glm::all(glm::equal(F, glm::mat4x2(1), glm::epsilon())) ? 0 : 1; + + glm::dmat4x2 D; + Error += glm::all(glm::equal(D, glm::dmat4x2(1), glm::epsilon())) ? 0 : 1; + } + + { + glm::mat4x3 F; + Error += glm::all(glm::equal(F, glm::mat4x3(1), glm::epsilon())) ? 0 : 1; + + glm::dmat4x3 D; + Error += glm::all(glm::equal(D, glm::dmat4x3(1), glm::epsilon())) ? 0 : 1; + } + + { + glm::mat4x4 F; + Error += glm::all(glm::equal(F, glm::mat4x4(1), glm::epsilon())) ? 0 : 1; + + glm::dmat4x4 D; + Error += glm::all(glm::equal(D, glm::dmat4x4(1), glm::epsilon())) ? 0 : 1; + } + + return Error; +} + +static int test_qua() +{ + int Error = 0; + + glm::quat F; + Error += glm::all(glm::equal(F, glm::quat(1, 0, 0, 0), glm::epsilon())) ? 0 : 1; + + glm::dquat D; + Error += glm::all(glm::equal(D, glm::dquat(1, 0, 0, 0), glm::epsilon())) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_vec(); + Error += test_mat(); + Error += test_qua(); + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_cxx03.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_cxx03.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fc6e9c5dc0bf396e72af2f28c14c47606fd11a42 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_cxx03.cpp @@ -0,0 +1,14 @@ +#ifndef GLM_FORCE_CXX03 +# define GLM_FORCE_CXX03 +#endif + +#include +#include + +int main() +{ + int Error = 0; + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_cxx98.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_cxx98.cpp new file mode 100644 index 0000000000000000000000000000000000000000..42a5c259f7e36fe56e513f2f4cf23c7bda1656ec --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_cxx98.cpp @@ -0,0 +1,14 @@ +#ifndef GLM_FORCE_CXX98 +# define GLM_FORCE_CXX98 +#endif + +#include +#include + +int main() +{ + int Error = 0; + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_cxx_unknown.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_cxx_unknown.cpp new file mode 100644 index 0000000000000000000000000000000000000000..62299d6a78a5042b3ab1114f20344034828ca780 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_cxx_unknown.cpp @@ -0,0 +1,14 @@ +#ifndef GLM_FORCE_CXX_UNKNOWN +# define GLM_FORCE_CXX_UNKNOWN +#endif + +#include +#include + +int main() +{ + int Error = 0; + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_depth_zero_to_one.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_depth_zero_to_one.cpp new file mode 100644 index 0000000000000000000000000000000000000000..23b361591c3d54cc52aed1e4a7259bd5869784a9 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_depth_zero_to_one.cpp @@ -0,0 +1,12 @@ +#define GLM_FORCE_DEPTH_ZERO_TO_ONE + +#include +#include + +int main() +{ + int Error = 0; + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_explicit_ctor.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_explicit_ctor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7af5b79f3165c4cdaf780f582337d2eebad1ae27 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_explicit_ctor.cpp @@ -0,0 +1,17 @@ +#define GLM_FORCE_EXPLICIT_CTOR + +#include +#include + +int main() +{ + int Error = 0; + + glm::ivec4 B(1); + Error += B == glm::ivec4(1) ? 0 : 1; + + //glm::vec4 A = B; + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_inline.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_inline.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cd23fd9844537db6c4fdedb6178e9c1f6753e81b --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_inline.cpp @@ -0,0 +1,12 @@ +#define GLM_FORCE_INLINE + +#include +#include + +int main() +{ + int Error = 0; + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_left_handed.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_left_handed.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b7ec31b5ac6726f5e17e31eb6da3eefd8595a0b7 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_left_handed.cpp @@ -0,0 +1,12 @@ +#define GLM_FORCE_LEFT_HANDED + +#include +#include + +int main() +{ + int Error = 0; + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_platform_unknown.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_platform_unknown.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fb7fa75795e4f604fff0bb04e3bab9d03b7857cd --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_platform_unknown.cpp @@ -0,0 +1,14 @@ +#ifndef GLM_FORCE_PLATFORM_UNKNOWN +# define GLM_FORCE_PLATFORM_UNKNOWN +#endif + +#include +#include + +int main() +{ + int Error = 0; + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_pure.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_pure.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a32a4edea152faaeeed19c84577329f30bb5b1eb --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_pure.cpp @@ -0,0 +1,434 @@ +#ifndef GLM_FORCE_PURE +# define GLM_FORCE_PURE +#endif//GLM_FORCE_PURE +#define GLM_FORCE_DEFAULT_ALIGNED_GENTYPES +#define GLM_FORCE_SWIZZLE +#include +#include +#include +#include +#include +#include +#include + +static int test_vec4_ctor() +{ + int Error = 0; + + { + glm::ivec4 A(1, 2, 3, 4); + glm::ivec4 B(A); + Error += glm::all(glm::equal(A, B)) ? 0 : 1; + } + +# if GLM_HAS_TRIVIAL_QUERIES + // Error += std::is_trivially_default_constructible::value ? 0 : 1; + // Error += std::is_trivially_copy_assignable::value ? 0 : 1; + Error += std::is_trivially_copyable::value ? 0 : 1; + Error += std::is_trivially_copyable::value ? 0 : 1; + Error += std::is_trivially_copyable::value ? 0 : 1; + Error += std::is_trivially_copyable::value ? 0 : 1; + + Error += std::is_copy_constructible::value ? 0 : 1; +# endif + +#if GLM_HAS_INITIALIZER_LISTS + { + glm::vec4 a{ 0, 1, 2, 3 }; + std::vector v = { + {0, 1, 2, 3}, + {4, 5, 6, 7}, + {8, 9, 0, 1}}; + } + + { + glm::dvec4 a{ 0, 1, 2, 3 }; + std::vector v = { + {0, 1, 2, 3}, + {4, 5, 6, 7}, + {8, 9, 0, 1}}; + } +#endif + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + { + glm::ivec4 A = glm::vec4(1.0f, 2.0f, 3.0f, 4.0f); + glm::ivec4 B = A.xyzw; + glm::ivec4 C(A.xyzw); + glm::ivec4 D(A.xyzw()); + glm::ivec4 E(A.x, A.yzw); + glm::ivec4 F(A.x, A.yzw()); + glm::ivec4 G(A.xyz, A.w); + glm::ivec4 H(A.xyz(), A.w); + glm::ivec4 I(A.xy, A.zw); + glm::ivec4 J(A.xy(), A.zw()); + glm::ivec4 K(A.x, A.y, A.zw); + glm::ivec4 L(A.x, A.yz, A.w); + glm::ivec4 M(A.xy, A.z, A.w); + + Error += glm::all(glm::equal(A, B)) ? 0 : 1; + Error += glm::all(glm::equal(A, C)) ? 0 : 1; + Error += glm::all(glm::equal(A, D)) ? 0 : 1; + Error += glm::all(glm::equal(A, E)) ? 0 : 1; + Error += glm::all(glm::equal(A, F)) ? 0 : 1; + Error += glm::all(glm::equal(A, G)) ? 0 : 1; + Error += glm::all(glm::equal(A, H)) ? 0 : 1; + Error += glm::all(glm::equal(A, I)) ? 0 : 1; + Error += glm::all(glm::equal(A, J)) ? 0 : 1; + Error += glm::all(glm::equal(A, K)) ? 0 : 1; + Error += glm::all(glm::equal(A, L)) ? 0 : 1; + Error += glm::all(glm::equal(A, M)) ? 0 : 1; + } +# endif + +# if GLM_CONFIG_SWIZZLE + { + glm::ivec4 A = glm::vec4(1.0f, 2.0f, 3.0f, 4.0f); + glm::ivec4 B = A.xyzw(); + glm::ivec4 C(A.xyzw()); + glm::ivec4 D(A.xyzw()); + glm::ivec4 E(A.x, A.yzw()); + glm::ivec4 F(A.x, A.yzw()); + glm::ivec4 G(A.xyz(), A.w); + glm::ivec4 H(A.xyz(), A.w); + glm::ivec4 I(A.xy(), A.zw()); + glm::ivec4 J(A.xy(), A.zw()); + glm::ivec4 K(A.x, A.y, A.zw()); + glm::ivec4 L(A.x, A.yz(), A.w); + glm::ivec4 M(A.xy(), A.z, A.w); + + Error += glm::all(glm::equal(A, B)) ? 0 : 1; + Error += glm::all(glm::equal(A, C)) ? 0 : 1; + Error += glm::all(glm::equal(A, D)) ? 0 : 1; + Error += glm::all(glm::equal(A, E)) ? 0 : 1; + Error += glm::all(glm::equal(A, F)) ? 0 : 1; + Error += glm::all(glm::equal(A, G)) ? 0 : 1; + Error += glm::all(glm::equal(A, H)) ? 0 : 1; + Error += glm::all(glm::equal(A, I)) ? 0 : 1; + Error += glm::all(glm::equal(A, J)) ? 0 : 1; + Error += glm::all(glm::equal(A, K)) ? 0 : 1; + Error += glm::all(glm::equal(A, L)) ? 0 : 1; + Error += glm::all(glm::equal(A, M)) ? 0 : 1; + } +# endif//GLM_CONFIG_SWIZZLE + + { + glm::ivec4 A(1); + glm::ivec4 B(1, 1, 1, 1); + + Error += A == B ? 0 : 1; + } + + { + std::vector Tests; + Tests.push_back(glm::ivec4(glm::ivec2(1, 2), 3, 4)); + Tests.push_back(glm::ivec4(1, glm::ivec2(2, 3), 4)); + Tests.push_back(glm::ivec4(1, 2, glm::ivec2(3, 4))); + Tests.push_back(glm::ivec4(glm::ivec3(1, 2, 3), 4)); + Tests.push_back(glm::ivec4(1, glm::ivec3(2, 3, 4))); + Tests.push_back(glm::ivec4(glm::ivec2(1, 2), glm::ivec2(3, 4))); + Tests.push_back(glm::ivec4(1, 2, 3, 4)); + Tests.push_back(glm::ivec4(glm::ivec4(1, 2, 3, 4))); + + for(std::size_t i = 0; i < Tests.size(); ++i) + Error += Tests[i] == glm::ivec4(1, 2, 3, 4) ? 0 : 1; + } + + return Error; +} + +static int test_bvec4_ctor() +{ + int Error = 0; + + glm::bvec4 const A(true); + glm::bvec4 const B(true); + glm::bvec4 const C(false); + glm::bvec4 const D = A && B; + glm::bvec4 const E = A && C; + glm::bvec4 const F = A || C; + + Error += D == glm::bvec4(true) ? 0 : 1; + Error += E == glm::bvec4(false) ? 0 : 1; + Error += F == glm::bvec4(true) ? 0 : 1; + + bool const G = A == C; + bool const H = A != C; + + Error += !G ? 0 : 1; + Error += H ? 0 : 1; + + return Error; +} + +static int test_vec4_operators() +{ + int Error = 0; + + { + glm::ivec4 A(1); + glm::ivec4 B(1); + bool R = A != B; + bool S = A == B; + + Error += (S && !R) ? 0 : 1; + } + + { + glm::vec4 const A(1.0f, 2.0f, 3.0f, 4.0f); + glm::vec4 const B(4.0f, 5.0f, 6.0f, 7.0f); + + glm::vec4 const C = A + B; + Error += glm::all(glm::equal(C, glm::vec4(5, 7, 9, 11), 0.001f)) ? 0 : 1; + + glm::vec4 D = B - A; + Error += glm::all(glm::equal(D, glm::vec4(3, 3, 3, 3), 0.001f)) ? 0 : 1; + + glm::vec4 E = A * B; + Error += glm::all(glm::equal(E, glm::vec4(4, 10, 18, 28), 0.001f)) ? 0 : 1; + + glm::vec4 F = B / A; + Error += glm::all(glm::equal(F, glm::vec4(4, 2.5, 2, 7.0f / 4.0f), 0.001f)) ? 0 : 1; + + glm::vec4 G = A + 1.0f; + Error += glm::all(glm::equal(G, glm::vec4(2, 3, 4, 5), 0.001f)) ? 0 : 1; + + glm::vec4 H = B - 1.0f; + Error += glm::all(glm::equal(H, glm::vec4(3, 4, 5, 6), 0.001f)) ? 0 : 1; + + glm::vec4 I = A * 2.0f; + Error += glm::all(glm::equal(I, glm::vec4(2, 4, 6, 8), 0.001f)) ? 0 : 1; + + glm::vec4 J = B / 2.0f; + Error += glm::all(glm::equal(J, glm::vec4(2, 2.5, 3, 3.5), 0.001f)) ? 0 : 1; + + glm::vec4 K = 1.0f + A; + Error += glm::all(glm::equal(K, glm::vec4(2, 3, 4, 5), 0.001f)) ? 0 : 1; + + glm::vec4 L = 1.0f - B; + Error += glm::all(glm::equal(L, glm::vec4(-3, -4, -5, -6), 0.001f)) ? 0 : 1; + + glm::vec4 M = 2.0f * A; + Error += glm::all(glm::equal(M, glm::vec4(2, 4, 6, 8), 0.001f)) ? 0 : 1; + + glm::vec4 const N = 2.0f / B; + Error += glm::all(glm::equal(N, glm::vec4(0.5, 2.0 / 5.0, 2.0 / 6.0, 2.0 / 7.0), 0.0001f)) ? 0 : 1; + } + + { + glm::ivec4 A(1.0f, 2.0f, 3.0f, 4.0f); + glm::ivec4 B(4.0f, 5.0f, 6.0f, 7.0f); + + A += B; + Error += A == glm::ivec4(5, 7, 9, 11) ? 0 : 1; + + A += 1; + Error += A == glm::ivec4(6, 8, 10, 12) ? 0 : 1; + } + { + glm::ivec4 A(1.0f, 2.0f, 3.0f, 4.0f); + glm::ivec4 B(4.0f, 5.0f, 6.0f, 7.0f); + + B -= A; + Error += B == glm::ivec4(3, 3, 3, 3) ? 0 : 1; + + B -= 1; + Error += B == glm::ivec4(2, 2, 2, 2) ? 0 : 1; + } + { + glm::ivec4 A(1.0f, 2.0f, 3.0f, 4.0f); + glm::ivec4 B(4.0f, 5.0f, 6.0f, 7.0f); + + A *= B; + Error += A == glm::ivec4(4, 10, 18, 28) ? 0 : 1; + + A *= 2; + Error += A == glm::ivec4(8, 20, 36, 56) ? 0 : 1; + } + { + glm::ivec4 A(1.0f, 2.0f, 3.0f, 4.0f); + glm::ivec4 B(4.0f, 4.0f, 6.0f, 8.0f); + + B /= A; + Error += B == glm::ivec4(4, 2, 2, 2) ? 0 : 1; + + B /= 2; + Error += B == glm::ivec4(2, 1, 1, 1) ? 0 : 1; + } + { + glm::ivec4 B(2); + + B /= B.y; + Error += B == glm::ivec4(1) ? 0 : 1; + } + + { + glm::ivec4 A(1.0f, 2.0f, 3.0f, 4.0f); + glm::ivec4 B = -A; + Error += B == glm::ivec4(-1.0f, -2.0f, -3.0f, -4.0f) ? 0 : 1; + } + + { + glm::ivec4 A(1.0f, 2.0f, 3.0f, 4.0f); + glm::ivec4 B = --A; + Error += B == glm::ivec4(0.0f, 1.0f, 2.0f, 3.0f) ? 0 : 1; + } + + { + glm::ivec4 A(1.0f, 2.0f, 3.0f, 4.0f); + glm::ivec4 B = A--; + Error += B == glm::ivec4(1.0f, 2.0f, 3.0f, 4.0f) ? 0 : 1; + Error += A == glm::ivec4(0.0f, 1.0f, 2.0f, 3.0f) ? 0 : 1; + } + + { + glm::ivec4 A(1.0f, 2.0f, 3.0f, 4.0f); + glm::ivec4 B = ++A; + Error += B == glm::ivec4(2.0f, 3.0f, 4.0f, 5.0f) ? 0 : 1; + } + + { + glm::ivec4 A(1.0f, 2.0f, 3.0f, 4.0f); + glm::ivec4 B = A++; + Error += B == glm::ivec4(1.0f, 2.0f, 3.0f, 4.0f) ? 0 : 1; + Error += A == glm::ivec4(2.0f, 3.0f, 4.0f, 5.0f) ? 0 : 1; + } + + return Error; +} + +static int test_vec4_equal() +{ + int Error = 0; + + { + glm::uvec4 const A(1, 2, 3, 4); + glm::uvec4 const B(1, 2, 3, 4); + Error += A == B ? 0 : 1; + Error += A != B ? 1 : 0; + } + + { + glm::ivec4 const A(1, 2, 3, 4); + glm::ivec4 const B(1, 2, 3, 4); + Error += A == B ? 0 : 1; + Error += A != B ? 1 : 0; + } + + return Error; +} + +static int test_vec4_size() +{ + int Error = 0; + + Error += sizeof(glm::vec4) == sizeof(glm::lowp_vec4) ? 0 : 1; + Error += sizeof(glm::vec4) == sizeof(glm::mediump_vec4) ? 0 : 1; + Error += sizeof(glm::vec4) == sizeof(glm::highp_vec4) ? 0 : 1; + Error += 16 == sizeof(glm::mediump_vec4) ? 0 : 1; + Error += sizeof(glm::dvec4) == sizeof(glm::lowp_dvec4) ? 0 : 1; + Error += sizeof(glm::dvec4) == sizeof(glm::mediump_dvec4) ? 0 : 1; + Error += sizeof(glm::dvec4) == sizeof(glm::highp_dvec4) ? 0 : 1; + Error += 32 == sizeof(glm::highp_dvec4) ? 0 : 1; + Error += glm::vec4().length() == 4 ? 0 : 1; + Error += glm::dvec4().length() == 4 ? 0 : 1; + + return Error; +} + +static int test_vec4_swizzle_partial() +{ + int Error = 0; + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + + glm::ivec4 A(1, 2, 3, 4); + + { + glm::ivec4 B(A.xy, A.zw); + Error += A == B ? 0 : 1; + } + { + glm::ivec4 B(A.xy, 3, 4); + Error += A == B ? 0 : 1; + } + { + glm::ivec4 B(1, A.yz, 4); + Error += A == B ? 0 : 1; + } + { + glm::ivec4 B(1, 2, A.zw); + Error += A == B ? 0 : 1; + } + + { + glm::ivec4 B(A.xyz, 4); + Error += A == B ? 0 : 1; + } + { + glm::ivec4 B(1, A.yzw); + Error += A == B ? 0 : 1; + } +# endif + + return Error; +} + +static int test_operator_increment() +{ + int Error(0); + + glm::ivec4 v0(1); + glm::ivec4 v1(v0); + glm::ivec4 v2(v0); + glm::ivec4 v3 = ++v1; + glm::ivec4 v4 = v2++; + + Error += glm::all(glm::equal(v0, v4)) ? 0 : 1; + Error += glm::all(glm::equal(v1, v2)) ? 0 : 1; + Error += glm::all(glm::equal(v1, v3)) ? 0 : 1; + + int i0(1); + int i1(i0); + int i2(i0); + int i3 = ++i1; + int i4 = i2++; + + Error += i0 == i4 ? 0 : 1; + Error += i1 == i2 ? 0 : 1; + Error += i1 == i3 ? 0 : 1; + + return Error; +} + +static int test_vec4_simd() +{ + int Error = 0; + + glm::vec4 const a(std::clock(), std::clock(), std::clock(), std::clock()); + glm::vec4 const b(std::clock(), std::clock(), std::clock(), std::clock()); + + glm::vec4 const c(b * a); + glm::vec4 const d(a + c); + + Error += glm::all(glm::greaterThanEqual(d, glm::vec4(0))) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_vec4_ctor(); + Error += test_bvec4_ctor(); + Error += test_vec4_size(); + Error += test_vec4_operators(); + Error += test_vec4_equal(); + Error += test_vec4_swizzle_partial(); + Error += test_vec4_simd(); + Error += test_operator_increment(); + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_quat_xyzw.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_quat_xyzw.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7d5281c224d2598cba6dae83b11626e6b4d0e22a --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_quat_xyzw.cpp @@ -0,0 +1,13 @@ +#define GLM_FORCE_QUAT_DATA_XYZW +#define GLM_FORCE_INLINE + +#include +#include + +int main() +{ + int Error = 0; + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_size_t_length.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_size_t_length.cpp new file mode 100644 index 0000000000000000000000000000000000000000..19dac8974dd157302396255c93dde171ad1d184b --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_size_t_length.cpp @@ -0,0 +1,12 @@ +#define GLM_FORCE_SIZE_T_LENGTH + +#include +#include + +int main() +{ + int Error = 0; + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_unrestricted_gentype.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_unrestricted_gentype.cpp new file mode 100644 index 0000000000000000000000000000000000000000..21d6e520a718b554e47d14ec5c4f8c8af6ace1ba --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_unrestricted_gentype.cpp @@ -0,0 +1,12 @@ +#define GLM_FORCE_UNRESTRICTED_GENTYPE + +#include +#include + +int main() +{ + int Error = 0; + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_xyzw_only.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_xyzw_only.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d19509de1ddb8df78d15278ef0f871d043970281 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_force_xyzw_only.cpp @@ -0,0 +1,58 @@ +#define GLM_FORCE_XYZW_ONLY + +#include +#include +#include +#include +#include +#include + +static int test_comp() +{ + int Error = 0; + + { + glm::ivec1 const A(1); + Error += A.x == 1 ? 0 : 1; + } + + { + glm::ivec2 const A(1, 2); + Error += A.x == 1 ? 0 : 1; + Error += A.y == 2 ? 0 : 1; + } + + { + glm::ivec3 const A(1, 2, 3); + Error += A.x == 1 ? 0 : 1; + Error += A.y == 2 ? 0 : 1; + Error += A.z == 3 ? 0 : 1; + } + + { + glm::ivec4 const A(1, 2, 3, 4); + Error += A.x == 1 ? 0 : 1; + Error += A.y == 2 ? 0 : 1; + Error += A.z == 3 ? 0 : 1; + Error += A.w == 4 ? 0 : 1; + } + + return Error; +} + +static int test_constexpr() +{ + int Error = 0; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_comp(); + Error += test_constexpr(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_common.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_common.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f4b28e8f97f033af4eee3dc4a5becbe99c1da5f4 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_common.cpp @@ -0,0 +1,1349 @@ +#define GLM_FORCE_EXPLICIT_CTOR +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// This file has divisions by zero to test isnan +#if GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(disable : 4723) +#endif + +namespace floor_ +{ + static int test() + { + int Error = 0; + + { + float A = 1.1f; + float B = glm::floor(A); + Error += glm::equal(B, 1.f, 0.0001f) ? 0 : 1; + } + + { + double A = 1.1; + double B = glm::floor(A); + Error += glm::equal(B, 1.0, 0.0001) ? 0 : 1; + } + + { + glm::vec1 A(1.1f); + glm::vec1 B = glm::floor(A); + + Error += glm::all(glm::equal(B, glm::vec1(1.0), 0.0001f)) ? 0 : 1; + } + + { + glm::dvec1 A(1.1); + glm::dvec1 B = glm::floor(A); + + Error += glm::all(glm::equal(B, glm::dvec1(1.0), 0.0001)) ? 0 : 1; + } + + { + glm::vec2 A(1.1f); + glm::vec2 B = glm::floor(A); + + Error += glm::all(glm::equal(B, glm::vec2(1.0), 0.0001f)) ? 0 : 1; + } + + { + glm::dvec2 A(1.1); + glm::dvec2 B = glm::floor(A); + + Error += glm::all(glm::equal(B, glm::dvec2(1.0), 0.0001)) ? 0 : 1; + } + + { + glm::vec3 A(1.1f); + glm::vec3 B = glm::floor(A); + + Error += glm::all(glm::equal(B, glm::vec3(1.0), 0.0001f)) ? 0 : 1; + } + + { + glm::dvec3 A(1.1); + glm::dvec3 B = glm::floor(A); + + Error += glm::all(glm::equal(B, glm::dvec3(1.0), 0.0001)) ? 0 : 1; + } + + { + glm::vec4 A(1.1f); + glm::vec4 B = glm::floor(A); + + Error += glm::all(glm::equal(B, glm::vec4(1.0), 0.0001f)) ? 0 : 1; + } + + { + glm::dvec4 A(1.1); + glm::dvec4 B = glm::floor(A); + + Error += glm::all(glm::equal(B, glm::dvec4(1.0), 0.0001)) ? 0 : 1; + } + + return Error; + } +}//namespace floor + +namespace modf_ +{ + static int test() + { + int Error(0); + + { + float X(1.5f); + float I(0.0f); + float A = glm::modf(X, I); + + Error += glm::equal(I, 1.0f, 0.0001f) ? 0 : 1; + Error += glm::equal(A, 0.5f, 0.0001f) ? 0 : 1; + } + + { + glm::vec4 X(1.1f, 1.2f, 1.5f, 1.7f); + glm::vec4 I(0.0f); + glm::vec4 A = glm::modf(X, I); + + Error += glm::ivec4(I) == glm::ivec4(1) ? 0 : 1; + Error += glm::all(glm::equal(A, glm::vec4(0.1f, 0.2f, 0.5f, 0.7f), 0.00001f)) ? 0 : 1; + } + + { + glm::dvec4 X(1.1, 1.2, 1.5, 1.7); + glm::dvec4 I(0.0); + glm::dvec4 A = glm::modf(X, I); + + Error += glm::ivec4(I) == glm::ivec4(1) ? 0 : 1; + Error += glm::all(glm::equal(A, glm::dvec4(0.1, 0.2, 0.5, 0.7), 0.000000001)) ? 0 : 1; + } + + { + double X(1.5); + double I(0.0); + double A = glm::modf(X, I); + + Error += glm::equal(I, 1.0, 0.0001) ? 0 : 1; + Error += glm::equal(A, 0.5, 0.0001) ? 0 : 1; + } + + return Error; + } +}//namespace modf + +namespace mod_ +{ + static int test() + { + int Error(0); + + { + float A(1.5f); + float B(1.0f); + float C = glm::mod(A, B); + + Error += glm::equal(C, 0.5f, 0.00001f) ? 0 : 1; + } + + { + float A(-0.2f); + float B(1.0f); + float C = glm::mod(A, B); + + Error += glm::equal(C, 0.8f, 0.00001f) ? 0 : 1; + } + + { + float A(3.0); + float B(2.0f); + float C = glm::mod(A, B); + + Error += glm::equal(C, 1.0f, 0.00001f) ? 0 : 1; + } + + { + glm::vec4 A(3.0); + float B(2.0f); + glm::vec4 C = glm::mod(A, B); + + Error += glm::all(glm::equal(C, glm::vec4(1.0f), 0.00001f)) ? 0 : 1; + } + + { + glm::vec4 A(3.0); + glm::vec4 B(2.0f); + glm::vec4 C = glm::mod(A, B); + + Error += glm::all(glm::equal(C, glm::vec4(1.0f), 0.00001f)) ? 0 : 1; + } + + return Error; + } +}//namespace mod_ + +namespace floatBitsToInt +{ + static int test() + { + int Error = 0; + + { + float A = 1.0f; + int B = glm::floatBitsToInt(A); + float C = glm::intBitsToFloat(B); + Error += glm::equal(A, C, 0.0001f) ? 0 : 1; + } + + { + glm::vec2 A(1.0f, 2.0f); + glm::ivec2 B = glm::floatBitsToInt(A); + glm::vec2 C = glm::intBitsToFloat(B); + Error += glm::all(glm::equal(A, C, 0.0001f)) ? 0 : 1; + } + + { + glm::vec3 A(1.0f, 2.0f, 3.0f); + glm::ivec3 B = glm::floatBitsToInt(A); + glm::vec3 C = glm::intBitsToFloat(B); + Error += glm::all(glm::equal(A, C, 0.0001f)) ? 0 : 1; + } + + { + glm::vec4 A(1.0f, 2.0f, 3.0f, 4.0f); + glm::ivec4 B = glm::floatBitsToInt(A); + glm::vec4 C = glm::intBitsToFloat(B); + Error += glm::all(glm::equal(A, C, 0.0001f)) ? 0 : 1; + } + + return Error; + } +}//namespace floatBitsToInt + +namespace floatBitsToUint +{ + static int test() + { + int Error = 0; + + { + float A = 1.0f; + glm::uint B = glm::floatBitsToUint(A); + float C = glm::uintBitsToFloat(B); + Error += glm::equal(A, C, 0.0001f) ? 0 : 1; + } + + { + glm::vec2 A(1.0f, 2.0f); + glm::uvec2 B = glm::floatBitsToUint(A); + glm::vec2 C = glm::uintBitsToFloat(B); + Error += glm::all(glm::equal(A, C, 0.0001f)) ? 0 : 1; + } + + { + glm::vec3 A(1.0f, 2.0f, 3.0f); + glm::uvec3 B = glm::floatBitsToUint(A); + glm::vec3 C = glm::uintBitsToFloat(B); + Error += glm::all(glm::equal(A, C, 0.0001f)) ? 0 : 1; + } + + { + glm::vec4 A(1.0f, 2.0f, 3.0f, 4.0f); + glm::uvec4 B = glm::floatBitsToUint(A); + glm::vec4 C = glm::uintBitsToFloat(B); + Error += glm::all(glm::equal(A, C, 0.0001f)) ? 0 : 1; + } + + return Error; + } +}//namespace floatBitsToUint + +namespace min_ +{ + static int test() + { + int Error = 0; + + glm::vec1 A0 = glm::min(glm::vec1(1), glm::vec1(1)); + bool A1 = glm::all(glm::equal(A0, glm::vec1(1), glm::epsilon())); + Error += A1 ? 0 : 1; + + glm::vec2 B0 = glm::min(glm::vec2(1), glm::vec2(1)); + glm::vec2 B1 = glm::min(glm::vec2(1), 1.0f); + bool B2 = glm::all(glm::equal(B0, B1, glm::epsilon())); + Error += B2 ? 0 : 1; + + glm::vec3 C0 = glm::min(glm::vec3(1), glm::vec3(1)); + glm::vec3 C1 = glm::min(glm::vec3(1), 1.0f); + bool C2 = glm::all(glm::equal(C0, C1, glm::epsilon())); + Error += C2 ? 0 : 1; + + glm::vec4 D0 = glm::min(glm::vec4(1), glm::vec4(1)); + glm::vec4 D1 = glm::min(glm::vec4(1), 1.0f); + bool D2 = glm::all(glm::equal(D0, D1, glm::epsilon())); + Error += D2 ? 0 : 1; + + return Error; + } + + int min_tern(int a, int b) + { + return a < b ? a : b; + } + + int min_int(int x, int y) + { + return y ^ ((x ^ y) & -(x < y)); + } + + static int perf(std::size_t Count) + { + std::vector A(Count); + std::vector B(Count); + + std::size_t const InternalCount = 200000; + + for(std::size_t i = 0; i < Count; ++i) + { + A[i] = glm::linearRand(-1000, 1000); + B[i] = glm::linearRand(-1000, 1000); + } + + int Error = 0; + + glm::int32 SumA = 0; + { + std::clock_t Timestamp0 = std::clock(); + + for (std::size_t j = 0; j < InternalCount; ++j) + for (std::size_t i = 0; i < Count; ++i) + SumA += min_tern(A[i], B[i]); + + std::clock_t Timestamp1 = std::clock(); + + std::printf("min_tern Time %d clocks\n", static_cast(Timestamp1 - Timestamp0)); + } + + glm::int32 SumB = 0; + { + std::clock_t Timestamp0 = std::clock(); + + for (std::size_t j = 0; j < InternalCount; ++j) + for (std::size_t i = 0; i < Count; ++i) + SumB += min_int(A[i], B[i]); + + std::clock_t Timestamp1 = std::clock(); + + std::printf("min_int Time %d clocks\n", static_cast(Timestamp1 - Timestamp0)); + } + + Error += SumA == SumB ? 0 : 1; + + return Error; + } +}//namespace min_ + +namespace max_ +{ + static int test() + { + int Error = 0; + + glm::vec1 A0 = glm::max(glm::vec1(1), glm::vec1(1)); + bool A1 = glm::all(glm::equal(A0, glm::vec1(1), glm::epsilon())); + Error += A1 ? 0 : 1; + + + glm::vec2 B0 = glm::max(glm::vec2(1), glm::vec2(1)); + glm::vec2 B1 = glm::max(glm::vec2(1), 1.0f); + bool B2 = glm::all(glm::equal(B0, B1, glm::epsilon())); + Error += B2 ? 0 : 1; + + glm::vec3 C0 = glm::max(glm::vec3(1), glm::vec3(1)); + glm::vec3 C1 = glm::max(glm::vec3(1), 1.0f); + bool C2 = glm::all(glm::equal(C0, C1, glm::epsilon())); + Error += C2 ? 0 : 1; + + glm::vec4 D0 = glm::max(glm::vec4(1), glm::vec4(1)); + glm::vec4 D1 = glm::max(glm::vec4(1), 1.0f); + bool D2 = glm::all(glm::equal(D0, D1, glm::epsilon())); + Error += D2 ? 0 : 1; + + return Error; + } +}//namespace max_ + +namespace clamp_ +{ + static int test() + { + int Error = 0; + + return Error; + } +}//namespace clamp_ + +namespace mix_ +{ + template + struct entry + { + T x; + T y; + B a; + T Result; + }; + + entry const TestBool[] = + { + {0.0f, 1.0f, false, 0.0f}, + {0.0f, 1.0f, true, 1.0f}, + {-1.0f, 1.0f, false, -1.0f}, + {-1.0f, 1.0f, true, 1.0f} + }; + + entry const TestFloat[] = + { + {0.0f, 1.0f, 0.0f, 0.0f}, + {0.0f, 1.0f, 1.0f, 1.0f}, + {-1.0f, 1.0f, 0.0f, -1.0f}, + {-1.0f, 1.0f, 1.0f, 1.0f} + }; + + entry const TestVec2Bool[] = + { + {glm::vec2(0.0f), glm::vec2(1.0f), false, glm::vec2(0.0f)}, + {glm::vec2(0.0f), glm::vec2(1.0f), true, glm::vec2(1.0f)}, + {glm::vec2(-1.0f), glm::vec2(1.0f), false, glm::vec2(-1.0f)}, + {glm::vec2(-1.0f), glm::vec2(1.0f), true, glm::vec2(1.0f)} + }; + + entry const TestBVec2[] = + { + {glm::vec2(0.0f), glm::vec2(1.0f), glm::bvec2(false), glm::vec2(0.0f)}, + {glm::vec2(0.0f), glm::vec2(1.0f), glm::bvec2(true), glm::vec2(1.0f)}, + {glm::vec2(-1.0f), glm::vec2(1.0f), glm::bvec2(false), glm::vec2(-1.0f)}, + {glm::vec2(-1.0f), glm::vec2(1.0f), glm::bvec2(true), glm::vec2(1.0f)}, + {glm::vec2(-1.0f), glm::vec2(1.0f), glm::bvec2(true, false), glm::vec2(1.0f, -1.0f)} + }; + + entry const TestVec3Bool[] = + { + {glm::vec3(0.0f), glm::vec3(1.0f), false, glm::vec3(0.0f)}, + {glm::vec3(0.0f), glm::vec3(1.0f), true, glm::vec3(1.0f)}, + {glm::vec3(-1.0f), glm::vec3(1.0f), false, glm::vec3(-1.0f)}, + {glm::vec3(-1.0f), glm::vec3(1.0f), true, glm::vec3(1.0f)} + }; + + entry const TestBVec3[] = + { + {glm::vec3(0.0f), glm::vec3(1.0f), glm::bvec3(false), glm::vec3(0.0f)}, + {glm::vec3(0.0f), glm::vec3(1.0f), glm::bvec3(true), glm::vec3(1.0f)}, + {glm::vec3(-1.0f), glm::vec3(1.0f), glm::bvec3(false), glm::vec3(-1.0f)}, + {glm::vec3(-1.0f), glm::vec3(1.0f), glm::bvec3(true), glm::vec3(1.0f)}, + {glm::vec3(1.0f, 2.0f, 3.0f), glm::vec3(4.0f, 5.0f, 6.0f), glm::bvec3(true, false, true), glm::vec3(4.0f, 2.0f, 6.0f)} + }; + + entry const TestVec4Bool[] = + { + {glm::vec4(0.0f), glm::vec4(1.0f), false, glm::vec4(0.0f)}, + {glm::vec4(0.0f), glm::vec4(1.0f), true, glm::vec4(1.0f)}, + {glm::vec4(-1.0f), glm::vec4(1.0f), false, glm::vec4(-1.0f)}, + {glm::vec4(-1.0f), glm::vec4(1.0f), true, glm::vec4(1.0f)} + }; + + entry const TestBVec4[] = + { + {glm::vec4(0.0f, 0.0f, 1.0f, 1.0f), glm::vec4(2.0f, 2.0f, 3.0f, 3.0f), glm::bvec4(false, true, false, true), glm::vec4(0.0f, 2.0f, 1.0f, 3.0f)}, + {glm::vec4(0.0f), glm::vec4(1.0f), glm::bvec4(true), glm::vec4(1.0f)}, + {glm::vec4(-1.0f), glm::vec4(1.0f), glm::bvec4(false), glm::vec4(-1.0f)}, + {glm::vec4(-1.0f), glm::vec4(1.0f), glm::bvec4(true), glm::vec4(1.0f)}, + {glm::vec4(1.0f, 2.0f, 3.0f, 4.0f), glm::vec4(5.0f, 6.0f, 7.0f, 8.0f), glm::bvec4(true, false, true, false), glm::vec4(5.0f, 2.0f, 7.0f, 4.0f)} + }; + + static int test() + { + int Error = 0; + + // Float with bool + { + for(std::size_t i = 0; i < sizeof(TestBool) / sizeof(entry); ++i) + { + float Result = glm::mix(TestBool[i].x, TestBool[i].y, TestBool[i].a); + Error += glm::equal(Result, TestBool[i].Result, glm::epsilon()) ? 0 : 1; + } + } + + // Float with float + { + for(std::size_t i = 0; i < sizeof(TestFloat) / sizeof(entry); ++i) + { + float Result = glm::mix(TestFloat[i].x, TestFloat[i].y, TestFloat[i].a); + Error += glm::equal(Result, TestFloat[i].Result, glm::epsilon()) ? 0 : 1; + } + } + + // vec2 with bool + { + for(std::size_t i = 0; i < sizeof(TestVec2Bool) / sizeof(entry); ++i) + { + glm::vec2 Result = glm::mix(TestVec2Bool[i].x, TestVec2Bool[i].y, TestVec2Bool[i].a); + Error += glm::equal(Result.x, TestVec2Bool[i].Result.x, glm::epsilon()) ? 0 : 1; + Error += glm::equal(Result.y, TestVec2Bool[i].Result.y, glm::epsilon()) ? 0 : 1; + } + } + + // vec2 with bvec2 + { + for(std::size_t i = 0; i < sizeof(TestBVec2) / sizeof(entry); ++i) + { + glm::vec2 Result = glm::mix(TestBVec2[i].x, TestBVec2[i].y, TestBVec2[i].a); + Error += glm::equal(Result.x, TestBVec2[i].Result.x, glm::epsilon()) ? 0 : 1; + Error += glm::equal(Result.y, TestBVec2[i].Result.y, glm::epsilon()) ? 0 : 1; + } + } + + // vec3 with bool + { + for(std::size_t i = 0; i < sizeof(TestVec3Bool) / sizeof(entry); ++i) + { + glm::vec3 Result = glm::mix(TestVec3Bool[i].x, TestVec3Bool[i].y, TestVec3Bool[i].a); + Error += glm::equal(Result.x, TestVec3Bool[i].Result.x, glm::epsilon()) ? 0 : 1; + Error += glm::equal(Result.y, TestVec3Bool[i].Result.y, glm::epsilon()) ? 0 : 1; + Error += glm::equal(Result.z, TestVec3Bool[i].Result.z, glm::epsilon()) ? 0 : 1; + } + } + + // vec3 with bvec3 + { + for(std::size_t i = 0; i < sizeof(TestBVec3) / sizeof(entry); ++i) + { + glm::vec3 Result = glm::mix(TestBVec3[i].x, TestBVec3[i].y, TestBVec3[i].a); + Error += glm::equal(Result.x, TestBVec3[i].Result.x, glm::epsilon()) ? 0 : 1; + Error += glm::equal(Result.y, TestBVec3[i].Result.y, glm::epsilon()) ? 0 : 1; + Error += glm::equal(Result.z, TestBVec3[i].Result.z, glm::epsilon()) ? 0 : 1; + } + } + + // vec4 with bool + { + for(std::size_t i = 0; i < sizeof(TestVec4Bool) / sizeof(entry); ++i) + { + glm::vec4 Result = glm::mix(TestVec4Bool[i].x, TestVec4Bool[i].y, TestVec4Bool[i].a); + Error += glm::equal(Result.x, TestVec4Bool[i].Result.x, glm::epsilon()) ? 0 : 1; + Error += glm::equal(Result.y, TestVec4Bool[i].Result.y, glm::epsilon()) ? 0 : 1; + Error += glm::equal(Result.z, TestVec4Bool[i].Result.z, glm::epsilon()) ? 0 : 1; + Error += glm::equal(Result.w, TestVec4Bool[i].Result.w, glm::epsilon()) ? 0 : 1; + } + } + + // vec4 with bvec4 + { + for(std::size_t i = 0; i < sizeof(TestBVec4) / sizeof(entry); ++i) + { + glm::vec4 Result = glm::mix(TestBVec4[i].x, TestBVec4[i].y, TestBVec4[i].a); + Error += glm::equal(Result.x, TestBVec4[i].Result.x, glm::epsilon()) ? 0 : 1; + Error += glm::equal(Result.y, TestBVec4[i].Result.y, glm::epsilon()) ? 0 : 1; + Error += glm::equal(Result.z, TestBVec4[i].Result.z, glm::epsilon()) ? 0 : 1; + Error += glm::equal(Result.w, TestBVec4[i].Result.w, glm::epsilon()) ? 0 : 1; + } + } + + return Error; + } +}//namespace mix_ + +namespace step_ +{ + template + struct entry + { + EDGE edge; + VEC x; + VEC result; + }; + + entry TestVec4Scalar [] = + { + { 1.0f, glm::vec4(1.0f, 2.0f, 3.0f, 4.0f), glm::vec4(1.0f) }, + { 0.0f, glm::vec4(1.0f, 2.0f, 3.0f, 4.0f), glm::vec4(1.0f) }, + { 0.0f, glm::vec4(-1.0f, -2.0f, -3.0f, -4.0f), glm::vec4(0.0f) } + }; + + entry TestVec4Vector [] = + { + { glm::vec4(-1.0f, -2.0f, -3.0f, -4.0f), glm::vec4(-2.0f, -3.0f, -4.0f, -5.0f), glm::vec4(0.0f) }, + { glm::vec4( 0.0f, 1.0f, 2.0f, 3.0f), glm::vec4( 1.0f, 2.0f, 3.0f, 4.0f), glm::vec4(1.0f) }, + { glm::vec4( 2.0f, 3.0f, 4.0f, 5.0f), glm::vec4( 1.0f, 2.0f, 3.0f, 4.0f), glm::vec4(0.0f) }, + { glm::vec4( 0.0f, 1.0f, 2.0f, 3.0f), glm::vec4(-1.0f,-2.0f,-3.0f,-4.0f), glm::vec4(0.0f) } + }; + + static int test() + { + int Error = 0; + + // scalar + { + float const Edge = 2.0f; + + float const A = glm::step(Edge, 1.0f); + Error += glm::equal(A, 0.0f, glm::epsilon()) ? 0 : 1; + + float const B = glm::step(Edge, 3.0f); + Error += glm::equal(B, 1.0f, glm::epsilon()) ? 0 : 1; + + float const C = glm::step(Edge, 2.0f); + Error += glm::equal(C, 1.0f, glm::epsilon()) ? 0 : 1; + } + + // vec4 and float + { + for (std::size_t i = 0; i < sizeof(TestVec4Scalar) / sizeof(entry); ++i) + { + glm::vec4 Result = glm::step(TestVec4Scalar[i].edge, TestVec4Scalar[i].x); + Error += glm::all(glm::equal(Result, TestVec4Scalar[i].result, glm::epsilon())) ? 0 : 1; + } + } + + // vec4 and vec4 + { + for (std::size_t i = 0; i < sizeof(TestVec4Vector) / sizeof(entry); ++i) + { + glm::vec4 Result = glm::step(TestVec4Vector[i].edge, TestVec4Vector[i].x); + Error += glm::all(glm::equal(Result, TestVec4Vector[i].result, glm::epsilon())) ? 0 : 1; + } + } + + return Error; + } +}//namespace step_ + +namespace round_ +{ + static int test() + { + int Error = 0; + + { + float A = glm::round(0.0f); + Error += glm::equal(A, 0.0f, glm::epsilon()) ? 0 : 1; + float B = glm::round(0.5f); + Error += (glm::equal(B, 1.0f, glm::epsilon()) || glm::equal(B, 0.0f, glm::epsilon())) ? 0 : 1; + float C = glm::round(1.0f); + Error += glm::equal(C, 1.0f, glm::epsilon()) ? 0 : 1; + float D = glm::round(0.1f); + Error += glm::equal(D, 0.0f, glm::epsilon()) ? 0 : 1; + float E = glm::round(0.9f); + Error += glm::equal(E, 1.0f, glm::epsilon()) ? 0 : 1; + float F = glm::round(1.5f); + Error += glm::equal(F, 2.0f, glm::epsilon()) ? 0 : 1; + float G = glm::round(1.9f); + Error += glm::equal(G, 2.0f, glm::epsilon()) ? 0 : 1; + } + + { + float A = glm::round(-0.0f); + Error += glm::equal(A, 0.0f, glm::epsilon()) ? 0 : 1; + float B = glm::round(-0.5f); + Error += (glm::equal(B, -1.0f, glm::epsilon()) || glm::equal(B, 0.0f, glm::epsilon())) ? 0 : 1; + float C = glm::round(-1.0f); + Error += glm::equal(C, -1.0f, glm::epsilon()) ? 0 : 1; + float D = glm::round(-0.1f); + Error += glm::equal(D, 0.0f, glm::epsilon()) ? 0 : 1; + float E = glm::round(-0.9f); + Error += glm::equal(E, -1.0f, glm::epsilon()) ? 0 : 1; + float F = glm::round(-1.5f); + Error += glm::equal(F, -2.0f, glm::epsilon()) ? 0 : 1; + float G = glm::round(-1.9f); + Error += glm::equal(G, -2.0f, glm::epsilon()) ? 0 : 1; + } + + return Error; + } +}//namespace round_ + +namespace roundEven +{ + static int test() + { + int Error = 0; + + { + float A1 = glm::roundEven(-1.5f); + Error += glm::equal(A1, -2.0f, 0.0001f) ? 0 : 1; + + float A2 = glm::roundEven(1.5f); + Error += glm::equal(A2, 2.0f, 0.0001f) ? 0 : 1; + + float A5 = glm::roundEven(-2.5f); + Error += glm::equal(A5, -2.0f, 0.0001f) ? 0 : 1; + + float A6 = glm::roundEven(2.5f); + Error += glm::equal(A6, 2.0f, 0.0001f) ? 0 : 1; + + float A3 = glm::roundEven(-3.5f); + Error += glm::equal(A3, -4.0f, 0.0001f) ? 0 : 1; + + float A4 = glm::roundEven(3.5f); + Error += glm::equal(A4, 4.0f, 0.0001f) ? 0 : 1; + + float C7 = glm::roundEven(-4.5f); + Error += glm::equal(C7, -4.0f, 0.0001f) ? 0 : 1; + + float C8 = glm::roundEven(4.5f); + Error += glm::equal(C8, 4.0f, 0.0001f) ? 0 : 1; + + float C1 = glm::roundEven(-5.5f); + Error += glm::equal(C1, -6.0f, 0.0001f) ? 0 : 1; + + float C2 = glm::roundEven(5.5f); + Error += glm::equal(C2, 6.0f, 0.0001f) ? 0 : 1; + + float C3 = glm::roundEven(-6.5f); + Error += glm::equal(C3, -6.0f, 0.0001f) ? 0 : 1; + + float C4 = glm::roundEven(6.5f); + Error += glm::equal(C4, 6.0f, 0.0001f) ? 0 : 1; + + float C5 = glm::roundEven(-7.5f); + Error += glm::equal(C5, -8.0f, 0.0001f) ? 0 : 1; + + float C6 = glm::roundEven(7.5f); + Error += glm::equal(C6, 8.0f, 0.0001f) ? 0 : 1; + + Error += 0; + } + + { + float A7 = glm::roundEven(-2.4f); + Error += glm::equal(A7, -2.0f, 0.0001f) ? 0 : 1; + + float A8 = glm::roundEven(2.4f); + Error += glm::equal(A8, 2.0f, 0.0001f) ? 0 : 1; + + float B1 = glm::roundEven(-2.6f); + Error += glm::equal(B1, -3.0f, 0.0001f) ? 0 : 1; + + float B2 = glm::roundEven(2.6f); + Error += glm::equal(B2, 3.0f, 0.0001f) ? 0 : 1; + + float B3 = glm::roundEven(-2.0f); + Error += glm::equal(B3, -2.0f, 0.0001f) ? 0 : 1; + + float B4 = glm::roundEven(2.0f); + Error += glm::equal(B4, 2.0f, 0.0001f) ? 0 : 1; + + Error += 0; + } + + { + float A = glm::roundEven(0.0f); + Error += glm::equal(A, 0.0f, glm::epsilon()) ? 0 : 1; + float B = glm::roundEven(0.5f); + Error += glm::equal(B, 0.0f, glm::epsilon()) ? 0 : 1; + float C = glm::roundEven(1.0f); + Error += glm::equal(C, 1.0f, glm::epsilon()) ? 0 : 1; + float D = glm::roundEven(0.1f); + Error += glm::equal(D, 0.0f, glm::epsilon()) ? 0 : 1; + float E = glm::roundEven(0.9f); + Error += glm::equal(E, 1.0f, glm::epsilon()) ? 0 : 1; + float F = glm::roundEven(1.5f); + Error += glm::equal(F, 2.0f, glm::epsilon()) ? 0 : 1; + float G = glm::roundEven(1.9f); + Error += glm::equal(G, 2.0f, glm::epsilon()) ? 0 : 1; + } + + { + float A = glm::roundEven(-0.0f); + Error += glm::equal(A, 0.0f, glm::epsilon()) ? 0 : 1; + float B = glm::roundEven(-0.5f); + Error += glm::equal(B, -0.0f, glm::epsilon()) ? 0 : 1; + float C = glm::roundEven(-1.0f); + Error += glm::equal(C, -1.0f, glm::epsilon()) ? 0 : 1; + float D = glm::roundEven(-0.1f); + Error += glm::equal(D, 0.0f, glm::epsilon()) ? 0 : 1; + float E = glm::roundEven(-0.9f); + Error += glm::equal(E, -1.0f, glm::epsilon()) ? 0 : 1; + float F = glm::roundEven(-1.5f); + Error += glm::equal(F, -2.0f, glm::epsilon()) ? 0 : 1; + float G = glm::roundEven(-1.9f); + Error += glm::equal(G, -2.0f, glm::epsilon()) ? 0 : 1; + } + + { + float A = glm::roundEven(1.5f); + Error += glm::equal(A, 2.0f, glm::epsilon()) ? 0 : 1; + float B = glm::roundEven(2.5f); + Error += glm::equal(B, 2.0f, glm::epsilon()) ? 0 : 1; + float C = glm::roundEven(3.5f); + Error += glm::equal(C, 4.0f, glm::epsilon()) ? 0 : 1; + float D = glm::roundEven(4.5f); + Error += glm::equal(D, 4.0f, glm::epsilon()) ? 0 : 1; + float E = glm::roundEven(5.5f); + Error += glm::equal(E, 6.0f, glm::epsilon()) ? 0 : 1; + float F = glm::roundEven(6.5f); + Error += glm::equal(F, 6.0f, glm::epsilon()) ? 0 : 1; + float G = glm::roundEven(7.5f); + Error += glm::equal(G, 8.0f, glm::epsilon()) ? 0 : 1; + } + + { + float A = glm::roundEven(-1.5f); + Error += glm::equal(A, -2.0f, glm::epsilon()) ? 0 : 1; + float B = glm::roundEven(-2.5f); + Error += glm::equal(B, -2.0f, glm::epsilon()) ? 0 : 1; + float C = glm::roundEven(-3.5f); + Error += glm::equal(C, -4.0f, glm::epsilon()) ? 0 : 1; + float D = glm::roundEven(-4.5f); + Error += glm::equal(D, -4.0f, glm::epsilon()) ? 0 : 1; + float E = glm::roundEven(-5.5f); + Error += glm::equal(E, -6.0f, glm::epsilon()) ? 0 : 1; + float F = glm::roundEven(-6.5f); + Error += glm::equal(F, -6.0f, glm::epsilon()) ? 0 : 1; + float G = glm::roundEven(-7.5f); + Error += glm::equal(G, -8.0f, glm::epsilon()) ? 0 : 1; + } + + return Error; + } +}//namespace roundEven + +namespace isnan_ +{ + static int test() + { + int Error = 0; + + float Zero_f = 0.0; + double Zero_d = 0.0; + + { + Error += true == glm::isnan(0.0/Zero_d) ? 0 : 1; + Error += true == glm::any(glm::isnan(glm::dvec2(0.0 / Zero_d))) ? 0 : 1; + Error += true == glm::any(glm::isnan(glm::dvec3(0.0 / Zero_d))) ? 0 : 1; + Error += true == glm::any(glm::isnan(glm::dvec4(0.0 / Zero_d))) ? 0 : 1; + } + + { + Error += true == glm::isnan(0.0f/Zero_f) ? 0 : 1; + Error += true == glm::any(glm::isnan(glm::vec2(0.0f/Zero_f))) ? 0 : 1; + Error += true == glm::any(glm::isnan(glm::vec3(0.0f/Zero_f))) ? 0 : 1; + Error += true == glm::any(glm::isnan(glm::vec4(0.0f/Zero_f))) ? 0 : 1; + } + + return Error; + } +}//namespace isnan_ + +namespace isinf_ +{ + static int test() + { + int Error = 0; + + float Zero_f = 0.0; + double Zero_d = 0.0; + + { + Error += true == glm::isinf( 1.0/Zero_d) ? 0 : 1; + Error += true == glm::isinf(-1.0/Zero_d) ? 0 : 1; + Error += true == glm::any(glm::isinf(glm::dvec2( 1.0/Zero_d))) ? 0 : 1; + Error += true == glm::any(glm::isinf(glm::dvec2(-1.0/Zero_d))) ? 0 : 1; + Error += true == glm::any(glm::isinf(glm::dvec3( 1.0/Zero_d))) ? 0 : 1; + Error += true == glm::any(glm::isinf(glm::dvec3(-1.0/Zero_d))) ? 0 : 1; + Error += true == glm::any(glm::isinf(glm::dvec4( 1.0/Zero_d))) ? 0 : 1; + Error += true == glm::any(glm::isinf(glm::dvec4(-1.0/Zero_d))) ? 0 : 1; + } + + { + Error += true == glm::isinf( 1.0f/Zero_f) ? 0 : 1; + Error += true == glm::isinf(-1.0f/Zero_f) ? 0 : 1; + Error += true == glm::any(glm::isinf(glm::vec2( 1.0f/Zero_f))) ? 0 : 1; + Error += true == glm::any(glm::isinf(glm::vec2(-1.0f/Zero_f))) ? 0 : 1; + Error += true == glm::any(glm::isinf(glm::vec3( 1.0f/Zero_f))) ? 0 : 1; + Error += true == glm::any(glm::isinf(glm::vec3(-1.0f/Zero_f))) ? 0 : 1; + Error += true == glm::any(glm::isinf(glm::vec4( 1.0f/Zero_f))) ? 0 : 1; + Error += true == glm::any(glm::isinf(glm::vec4(-1.0f/Zero_f))) ? 0 : 1; + } + + return Error; + } +}//namespace isinf_ + +namespace sign +{ + template + GLM_FUNC_QUALIFIER genFIType sign_if(genFIType x) + { + GLM_STATIC_ASSERT( + std::numeric_limits::is_iec559 || + (std::numeric_limits::is_signed && std::numeric_limits::is_integer), "'sign' only accept signed inputs"); + + genFIType result; + if(x > genFIType(0)) + result = genFIType(1); + else if(x < genFIType(0)) + result = genFIType(-1); + else + result = genFIType(0); + return result; + } + + template + GLM_FUNC_QUALIFIER genFIType sign_alu1(genFIType x) + { + GLM_STATIC_ASSERT( + std::numeric_limits::is_signed && std::numeric_limits::is_integer, + "'sign' only accept integer inputs"); + + return (x >> 31) | (static_cast(-x) >> 31); + } + + GLM_FUNC_QUALIFIER int sign_alu2(int x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_signed && std::numeric_limits::is_integer, "'sign' only accept integer inputs"); + +# if GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(push) +# pragma warning(disable : 4146) //cast truncates constant value +# endif + + return -(static_cast(x) >> 31) | (-static_cast(x) >> 31); + +# if GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(pop) +# endif + } + + template + GLM_FUNC_QUALIFIER genFIType sign_sub(genFIType x) + { + GLM_STATIC_ASSERT( + std::numeric_limits::is_signed && std::numeric_limits::is_integer, + "'sign' only accept integer inputs"); + + return (static_cast(-x) >> 31) - (static_cast(x) >> 31); + } + + template + GLM_FUNC_QUALIFIER genFIType sign_cmp(genFIType x) + { + GLM_STATIC_ASSERT( + std::numeric_limits::is_signed && std::numeric_limits::is_integer, + "'sign' only accept integer inputs"); + + return (x > 0) - (x < 0); + } + + template + struct type + { + genType Value; + genType Return; + }; + + int test_int32() + { + type const Data[] = + { + { std::numeric_limits::max(), 1}, + { std::numeric_limits::min(), -1}, + { 0, 0}, + { 1, 1}, + { 2, 1}, + { 3, 1}, + {-1,-1}, + {-2,-1}, + {-3,-1} + }; + + int Error = 0; + + for(std::size_t i = 0; i < sizeof(Data) / sizeof(type); ++i) + { + glm::int32 Result = glm::sign(Data[i].Value); + Error += Data[i].Return == Result ? 0 : 1; + } + + for(std::size_t i = 0; i < sizeof(Data) / sizeof(type); ++i) + { + glm::int32 Result = sign_cmp(Data[i].Value); + Error += Data[i].Return == Result ? 0 : 1; + } + + for(std::size_t i = 0; i < sizeof(Data) / sizeof(type); ++i) + { + glm::int32 Result = sign_if(Data[i].Value); + Error += Data[i].Return == Result ? 0 : 1; + } + + for(std::size_t i = 0; i < sizeof(Data) / sizeof(type); ++i) + { + glm::int32 Result = sign_alu1(Data[i].Value); + Error += Data[i].Return == Result ? 0 : 1; + } + + for(std::size_t i = 0; i < sizeof(Data) / sizeof(type); ++i) + { + glm::int32 Result = sign_alu2(Data[i].Value); + Error += Data[i].Return == Result ? 0 : 1; + } + + return Error; + } + + int test_i32vec4() + { + type const Data[] = + { + {glm::ivec4( 1), glm::ivec4( 1)}, + {glm::ivec4( 0), glm::ivec4( 0)}, + {glm::ivec4( 2), glm::ivec4( 1)}, + {glm::ivec4( 3), glm::ivec4( 1)}, + {glm::ivec4(-1), glm::ivec4(-1)}, + {glm::ivec4(-2), glm::ivec4(-1)}, + {glm::ivec4(-3), glm::ivec4(-1)} + }; + + int Error = 0; + + for(std::size_t i = 0; i < sizeof(Data) / sizeof(type); ++i) + { + glm::ivec4 Result = glm::sign(Data[i].Value); + Error += glm::all(glm::equal(Data[i].Return, Result)) ? 0 : 1; + } + + return Error; + } + + int test_f32vec4() + { + type const Data[] = + { + {glm::vec4( 1), glm::vec4( 1)}, + {glm::vec4( 0), glm::vec4( 0)}, + {glm::vec4( 2), glm::vec4( 1)}, + {glm::vec4( 3), glm::vec4( 1)}, + {glm::vec4(-1), glm::vec4(-1)}, + {glm::vec4(-2), glm::vec4(-1)}, + {glm::vec4(-3), glm::vec4(-1)} + }; + + int Error = 0; + + for(std::size_t i = 0; i < sizeof(Data) / sizeof(type); ++i) + { + glm::vec4 Result = glm::sign(Data[i].Value); + Error += glm::all(glm::equal(Data[i].Return, Result, glm::epsilon())) ? 0 : 1; + } + + return Error; + } + + static int test() + { + int Error = 0; + + Error += test_int32(); + Error += test_i32vec4(); + Error += test_f32vec4(); + + return Error; + } + + int perf_rand(std::size_t Samples) + { + int Error = 0; + + std::size_t const Count = Samples; + std::vector Input, Output; + Input.resize(Count); + Output.resize(Count); + for(std::size_t i = 0; i < Count; ++i) + Input[i] = static_cast(glm::linearRand(-65536.f, 65536.f)); + + std::clock_t Timestamp0 = std::clock(); + + for(std::size_t i = 0; i < Count; ++i) + Output[i] = sign_cmp(Input[i]); + + std::clock_t Timestamp1 = std::clock(); + + for(std::size_t i = 0; i < Count; ++i) + Output[i] = sign_if(Input[i]); + + std::clock_t Timestamp2 = std::clock(); + + for(std::size_t i = 0; i < Count; ++i) + Output[i] = sign_alu1(Input[i]); + + std::clock_t Timestamp3 = std::clock(); + + for(std::size_t i = 0; i < Count; ++i) + Output[i] = sign_alu2(Input[i]); + + std::clock_t Timestamp4 = std::clock(); + + for(std::size_t i = 0; i < Count; ++i) + Output[i] = sign_sub(Input[i]); + + std::clock_t Timestamp5 = std::clock(); + + for(std::size_t i = 0; i < Count; ++i) + Output[i] = glm::sign(Input[i]); + + std::clock_t Timestamp6 = std::clock(); + + std::printf("sign_cmp(rand) Time %d clocks\n", static_cast(Timestamp1 - Timestamp0)); + std::printf("sign_if(rand) Time %d clocks\n", static_cast(Timestamp2 - Timestamp1)); + std::printf("sign_alu1(rand) Time %d clocks\n", static_cast(Timestamp3 - Timestamp2)); + std::printf("sign_alu2(rand) Time %d clocks\n", static_cast(Timestamp4 - Timestamp3)); + std::printf("sign_sub(rand) Time %d clocks\n", static_cast(Timestamp5 - Timestamp4)); + std::printf("glm::sign(rand) Time %d clocks\n", static_cast(Timestamp6 - Timestamp5)); + + return Error; + } + + int perf_linear(std::size_t Samples) + { + int Error = 0; + + std::size_t const Count = Samples; + std::vector Input, Output; + Input.resize(Count); + Output.resize(Count); + for(std::size_t i = 0; i < Count; ++i) + Input[i] = static_cast(i); + + std::clock_t Timestamp0 = std::clock(); + + for(std::size_t i = 0; i < Count; ++i) + Output[i] = sign_cmp(Input[i]); + + std::clock_t Timestamp1 = std::clock(); + + for(std::size_t i = 0; i < Count; ++i) + Output[i] = sign_if(Input[i]); + + std::clock_t Timestamp2 = std::clock(); + + for(std::size_t i = 0; i < Count; ++i) + Output[i] = sign_alu1(Input[i]); + + std::clock_t Timestamp3 = std::clock(); + + for(std::size_t i = 0; i < Count; ++i) + Output[i] = sign_alu2(Input[i]); + + std::clock_t Timestamp4 = std::clock(); + + for(std::size_t i = 0; i < Count; ++i) + Output[i] = sign_sub(Input[i]); + + std::clock_t Timestamp5 = std::clock(); + + std::printf("sign_cmp(linear) Time %d clocks\n", static_cast(Timestamp1 - Timestamp0)); + std::printf("sign_if(linear) Time %d clocks\n", static_cast(Timestamp2 - Timestamp1)); + std::printf("sign_alu1(linear) Time %d clocks\n", static_cast(Timestamp3 - Timestamp2)); + std::printf("sign_alu2(linear) Time %d clocks\n", static_cast(Timestamp4 - Timestamp3)); + std::printf("sign_sub(linear) Time %d clocks\n", static_cast(Timestamp5 - Timestamp4)); + + return Error; + } + + int perf_linear_cal(std::size_t Samples) + { + int Error = 0; + + glm::int32 const Count = static_cast(Samples); + + std::clock_t Timestamp0 = std::clock(); + glm::int32 Sum = 0; + + for(glm::int32 i = 1; i < Count; ++i) + Sum += sign_cmp(i); + + std::clock_t Timestamp1 = std::clock(); + + for(glm::int32 i = 1; i < Count; ++i) + Sum += sign_if(i); + + std::clock_t Timestamp2 = std::clock(); + + for(glm::int32 i = 1; i < Count; ++i) + Sum += sign_alu1(i); + + std::clock_t Timestamp3 = std::clock(); + + for(glm::int32 i = 1; i < Count; ++i) + Sum += sign_alu2(i); + + std::clock_t Timestamp4 = std::clock(); + + for(glm::int32 i = 1; i < Count; ++i) + Sum += sign_sub(i); + + std::clock_t Timestamp5 = std::clock(); + + std::printf("Sum %d\n", static_cast(Sum)); + + std::printf("sign_cmp(linear_cal) Time %d clocks\n", static_cast(Timestamp1 - Timestamp0)); + std::printf("sign_if(linear_cal) Time %d clocks\n", static_cast(Timestamp2 - Timestamp1)); + std::printf("sign_alu1(linear_cal) Time %d clocks\n", static_cast(Timestamp3 - Timestamp2)); + std::printf("sign_alu2(linear_cal) Time %d clocks\n", static_cast(Timestamp4 - Timestamp3)); + std::printf("sign_sub(linear_cal) Time %d clocks\n", static_cast(Timestamp5 - Timestamp4)); + + return Error; + } + + static int perf(std::size_t Samples) + { + int Error(0); + + Error += perf_linear_cal(Samples); + Error += perf_linear(Samples); + Error += perf_rand(Samples); + + return Error; + } +}//namespace sign + +namespace frexp_ +{ + static int test() + { + int Error = 0; + + { + glm::vec1 const x(1024); + glm::ivec1 exp; + glm::vec1 A = glm::frexp(x, exp); + Error += glm::all(glm::equal(A, glm::vec1(0.5), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(exp, glm::ivec1(11))) ? 0 : 1; + } + + { + glm::vec2 const x(1024, 0.24); + glm::ivec2 exp; + glm::vec2 A = glm::frexp(x, exp); + Error += glm::all(glm::equal(A, glm::vec2(0.5, 0.96), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(exp, glm::ivec2(11, -2))) ? 0 : 1; + } + + { + glm::vec3 const x(1024, 0.24, 0); + glm::ivec3 exp; + glm::vec3 A = glm::frexp(x, exp); + Error += glm::all(glm::equal(A, glm::vec3(0.5, 0.96, 0.0), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(exp, glm::ivec3(11, -2, 0))) ? 0 : 1; + } + + { + glm::vec4 const x(1024, 0.24, 0, -1.33); + glm::ivec4 exp; + glm::vec4 A = glm::frexp(x, exp); + Error += glm::all(glm::equal(A, glm::vec4(0.5, 0.96, 0.0, -0.665), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(exp, glm::ivec4(11, -2, 0, 1))) ? 0 : 1; + } + + return Error; + } +}//namespace frexp_ + +namespace ldexp_ +{ + static int test() + { + int Error(0); + + { + glm::vec1 A = glm::vec1(0.5); + glm::ivec1 exp = glm::ivec1(11); + glm::vec1 x = glm::ldexp(A, exp); + Error += glm::all(glm::equal(x, glm::vec1(1024),0.00001f)) ? 0 : 1; + } + + { + glm::vec2 A = glm::vec2(0.5, 0.96); + glm::ivec2 exp = glm::ivec2(11, -2); + glm::vec2 x = glm::ldexp(A, exp); + Error += glm::all(glm::equal(x, glm::vec2(1024, .24),0.00001f)) ? 0 : 1; + } + + { + glm::vec3 A = glm::vec3(0.5, 0.96, 0.0); + glm::ivec3 exp = glm::ivec3(11, -2, 0); + glm::vec3 x = glm::ldexp(A, exp); + Error += glm::all(glm::equal(x, glm::vec3(1024, .24, 0),0.00001f)) ? 0 : 1; + } + + { + glm::vec4 A = glm::vec4(0.5, 0.96, 0.0, -0.665); + glm::ivec4 exp = glm::ivec4(11, -2, 0, 1); + glm::vec4 x = glm::ldexp(A, exp); + Error += glm::all(glm::equal(x, glm::vec4(1024, .24, 0, -1.33),0.00001f)) ? 0 : 1; + } + + return Error; + } +}//namespace ldexp_ + +static int test_constexpr() +{ +#if GLM_HAS_CONSTEXPR + static_assert(glm::abs(1.0f) > 0.0f, "GLM: Failed constexpr"); + constexpr glm::vec1 const A = glm::abs(glm::vec1(1.0f)); + constexpr glm::vec2 const B = glm::abs(glm::vec2(1.0f)); + constexpr glm::vec3 const C = glm::abs(glm::vec3(1.0f)); + constexpr glm::vec4 const D = glm::abs(glm::vec4(1.0f)); +#endif // GLM_HAS_CONSTEXPR + + return 0; +} + +int main() +{ + int Error = 0; + + Error += test_constexpr(); + Error += sign::test(); + Error += floor_::test(); + Error += mod_::test(); + Error += modf_::test(); + Error += floatBitsToInt::test(); + Error += floatBitsToUint::test(); + Error += mix_::test(); + Error += step_::test(); + Error += max_::test(); + Error += min_::test(); + Error += clamp_::test(); + Error += round_::test(); + Error += roundEven::test(); + Error += isnan_::test(); + Error += isinf_::test(); + Error += frexp_::test(); + Error += ldexp_::test(); + +# ifdef NDEBUG + std::size_t Samples = 1000; +# else + std::size_t Samples = 1; +# endif + Error += sign::perf(Samples); + + Error += min_::perf(Samples); + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_exponential.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_exponential.cpp new file mode 100644 index 0000000000000000000000000000000000000000..380cdfb1346674530f3e63ee3223de699251c678 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_exponential.cpp @@ -0,0 +1,185 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int test_pow() +{ + int Error(0); + + float A = glm::pow(2.f, 2.f); + Error += glm::equal(A, 4.f, 0.01f) ? 0 : 1; + + glm::vec1 B = glm::pow(glm::vec1(2.f), glm::vec1(2.f)); + Error += glm::all(glm::equal(B, glm::vec1(4.f), 0.01f)) ? 0 : 1; + + glm::vec2 C = glm::pow(glm::vec2(2.f), glm::vec2(2.f)); + Error += glm::all(glm::equal(C, glm::vec2(4.f), 0.01f)) ? 0 : 1; + + glm::vec3 D = glm::pow(glm::vec3(2.f), glm::vec3(2.f)); + Error += glm::all(glm::equal(D, glm::vec3(4.f), 0.01f)) ? 0 : 1; + + glm::vec4 E = glm::pow(glm::vec4(2.f), glm::vec4(2.f)); + Error += glm::all(glm::equal(E, glm::vec4(4.f), 0.01f)) ? 0 : 1; + + return Error; +} + +static int test_sqrt() +{ + int Error = 0; + + float A = glm::sqrt(4.f); + Error += glm::equal(A, 2.f, 0.01f) ? 0 : 1; + + glm::vec1 B = glm::sqrt(glm::vec1(4.f)); + Error += glm::all(glm::equal(B, glm::vec1(2.f), 0.01f)) ? 0 : 1; + + glm::vec2 C = glm::sqrt(glm::vec2(4.f)); + Error += glm::all(glm::equal(C, glm::vec2(2.f), 0.01f)) ? 0 : 1; + + glm::vec3 D = glm::sqrt(glm::vec3(4.f)); + Error += glm::all(glm::equal(D, glm::vec3(2.f), 0.01f)) ? 0 : 1; + + glm::vec4 E = glm::sqrt(glm::vec4(4.f)); + Error += glm::all(glm::equal(E, glm::vec4(2.f), 0.01f)) ? 0 : 1; + + return Error; +} + +static int test_exp() +{ + int Error = 0; + + float A = glm::exp(1.f); + Error += glm::equal(A, glm::e(), 0.01f) ? 0 : 1; + + glm::vec1 B = glm::exp(glm::vec1(1.f)); + Error += glm::all(glm::equal(B, glm::vec1(glm::e()), 0.01f)) ? 0 : 1; + + glm::vec2 C = glm::exp(glm::vec2(1.f)); + Error += glm::all(glm::equal(C, glm::vec2(glm::e()), 0.01f)) ? 0 : 1; + + glm::vec3 D = glm::exp(glm::vec3(1.f)); + Error += glm::all(glm::equal(D, glm::vec3(glm::e()), 0.01f)) ? 0 : 1; + + glm::vec4 E = glm::exp(glm::vec4(1.f)); + Error += glm::all(glm::equal(E, glm::vec4(glm::e()), 0.01f)) ? 0 : 1; + + return Error; +} + +static int test_log() +{ + int Error = 0; + + float const A = glm::log(glm::e()); + Error += glm::equal(A, 1.f, 0.01f) ? 0 : 1; + + glm::vec1 const B = glm::log(glm::vec1(glm::e())); + Error += glm::all(glm::equal(B, glm::vec1(1.f), 0.01f)) ? 0 : 1; + + glm::vec2 const C = glm::log(glm::vec2(glm::e())); + Error += glm::all(glm::equal(C, glm::vec2(1.f), 0.01f)) ? 0 : 1; + + glm::vec3 const D = glm::log(glm::vec3(glm::e())); + Error += glm::all(glm::equal(D, glm::vec3(1.f), 0.01f)) ? 0 : 1; + + glm::vec4 const E = glm::log(glm::vec4(glm::e())); + Error += glm::all(glm::equal(E, glm::vec4(1.f), 0.01f)) ? 0 : 1; + + return Error; +} + +static int test_exp2() +{ + int Error = 0; + + float A = glm::exp2(4.f); + Error += glm::equal(A, 16.f, 0.01f) ? 0 : 1; + + glm::vec1 B = glm::exp2(glm::vec1(4.f)); + Error += glm::all(glm::equal(B, glm::vec1(16.f), 0.01f)) ? 0 : 1; + + glm::vec2 C = glm::exp2(glm::vec2(4.f, 3.f)); + Error += glm::all(glm::equal(C, glm::vec2(16.f, 8.f), 0.01f)) ? 0 : 1; + + glm::vec3 D = glm::exp2(glm::vec3(4.f, 3.f, 2.f)); + Error += glm::all(glm::equal(D, glm::vec3(16.f, 8.f, 4.f), 0.01f)) ? 0 : 1; + + glm::vec4 E = glm::exp2(glm::vec4(4.f, 3.f, 2.f, 1.f)); + Error += glm::all(glm::equal(E, glm::vec4(16.f, 8.f, 4.f, 2.f), 0.01f)) ? 0 : 1; + +# if GLM_HAS_CXX11_STL + //large exponent + float F = glm::exp2(23.f); + Error += glm::equal(F, 8388608.f, 0.01f) ? 0 : 1; +# endif + + return Error; +} + +static int test_log2() +{ + int Error = 0; + + float A = glm::log2(16.f); + Error += glm::equal(A, 4.f, 0.01f) ? 0 : 1; + + glm::vec1 B = glm::log2(glm::vec1(16.f)); + Error += glm::all(glm::equal(B, glm::vec1(4.f), 0.01f)) ? 0 : 1; + + glm::vec2 C = glm::log2(glm::vec2(16.f, 8.f)); + Error += glm::all(glm::equal(C, glm::vec2(4.f, 3.f), 0.01f)) ? 0 : 1; + + glm::vec3 D = glm::log2(glm::vec3(16.f, 8.f, 4.f)); + Error += glm::all(glm::equal(D, glm::vec3(4.f, 3.f, 2.f), 0.01f)) ? 0 : 1; + + glm::vec4 E = glm::log2(glm::vec4(16.f, 8.f, 4.f, 2.f)); + Error += glm::all(glm::equal(E, glm::vec4(4.f, 3.f, 2.f, 1.f), 0.01f)) ? 0 : 1; + + return Error; +} + +static int test_inversesqrt() +{ + int Error = 0; + + float A = glm::inversesqrt(16.f) * glm::sqrt(16.f); + Error += glm::equal(A, 1.f, 0.01f) ? 0 : 1; + + glm::vec1 B = glm::inversesqrt(glm::vec1(16.f)) * glm::sqrt(16.f); + Error += glm::all(glm::equal(B, glm::vec1(1.f), 0.01f)) ? 0 : 1; + + glm::vec2 C = glm::inversesqrt(glm::vec2(16.f)) * glm::sqrt(16.f); + Error += glm::all(glm::equal(C, glm::vec2(1.f), 0.01f)) ? 0 : 1; + + glm::vec3 D = glm::inversesqrt(glm::vec3(16.f)) * glm::sqrt(16.f); + Error += glm::all(glm::equal(D, glm::vec3(1.f), 0.01f)) ? 0 : 1; + + glm::vec4 E = glm::inversesqrt(glm::vec4(16.f)) * glm::sqrt(16.f); + Error += glm::all(glm::equal(E, glm::vec4(1.f), 0.01f)) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_pow(); + Error += test_sqrt(); + Error += test_exp(); + Error += test_log(); + Error += test_exp2(); + Error += test_log2(); + Error += test_inversesqrt(); + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_geometric.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_geometric.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7ef9c6838a97c23a68e7e1f8f61e210949132b71 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_geometric.cpp @@ -0,0 +1,200 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace length +{ + int test() + { + float Length1 = glm::length(glm::vec1(1)); + float Length2 = glm::length(glm::vec2(1, 0)); + float Length3 = glm::length(glm::vec3(1, 0, 0)); + float Length4 = glm::length(glm::vec4(1, 0, 0, 0)); + + int Error = 0; + + Error += glm::abs(Length1 - 1.0f) < std::numeric_limits::epsilon() ? 0 : 1; + Error += glm::abs(Length2 - 1.0f) < std::numeric_limits::epsilon() ? 0 : 1; + Error += glm::abs(Length3 - 1.0f) < std::numeric_limits::epsilon() ? 0 : 1; + Error += glm::abs(Length4 - 1.0f) < std::numeric_limits::epsilon() ? 0 : 1; + + return Error; + } +}//namespace length + +namespace distance +{ + int test() + { + float Distance1 = glm::distance(glm::vec1(1), glm::vec1(1)); + float Distance2 = glm::distance(glm::vec2(1, 0), glm::vec2(1, 0)); + float Distance3 = glm::distance(glm::vec3(1, 0, 0), glm::vec3(1, 0, 0)); + float Distance4 = glm::distance(glm::vec4(1, 0, 0, 0), glm::vec4(1, 0, 0, 0)); + + int Error = 0; + + Error += glm::abs(Distance1) < std::numeric_limits::epsilon() ? 0 : 1; + Error += glm::abs(Distance2) < std::numeric_limits::epsilon() ? 0 : 1; + Error += glm::abs(Distance3) < std::numeric_limits::epsilon() ? 0 : 1; + Error += glm::abs(Distance4) < std::numeric_limits::epsilon() ? 0 : 1; + + return Error; + } +}//namespace distance + +namespace dot +{ + int test() + { + float Dot1 = glm::dot(glm::vec1(1), glm::vec1(1)); + float Dot2 = glm::dot(glm::vec2(1), glm::vec2(1)); + float Dot3 = glm::dot(glm::vec3(1), glm::vec3(1)); + float Dot4 = glm::dot(glm::vec4(1), glm::vec4(1)); + + int Error = 0; + + Error += glm::abs(Dot1 - 1.0f) < std::numeric_limits::epsilon() ? 0 : 1; + Error += glm::abs(Dot2 - 2.0f) < std::numeric_limits::epsilon() ? 0 : 1; + Error += glm::abs(Dot3 - 3.0f) < std::numeric_limits::epsilon() ? 0 : 1; + Error += glm::abs(Dot4 - 4.0f) < std::numeric_limits::epsilon() ? 0 : 1; + + return Error; + } +}//namespace dot + +namespace cross +{ + int test() + { + glm::vec3 Cross1 = glm::cross(glm::vec3(1, 0, 0), glm::vec3(0, 1, 0)); + glm::vec3 Cross2 = glm::cross(glm::vec3(0, 1, 0), glm::vec3(1, 0, 0)); + + int Error = 0; + + Error += glm::all(glm::lessThan(glm::abs(Cross1 - glm::vec3(0, 0, 1)), glm::vec3(std::numeric_limits::epsilon()))) ? 0 : 1; + Error += glm::all(glm::lessThan(glm::abs(Cross2 - glm::vec3(0, 0,-1)), glm::vec3(std::numeric_limits::epsilon()))) ? 0 : 1; + + return Error; + } +}//namespace cross + +namespace normalize +{ + int test() + { + glm::vec3 Normalize1 = glm::normalize(glm::vec3(1, 0, 0)); + glm::vec3 Normalize2 = glm::normalize(glm::vec3(2, 0, 0)); + + glm::vec3 Normalize3 = glm::normalize(glm::vec3(-0.6, 0.7, -0.5)); + + glm::vec3 ro = glm::vec3(glm::cos(5.f) * 3.f, 2.f, glm::sin(5.f) * 3.f); + glm::vec3 w = glm::normalize(glm::vec3(0, -0.2f, 0) - ro); + glm::vec3 u = glm::normalize(glm::cross(w, glm::vec3(0, 1, 0))); + glm::vec3 v = glm::cross(u, w); + + int Error = 0; + + Error += glm::all(glm::lessThan(glm::abs(Normalize1 - glm::vec3(1, 0, 0)), glm::vec3(std::numeric_limits::epsilon()))) ? 0 : 1; + Error += glm::all(glm::lessThan(glm::abs(Normalize2 - glm::vec3(1, 0, 0)), glm::vec3(std::numeric_limits::epsilon()))) ? 0 : 1; + + return Error; + } +}//namespace normalize + +namespace faceforward +{ + int test() + { + int Error = 0; + + { + glm::vec3 N(0.0f, 0.0f, 1.0f); + glm::vec3 I(1.0f, 0.0f, 1.0f); + glm::vec3 Nref(0.0f, 0.0f, 1.0f); + glm::vec3 F = glm::faceforward(N, I, Nref); + } + + return Error; + } +}//namespace faceforward + +namespace reflect +{ + int test() + { + int Error = 0; + + { + glm::vec2 A(1.0f,-1.0f); + glm::vec2 B(0.0f, 1.0f); + glm::vec2 C = glm::reflect(A, B); + Error += glm::all(glm::equal(C, glm::vec2(1.0, 1.0), 0.0001f)) ? 0 : 1; + } + + { + glm::dvec2 A(1.0f,-1.0f); + glm::dvec2 B(0.0f, 1.0f); + glm::dvec2 C = glm::reflect(A, B); + Error += glm::all(glm::equal(C, glm::dvec2(1.0, 1.0), 0.0001)) ? 0 : 1; + } + + return Error; + } +}//namespace reflect + +namespace refract +{ + int test() + { + int Error = 0; + + { + float A(-1.0f); + float B(1.0f); + float C = glm::refract(A, B, 0.5f); + Error += glm::equal(C, -1.0f, 0.0001f) ? 0 : 1; + } + + { + glm::vec2 A(0.0f,-1.0f); + glm::vec2 B(0.0f, 1.0f); + glm::vec2 C = glm::refract(A, B, 0.5f); + Error += glm::all(glm::equal(C, glm::vec2(0.0, -1.0), 0.0001f)) ? 0 : 1; + } + + { + glm::dvec2 A(0.0f,-1.0f); + glm::dvec2 B(0.0f, 1.0f); + glm::dvec2 C = glm::refract(A, B, 0.5); + Error += glm::all(glm::equal(C, glm::dvec2(0.0, -1.0), 0.0001)) ? 0 : 1; + } + + return Error; + } +}//namespace refract + +int main() +{ + int Error(0); + + Error += length::test(); + Error += distance::test(); + Error += dot::test(); + Error += cross::test(); + Error += normalize::test(); + Error += faceforward::test(); + Error += reflect::test(); + Error += refract::test(); + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_integer.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_integer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..95d650c76d96654282fd57b19c295bba16dfc826 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_integer.cpp @@ -0,0 +1,1556 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum result +{ + SUCCESS, + FAIL, + ASSERT, + STATIC_ASSERT +}; + +namespace bitfieldInsert +{ + template + struct type + { + genType Base; + genType Insert; + int Offset; + int Bits; + genType Return; + }; + + typedef type typeU32; + + typeU32 const Data32[] = + { + {0x00000000, 0xffffffff, 0, 32, 0xffffffff}, + {0x00000000, 0xffffffff, 0, 31, 0x7fffffff}, + {0x00000000, 0xffffffff, 0, 0, 0x00000000}, + {0xff000000, 0x000000ff, 8, 8, 0xff00ff00}, + {0xffff0000, 0xffff0000, 16, 16, 0x00000000}, + {0x0000ffff, 0x0000ffff, 16, 16, 0xffffffff} + }; + + static int test() + { + int Error = 0; + glm::uint count = sizeof(Data32) / sizeof(typeU32); + + for(glm::uint i = 0; i < count; ++i) + { + glm::uint Return = glm::bitfieldInsert( + Data32[i].Base, + Data32[i].Insert, + Data32[i].Offset, + Data32[i].Bits); + + Error += Data32[i].Return == Return ? 0 : 1; + } + + return Error; + } +}//bitfieldInsert + +namespace bitfieldExtract +{ + template + struct type + { + genType Value; + int Offset; + int Bits; + genType Return; + result Result; + }; + + typedef type typeU32; + + typeU32 const Data32[] = + { + {0xffffffff, 0,32, 0xffffffff, SUCCESS}, + {0xffffffff, 8, 0, 0x00000000, SUCCESS}, + {0x00000000, 0,32, 0x00000000, SUCCESS}, + {0x0f0f0f0f, 0,32, 0x0f0f0f0f, SUCCESS}, + {0x00000000, 8, 0, 0x00000000, SUCCESS}, + {0x80000000,31, 1, 0x00000001, SUCCESS}, + {0x7fffffff,31, 1, 0x00000000, SUCCESS}, + {0x00000300, 8, 8, 0x00000003, SUCCESS}, + {0x0000ff00, 8, 8, 0x000000ff, SUCCESS}, + {0xfffffff0, 0, 5, 0x00000010, SUCCESS}, + {0x000000ff, 1, 3, 0x00000007, SUCCESS}, + {0x000000ff, 0, 3, 0x00000007, SUCCESS}, + {0x00000000, 0, 2, 0x00000000, SUCCESS}, + {0xffffffff, 0, 8, 0x000000ff, SUCCESS}, + {0xffff0000,16,16, 0x0000ffff, SUCCESS}, + {0xfffffff0, 0, 8, 0x00000000, FAIL}, + {0xffffffff,16,16, 0x00000000, FAIL}, + //{0xffffffff,32, 1, 0x00000000, ASSERT}, // Throw an assert + //{0xffffffff, 0,33, 0x00000000, ASSERT}, // Throw an assert + //{0xffffffff,16,16, 0x00000000, ASSERT}, // Throw an assert + }; + + static int test() + { + int Error = 0; + + glm::uint count = sizeof(Data32) / sizeof(typeU32); + + for(glm::uint i = 0; i < count; ++i) + { + glm::uint Return = glm::bitfieldExtract( + Data32[i].Value, + Data32[i].Offset, + Data32[i].Bits); + + bool Compare = Data32[i].Return == Return; + + if(Data32[i].Result == SUCCESS && Compare) + continue; + else if(Data32[i].Result == FAIL && !Compare) + continue; + + Error += 1; + } + + return Error; + } +}//extractField + +namespace bitfieldReverse +{ +/* + GLM_FUNC_QUALIFIER unsigned int bitfieldReverseLoop(unsigned int v) + { + unsigned int Result(0); + unsigned int const BitSize = static_cast(sizeof(unsigned int) * 8); + for(unsigned int i = 0; i < BitSize; ++i) + { + unsigned int const BitSet(v & (static_cast(1) << i)); + unsigned int const BitFirst(BitSet >> i); + Result |= BitFirst << (BitSize - 1 - i); + } + return Result; + } + + GLM_FUNC_QUALIFIER glm::uint64_t bitfieldReverseLoop(glm::uint64_t v) + { + glm::uint64_t Result(0); + glm::uint64_t const BitSize = static_cast(sizeof(unsigned int) * 8); + for(glm::uint64_t i = 0; i < BitSize; ++i) + { + glm::uint64_t const BitSet(v & (static_cast(1) << i)); + glm::uint64_t const BitFirst(BitSet >> i); + Result |= BitFirst << (BitSize - 1 - i); + } + return Result; + } +*/ + template + GLM_FUNC_QUALIFIER glm::vec bitfieldReverseLoop(glm::vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldReverse' only accept integer values"); + + glm::vec Result(0); + T const BitSize = static_cast(sizeof(T) * 8); + for(T i = 0; i < BitSize; ++i) + { + glm::vec const BitSet(v & (static_cast(1) << i)); + glm::vec const BitFirst(BitSet >> i); + Result |= BitFirst << (BitSize - 1 - i); + } + return Result; + } + + template + GLM_FUNC_QUALIFIER T bitfieldReverseLoop(T v) + { + return bitfieldReverseLoop(glm::vec<1, T>(v)).x; + } + + GLM_FUNC_QUALIFIER glm::uint32 bitfieldReverseUint32(glm::uint32 x) + { + x = (x & 0x55555555) << 1 | (x & 0xAAAAAAAA) >> 1; + x = (x & 0x33333333) << 2 | (x & 0xCCCCCCCC) >> 2; + x = (x & 0x0F0F0F0F) << 4 | (x & 0xF0F0F0F0) >> 4; + x = (x & 0x00FF00FF) << 8 | (x & 0xFF00FF00) >> 8; + x = (x & 0x0000FFFF) << 16 | (x & 0xFFFF0000) >> 16; + return x; + } + + GLM_FUNC_QUALIFIER glm::uint64 bitfieldReverseUint64(glm::uint64 x) + { + x = (x & 0x5555555555555555) << 1 | (x & 0xAAAAAAAAAAAAAAAA) >> 1; + x = (x & 0x3333333333333333) << 2 | (x & 0xCCCCCCCCCCCCCCCC) >> 2; + x = (x & 0x0F0F0F0F0F0F0F0F) << 4 | (x & 0xF0F0F0F0F0F0F0F0) >> 4; + x = (x & 0x00FF00FF00FF00FF) << 8 | (x & 0xFF00FF00FF00FF00) >> 8; + x = (x & 0x0000FFFF0000FFFF) << 16 | (x & 0xFFFF0000FFFF0000) >> 16; + x = (x & 0x00000000FFFFFFFF) << 32 | (x & 0xFFFFFFFF00000000) >> 32; + return x; + } + + template + struct compute_bitfieldReverseStep + { + template + GLM_FUNC_QUALIFIER static glm::vec call(glm::vec const& v, T, T) + { + return v; + } + }; + + template<> + struct compute_bitfieldReverseStep + { + template + GLM_FUNC_QUALIFIER static glm::vec call(glm::vec const& v, T Mask, T Shift) + { + return (v & Mask) << Shift | (v & (~Mask)) >> Shift; + } + }; + + template + GLM_FUNC_QUALIFIER glm::vec bitfieldReverseOps(glm::vec const& v) + { + glm::vec x(v); + x = compute_bitfieldReverseStep= 2>::call(x, static_cast(0x5555555555555555ull), static_cast( 1)); + x = compute_bitfieldReverseStep= 4>::call(x, static_cast(0x3333333333333333ull), static_cast( 2)); + x = compute_bitfieldReverseStep= 8>::call(x, static_cast(0x0F0F0F0F0F0F0F0Full), static_cast( 4)); + x = compute_bitfieldReverseStep= 16>::call(x, static_cast(0x00FF00FF00FF00FFull), static_cast( 8)); + x = compute_bitfieldReverseStep= 32>::call(x, static_cast(0x0000FFFF0000FFFFull), static_cast(16)); + x = compute_bitfieldReverseStep= 64>::call(x, static_cast(0x00000000FFFFFFFFull), static_cast(32)); + return x; + } + + template + GLM_FUNC_QUALIFIER genType bitfieldReverseOps(genType x) + { + return bitfieldReverseOps(glm::vec<1, genType, glm::defaultp>(x)).x; + } + + template + struct type + { + genType Value; + genType Return; + result Result; + }; + + typedef type typeU32; + + typeU32 const Data32[] = + { + {0x00000001, 0x80000000, SUCCESS}, + {0x0000000f, 0xf0000000, SUCCESS}, + {0x000000ff, 0xff000000, SUCCESS}, + {0xf0000000, 0x0000000f, SUCCESS}, + {0xff000000, 0x000000ff, SUCCESS}, + {0xffffffff, 0xffffffff, SUCCESS}, + {0x00000000, 0x00000000, SUCCESS} + }; + + typedef type typeU64; + + typeU64 const Data64[] = + { + {0x00000000000000ff, 0xff00000000000000, SUCCESS}, + {0x000000000000000f, 0xf000000000000000, SUCCESS}, + {0xf000000000000000, 0x000000000000000f, SUCCESS}, + {0xffffffffffffffff, 0xffffffffffffffff, SUCCESS}, + {0x0000000000000000, 0x0000000000000000, SUCCESS} + }; + + static int test32_bitfieldReverse() + { + int Error = 0; + std::size_t const Count = sizeof(Data32) / sizeof(typeU32); + + for(std::size_t i = 0; i < Count; ++i) + { + glm::uint Return = glm::bitfieldReverse(Data32[i].Value); + + bool Compare = Data32[i].Return == Return; + + if(Data32[i].Result == SUCCESS) + Error += Compare ? 0 : 1; + else + Error += Compare ? 1 : 0; + } + + return Error; + } + + static int test32_bitfieldReverseLoop() + { + int Error = 0; + std::size_t const Count = sizeof(Data32) / sizeof(typeU32); + + for(std::size_t i = 0; i < Count; ++i) + { + glm::uint Return = bitfieldReverseLoop(Data32[i].Value); + + bool Compare = Data32[i].Return == Return; + + if(Data32[i].Result == SUCCESS) + Error += Compare ? 0 : 1; + else + Error += Compare ? 1 : 0; + } + + return Error; + } + + static int test32_bitfieldReverseUint32() + { + int Error = 0; + std::size_t const Count = sizeof(Data32) / sizeof(typeU32); + + for(std::size_t i = 0; i < Count; ++i) + { + glm::uint Return = bitfieldReverseUint32(Data32[i].Value); + + bool Compare = Data32[i].Return == Return; + + if(Data32[i].Result == SUCCESS) + Error += Compare ? 0 : 1; + else + Error += Compare ? 1 : 0; + } + + return Error; + } + + static int test32_bitfieldReverseOps() + { + int Error = 0; + std::size_t const Count = sizeof(Data32) / sizeof(typeU32); + + for(std::size_t i = 0; i < Count; ++i) + { + glm::uint Return = bitfieldReverseOps(Data32[i].Value); + + bool Compare = Data32[i].Return == Return; + + if(Data32[i].Result == SUCCESS) + Error += Compare ? 0 : 1; + else + Error += Compare ? 1 : 0; + } + + return Error; + } + + static int test64_bitfieldReverse() + { + int Error = 0; + std::size_t const Count = sizeof(Data64) / sizeof(typeU64); + + for(std::size_t i = 0; i < Count; ++i) + { + glm::uint64 Return = glm::bitfieldReverse(Data64[i].Value); + + bool Compare = Data64[i].Return == Return; + + if(Data64[i].Result == SUCCESS) + Error += Compare ? 0 : 1; + else + Error += Compare ? 1 : 0; + } + + return Error; + } + + static int test64_bitfieldReverseLoop() + { + int Error = 0; + std::size_t const Count = sizeof(Data64) / sizeof(typeU64); + + for(std::size_t i = 0; i < Count; ++i) + { + glm::uint64 Return = bitfieldReverseLoop(Data64[i].Value); + + bool Compare = Data64[i].Return == Return; + + if(Data32[i].Result == SUCCESS) + Error += Compare ? 0 : 1; + else + Error += Compare ? 1 : 0; + } + + return Error; + } + + static int test64_bitfieldReverseUint64() + { + int Error = 0; + std::size_t const Count = sizeof(Data64) / sizeof(typeU64); + + for(std::size_t i = 0; i < Count; ++i) + { + glm::uint64 Return = bitfieldReverseUint64(Data64[i].Value); + + bool Compare = Data64[i].Return == Return; + + if(Data64[i].Result == SUCCESS) + Error += Compare ? 0 : 1; + else + Error += Compare ? 1 : 0; + } + + return Error; + } + + static int test64_bitfieldReverseOps() + { + int Error = 0; + std::size_t const Count = sizeof(Data64) / sizeof(typeU64); + + for(std::size_t i = 0; i < Count; ++i) + { + glm::uint64 Return = bitfieldReverseOps(Data64[i].Value); + + bool Compare = Data64[i].Return == Return; + + if(Data64[i].Result == SUCCESS) + Error += Compare ? 0 : 1; + else + Error += Compare ? 1 : 0; + } + + return Error; + } + + static int test() + { + int Error = 0; + + Error += test32_bitfieldReverse(); + Error += test32_bitfieldReverseLoop(); + Error += test32_bitfieldReverseUint32(); + Error += test32_bitfieldReverseOps(); + + Error += test64_bitfieldReverse(); + Error += test64_bitfieldReverseLoop(); + Error += test64_bitfieldReverseUint64(); + Error += test64_bitfieldReverseOps(); + + return Error; + } + + static int perf32(glm::uint32 Count) + { + int Error = 0; + + std::vector Data; + Data.resize(static_cast(Count)); + + std::clock_t Timestamps0 = std::clock(); + + for(glm::uint32 k = 0; k < Count; ++k) + Data[k] = glm::bitfieldReverse(k); + + std::clock_t Timestamps1 = std::clock(); + + for(glm::uint32 k = 0; k < Count; ++k) + Data[k] = bitfieldReverseLoop(k); + + std::clock_t Timestamps2 = std::clock(); + + for(glm::uint32 k = 0; k < Count; ++k) + Data[k] = bitfieldReverseUint32(k); + + std::clock_t Timestamps3 = std::clock(); + + for(glm::uint32 k = 0; k < Count; ++k) + Data[k] = bitfieldReverseOps(k); + + std::clock_t Timestamps4 = std::clock(); + + std::printf("glm::bitfieldReverse: %d clocks\n", static_cast(Timestamps1 - Timestamps0)); + std::printf("bitfieldReverseLoop: %d clocks\n", static_cast(Timestamps2 - Timestamps1)); + std::printf("bitfieldReverseUint32: %d clocks\n", static_cast(Timestamps3 - Timestamps2)); + std::printf("bitfieldReverseOps: %d clocks\n", static_cast(Timestamps4 - Timestamps3)); + + return Error; + } + + static int perf64(glm::uint64 Count) + { + int Error = 0; + + std::vector Data; + Data.resize(static_cast(Count)); + + std::clock_t Timestamps0 = std::clock(); + + for(glm::uint64 k = 0; k < Count; ++k) + Data[static_cast(k)] = glm::bitfieldReverse(k); + + std::clock_t Timestamps1 = std::clock(); + + for(glm::uint64 k = 0; k < Count; ++k) + Data[static_cast(k)] = bitfieldReverseLoop(k); + + std::clock_t Timestamps2 = std::clock(); + + for(glm::uint64 k = 0; k < Count; ++k) + Data[static_cast(k)] = bitfieldReverseUint64(k); + + std::clock_t Timestamps3 = std::clock(); + + for(glm::uint64 k = 0; k < Count; ++k) + Data[static_cast(k)] = bitfieldReverseOps(k); + + std::clock_t Timestamps4 = std::clock(); + + std::printf("glm::bitfieldReverse - 64: %d clocks\n", static_cast(Timestamps1 - Timestamps0)); + std::printf("bitfieldReverseLoop - 64: %d clocks\n", static_cast(Timestamps2 - Timestamps1)); + std::printf("bitfieldReverseUint - 64: %d clocks\n", static_cast(Timestamps3 - Timestamps2)); + std::printf("bitfieldReverseOps - 64: %d clocks\n", static_cast(Timestamps4 - Timestamps3)); + + return Error; + } + + static int perf(std::size_t Samples) + { + int Error = 0; + + Error += perf32(static_cast(Samples)); + Error += perf64(static_cast(Samples)); + + return Error; + } +}//bitfieldReverse + +namespace findMSB +{ + template + struct type + { + genType Value; + retType Return; + }; + +# if GLM_HAS_BITSCAN_WINDOWS + template + static int findMSB_intrinsic(genIUType Value) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'findMSB' only accept integer values"); + + if(Value == 0) + return -1; + + unsigned long Result(0); + _BitScanReverse(&Result, Value); + return int(Result); + } +# endif//GLM_HAS_BITSCAN_WINDOWS + +# if GLM_ARCH & GLM_ARCH_AVX && GLM_COMPILER & GLM_COMPILER_VC + template + static int findMSB_avx(genIUType Value) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'findMSB' only accept integer values"); + + if(Value == 0) + return -1; + + return int(_tzcnt_u32(Value)); + } +# endif//GLM_ARCH & GLM_ARCH_AVX && GLM_PLATFORM & GLM_PLATFORM_WINDOWS + + template + static int findMSB_095(genIUType Value) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'findMSB' only accept integer values"); + + if(Value == genIUType(0) || Value == genIUType(-1)) + return -1; + else if(Value > 0) + { + genIUType Bit = genIUType(-1); + for(genIUType tmp = Value; tmp > 0; tmp >>= 1, ++Bit){} + return static_cast(Bit); + } + else //if(Value < 0) + { + int const BitCount(sizeof(genIUType) * 8); + int MostSignificantBit(-1); + for(int BitIndex(0); BitIndex < BitCount; ++BitIndex) + MostSignificantBit = (Value & (1 << BitIndex)) ? MostSignificantBit : BitIndex; + assert(MostSignificantBit >= 0); + return MostSignificantBit; + } + } + + template + static int findMSB_nlz1(genIUType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'findMSB' only accept integer values"); + + if (x == 0) + return -1; + + int n = 0; + if (x <= 0x0000FFFF) {n = n +16; x = x <<16;} + if (x <= 0x00FFFFFF) {n = n + 8; x = x << 8;} + if (x <= 0x0FFFFFFF) {n = n + 4; x = x << 4;} + if (x <= 0x3FFFFFFF) {n = n + 2; x = x << 2;} + if (x <= 0x7FFFFFFF) {n = n + 1;} + return 31 - n; + } + + static int findMSB_nlz2(unsigned int x) + { + unsigned int y; + int n = 32; + + y = x >>16; if (y != 0) {n = n -16; x = y;} + y = x >> 8; if (y != 0) {n = n - 8; x = y;} + y = x >> 4; if (y != 0) {n = n - 4; x = y;} + y = x >> 2; if (y != 0) {n = n - 2; x = y;} + y = x >> 1; if (y != 0) return n - 2; + return 32 - (n - static_cast(x)); + } + + static int findMSB_pop(unsigned int x) + { + x = x | (x >> 1); + x = x | (x >> 2); + x = x | (x >> 4); + x = x | (x >> 8); + x = x | (x >>16); + return 31 - glm::bitCount(~x); + } + + static int perf_int(std::size_t Count) + { + type const Data[] = + { + {0x00000000, -1}, + {0x00000001, 0}, + {0x00000002, 1}, + {0x00000003, 1}, + {0x00000004, 2}, + {0x00000005, 2}, + {0x00000007, 2}, + {0x00000008, 3}, + {0x00000010, 4}, + {0x00000020, 5}, + {0x00000040, 6}, + {0x00000080, 7}, + {0x00000100, 8}, + {0x00000200, 9}, + {0x00000400, 10}, + {0x00000800, 11}, + {0x00001000, 12}, + {0x00002000, 13}, + {0x00004000, 14}, + {0x00008000, 15}, + {0x00010000, 16}, + {0x00020000, 17}, + {0x00040000, 18}, + {0x00080000, 19}, + {0x00100000, 20}, + {0x00200000, 21}, + {0x00400000, 22}, + {0x00800000, 23}, + {0x01000000, 24}, + {0x02000000, 25}, + {0x04000000, 26}, + {0x08000000, 27}, + {0x10000000, 28}, + {0x20000000, 29}, + {0x40000000, 30} + }; + + int Error(0); + + std::clock_t Timestamps0 = std::clock(); + + for(std::size_t k = 0; k < Count; ++k) + for(std::size_t i = 0; i < sizeof(Data) / sizeof(type); ++i) + { + int Result = glm::findMSB(Data[i].Value); + Error += Data[i].Return == Result ? 0 : 1; + } + + std::clock_t Timestamps1 = std::clock(); + + for(std::size_t k = 0; k < Count; ++k) + for(std::size_t i = 0; i < sizeof(Data) / sizeof(type); ++i) + { + int Result = findMSB_nlz1(Data[i].Value); + Error += Data[i].Return == Result ? 0 : 1; + } + + std::clock_t Timestamps2 = std::clock(); + + for(std::size_t k = 0; k < Count; ++k) + for(std::size_t i = 0; i < sizeof(Data) / sizeof(type); ++i) + { + int Result = findMSB_nlz2(static_cast(Data[i].Value)); + Error += Data[i].Return == Result ? 0 : 1; + } + + std::clock_t Timestamps3 = std::clock(); + + for(std::size_t k = 0; k < Count; ++k) + for(std::size_t i = 0; i < sizeof(Data) / sizeof(type); ++i) + { + int Result = findMSB_095(static_cast(Data[i].Value)); + Error += Data[i].Return == Result ? 0 : 1; + } + + std::clock_t Timestamps4 = std::clock(); + +# if GLM_HAS_BITSCAN_WINDOWS + for(std::size_t k = 0; k < Count; ++k) + for(std::size_t i = 0; i < sizeof(Data) / sizeof(type); ++i) + { + int Result = findMSB_intrinsic(Data[i].Value); + Error += Data[i].Return == Result ? 0 : 1; + } +# endif//GLM_HAS_BITSCAN_WINDOWS + + std::clock_t Timestamps5 = std::clock(); + + for(std::size_t k = 0; k < Count; ++k) + for(std::size_t i = 0; i < sizeof(Data) / sizeof(type); ++i) + { + int Result = findMSB_pop(static_cast(Data[i].Value)); + Error += Data[i].Return == Result ? 0 : 1; + } + + std::clock_t Timestamps6 = std::clock(); + +# if GLM_ARCH & GLM_ARCH_AVX && GLM_COMPILER & GLM_COMPILER_VC + for(std::size_t k = 0; k < Count; ++k) + for(std::size_t i = 0; i < sizeof(Data) / sizeof(type); ++i) + { + int Result = findMSB_avx(Data[i].Value); + Error += Data[i].Return == Result ? 0 : 1; + } + + std::clock_t Timestamps7 = std::clock(); +# endif + + std::printf("glm::findMSB: %d clocks\n", static_cast(Timestamps1 - Timestamps0)); + std::printf("findMSB - nlz1: %d clocks\n", static_cast(Timestamps2 - Timestamps1)); + std::printf("findMSB - nlz2: %d clocks\n", static_cast(Timestamps3 - Timestamps2)); + std::printf("findMSB - 0.9.5: %d clocks\n", static_cast(Timestamps4 - Timestamps3)); + +# if GLM_HAS_BITSCAN_WINDOWS + std::printf("findMSB - intrinsics: %d clocks\n", static_cast(Timestamps5 - Timestamps4)); +# endif//GLM_HAS_BITSCAN_WINDOWS + std::printf("findMSB - pop: %d clocks\n", static_cast(Timestamps6 - Timestamps5)); + +# if GLM_ARCH & GLM_ARCH_AVX && GLM_COMPILER & GLM_COMPILER_VC + std::printf("findMSB - avx tzcnt: %d clocks\n", static_cast(Timestamps7 - Timestamps6)); +# endif//GLM_ARCH & GLM_ARCH_AVX && GLM_PLATFORM & GLM_PLATFORM_WINDOWS + + return Error; + } + + static int test_ivec4() + { + type const Data[] = + { + {glm::ivec4(0x00000000), glm::ivec4(-1)}, + {glm::ivec4(0x00000001), glm::ivec4( 0)}, + {glm::ivec4(0x00000002), glm::ivec4( 1)}, + {glm::ivec4(0x00000003), glm::ivec4( 1)}, + {glm::ivec4(0x00000004), glm::ivec4( 2)}, + {glm::ivec4(0x00000005), glm::ivec4( 2)}, + {glm::ivec4(0x00000007), glm::ivec4( 2)}, + {glm::ivec4(0x00000008), glm::ivec4( 3)}, + {glm::ivec4(0x00000010), glm::ivec4( 4)}, + {glm::ivec4(0x00000020), glm::ivec4( 5)}, + {glm::ivec4(0x00000040), glm::ivec4( 6)}, + {glm::ivec4(0x00000080), glm::ivec4( 7)}, + {glm::ivec4(0x00000100), glm::ivec4( 8)}, + {glm::ivec4(0x00000200), glm::ivec4( 9)}, + {glm::ivec4(0x00000400), glm::ivec4(10)}, + {glm::ivec4(0x00000800), glm::ivec4(11)}, + {glm::ivec4(0x00001000), glm::ivec4(12)}, + {glm::ivec4(0x00002000), glm::ivec4(13)}, + {glm::ivec4(0x00004000), glm::ivec4(14)}, + {glm::ivec4(0x00008000), glm::ivec4(15)}, + {glm::ivec4(0x00010000), glm::ivec4(16)}, + {glm::ivec4(0x00020000), glm::ivec4(17)}, + {glm::ivec4(0x00040000), glm::ivec4(18)}, + {glm::ivec4(0x00080000), glm::ivec4(19)}, + {glm::ivec4(0x00100000), glm::ivec4(20)}, + {glm::ivec4(0x00200000), glm::ivec4(21)}, + {glm::ivec4(0x00400000), glm::ivec4(22)}, + {glm::ivec4(0x00800000), glm::ivec4(23)}, + {glm::ivec4(0x01000000), glm::ivec4(24)}, + {glm::ivec4(0x02000000), glm::ivec4(25)}, + {glm::ivec4(0x04000000), glm::ivec4(26)}, + {glm::ivec4(0x08000000), glm::ivec4(27)}, + {glm::ivec4(0x10000000), glm::ivec4(28)}, + {glm::ivec4(0x20000000), glm::ivec4(29)}, + {glm::ivec4(0x40000000), glm::ivec4(30)} + }; + + int Error(0); + + for(std::size_t i = 0; i < sizeof(Data) / sizeof(type); ++i) + { + glm::ivec4 Result0 = glm::findMSB(Data[i].Value); + Error += glm::all(glm::equal(Data[i].Return, Result0)) ? 0 : 1; + } + + return Error; + } + + static int test_int() + { + typedef type entry; + + entry const Data[] = + { + {0x00000000, -1}, + {0x00000001, 0}, + {0x00000002, 1}, + {0x00000003, 1}, + {0x00000004, 2}, + {0x00000005, 2}, + {0x00000007, 2}, + {0x00000008, 3}, + {0x00000010, 4}, + {0x00000020, 5}, + {0x00000040, 6}, + {0x00000080, 7}, + {0x00000100, 8}, + {0x00000200, 9}, + {0x00000400, 10}, + {0x00000800, 11}, + {0x00001000, 12}, + {0x00002000, 13}, + {0x00004000, 14}, + {0x00008000, 15}, + {0x00010000, 16}, + {0x00020000, 17}, + {0x00040000, 18}, + {0x00080000, 19}, + {0x00100000, 20}, + {0x00200000, 21}, + {0x00400000, 22}, + {0x00800000, 23}, + {0x01000000, 24}, + {0x02000000, 25}, + {0x04000000, 26}, + {0x08000000, 27}, + {0x10000000, 28}, + {0x20000000, 29}, + {0x40000000, 30} + }; + + int Error(0); + + for(std::size_t i = 0; i < sizeof(Data) / sizeof(entry); ++i) + { + int Result0 = glm::findMSB(Data[i].Value); + Error += Data[i].Return == Result0 ? 0 : 1; + } + + for(std::size_t i = 0; i < sizeof(Data) / sizeof(entry); ++i) + { + int Result0 = findMSB_nlz1(Data[i].Value); + Error += Data[i].Return == Result0 ? 0 : 1; + } +/* + for(std::size_t i = 0; i < sizeof(Data) / sizeof(entry); ++i) + { + int Result0 = findMSB_nlz2(Data[i].Value); + Error += Data[i].Return == Result0 ? 0 : 1; + } +*/ + for(std::size_t i = 0; i < sizeof(Data) / sizeof(entry); ++i) + { + int Result0 = findMSB_095(Data[i].Value); + Error += Data[i].Return == Result0 ? 0 : 1; + } + +# if GLM_HAS_BITSCAN_WINDOWS + for(std::size_t i = 0; i < sizeof(Data) / sizeof(entry); ++i) + { + int Result0 = findMSB_intrinsic(Data[i].Value); + Error += Data[i].Return == Result0 ? 0 : 1; + } +# endif//GLM_HAS_BITSCAN_WINDOWS + + for(std::size_t i = 0; i < sizeof(Data) / sizeof(entry); ++i) + { + int Result0 = findMSB_pop(Data[i].Value); + Error += Data[i].Return == Result0 ? 0 : 1; + } + + return Error; + } + + static int test() + { + int Error(0); + + Error += test_ivec4(); + Error += test_int(); + + return Error; + } + + static int perf(std::size_t Samples) + { + int Error(0); + + Error += perf_int(Samples); + + return Error; + } +}//findMSB + +namespace findLSB +{ + template + struct type + { + genType Value; + retType Return; + }; + + typedef type entry; + + entry const DataI32[] = + { + {0x00000001, 0}, + {0x00000003, 0}, + {0x00000002, 1}, + // {0x80000000, 31}, // Clang generates an error with this + {0x00010000, 16}, + {0x7FFF0000, 16}, + {0x7F000000, 24}, + {0x7F00FF00, 8}, + {0x00000000, -1} + }; + +# if GLM_HAS_BITSCAN_WINDOWS + template + static int findLSB_intrinsic(genIUType Value) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'findLSB' only accept integer values"); + + if(Value == 0) + return -1; + + unsigned long Result(0); + _BitScanForward(&Result, Value); + return int(Result); + } +# endif + + template + static int findLSB_095(genIUType Value) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'findLSB' only accept integer values"); + if(Value == 0) + return -1; + + genIUType Bit; + for(Bit = genIUType(0); !(Value & (1 << Bit)); ++Bit){} + return Bit; + } + + template + static int findLSB_ntz2(genIUType x) + { + if(x == 0) + return -1; + + return glm::bitCount(~x & (x - static_cast(1))); + } + + template + static int findLSB_branchfree(genIUType x) + { + bool IsNull(x == 0); + int const Keep(!IsNull); + int const Discard(IsNull); + + return static_cast(glm::bitCount(~x & (x - static_cast(1)))) * Keep + Discard * -1; + } + + static int test_int() + { + int Error(0); + + for(std::size_t i = 0; i < sizeof(DataI32) / sizeof(entry); ++i) + { + int Result = glm::findLSB(DataI32[i].Value); + Error += DataI32[i].Return == Result ? 0 : 1; + } + + for(std::size_t i = 0; i < sizeof(DataI32) / sizeof(entry); ++i) + { + int Result = findLSB_095(DataI32[i].Value); + Error += DataI32[i].Return == Result ? 0 : 1; + } + +# if GLM_HAS_BITSCAN_WINDOWS + for(std::size_t i = 0; i < sizeof(DataI32) / sizeof(entry); ++i) + { + int Result = findLSB_intrinsic(DataI32[i].Value); + Error += DataI32[i].Return == Result ? 0 : 1; + } +# endif + + for(std::size_t i = 0; i < sizeof(DataI32) / sizeof(entry); ++i) + { + int Result = findLSB_ntz2(DataI32[i].Value); + Error += DataI32[i].Return == Result ? 0 : 1; + } + + for(std::size_t i = 0; i < sizeof(DataI32) / sizeof(entry); ++i) + { + int Result = findLSB_branchfree(DataI32[i].Value); + Error += DataI32[i].Return == Result ? 0 : 1; + } + + return Error; + } + + static int test() + { + int Error(0); + + Error += test_int(); + + return Error; + } + + static int perf_int(std::size_t Count) + { + int Error(0); + + std::clock_t Timestamps0 = std::clock(); + + for(std::size_t k = 0; k < Count; ++k) + for(std::size_t i = 0; i < sizeof(DataI32) / sizeof(entry); ++i) + { + int Result = glm::findLSB(DataI32[i].Value); + Error += DataI32[i].Return == Result ? 0 : 1; + } + + std::clock_t Timestamps1 = std::clock(); + + for(std::size_t k = 0; k < Count; ++k) + for(std::size_t i = 0; i < sizeof(DataI32) / sizeof(entry); ++i) + { + int Result = findLSB_095(DataI32[i].Value); + Error += DataI32[i].Return == Result ? 0 : 1; + } + + std::clock_t Timestamps2 = std::clock(); + +# if GLM_HAS_BITSCAN_WINDOWS + for(std::size_t k = 0; k < Count; ++k) + for(std::size_t i = 0; i < sizeof(DataI32) / sizeof(entry); ++i) + { + int Result = findLSB_intrinsic(DataI32[i].Value); + Error += DataI32[i].Return == Result ? 0 : 1; + } +# endif + + std::clock_t Timestamps3 = std::clock(); + + for(std::size_t k = 0; k < Count; ++k) + for(std::size_t i = 0; i < sizeof(DataI32) / sizeof(entry); ++i) + { + int Result = findLSB_ntz2(DataI32[i].Value); + Error += DataI32[i].Return == Result ? 0 : 1; + } + + std::clock_t Timestamps4 = std::clock(); + + for(std::size_t k = 0; k < Count; ++k) + for(std::size_t i = 0; i < sizeof(DataI32) / sizeof(entry); ++i) + { + int Result = findLSB_branchfree(DataI32[i].Value); + Error += DataI32[i].Return == Result ? 0 : 1; + } + + std::clock_t Timestamps5 = std::clock(); + + std::printf("glm::findLSB: %d clocks\n", static_cast(Timestamps1 - Timestamps0)); + std::printf("findLSB - 0.9.5: %d clocks\n", static_cast(Timestamps2 - Timestamps1)); + +# if GLM_HAS_BITSCAN_WINDOWS + std::printf("findLSB - intrinsics: %d clocks\n", static_cast(Timestamps3 - Timestamps2)); +# endif + + std::printf("findLSB - ntz2: %d clocks\n", static_cast(Timestamps4 - Timestamps3)); + std::printf("findLSB - branchfree: %d clocks\n", static_cast(Timestamps5 - Timestamps4)); + + return Error; + } + + static int perf(std::size_t Samples) + { + int Error(0); + + Error += perf_int(Samples); + + return Error; + } +}//findLSB + +namespace uaddCarry +{ + static int test() + { + int Error(0); + + { + glm::uint x = std::numeric_limits::max(); + glm::uint y = 0; + glm::uint Carry = 0; + glm::uint Result = glm::uaddCarry(x, y, Carry); + + Error += Carry == 0 ? 0 : 1; + Error += Result == std::numeric_limits::max() ? 0 : 1; + } + + { + glm::uint x = std::numeric_limits::max(); + glm::uint y = 1; + glm::uint Carry = 0; + glm::uint Result = glm::uaddCarry(x, y, Carry); + + Error += Carry == 1 ? 0 : 1; + Error += Result == 0 ? 0 : 1; + } + + { + glm::uvec1 x(std::numeric_limits::max()); + glm::uvec1 y(0); + glm::uvec1 Carry(0); + glm::uvec1 Result(glm::uaddCarry(x, y, Carry)); + + Error += glm::all(glm::equal(Carry, glm::uvec1(0))) ? 0 : 1; + Error += glm::all(glm::equal(Result, glm::uvec1(std::numeric_limits::max()))) ? 0 : 1; + } + + { + glm::uvec1 x(std::numeric_limits::max()); + glm::uvec1 y(1); + glm::uvec1 Carry(0); + glm::uvec1 Result(glm::uaddCarry(x, y, Carry)); + + Error += glm::all(glm::equal(Carry, glm::uvec1(1))) ? 0 : 1; + Error += glm::all(glm::equal(Result, glm::uvec1(0))) ? 0 : 1; + } + + return Error; + } +}//namespace uaddCarry + +namespace usubBorrow +{ + static int test() + { + int Error(0); + + { + glm::uint x = 16; + glm::uint y = 17; + glm::uint Borrow = 0; + glm::uint Result = glm::usubBorrow(x, y, Borrow); + + Error += Borrow == 1 ? 0 : 1; + Error += Result == 1 ? 0 : 1; + } + + { + glm::uvec1 x(16); + glm::uvec1 y(17); + glm::uvec1 Borrow(0); + glm::uvec1 Result(glm::usubBorrow(x, y, Borrow)); + + Error += glm::all(glm::equal(Borrow, glm::uvec1(1))) ? 0 : 1; + Error += glm::all(glm::equal(Result, glm::uvec1(1))) ? 0 : 1; + } + + { + glm::uvec2 x(16); + glm::uvec2 y(17); + glm::uvec2 Borrow(0); + glm::uvec2 Result(glm::usubBorrow(x, y, Borrow)); + + Error += glm::all(glm::equal(Borrow, glm::uvec2(1))) ? 0 : 1; + Error += glm::all(glm::equal(Result, glm::uvec2(1))) ? 0 : 1; + } + + { + glm::uvec3 x(16); + glm::uvec3 y(17); + glm::uvec3 Borrow(0); + glm::uvec3 Result(glm::usubBorrow(x, y, Borrow)); + + Error += glm::all(glm::equal(Borrow, glm::uvec3(1))) ? 0 : 1; + Error += glm::all(glm::equal(Result, glm::uvec3(1))) ? 0 : 1; + } + + { + glm::uvec4 x(16); + glm::uvec4 y(17); + glm::uvec4 Borrow(0); + glm::uvec4 Result(glm::usubBorrow(x, y, Borrow)); + + Error += glm::all(glm::equal(Borrow, glm::uvec4(1))) ? 0 : 1; + Error += glm::all(glm::equal(Result, glm::uvec4(1))) ? 0 : 1; + } + + return Error; + } +}//namespace usubBorrow + +namespace umulExtended +{ + static int test() + { + int Error(0); + + { + glm::uint x = 2; + glm::uint y = 3; + glm::uint msb = 0; + glm::uint lsb = 0; + glm::umulExtended(x, y, msb, lsb); + + Error += msb == 0 ? 0 : 1; + Error += lsb == 6 ? 0 : 1; + } + + { + glm::uvec1 x(2); + glm::uvec1 y(3); + glm::uvec1 msb(0); + glm::uvec1 lsb(0); + glm::umulExtended(x, y, msb, lsb); + + Error += glm::all(glm::equal(msb, glm::uvec1(0))) ? 0 : 1; + Error += glm::all(glm::equal(lsb, glm::uvec1(6))) ? 0 : 1; + } + + { + glm::uvec2 x(2); + glm::uvec2 y(3); + glm::uvec2 msb(0); + glm::uvec2 lsb(0); + glm::umulExtended(x, y, msb, lsb); + + Error += glm::all(glm::equal(msb, glm::uvec2(0))) ? 0 : 1; + Error += glm::all(glm::equal(lsb, glm::uvec2(6))) ? 0 : 1; + } + + { + glm::uvec3 x(2); + glm::uvec3 y(3); + glm::uvec3 msb(0); + glm::uvec3 lsb(0); + glm::umulExtended(x, y, msb, lsb); + + Error += glm::all(glm::equal(msb, glm::uvec3(0))) ? 0 : 1; + Error += glm::all(glm::equal(lsb, glm::uvec3(6))) ? 0 : 1; + } + + { + glm::uvec4 x(2); + glm::uvec4 y(3); + glm::uvec4 msb(0); + glm::uvec4 lsb(0); + glm::umulExtended(x, y, msb, lsb); + + Error += glm::all(glm::equal(msb, glm::uvec4(0))) ? 0 : 1; + Error += glm::all(glm::equal(lsb, glm::uvec4(6))) ? 0 : 1; + } + + return Error; + } +}//namespace umulExtended + +namespace imulExtended +{ + static int test() + { + int Error(0); + + { + int x = 2; + int y = 3; + int msb = 0; + int lsb = 0; + glm::imulExtended(x, y, msb, lsb); + + Error += msb == 0 ? 0 : 1; + Error += lsb == 6 ? 0 : 1; + } + + { + glm::ivec1 x(2); + glm::ivec1 y(3); + glm::ivec1 msb(0); + glm::ivec1 lsb(0); + glm::imulExtended(x, y, msb, lsb); + + Error += glm::all(glm::equal(msb, glm::ivec1(0))) ? 0 : 1; + Error += glm::all(glm::equal(lsb, glm::ivec1(6))) ? 0 : 1; + } + + { + glm::ivec2 x(2); + glm::ivec2 y(3); + glm::ivec2 msb(0); + glm::ivec2 lsb(0); + glm::imulExtended(x, y, msb, lsb); + + Error += glm::all(glm::equal(msb, glm::ivec2(0))) ? 0 : 1; + Error += glm::all(glm::equal(lsb, glm::ivec2(6))) ? 0 : 1; + } + + { + glm::ivec3 x(2); + glm::ivec3 y(3); + glm::ivec3 msb(0); + glm::ivec3 lsb(0); + glm::imulExtended(x, y, msb, lsb); + + Error += glm::all(glm::equal(msb, glm::ivec3(0))) ? 0 : 1; + Error += glm::all(glm::equal(lsb, glm::ivec3(6))) ? 0 : 1; + } + + { + glm::ivec4 x(2); + glm::ivec4 y(3); + glm::ivec4 msb(0); + glm::ivec4 lsb(0); + glm::imulExtended(x, y, msb, lsb); + + Error += glm::all(glm::equal(msb, glm::ivec4(0))) ? 0 : 1; + Error += glm::all(glm::equal(lsb, glm::ivec4(6))) ? 0 : 1; + } + + return Error; + } +}//namespace imulExtended + +namespace bitCount +{ + template + struct type + { + genType Value; + genType Return; + }; + + type const DataI32[] = + { + {0x00000001, 1}, + {0x00000003, 2}, + {0x00000002, 1}, + {0x7fffffff, 31}, + {0x00000000, 0} + }; + + template + inline int bitCount_if(T v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitCount' only accept integer values"); + + int Count(0); + for(T i = 0, n = static_cast(sizeof(T) * 8); i < n; ++i) + { + if(v & static_cast(1 << i)) + ++Count; + } + return Count; + } + + template + inline int bitCount_vec(T v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitCount' only accept integer values"); + + int Count(0); + for(T i = 0, n = static_cast(sizeof(T) * 8); i < n; ++i) + { + Count += static_cast((v >> i) & static_cast(1)); + } + return Count; + } + + template + struct compute_bitfieldBitCountStep + { + template + GLM_FUNC_QUALIFIER static glm::vec call(glm::vec const& v, T, T) + { + return v; + } + }; + + template<> + struct compute_bitfieldBitCountStep + { + template + GLM_FUNC_QUALIFIER static glm::vec call(glm::vec const& v, T Mask, T Shift) + { + return (v & Mask) + ((v >> Shift) & Mask); + } + }; + + template + static glm::vec bitCount_bitfield(glm::vec const& v) + { + glm::vec::type, Q> x(*reinterpret_cast::type, Q> const *>(&v)); + x = compute_bitfieldBitCountStep= 2>::call(x, static_cast::type>(0x5555555555555555ull), static_cast::type>( 1)); + x = compute_bitfieldBitCountStep= 4>::call(x, static_cast::type>(0x3333333333333333ull), static_cast::type>( 2)); + x = compute_bitfieldBitCountStep= 8>::call(x, static_cast::type>(0x0F0F0F0F0F0F0F0Full), static_cast::type>( 4)); + x = compute_bitfieldBitCountStep= 16>::call(x, static_cast::type>(0x00FF00FF00FF00FFull), static_cast::type>( 8)); + x = compute_bitfieldBitCountStep= 32>::call(x, static_cast::type>(0x0000FFFF0000FFFFull), static_cast::type>(16)); + x = compute_bitfieldBitCountStep= 64>::call(x, static_cast::type>(0x00000000FFFFFFFFull), static_cast::type>(32)); + return glm::vec(x); + } + + template + static int bitCount_bitfield(genType x) + { + return bitCount_bitfield(glm::vec<1, genType, glm::defaultp>(x)).x; + } + + static int perf(std::size_t Size) + { + int Error(0); + + std::vector v; + v.resize(Size); + + std::vector w; + w.resize(Size); + + + std::clock_t TimestampsA = std::clock(); + + // bitCount - TimeIf + { + for(std::size_t i = 0, n = v.size(); i < n; ++i) + v[i] = bitCount_if(static_cast(i)); + } + + std::clock_t TimestampsB = std::clock(); + + // bitCount - TimeVec + { + for(std::size_t i = 0, n = v.size(); i < n; ++i) + v[i] = bitCount_vec(i); + } + + std::clock_t TimestampsC = std::clock(); + + // bitCount - TimeDefault + { + for(std::size_t i = 0, n = v.size(); i < n; ++i) + v[i] = glm::bitCount(i); + } + + std::clock_t TimestampsD = std::clock(); + + // bitCount - TimeVec4 + { + for(std::size_t i = 0, n = v.size(); i < n; ++i) + w[i] = glm::bitCount(glm::ivec4(static_cast(i))); + } + + std::clock_t TimestampsE = std::clock(); + + { + for(std::size_t i = 0, n = v.size(); i < n; ++i) + v[i] = bitCount_bitfield(static_cast(i)); + } + + std::clock_t TimestampsF = std::clock(); + + std::printf("bitCount - TimeIf %d\n", static_cast(TimestampsB - TimestampsA)); + std::printf("bitCount - TimeVec %d\n", static_cast(TimestampsC - TimestampsB)); + std::printf("bitCount - TimeDefault %d\n", static_cast(TimestampsD - TimestampsC)); + std::printf("bitCount - TimeVec4 %d\n", static_cast(TimestampsE - TimestampsD)); + std::printf("bitCount - bitfield %d\n", static_cast(TimestampsF - TimestampsE)); + + return Error; + } + + static int test() + { + int Error(0); + + for(std::size_t i = 0, n = sizeof(DataI32) / sizeof(type); i < n; ++i) + { + int ResultA = glm::bitCount(DataI32[i].Value); + int ResultB = bitCount_if(DataI32[i].Value); + int ResultC = bitCount_vec(DataI32[i].Value); + int ResultE = bitCount_bitfield(DataI32[i].Value); + + Error += DataI32[i].Return == ResultA ? 0 : 1; + Error += DataI32[i].Return == ResultB ? 0 : 1; + Error += DataI32[i].Return == ResultC ? 0 : 1; + Error += DataI32[i].Return == ResultE ? 0 : 1; + + assert(!Error); + } + + return Error; + } +}//bitCount + +int main() +{ + int Error = 0; + + Error += ::bitCount::test(); + Error += ::bitfieldReverse::test(); + Error += ::findMSB::test(); + Error += ::findLSB::test(); + Error += ::umulExtended::test(); + Error += ::imulExtended::test(); + Error += ::uaddCarry::test(); + Error += ::usubBorrow::test(); + Error += ::bitfieldInsert::test(); + Error += ::bitfieldExtract::test(); + +# ifdef NDEBUG + std::size_t const Samples = 1000; +# else + std::size_t const Samples = 1; +# endif + + ::bitCount::perf(Samples); + ::bitfieldReverse::perf(Samples); + ::findMSB::perf(Samples); + ::findLSB::perf(Samples); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_integer_bit_count.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_integer_bit_count.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0fa11fbe3fcc847320badab823edebbb261186eb --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_integer_bit_count.cpp @@ -0,0 +1,291 @@ +// This has the programs for computing the number of 1-bits +// in a word, or byte, etc. +// Max line length is 57, to fit in hacker.book. +#include +#include //To define "exit", req'd by XLC. +#include + +unsigned rotatel(unsigned x, int n) +{ + if (static_cast(n) > 63) { std::printf("rotatel, n out of range.\n"); std::exit(1);} + return (x << n) | (x >> (32 - n)); +} + +int pop0(unsigned x) +{ + x = (x & 0x55555555) + ((x >> 1) & 0x55555555); + x = (x & 0x33333333) + ((x >> 2) & 0x33333333); + x = (x & 0x0F0F0F0F) + ((x >> 4) & 0x0F0F0F0F); + x = (x & 0x00FF00FF) + ((x >> 8) & 0x00FF00FF); + x = (x & 0x0000FFFF) + ((x >>16) & 0x0000FFFF); + return x; +} + +int pop1(unsigned x) +{ + x = x - ((x >> 1) & 0x55555555); + x = (x & 0x33333333) + ((x >> 2) & 0x33333333); + x = (x + (x >> 4)) & 0x0F0F0F0F; + x = x + (x >> 8); + x = x + (x >> 16); + return x & 0x0000003F; +} +/* Note: an alternative to the last three executable lines above is: + return x*0x01010101 >> 24; +if your machine has a fast multiplier (suggested by Jari Kirma). */ + +int pop2(unsigned x) +{ + unsigned n; + + n = (x >> 1) & 033333333333; // Count bits in + x = x - n; // each 3-bit + n = (n >> 1) & 033333333333; // field. + x = x - n; + x = (x + (x >> 3)) & 030707070707; // 6-bit sums. + return x%63; // Add 6-bit sums. +} + +/* An alternative to the "return" statement above is: + return ((x * 0404040404) >> 26) + // Add 6-bit sums. + (x >> 30); +which runs faster on most machines (suggested by Norbert Juffa). */ + +int pop3(unsigned x) +{ + unsigned n; + + n = (x >> 1) & 0x77777777; // Count bits in + x = x - n; // each 4-bit + n = (n >> 1) & 0x77777777; // field. + x = x - n; + n = (n >> 1) & 0x77777777; + x = x - n; + x = (x + (x >> 4)) & 0x0F0F0F0F; // Get byte sums. + x = x*0x01010101; // Add the bytes. + return x >> 24; +} + +int pop4(unsigned x) +{ + int n; + + n = 0; + while (x != 0) { + n = n + 1; + x = x & (x - 1); + } + return n; +} + +int pop5(unsigned x) +{ + int i, sum; + + // Rotate and sum method // Shift right & subtract + + sum = x; // sum = x; + for (i = 1; i <= 31; i++) { // while (x != 0) { + x = rotatel(x, 1); // x = x >> 1; + sum = sum + x; // sum = sum - x; + } // } + return -sum; // return sum; +} + +int pop5a(unsigned x) +{ + int sum; + + // Shift right & subtract + + sum = x; + while (x != 0) { + x = x >> 1; + sum = sum - x; + } + return sum; +} + +int pop6(unsigned x) +{ // Table lookup. + static char table[256] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8}; + + return table[x & 0xFF] + + table[(x >> 8) & 0xFF] + + table[(x >> 16) & 0xFF] + + table[(x >> 24)]; +} + +// The following works only for 8-bit quantities. +int pop7(unsigned x) +{ + x = x*0x08040201; // Make 4 copies. + x = x >> 3; // So next step hits proper bits. + x = x & 0x11111111; // Every 4th bit. + x = x*0x11111111; // Sum the digits (each 0 or 1). + x = x >> 28; // Position the result. + return x; +} + +// The following works only for 7-bit quantities. +int pop8(unsigned x) +{ + x = x*0x02040810; // Make 4 copies, left-adjusted. + x = x & 0x11111111; // Every 4th bit. + x = x*0x11111111; // Sum the digits (each 0 or 1). + x = x >> 28; // Position the result. + return x; +} + +// The following works only for 15-bit quantities. +int pop9(unsigned x) +{ + unsigned long long y; + y = x * 0x0002000400080010ULL; + y = y & 0x1111111111111111ULL; + y = y * 0x1111111111111111ULL; + y = y >> 60; + return static_cast(y); +} + +int errors; +void error(int x, int y) +{ + errors = errors + 1; + std::printf("Error for x = %08x, got %08x\n", x, y); +} + +int main() +{ +# ifdef NDEBUG + + int i, n; + static unsigned test[] = {0,0, 1,1, 2,1, 3,2, 4,1, 5,2, 6,2, 7,3, + 8,1, 9,2, 10,2, 11,3, 12,2, 13,3, 14,3, 15,4, 16,1, 17,2, + 0x3F,6, 0x40,1, 0x41,2, 0x7f,7, 0x80,1, 0x81,2, 0xfe,7, 0xff,8, + 0x4000,1, 0x4001,2, 0x7000,3, 0x7fff,15, + 0x55555555,16, 0xAAAAAAAA, 16, 0xFF000000,8, 0xC0C0C0C0,8, + 0x0FFFFFF0,24, 0x80000000,1, 0xFFFFFFFF,32}; + + std::size_t const Count = 1000000; + + n = sizeof(test)/4; + + std::clock_t TimestampBeg = 0; + std::clock_t TimestampEnd = 0; + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if (pop0(test[i]) != test[i+1]) error(test[i], pop0(test[i]));} + TimestampEnd = std::clock(); + + std::printf("pop0: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if (pop1(test[i]) != test[i+1]) error(test[i], pop1(test[i]));} + TimestampEnd = std::clock(); + + std::printf("pop1: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if (pop2(test[i]) != test[i+1]) error(test[i], pop2(test[i]));} + TimestampEnd = std::clock(); + + std::printf("pop2: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if (pop3(test[i]) != test[i+1]) error(test[i], pop3(test[i]));} + TimestampEnd = std::clock(); + + std::printf("pop3: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if (pop4(test[i]) != test[i+1]) error(test[i], pop4(test[i]));} + TimestampEnd = std::clock(); + + std::printf("pop4: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if (pop5(test[i]) != test[i+1]) error(test[i], pop5(test[i]));} + TimestampEnd = std::clock(); + + std::printf("pop5: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if (pop5a(test[i]) != test[i+1]) error(test[i], pop5a(test[i]));} + TimestampEnd = std::clock(); + + std::printf("pop5a: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if (pop6(test[i]) != test[i+1]) error(test[i], pop6(test[i]));} + TimestampEnd = std::clock(); + + std::printf("pop6: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if ((test[i] & 0xffffff00) == 0) + if (pop7(test[i]) != test[i+1]) error(test[i], pop7(test[i]));} + TimestampEnd = std::clock(); + + std::printf("pop7: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if ((test[i] & 0xffffff80) == 0) + if (pop8(test[i]) != test[i+1]) error(test[i], pop8(test[i]));} + TimestampEnd = std::clock(); + + std::printf("pop8: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if ((test[i] & 0xffff8000) == 0) + if (pop9(test[i]) != test[i+1]) error(test[i], pop9(test[i]));} + TimestampEnd = std::clock(); + + std::printf("pop9: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + if (errors == 0) + std::printf("Passed all %d cases.\n", static_cast(sizeof(test)/8)); + +# endif//NDEBUG +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_integer_find_lsb.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_integer_find_lsb.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7b42d33ebfec5665d8150956fe81c199e82a0116 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_integer_find_lsb.cpp @@ -0,0 +1,416 @@ +#include +#include +#include //To define "exit", req'd by XLC. +#include + +int nlz(unsigned x) +{ + int pop(unsigned x); + + x = x | (x >> 1); + x = x | (x >> 2); + x = x | (x >> 4); + x = x | (x >> 8); + x = x | (x >>16); + return pop(~x); +} + +int pop(unsigned x) +{ + x = x - ((x >> 1) & 0x55555555); + x = (x & 0x33333333) + ((x >> 2) & 0x33333333); + x = (x + (x >> 4)) & 0x0F0F0F0F; + x = x + (x << 8); + x = x + (x << 16); + return x >> 24; +} + +int ntz1(unsigned x) +{ + return 32 - nlz(~x & (x-1)); +} + +int ntz2(unsigned x) +{ + return pop(~x & (x - 1)); +} + +int ntz3(unsigned x) +{ + int n; + + if (x == 0) return(32); + n = 1; + if ((x & 0x0000FFFF) == 0) {n = n +16; x = x >>16;} + if ((x & 0x000000FF) == 0) {n = n + 8; x = x >> 8;} + if ((x & 0x0000000F) == 0) {n = n + 4; x = x >> 4;} + if ((x & 0x00000003) == 0) {n = n + 2; x = x >> 2;} + return n - (x & 1); +} + +int ntz4(unsigned x) +{ + unsigned y; + int n; + + if (x == 0) return 32; + n = 31; + y = x <<16; if (y != 0) {n = n -16; x = y;} + y = x << 8; if (y != 0) {n = n - 8; x = y;} + y = x << 4; if (y != 0) {n = n - 4; x = y;} + y = x << 2; if (y != 0) {n = n - 2; x = y;} + y = x << 1; if (y != 0) {n = n - 1;} + return n; +} + +int ntz4a(unsigned x) +{ + unsigned y; + int n; + + if (x == 0) return 32; + n = 31; + y = x <<16; if (y != 0) {n = n -16; x = y;} + y = x << 8; if (y != 0) {n = n - 8; x = y;} + y = x << 4; if (y != 0) {n = n - 4; x = y;} + y = x << 2; if (y != 0) {n = n - 2; x = y;} + n = n - ((x << 1) >> 31); + return n; +} + +int ntz5(char x) +{ + if (x & 15) { + if (x & 3) { + if (x & 1) return 0; + else return 1; + } + else if (x & 4) return 2; + else return 3; + } + else if (x & 0x30) { + if (x & 0x10) return 4; + else return 5; + } + else if (x & 0x40) return 6; + else if (x) return 7; + else return 8; +} + +int ntz6(unsigned x) +{ + int n; + + x = ~x & (x - 1); + n = 0; // n = 32; + while(x != 0) + { // while (x != 0) { + n = n + 1; // n = n - 1; + x = x >> 1; // x = x + x; + } // } + return n; // return n; +} + +int ntz6a(unsigned x) +{ + int n = 32; + + while (x != 0) { + n = n - 1; + x = x + x; + } + return n; +} + +/* Dean Gaudet's algorithm. To be most useful there must be a good way +to evaluate the C "conditional expression" (a?b:c construction) without +branching. The result of a?b:c is b if a is true (nonzero), and c if a +is false (0). + For example, a compare to zero op that sets a target GPR to 1 if the +operand is 0, and to 0 if the operand is nonzero, will do it. With this +instruction, the algorithm is entirely branch-free. But the most +interesting thing about it is the high degree of parallelism. All six +lines with conditional expressions can be executed in parallel (on a +machine with sufficient computational units). + Although the instruction count is 30 measured statically, it could +execute in only 10 cycles on a machine with sufficient parallelism. + The first two uses of y can instead be x, which would increase the +useful parallelism on most machines (the assignments to y, bz, and b4 +could then all run in parallel). */ + +int ntz7(unsigned x) +{ + unsigned y, bz, b4, b3, b2, b1, b0; + + y = x & -x; // Isolate rightmost 1-bit. + bz = y ? 0 : 1; // 1 if y = 0. + b4 = (y & 0x0000FFFF) ? 0 : 16; + b3 = (y & 0x00FF00FF) ? 0 : 8; + b2 = (y & 0x0F0F0F0F) ? 0 : 4; + b1 = (y & 0x33333333) ? 0 : 2; + b0 = (y & 0x55555555) ? 0 : 1; + return bz + b4 + b3 + b2 + b1 + b0; +} + +// This file has divisions by zero to test isnan +#if GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(disable : 4800) +#endif + +int ntz7_christophe(unsigned x) +{ + unsigned y, bz, b4, b3, b2, b1, b0; + + y = x & -x; // Isolate rightmost 1-bit. + bz = unsigned(!bool(y)); // 1 if y = 0. + b4 = unsigned(!bool(y & 0x0000FFFF)) * 16; + b3 = unsigned(!bool(y & 0x00FF00FF)) * 8; + b2 = unsigned(!bool(y & 0x0F0F0F0F)) * 4; + b1 = unsigned(!bool(y & 0x33333333)) * 2; + b0 = unsigned(!bool(y & 0x55555555)) * 1; + return bz + b4 + b3 + b2 + b1 + b0; +} + +/* Below is David Seal's algorithm, found at +http://www.ciphersbyritter.com/NEWS4/BITCT.HTM Table +entries marked "u" are unused. 6 ops including a +multiply, plus an indexed load. */ + +#define u 99 +int ntz8(unsigned x) +{ + static char table[64] = + {32, 0, 1,12, 2, 6, u,13, 3, u, 7, u, u, u, u,14, + 10, 4, u, u, 8, u, u,25, u, u, u, u, u,21,27,15, + 31,11, 5, u, u, u, u, u, 9, u, u,24, u, u,20,26, + 30, u, u, u, u,23, u,19, 29, u,22,18,28,17,16, u}; + + x = (x & -x)*0x0450FBAF; + return table[x >> 26]; +} + +/* Seal's algorithm with multiply expanded. +9 elementary ops plus an indexed load. */ + +int ntz8a(unsigned x) +{ + static char table[64] = + {32, 0, 1,12, 2, 6, u,13, 3, u, 7, u, u, u, u,14, + 10, 4, u, u, 8, u, u,25, u, u, u, u, u,21,27,15, + 31,11, 5, u, u, u, u, u, 9, u, u,24, u, u,20,26, + 30, u, u, u, u,23, u,19, 29, u,22,18,28,17,16, u}; + + x = (x & -x); + x = (x << 4) + x; // x = x*17. + x = (x << 6) + x; // x = x*65. + x = (x << 16) - x; // x = x*65535. + return table[x >> 26]; +} + +/* Reiser's algorithm. Three ops including a "remainder," +plus an indexed load. */ + +int ntz9(unsigned x) +{ + static char table[37] = { + 32, 0, 1, 26, 2, 23, 27, + u, 3, 16, 24, 30, 28, 11, u, 13, 4, + 7, 17, u, 25, 22, 31, 15, 29, 10, 12, + 6, u, 21, 14, 9, 5, 20, 8, 19, 18}; + + x = (x & -x)%37; + return table[x]; +} + +/* Using a de Bruijn sequence. This is a table lookup with a 32-entry +table. The de Bruijn sequence used here is + 0000 0100 1101 0111 0110 0101 0001 1111, +obtained from Danny Dube's October 3, 1997, posting in +comp.compression.research. Thanks to Norbert Juffa for this reference. */ + +int ntz10(unsigned x) { + + static char table[32] = + { 0, 1, 2,24, 3,19, 6,25, 22, 4,20,10,16, 7,12,26, + 31,23,18, 5,21, 9,15,11, 30,17, 8,14,29,13,28,27}; + + if (x == 0) return 32; + x = (x & -x)*0x04D7651F; + return table[x >> 27]; +} + +/* Norbert Juffa's code, answer to exercise 1 of Chapter 5 (2nd ed). */ + +#define SLOW_MUL +int ntz11 (unsigned int n) { + + static unsigned char tab[32] = + { 0, 1, 2, 24, 3, 19, 6, 25, + 22, 4, 20, 10, 16, 7, 12, 26, + 31, 23, 18, 5, 21, 9, 15, 11, + 30, 17, 8, 14, 29, 13, 28, 27 + }; + unsigned int k; + n = n & (-n); /* isolate lsb */ + printf("n = %d\n", n); +#if defined(SLOW_MUL) + k = (n << 11) - n; + k = (k << 2) + k; + k = (k << 8) + n; + k = (k << 5) - k; +#else + k = n * 0x4d7651f; +#endif + return n ? tab[k>>27] : 32; +} + +int errors; +void error(int x, int y) { + errors = errors + 1; + std::printf("Error for x = %08x, got %d\n", x, y); +} + +int main() +{ +# ifdef NDEBUG + + int i, m, n; + static unsigned test[] = {0,32, 1,0, 2,1, 3,0, 4,2, 5,0, 6,1, 7,0, + 8,3, 9,0, 16,4, 32,5, 64,6, 128,7, 255,0, 256,8, 512,9, 1024,10, + 2048,11, 4096,12, 8192,13, 16384,14, 32768,15, 65536,16, + 0x20000,17, 0x40000,18, 0x80000,19, 0x100000,20, 0x200000,21, + 0x400000,22, 0x800000,23, 0x1000000,24, 0x2000000,25, + 0x4000000,26, 0x8000000,27, 0x10000000,28, 0x20000000,29, + 0x40000000,30, 0x80000000,31, 0xFFFFFFF0,4, 0x3000FF00,8, + 0xC0000000,30, 0x60000000,29, 0x00011000, 12}; + + std::size_t const Count = 1000; + + n = sizeof(test)/4; + + std::clock_t TimestampBeg = 0; + std::clock_t TimestampEnd = 0; + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if (ntz1(test[i]) != test[i+1]) error(test[i], ntz1(test[i]));} + TimestampEnd = std::clock(); + + std::printf("ntz1: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if (ntz2(test[i]) != test[i+1]) error(test[i], ntz2(test[i]));} + TimestampEnd = std::clock(); + + std::printf("ntz2: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if (ntz3(test[i]) != test[i+1]) error(test[i], ntz3(test[i]));} + TimestampEnd = std::clock(); + + std::printf("ntz3: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if (ntz4(test[i]) != test[i+1]) error(test[i], ntz4(test[i]));} + TimestampEnd = std::clock(); + + std::printf("ntz4: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if (ntz4a(test[i]) != test[i+1]) error(test[i], ntz4a(test[i]));} + TimestampEnd = std::clock(); + + std::printf("ntz4a: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for(std::size_t k = 0; k < Count; ++k) + for(i = 0; i < n; i += 2) + { + m = test[i+1]; + if(m > 8) + m = 8; + if(ntz5(static_cast(test[i])) != m) + error(test[i], ntz5(static_cast(test[i]))); + } + TimestampEnd = std::clock(); + + std::printf("ntz5: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if (ntz6(test[i]) != test[i+1]) error(test[i], ntz6(test[i]));} + TimestampEnd = std::clock(); + + std::printf("ntz6: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if (ntz6a(test[i]) != test[i+1]) error(test[i], ntz6a(test[i]));} + TimestampEnd = std::clock(); + + std::printf("ntz6a: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if (ntz7(test[i]) != test[i+1]) error(test[i], ntz7(test[i]));} + TimestampEnd = std::clock(); + + std::printf("ntz7: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if (ntz7_christophe(test[i]) != test[i+1]) error(test[i], ntz7(test[i]));} + TimestampEnd = std::clock(); + + std::printf("ntz7_christophe: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if (ntz8(test[i]) != test[i+1]) error(test[i], ntz8(test[i]));} + TimestampEnd = std::clock(); + + std::printf("ntz8: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if (ntz8a(test[i]) != test[i+1]) error(test[i], ntz8a(test[i]));} + TimestampEnd = std::clock(); + + std::printf("ntz8a: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if (ntz9(test[i]) != test[i+1]) error(test[i], ntz9(test[i]));} + TimestampEnd = std::clock(); + + std::printf("ntz9: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if (ntz10(test[i]) != test[i+1]) error(test[i], ntz10(test[i]));} + TimestampEnd = std::clock(); + + std::printf("ntz10: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + if (errors == 0) + std::printf("Passed all %d cases.\n", static_cast(sizeof(test)/8)); + +# endif//NDEBUG +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_integer_find_msb.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_integer_find_msb.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c43546769d5f501205f08a12cf5940ef90c45c37 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_integer_find_msb.cpp @@ -0,0 +1,440 @@ +#include +#include +#include // To define "exit", req'd by XLC. +#include + +#define LE 1 // 1 for little-endian, 0 for big-endian. + +int pop(unsigned x) { + x = x - ((x >> 1) & 0x55555555); + x = (x & 0x33333333) + ((x >> 2) & 0x33333333); + x = (x + (x >> 4)) & 0x0F0F0F0F; + x = x + (x << 8); + x = x + (x << 16); + return x >> 24; +} + +int nlz1(unsigned x) { + int n; + + if (x == 0) return(32); + n = 0; + if (x <= 0x0000FFFF) {n = n +16; x = x <<16;} + if (x <= 0x00FFFFFF) {n = n + 8; x = x << 8;} + if (x <= 0x0FFFFFFF) {n = n + 4; x = x << 4;} + if (x <= 0x3FFFFFFF) {n = n + 2; x = x << 2;} + if (x <= 0x7FFFFFFF) {n = n + 1;} + return n; +} + +int nlz1a(unsigned x) { + int n; + +/* if (x == 0) return(32); */ + if (static_cast(x) <= 0) return (~x >> 26) & 32; + n = 1; + if ((x >> 16) == 0) {n = n +16; x = x <<16;} + if ((x >> 24) == 0) {n = n + 8; x = x << 8;} + if ((x >> 28) == 0) {n = n + 4; x = x << 4;} + if ((x >> 30) == 0) {n = n + 2; x = x << 2;} + n = n - (x >> 31); + return n; +} +// On basic Risc, 12 to 20 instructions. + +int nlz2(unsigned x) { + unsigned y; + int n; + + n = 32; + y = x >>16; if (y != 0) {n = n -16; x = y;} + y = x >> 8; if (y != 0) {n = n - 8; x = y;} + y = x >> 4; if (y != 0) {n = n - 4; x = y;} + y = x >> 2; if (y != 0) {n = n - 2; x = y;} + y = x >> 1; if (y != 0) return n - 2; + return n - x; +} + +// As above but coded as a loop for compactness: +// 23 to 33 basic Risc instructions. +int nlz2a(unsigned x) { + unsigned y; + int n, c; + + n = 32; + c = 16; + do { + y = x >> c; if (y != 0) {n = n - c; x = y;} + c = c >> 1; + } while (c != 0); + return n - x; +} + +int nlz3(int x) { + int y, n; + + n = 0; + y = x; +L: if (x < 0) return n; + if (y == 0) return 32 - n; + n = n + 1; + x = x << 1; + y = y >> 1; + goto L; +} + +int nlz4(unsigned x) { + int y, m, n; + + y = -(x >> 16); // If left half of x is 0, + m = (y >> 16) & 16; // set n = 16. If left half + n = 16 - m; // is nonzero, set n = 0 and + x = x >> m; // shift x right 16. + // Now x is of the form 0000xxxx. + y = x - 0x100; // If positions 8-15 are 0, + m = (y >> 16) & 8; // add 8 to n and shift x left 8. + n = n + m; + x = x << m; + + y = x - 0x1000; // If positions 12-15 are 0, + m = (y >> 16) & 4; // add 4 to n and shift x left 4. + n = n + m; + x = x << m; + + y = x - 0x4000; // If positions 14-15 are 0, + m = (y >> 16) & 2; // add 2 to n and shift x left 2. + n = n + m; + x = x << m; + + y = x >> 14; // Set y = 0, 1, 2, or 3. + m = y & ~(y >> 1); // Set m = 0, 1, 2, or 2 resp. + return n + 2 - m; +} + +int nlz5(unsigned x) { + int pop(unsigned x); + + x = x | (x >> 1); + x = x | (x >> 2); + x = x | (x >> 4); + x = x | (x >> 8); + x = x | (x >>16); + return pop(~x); +} + +/* The four programs below are not valid ANSI C programs. This is +because they refer to the same storage locations as two different types. +However, they work with xlc/AIX, gcc/AIX, and gcc/NT. If you try to +code them more compactly by declaring a variable xx to be "double," and +then using + + n = 1054 - (*((unsigned *)&xx + LE) >> 20); + +then you are violating not only the rule above, but also the ANSI C +rule that pointer arithmetic can be performed only on pointers to +array elements. + When coded with the above statement, the program fails with xlc, +gcc/AIX, and gcc/NT, at some optimization levels. + BTW, these programs use the "anonymous union" feature of C++, not +available in C. */ + +int nlz6(unsigned k) +{ + union { + unsigned asInt[2]; + double asDouble; + }; + int n; + + asDouble = static_cast(k) + 0.5; + n = 1054 - (asInt[LE] >> 20); + return n; +} + +int nlz7(unsigned k) +{ + union { + unsigned asInt[2]; + double asDouble; + }; + int n; + + asDouble = static_cast(k); + n = 1054 - (asInt[LE] >> 20); + n = (n & 31) + (n >> 9); + return n; +} + + /* In single qualifier, round-to-nearest mode, the basic method fails for: + k = 0, k = 01FFFFFF, 03FFFFFE <= k <= 03FFFFFF, + 07FFFFFC <= k <= 07FFFFFF, + 0FFFFFF8 <= k <= 0FFFFFFF, + ... + 7FFFFFC0 <= k <= 7FFFFFFF. + FFFFFF80 <= k <= FFFFFFFF. + For k = 0 it gives 158, and for the other values it is too low by 1. */ + +int nlz8(unsigned k) +{ + union { + unsigned asInt; + float asFloat; + }; + int n; + + k = k & ~(k >> 1); /* Fix problem with rounding. */ + asFloat = static_cast(k) + 0.5f; + n = 158 - (asInt >> 23); + return n; +} + +/* The example below shows how to make a macro for nlz. It uses an +extension to the C and C++ languages that is provided by the GNU C/C++ +compiler, namely, that of allowing statements and declarations in +expressions (see "Using and Porting GNU CC", by Richard M. Stallman +(1998). The underscores are necessary to protect against the +possibility that the macro argument will conflict with one of its local +variables, e.g., NLZ(k). */ + +int nlz9(unsigned k) +{ + union { + unsigned asInt; + float asFloat; + }; + int n; + + k = k & ~(k >> 1); /* Fix problem with rounding. */ + asFloat = static_cast(k); + n = 158 - (asInt >> 23); + n = (n & 31) + (n >> 6); /* Fix problem with k = 0. */ + return n; +} + +/* Below are three nearly equivalent programs for computing the number +of leading zeros in a word. This material is not in HD, but may be in a +future edition. + Immediately below is Robert Harley's algorithm, found at the +comp.arch newsgroup entry dated 7/12/96, pointed out to me by Norbert +Juffa. + Table entries marked "u" are unused. 14 ops including a multiply, +plus an indexed load. + The smallest multiplier that works is 0x045BCED1 = 17*65*129*513 (all +of form 2**k + 1). There are no multipliers of three terms of the form +2**k +- 1 that work, with a table size of 64 or 128. There are some, +with a table size of 64, if you precede the multiplication with x = x - +(x >> 1), but that seems less elegant. There are also some if you use a +table size of 256, the smallest is 0x01033CBF = 65*255*1025 (this would +save two instructions in the form of this algorithm with the +multiplication expanded into shifts and adds, but the table size is +getting a bit large). */ + +#define u 99 +int nlz10(unsigned x) +{ + static char table[64] = + {32,31, u,16, u,30, 3, u, 15, u, u, u,29,10, 2, u, + u, u,12,14,21, u,19, u, u,28, u,25, u, 9, 1, u, + 17, u, 4, u, u, u,11, u, 13,22,20, u,26, u, u,18, + 5, u, u,23, u,27, u, 6, u,24, 7, u, 8, u, 0, u}; + + x = x | (x >> 1); // Propagate leftmost + x = x | (x >> 2); // 1-bit to the right. + x = x | (x >> 4); + x = x | (x >> 8); + x = x | (x >>16); + x = x*0x06EB14F9; // Multiplier is 7*255**3. + return table[x >> 26]; +} + +/* Harley's algorithm with multiply expanded. +19 elementary ops plus an indexed load. */ + +int nlz10a(unsigned x) +{ + static char table[64] = + {32,31, u,16, u,30, 3, u, 15, u, u, u,29,10, 2, u, + u, u,12,14,21, u,19, u, u,28, u,25, u, 9, 1, u, + 17, u, 4, u, u, u,11, u, 13,22,20, u,26, u, u,18, + 5, u, u,23, u,27, u, 6, u,24, 7, u, 8, u, 0, u}; + + x = x | (x >> 1); // Propagate leftmost + x = x | (x >> 2); // 1-bit to the right. + x = x | (x >> 4); + x = x | (x >> 8); + x = x | (x >> 16); + x = (x << 3) - x; // Multiply by 7. + x = (x << 8) - x; // Multiply by 255. + x = (x << 8) - x; // Again. + x = (x << 8) - x; // Again. + return table[x >> 26]; +} + +/* Julius Goryavsky's version of Harley's algorithm. +17 elementary ops plus an indexed load, if the machine +has "and not." */ + +int nlz10b(unsigned x) +{ + static char table[64] = + {32,20,19, u, u,18, u, 7, 10,17, u, u,14, u, 6, u, + u, 9, u,16, u, u, 1,26, u,13, u, u,24, 5, u, u, + u,21, u, 8,11, u,15, u, u, u, u, 2,27, 0,25, u, + 22, u,12, u, u, 3,28, u, 23, u, 4,29, u, u,30,31}; + + x = x | (x >> 1); // Propagate leftmost + x = x | (x >> 2); // 1-bit to the right. + x = x | (x >> 4); + x = x | (x >> 8); + x = x & ~(x >> 16); + x = x*0xFD7049FF; // Activate this line or the following 3. + // x = (x << 9) - x; // Multiply by 511. + // x = (x << 11) - x; // Multiply by 2047. + // x = (x << 14) - x; // Multiply by 16383. + return table[x >> 26]; +} + +int errors; +void error(int x, int y) +{ + errors = errors + 1; + std::printf("Error for x = %08x, got %d\n", x, y); +} + +int main() +{ +# ifdef NDEBUG + + int i, n; + static unsigned test[] = {0,32, 1,31, 2,30, 3,30, 4,29, 5,29, 6,29, + 7,29, 8,28, 9,28, 16,27, 32,26, 64,25, 128,24, 255,24, 256,23, + 512,22, 1024,21, 2048,20, 4096,19, 8192,18, 16384,17, 32768,16, + 65536,15, 0x20000,14, 0x40000,13, 0x80000,12, 0x100000,11, + 0x200000,10, 0x400000,9, 0x800000,8, 0x1000000,7, 0x2000000,6, + 0x4000000,5, 0x8000000,4, 0x0FFFFFFF,4, 0x10000000,3, + 0x3000FFFF,2, 0x50003333,1, 0x7FFFFFFF,1, 0x80000000,0, + 0xFFFFFFFF,0}; + std::size_t const Count = 1000; + + n = sizeof(test)/4; + + std::clock_t TimestampBeg = 0; + std::clock_t TimestampEnd = 0; + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if (nlz1(test[i]) != test[i+1]) error(test[i], nlz1(test[i]));} + TimestampEnd = std::clock(); + + std::printf("nlz1: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if (nlz1a(test[i]) != test[i+1]) error(test[i], nlz1a(test[i]));} + TimestampEnd = std::clock(); + + std::printf("nlz1a: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if (nlz2(test[i]) != test[i+1]) error(test[i], nlz2(test[i]));} + TimestampEnd = std::clock(); + + std::printf("nlz2: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if (nlz2a(test[i]) != test[i+1]) error(test[i], nlz2a(test[i]));} + TimestampEnd = std::clock(); + + std::printf("nlz2a: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if (nlz3(test[i]) != test[i+1]) error(test[i], nlz3(test[i]));} + TimestampEnd = std::clock(); + + std::printf("nlz3: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if (nlz4(test[i]) != test[i+1]) error(test[i], nlz4(test[i]));} + TimestampEnd = std::clock(); + + std::printf("nlz4: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if (nlz5(test[i]) != test[i+1]) error(test[i], nlz5(test[i]));} + TimestampEnd = std::clock(); + + std::printf("nlz5: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if (nlz6(test[i]) != test[i+1]) error(test[i], nlz6(test[i]));} + TimestampEnd = std::clock(); + + std::printf("nlz6: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if (nlz7(test[i]) != test[i+1]) error(test[i], nlz7(test[i]));} + TimestampEnd = std::clock(); + + std::printf("nlz7: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if (nlz8(test[i]) != test[i+1]) error(test[i], nlz8(test[i]));} + TimestampEnd = std::clock(); + + std::printf("nlz8: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if (nlz9(test[i]) != test[i+1]) error(test[i], nlz9(test[i]));} + TimestampEnd = std::clock(); + + std::printf("nlz9: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if (nlz10(test[i]) != test[i+1]) error(test[i], nlz10(test[i]));} + TimestampEnd = std::clock(); + + std::printf("nlz10: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if (nlz10a(test[i]) != test[i+1]) error(test[i], nlz10a(test[i]));} + TimestampEnd = std::clock(); + + std::printf("nlz10a: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + TimestampBeg = std::clock(); + for (std::size_t k = 0; k < Count; ++k) + for (i = 0; i < n; i += 2) { + if (nlz10b(test[i]) != test[i+1]) error(test[i], nlz10b(test[i]));} + TimestampEnd = std::clock(); + + std::printf("nlz10b: %d clocks\n", static_cast(TimestampEnd - TimestampBeg)); + + if (errors == 0) + std::printf("Passed all %d cases.\n", static_cast(sizeof(test)/8)); + +# endif//NDEBUG +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_matrix.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_matrix.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b66ee7d66bbe6b3382e52289f85f8090a00e2f43 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_matrix.cpp @@ -0,0 +1,392 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace glm; + +int test_matrixCompMult() +{ + int Error(0); + + { + mat2 m(0, 1, 2, 3); + mat2 n = matrixCompMult(m, m); + mat2 expected = mat2(0, 1, 4, 9); + Error += all(equal(n, expected, epsilon())) ? 0 : 1; + } + + { + mat2x3 m(0, 1, 2, 3, 4, 5); + mat2x3 n = matrixCompMult(m, m); + mat2x3 expected = mat2x3(0, 1, 4, 9, 16, 25); + Error += all(equal(n, expected, epsilon())) ? 0 : 1; + } + + { + mat2x4 m(0, 1, 2, 3, 4, 5, 6, 7); + mat2x4 n = matrixCompMult(m, m); + mat2x4 expected = mat2x4(0, 1, 4, 9, 16, 25, 36, 49); + Error += all(equal(n, expected, epsilon())) ? 0 : 1; + } + + { + mat3 m(0, 1, 2, 3, 4, 5, 6, 7, 8); + mat3 n = matrixCompMult(m, m); + mat3 expected = mat3(0, 1, 4, 9, 16, 25, 36, 49, 64); + Error += all(equal(n, expected, epsilon())) ? 0 : 1; + } + + { + mat3x2 m(0, 1, 2, 3, 4, 5); + mat3x2 n = matrixCompMult(m, m); + mat3x2 expected = mat3x2(0, 1, 4, 9, 16, 25); + Error += all(equal(n, expected, epsilon())) ? 0 : 1; + } + + { + mat3x4 m(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11); + mat3x4 n = matrixCompMult(m, m); + mat3x4 expected = mat3x4(0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121); + Error += all(equal(n, expected, epsilon())) ? 0 : 1; + } + + { + mat4 m(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + mat4 n = matrixCompMult(m, m); + mat4 expected = mat4(0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225); + Error += all(equal(n, expected, epsilon())) ? 0 : 1; + } + + { + mat4x2 m(0, 1, 2, 3, 4, 5, 6, 7); + mat4x2 n = matrixCompMult(m, m); + mat4x2 expected = mat4x2(0, 1, 4, 9, 16, 25, 36, 49); + Error += all(equal(n, expected, epsilon())) ? 0 : 1; + } + + { + mat4x3 m(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11); + mat4x3 n = matrixCompMult(m, m); + mat4x3 expected = mat4x3(0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121); + Error += all(equal(n, expected, epsilon())) ? 0 : 1; + } + + return Error; +} + +int test_outerProduct() +{ + { glm::mat2 m = glm::outerProduct(glm::vec2(1.0f), glm::vec2(1.0f)); } + { glm::mat3 m = glm::outerProduct(glm::vec3(1.0f), glm::vec3(1.0f)); } + { glm::mat4 m = glm::outerProduct(glm::vec4(1.0f), glm::vec4(1.0f)); } + + { glm::mat2x3 m = glm::outerProduct(glm::vec3(1.0f), glm::vec2(1.0f)); } + { glm::mat2x4 m = glm::outerProduct(glm::vec4(1.0f), glm::vec2(1.0f)); } + + { glm::mat3x2 m = glm::outerProduct(glm::vec2(1.0f), glm::vec3(1.0f)); } + { glm::mat3x4 m = glm::outerProduct(glm::vec4(1.0f), glm::vec3(1.0f)); } + + { glm::mat4x2 m = glm::outerProduct(glm::vec2(1.0f), glm::vec4(1.0f)); } + { glm::mat4x3 m = glm::outerProduct(glm::vec3(1.0f), glm::vec4(1.0f)); } + + return 0; +} + +int test_transpose() +{ + int Error(0); + + { + mat2 const m(0, 1, 2, 3); + mat2 const t = transpose(m); + mat2 const expected = mat2(0, 2, 1, 3); + Error += all(equal(t, expected, epsilon())) ? 0 : 1; + } + + { + mat2x3 m(0, 1, 2, 3, 4, 5); + mat3x2 t = transpose(m); + mat3x2 const expected = mat3x2(0, 3, 1, 4, 2, 5); + Error += all(equal(t, expected, epsilon())) ? 0 : 1; + } + + { + mat2x4 m(0, 1, 2, 3, 4, 5, 6, 7); + mat4x2 t = transpose(m); + mat4x2 const expected = mat4x2(0, 4, 1, 5, 2, 6, 3, 7); + Error += all(equal(t, expected, epsilon())) ? 0 : 1; + } + + { + mat3 m(0, 1, 2, 3, 4, 5, 6, 7, 8); + mat3 t = transpose(m); + mat3 const expected = mat3(0, 3, 6, 1, 4, 7, 2, 5, 8); + Error += all(equal(t, expected, epsilon())) ? 0 : 1; + } + + { + mat3x2 m(0, 1, 2, 3, 4, 5); + mat2x3 t = transpose(m); + mat2x3 const expected = mat2x3(0, 2, 4, 1, 3, 5); + Error += all(equal(t, expected, epsilon())) ? 0 : 1; + } + + { + mat3x4 m(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11); + mat4x3 t = transpose(m); + mat4x3 const expected = mat4x3(0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11); + Error += all(equal(t, expected, epsilon())) ? 0 : 1; + } + + { + mat4 m(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + mat4 t = transpose(m); + mat4 const expected = mat4(0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15); + Error += all(equal(t, expected, epsilon())) ? 0 : 1; + } + + { + mat4x2 m(0, 1, 2, 3, 4, 5, 6, 7); + mat2x4 t = transpose(m); + mat2x4 const expected = mat2x4(0, 2, 4, 6, 1, 3, 5, 7); + Error += all(equal(t, expected, epsilon())) ? 0 : 1; + } + + { + mat4x3 m(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11); + mat3x4 t = transpose(m); + mat3x4 const expected = mat3x4(0, 3, 6, 9, 1, 4, 7, 10, 2, 5, 8, 11); + Error += all(equal(t, expected, epsilon())) ? 0 : 1; + } + + return Error; +} + +int test_determinant() +{ + + + return 0; +} + +int test_inverse() +{ + int Error = 0; + + { + glm::mat4x4 A4x4( + glm::vec4(1, 0, 1, 0), + glm::vec4(0, 1, 0, 0), + glm::vec4(0, 0, 1, 0), + glm::vec4(0, 0, 0, 1)); + glm::mat4x4 B4x4 = inverse(A4x4); + glm::mat4x4 I4x4 = A4x4 * B4x4; + glm::mat4x4 Identity(1); + Error += all(equal(I4x4, Identity, epsilon())) ? 0 : 1; + } + + { + glm::mat3x3 A3x3( + glm::vec3(1, 0, 1), + glm::vec3(0, 1, 0), + glm::vec3(0, 0, 1)); + glm::mat3x3 B3x3 = glm::inverse(A3x3); + glm::mat3x3 I3x3 = A3x3 * B3x3; + glm::mat3x3 Identity(1); + Error += all(equal(I3x3, Identity, epsilon())) ? 0 : 1; + } + + { + glm::mat2x2 A2x2( + glm::vec2(1, 1), + glm::vec2(0, 1)); + glm::mat2x2 B2x2 = glm::inverse(A2x2); + glm::mat2x2 I2x2 = A2x2 * B2x2; + glm::mat2x2 Identity(1); + Error += all(equal(I2x2, Identity, epsilon())) ? 0 : 1; + } + + return Error; +} + +int test_inverse_simd() +{ + int Error = 0; + + glm::mat4x4 const Identity(1); + + glm::mat4x4 const A4x4( + glm::vec4(1, 0, 1, 0), + glm::vec4(0, 1, 0, 0), + glm::vec4(0, 0, 1, 0), + glm::vec4(0, 0, 0, 1)); + glm::mat4x4 const B4x4 = glm::inverse(A4x4); + glm::mat4x4 const I4x4 = A4x4 * B4x4; + + Error += glm::all(glm::equal(I4x4, Identity, 0.001f)) ? 0 : 1; + + return Error; +} + +int test_shearing() +{ + int Error = 0; + + { + glm::vec3 const center(0, 0, 0); + glm::vec2 const l_x(2, 0); + glm::vec2 const l_y(0, 0); + glm::vec2 const l_z(0, 0); + glm::mat4x4 const A4x4( + glm::vec4(0, 0, 1, 1), + glm::vec4(0, 1, 1, 0), + glm::vec4(1, 1, 1, 0), + glm::vec4(1, 1, 0, 1)); + glm::mat4x4 const B4x4 = glm::shear(A4x4, center, l_x, l_y, l_z); + glm::mat4x4 const expected( + glm::vec4(0, 0, 1, 1), + glm::vec4(2, 1, 1, 0), + glm::vec4(3, 1, 1, 0), + glm::vec4(3, 1, 0, 1)); + Error += all(equal(B4x4, expected, epsilon())) ? 0 : 1; + } + + { + glm::vec3 const center(0, 0, 0); + glm::vec2 const l_x(1, 0); + glm::vec2 const l_y(0, 1); + glm::vec2 const l_z(1, 0); + glm::mat4x4 const A4x4( + glm::vec4(0, 0, 1, 0), + glm::vec4(0, 1, 1, 0), + glm::vec4(1, 1, 1, 0), + glm::vec4(1, 0, 0, 0)); + glm::mat4x4 const B4x4 = glm::shear(A4x4, center, l_x, l_y, l_z); + glm::mat4x4 const expected( + glm::vec4(0, 1, 1, 0), + glm::vec4(1, 2, 1, 0), + glm::vec4(2, 2, 2, 0), + glm::vec4(1, 0, 1, 0)); + Error += all(equal(B4x4, expected, epsilon())) ? 0 : 1; + } + + { + glm::vec3 const center(3, 2, 1); + glm::vec2 const l_x(1, 2); + glm::vec2 const l_y(3, 1); + glm::vec2 const l_z(4, 5); + glm::mat4x4 const A4x4(1); + glm::mat4x4 const B4x4 = glm::shear(A4x4, center, l_x, l_y, l_z); + glm::mat4x4 const expected( + glm::vec4(1, 3, 4, 0), + glm::vec4(1, 1, 5, 0), + glm::vec4(2, 1, 1, 0), + glm::vec4(-9, -8, -9, 1)); + Error += all(equal(B4x4, expected, epsilon())) ? 0 : 1; + } + + { + glm::vec3 const center(3, 2, 1); + glm::vec2 const l_x(1, 2); + glm::vec2 const l_y(3, 1); + glm::vec2 const l_z(4, 5); + glm::mat4x4 const A4x4( + glm::vec4(-3, 2, 1, 0), + glm::vec4(3, 2, 1, 0), + glm::vec4(4, -8, 0, 0), + glm::vec4(7, 1, -2, 0)); + glm::mat4x4 const B4x4 = glm::shear(A4x4, center, l_x, l_y, l_z); + glm::mat4x4 const expected( + glm::vec4(1, -6, -1, 0), + glm::vec4(7, 12, 23, 0), + glm::vec4(-4, 4, -24, 0), + glm::vec4(4, 20, 31, 0)); + Error += all(equal(B4x4, expected, epsilon())) ? 0 : 1; + } + + return Error; +} + +template +int test_inverse_perf(std::size_t Count, std::size_t Instance, char const * Message) +{ + std::vector TestInputs; + TestInputs.resize(Count); + std::vector TestOutputs; + TestOutputs.resize(TestInputs.size()); + + VEC3 Axis(glm::normalize(VEC3(1.0f, 2.0f, 3.0f))); + + for(std::size_t i = 0; i < TestInputs.size(); ++i) + { + typename MAT4::value_type f = static_cast(i + Instance) * typename MAT4::value_type(0.1) + typename MAT4::value_type(0.1); + TestInputs[i] = glm::rotate(glm::translate(MAT4(1), Axis * f), f, Axis); + //TestInputs[i] = glm::translate(MAT4(1), Axis * f); + } + + std::clock_t StartTime = std::clock(); + + for(std::size_t i = 0; i < TestInputs.size(); ++i) + TestOutputs[i] = glm::inverse(TestInputs[i]); + + std::clock_t EndTime = std::clock(); + + for(std::size_t i = 0; i < TestInputs.size(); ++i) + TestOutputs[i] = TestOutputs[i] * TestInputs[i]; + + typename MAT4::value_type Diff(0); + for(std::size_t Entry = 0; Entry < TestOutputs.size(); ++Entry) + { + MAT4 i(1.0); + MAT4 m(TestOutputs[Entry]); + for(glm::length_t y = 0; y < m.length(); ++y) + for(glm::length_t x = 0; x < m[y].length(); ++x) + Diff = glm::max(m[y][x], i[y][x]); + } + + //glm::uint Ulp = 0; + //Ulp = glm::max(glm::float_distance(*Dst, *Src), Ulp); + + std::printf("inverse<%s>(%f): %lu\n", Message, static_cast(Diff), EndTime - StartTime); + + return 0; +} + +int main() +{ + int Error = 0; + Error += test_matrixCompMult(); + Error += test_outerProduct(); + Error += test_transpose(); + Error += test_determinant(); + Error += test_inverse(); + Error += test_inverse_simd(); + Error += test_shearing(); + +# ifdef NDEBUG + std::size_t const Samples = 1000; +# else + std::size_t const Samples = 1; +# endif//NDEBUG + + for(std::size_t i = 0; i < 1; ++i) + { + Error += test_inverse_perf(Samples, i, "mat4"); + Error += test_inverse_perf(Samples, i, "dmat4"); + } + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_noise.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_noise.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4f0b430035376d4afc6d3ce6d2d8d0780044c45d --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_noise.cpp @@ -0,0 +1,7 @@ +int main() +{ + int Error = 0; + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_packing.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_packing.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c3cd14a205af9365f892ab1748dc258fceb6db97 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_packing.cpp @@ -0,0 +1,156 @@ +#include +#include +#include +#include +#include + +int test_packUnorm2x16() +{ + int Error = 0; + + std::vector A; + A.push_back(glm::vec2(1.0f, 0.0f)); + A.push_back(glm::vec2(0.5f, 0.7f)); + A.push_back(glm::vec2(0.1f, 0.2f)); + + for(std::size_t i = 0; i < A.size(); ++i) + { + glm::vec2 B(A[i]); + glm::uint32 C = glm::packUnorm2x16(B); + glm::vec2 D = glm::unpackUnorm2x16(C); + Error += glm::all(glm::epsilonEqual(B, D, 1.0f / 65535.f)) ? 0 : 1; + assert(!Error); + } + + return Error; +} + +int test_packSnorm2x16() +{ + int Error = 0; + + std::vector A; + A.push_back(glm::vec2( 1.0f, 0.0f)); + A.push_back(glm::vec2(-0.5f,-0.7f)); + A.push_back(glm::vec2(-0.1f, 0.1f)); + + for(std::size_t i = 0; i < A.size(); ++i) + { + glm::vec2 B(A[i]); + glm::uint32 C = glm::packSnorm2x16(B); + glm::vec2 D = glm::unpackSnorm2x16(C); + Error += glm::all(glm::epsilonEqual(B, D, 1.0f / 32767.0f * 2.0f)) ? 0 : 1; + assert(!Error); + } + + return Error; +} + +int test_packUnorm4x8() +{ + int Error = 0; + + glm::uint32 Packed = glm::packUnorm4x8(glm::vec4(1.0f, 0.5f, 0.0f, 1.0f)); + glm::u8vec4 Vec(255, 128, 0, 255); + glm::uint32 & Ref = *reinterpret_cast(&Vec[0]); + + Error += Packed == Ref ? 0 : 1; + + std::vector A; + A.push_back(glm::vec4(1.0f, 0.7f, 0.3f, 0.0f)); + A.push_back(glm::vec4(0.5f, 0.1f, 0.2f, 0.3f)); + + for(std::size_t i = 0; i < A.size(); ++i) + { + glm::vec4 B(A[i]); + glm::uint32 C = glm::packUnorm4x8(B); + glm::vec4 D = glm::unpackUnorm4x8(C); + Error += glm::all(glm::epsilonEqual(B, D, 1.0f / 255.f)) ? 0 : 1; + assert(!Error); + } + + return Error; +} + +int test_packSnorm4x8() +{ + int Error = 0; + + std::vector A; + A.push_back(glm::vec4( 1.0f, 0.0f,-0.5f,-1.0f)); + A.push_back(glm::vec4(-0.7f,-0.1f, 0.1f, 0.7f)); + + for(std::size_t i = 0; i < A.size(); ++i) + { + glm::vec4 B(A[i]); + glm::uint32 C = glm::packSnorm4x8(B); + glm::vec4 D = glm::unpackSnorm4x8(C); + Error += glm::all(glm::epsilonEqual(B, D, 1.0f / 127.f)) ? 0 : 1; + assert(!Error); + } + + return Error; +} + +int test_packHalf2x16() +{ + int Error = 0; +/* + std::vector A; + A.push_back(glm::hvec2(glm::half( 1.0f), glm::half( 2.0f))); + A.push_back(glm::hvec2(glm::half(-1.0f), glm::half(-2.0f))); + A.push_back(glm::hvec2(glm::half(-1.1f), glm::half( 1.1f))); +*/ + std::vector A; + A.push_back(glm::vec2( 1.0f, 2.0f)); + A.push_back(glm::vec2(-1.0f,-2.0f)); + A.push_back(glm::vec2(-1.1f, 1.1f)); + + for(std::size_t i = 0; i < A.size(); ++i) + { + glm::vec2 B(A[i]); + glm::uint C = glm::packHalf2x16(B); + glm::vec2 D = glm::unpackHalf2x16(C); + //Error += B == D ? 0 : 1; + Error += glm::all(glm::epsilonEqual(B, D, 1.0f / 127.f)) ? 0 : 1; + assert(!Error); + } + + return Error; +} + +int test_packDouble2x32() +{ + int Error = 0; + + std::vector A; + A.push_back(glm::uvec2( 1, 2)); + A.push_back(glm::uvec2(-1,-2)); + A.push_back(glm::uvec2(-1000, 1100)); + + for(std::size_t i = 0; i < A.size(); ++i) + { + glm::uvec2 B(A[i]); + double C = glm::packDouble2x32(B); + glm::uvec2 D = glm::unpackDouble2x32(C); + Error += B == D ? 0 : 1; + assert(!Error); + } + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_packSnorm4x8(); + Error += test_packUnorm4x8(); + Error += test_packSnorm2x16(); + Error += test_packUnorm2x16(); + Error += test_packHalf2x16(); + Error += test_packDouble2x32(); + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_swizzle.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_swizzle.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9758533f9d7ce0021cb4041a899ec78e68df0932 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_swizzle.cpp @@ -0,0 +1,164 @@ +#define GLM_FORCE_SWIZZLE +#include +#include +#include + +static int test_ivec2_swizzle() +{ + int Error = 0; + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR || GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION + { + glm::ivec2 A(1, 2); + glm::ivec2 B = A.yx(); + glm::ivec2 C = B.yx(); + + Error += A != B ? 0 : 1; + Error += A == C ? 0 : 1; + } +# endif//GLM_CONFIG_SWIZZLE + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + { + glm::ivec2 A(1, 2); + glm::ivec2 B = A.yx; + glm::ivec2 C = A.yx; + + Error += A != B ? 0 : 1; + Error += B == C ? 0 : 1; + + B.xy = B.yx; + C.xy = C.yx; + + Error += B == C ? 0 : 1; + + glm::ivec2 D(0, 0); + D.yx = A.xy; + Error += A.yx() == D ? 0 : 1; + + glm::ivec2 E = A.yx; + Error += E == D ? 0 : 1; + } +# endif//GLM_CONFIG_SWIZZLE + + return Error; +} + +int test_ivec3_swizzle() +{ + int Error = 0; + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR || GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION + { + glm::ivec3 A(1, 2, 3); + glm::ivec3 B = A.zyx(); + glm::ivec3 C = B.zyx(); + + Error += A != B ? 0 : 1; + Error += A == C ? 0 : 1; + } +# endif + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + { + glm::ivec3 const A(1, 2, 3); + glm::ivec2 B = A.yx; + glm::ivec2 C = A.yx; + + Error += A.yx() == B ? 0 : 1; + Error += B == C ? 0 : 1; + + B.xy = B.yx; + C.xy = C.yx; + + Error += B == C ? 0 : 1; + + glm::ivec2 D(0, 0); + D.yx = A.xy; + + Error += A.yx() == D ? 0 : 1; + + glm::ivec2 E(0, 0); + E.xy = A.xy(); + + Error += E == A.xy() ? 0 : 1; + Error += E.xy() == A.xy() ? 0 : 1; + + glm::ivec3 const F = A.xxx + A.xxx; + Error += F == glm::ivec3(2) ? 0 : 1; + + glm::ivec3 const G = A.xxx - A.xxx; + Error += G == glm::ivec3(0) ? 0 : 1; + + glm::ivec3 const H = A.xxx * A.xxx; + Error += H == glm::ivec3(1) ? 0 : 1; + + glm::ivec3 const I = A.xxx / A.xxx; + Error += I == glm::ivec3(1) ? 0 : 1; + + glm::ivec3 J(1, 2, 3); + J.xyz += glm::ivec3(1); + Error += J == glm::ivec3(2, 3, 4) ? 0 : 1; + + glm::ivec3 K(1, 2, 3); + K.xyz += A.xyz; + Error += K == glm::ivec3(2, 4, 6) ? 0 : 1; + } +# endif + + return Error; +} + +int test_ivec4_swizzle() +{ + int Error = 0; + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR || GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION + { + glm::ivec4 A(1, 2, 3, 4); + glm::ivec4 B = A.wzyx(); + glm::ivec4 C = B.wzyx(); + + Error += A != B ? 0 : 1; + Error += A == C ? 0 : 1; + } +# endif + + return Error; +} + +int test_vec4_swizzle() +{ + int Error = 0; + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR || GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION + { + glm::vec4 A(1, 2, 3, 4); + glm::vec4 B = A.wzyx(); + glm::vec4 C = B.wzyx(); + + Error += glm::any(glm::notEqual(A, B, 0.0001f)) ? 0 : 1; + Error += glm::all(glm::equal(A, C, 0.0001f)) ? 0 : 1; + + float D = glm::dot(C.wzyx(), C.xyzw()); + Error += glm::equal(D, 20.f, 0.001f) ? 0 : 1; + } +# endif + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_ivec2_swizzle(); + Error += test_ivec3_swizzle(); + Error += test_ivec4_swizzle(); + Error += test_vec4_swizzle(); + + return Error; +} + + + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_trigonometric.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_trigonometric.cpp new file mode 100644 index 0000000000000000000000000000000000000000..31723400a8645a93803bad2939a4eb4692e5f6fe --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_trigonometric.cpp @@ -0,0 +1,10 @@ +#include + +int main() +{ + int Error = 0; + + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_vector_relational.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_vector_relational.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0a4e7e7cac10a06e33fca4cbe7fd6f9d157cf9df --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_func_vector_relational.cpp @@ -0,0 +1,180 @@ +#include +#include +#include +#include +#include + +static int test_not() +{ + int Error = 0; + + { + glm::bvec1 v(false); + Error += glm::all(glm::not_(v)) ? 0 : 1; + } + + { + glm::bvec2 v(false); + Error += glm::all(glm::not_(v)) ? 0 : 1; + } + + { + glm::bvec3 v(false); + Error += glm::all(glm::not_(v)) ? 0 : 1; + } + + { + glm::bvec4 v(false); + Error += glm::all(glm::not_(v)) ? 0 : 1; + } + + return Error; +} + +static int test_less() +{ + int Error = 0; + + { + glm::vec2 const A(1, 2); + glm::vec2 const B(2, 3); + Error += glm::all(glm::lessThan(A, B)) ? 0: 1; + Error += glm::all(glm::lessThanEqual(A, B)) ? 0: 1; + } + + { + glm::vec3 const A(1, 2, 3); + glm::vec3 const B(2, 3, 4); + Error += glm::all(glm::lessThan(A, B)) ? 0: 1; + Error += glm::all(glm::lessThanEqual(A, B)) ? 0: 1; + } + + { + glm::vec4 const A(1, 2, 3, 4); + glm::vec4 const B(2, 3, 4, 5); + Error += glm::all(glm::lessThan(A, B)) ? 0: 1; + Error += glm::all(glm::lessThanEqual(A, B)) ? 0: 1; + } + + { + glm::ivec2 const A(1, 2); + glm::ivec2 const B(2, 3); + Error += glm::all(glm::lessThan(A, B)) ? 0: 1; + + glm::ivec2 const C(1, 3); + Error += glm::all(glm::lessThanEqual(A, C)) ? 0: 1; + } + + { + glm::ivec3 const A(1, 2, 3); + glm::ivec3 const B(2, 3, 4); + Error += glm::all(glm::lessThan(A, B)) ? 0: 1; + + glm::ivec3 const C(1, 3, 4); + Error += glm::all(glm::lessThanEqual(A, C)) ? 0: 1; + } + + { + glm::ivec4 const A(1, 2, 3, 4); + glm::ivec4 const B(2, 3, 4, 5); + Error += glm::all(glm::lessThan(A, B)) ? 0: 1; + + glm::ivec4 const C(1, 3, 4, 5); + Error += glm::all(glm::lessThanEqual(A, C)) ? 0: 1; + } + + return Error; +} + +static int test_greater() +{ + int Error = 0; + + { + glm::vec2 const A(1, 2); + glm::vec2 const B(2, 3); + Error += glm::all(glm::greaterThan(B, A)) ? 0: 1; + Error += glm::all(glm::greaterThanEqual(B, A)) ? 0: 1; + } + + { + glm::vec3 const A(1, 2, 3); + glm::vec3 const B(2, 3, 4); + Error += glm::all(glm::greaterThan(B, A)) ? 0: 1; + Error += glm::all(glm::greaterThanEqual(B, A)) ? 0: 1; + } + + { + glm::vec4 const A(1, 2, 3, 4); + glm::vec4 const B(2, 3, 4, 5); + Error += glm::all(glm::greaterThan(B, A)) ? 0: 1; + Error += glm::all(glm::greaterThanEqual(B, A)) ? 0: 1; + } + + { + glm::ivec2 const A(1, 2); + glm::ivec2 const B(2, 3); + Error += glm::all(glm::greaterThan(B, A)) ? 0: 1; + + glm::ivec2 const C(1, 3); + Error += glm::all(glm::greaterThanEqual(C, A)) ? 0: 1; + } + + { + glm::ivec3 const A(1, 2, 3); + glm::ivec3 const B(2, 3, 4); + Error += glm::all(glm::greaterThan(B, A)) ? 0: 1; + + glm::ivec3 const C(1, 3, 4); + Error += glm::all(glm::greaterThanEqual(C, A)) ? 0: 1; + } + + { + glm::ivec4 const A(1, 2, 3, 4); + glm::ivec4 const B(2, 3, 4, 5); + Error += glm::all(glm::greaterThan(B, A)) ? 0: 1; + + glm::ivec4 const C(1, 3, 4, 5); + Error += glm::all(glm::greaterThanEqual(C, A)) ? 0: 1; + } + + return Error; +} + +static int test_equal() +{ + int Error = 0; + + { + glm::ivec2 const A(1, 2); + glm::ivec2 const B(1, 2); + Error += glm::all(glm::equal(B, A)) ? 0: 1; + } + + { + glm::ivec3 const A(1, 2, 3); + glm::ivec3 const B(1, 2, 3); + Error += glm::all(glm::equal(B, A)) ? 0: 1; + } + + { + glm::ivec4 const A(1, 2, 3, 4); + glm::ivec4 const B(1, 2, 3, 4); + Error += glm::all(glm::equal(B, A)) ? 0: 1; + } + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_not(); + Error += test_less(); + Error += test_greater(); + Error += test_equal(); + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_setup_force_cxx98.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_setup_force_cxx98.cpp new file mode 100644 index 0000000000000000000000000000000000000000..32bb63c3f573900d8ae9c12d2ea9701a11908042 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_setup_force_cxx98.cpp @@ -0,0 +1,12 @@ +#ifndef GLM_FORCE_CXX98 +# define GLM_FORCE_CXX98 +#endif +#include +#include + +int main() +{ + int Error = 0; + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_setup_force_size_t_length.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_setup_force_size_t_length.cpp new file mode 100644 index 0000000000000000000000000000000000000000..36010e31b84d81a4312f06c322e292cb7651dfce --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_setup_force_size_t_length.cpp @@ -0,0 +1,22 @@ +#define GLM_FORCE_SIZE_T_LENGTH +#include +#include + +template +genType add(genType const& a, genType const& b) +{ + genType result(0); + for(glm::length_t i = 0; i < a.length(); ++i) + result[i] = a[i] + b[i]; + return result; +} + +int main() +{ + int Error = 0; + + glm::ivec4 v(1); + Error += add(v, v) == glm::ivec4(2) ? 0 : 1; + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_setup_message.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_setup_message.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7594743dc4e7a9eaae5a48c615e16086c4c96663 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_setup_message.cpp @@ -0,0 +1,230 @@ +#define GLM_FORCE_MESSAGES +#include +#include + +int test_compiler() +{ + int Error(0); + + if(GLM_COMPILER & GLM_COMPILER_VC) + { + switch(GLM_COMPILER) + { + case GLM_COMPILER_VC12: + std::printf("Visual C++ 12 - 2013\n"); + break; + case GLM_COMPILER_VC14: + std::printf("Visual C++ 14 - 2015\n"); + break; + case GLM_COMPILER_VC15: + std::printf("Visual C++ 15 - 2017\n"); + break; + case GLM_COMPILER_VC15_3: + std::printf("Visual C++ 15.3 - 2017\n"); + break; + case GLM_COMPILER_VC15_5: + std::printf("Visual C++ 15.5 - 2017\n"); + break; + case GLM_COMPILER_VC15_6: + std::printf("Visual C++ 15.6 - 2017\n"); + break; + case GLM_COMPILER_VC15_7: + std::printf("Visual C++ 15.7 - 2017\n"); + break; + case GLM_COMPILER_VC15_8: + std::printf("Visual C++ 15.8 - 2017\n"); + break; + case GLM_COMPILER_VC15_9: + std::printf("Visual C++ 15.9 - 2017\n"); + break; + case GLM_COMPILER_VC16: + std::printf("Visual C++ 16 - 2019\n"); + break; + default: + std::printf("Visual C++ version not detected\n"); + Error += 1; + break; + } + } + else if(GLM_COMPILER & GLM_COMPILER_GCC) + { + switch(GLM_COMPILER) + { + case GLM_COMPILER_GCC46: + std::printf("GCC 4.6\n"); + break; + case GLM_COMPILER_GCC47: + std::printf("GCC 4.7\n"); + break; + case GLM_COMPILER_GCC48: + std::printf("GCC 4.8\n"); + break; + case GLM_COMPILER_GCC49: + std::printf("GCC 4.9\n"); + break; + case GLM_COMPILER_GCC5: + std::printf("GCC 5\n"); + break; + case GLM_COMPILER_GCC6: + std::printf("GCC 6\n"); + break; + case GLM_COMPILER_GCC7: + std::printf("GCC 7\n"); + break; + case GLM_COMPILER_GCC8: + std::printf("GCC 8\n"); + break; + default: + std::printf("GCC version not detected\n"); + Error += 1; + break; + } + } + else if(GLM_COMPILER & GLM_COMPILER_CUDA) + { + std::printf("CUDA\n"); + } + else if(GLM_COMPILER & GLM_COMPILER_CLANG) + { + switch(GLM_COMPILER) + { + case GLM_COMPILER_CLANG34: + std::printf("Clang 3.4\n"); + break; + case GLM_COMPILER_CLANG35: + std::printf("Clang 3.5\n"); + break; + case GLM_COMPILER_CLANG36: + std::printf("Clang 3.6\n"); + break; + case GLM_COMPILER_CLANG37: + std::printf("Clang 3.7\n"); + break; + case GLM_COMPILER_CLANG38: + std::printf("Clang 3.8\n"); + break; + case GLM_COMPILER_CLANG39: + std::printf("Clang 3.9\n"); + break; + case GLM_COMPILER_CLANG40: + std::printf("Clang 4.0\n"); + break; + case GLM_COMPILER_CLANG41: + std::printf("Clang 4.1\n"); + break; + case GLM_COMPILER_CLANG42: + std::printf("Clang 4.2\n"); + break; + default: + std::printf("LLVM version not detected\n"); + break; + } + } + else if(GLM_COMPILER & GLM_COMPILER_INTEL) + { + switch(GLM_COMPILER) + { + case GLM_COMPILER_INTEL14: + std::printf("ICC 14 - 2013 SP1\n"); + break; + case GLM_COMPILER_INTEL15: + std::printf("ICC 15 - 2015\n"); + break; + case GLM_COMPILER_INTEL16: + std::printf("ICC 16 - 2017\n"); + break; + case GLM_COMPILER_INTEL17: + std::printf("ICC 17 - 20XX\n"); + break; + default: + std::printf("Intel compiler version not detected\n"); + Error += 1; + break; + } + } + else + { + std::printf("Undetected compiler\n"); + Error += 1; + } + + return Error; +} + +int test_model() +{ + int Error = 0; + + Error += ((sizeof(void*) == 4) && (GLM_MODEL == GLM_MODEL_32)) || ((sizeof(void*) == 8) && (GLM_MODEL == GLM_MODEL_64)) ? 0 : 1; + + if(GLM_MODEL == GLM_MODEL_32) + std::printf("GLM_MODEL_32\n"); + else if(GLM_MODEL == GLM_MODEL_64) + std::printf("GLM_MODEL_64\n"); + + return Error; +} + +int test_instruction_set() +{ + int Error = 0; + + std::printf("GLM_ARCH: "); + + if(GLM_ARCH & GLM_ARCH_ARM_BIT) + std::printf("ARM "); + if(GLM_ARCH & GLM_ARCH_NEON_BIT) + std::printf("NEON "); + if(GLM_ARCH & GLM_ARCH_AVX2_BIT) + std::printf("AVX2 "); + if(GLM_ARCH & GLM_ARCH_AVX_BIT) + std::printf("AVX "); + if(GLM_ARCH & GLM_ARCH_SSE42_BIT) + std::printf("SSE4.2 "); + if(GLM_ARCH & GLM_ARCH_SSE41_BIT) + std::printf("SSE4.1 "); + if(GLM_ARCH & GLM_ARCH_SSSE3_BIT) + std::printf("SSSE3 "); + if(GLM_ARCH & GLM_ARCH_SSE3_BIT) + std::printf("SSE3 "); + if(GLM_ARCH & GLM_ARCH_SSE2_BIT) + std::printf("SSE2 "); + + std::printf("\n"); + + return Error; +} + +int test_cpp_version() +{ + std::printf("__cplusplus: %d\n", static_cast(__cplusplus)); + + return 0; +} + +int test_operators() +{ + glm::ivec3 A(1); + glm::ivec3 B(1); + bool R = A != B; + bool S = A == B; + + return (S && !R) ? 0 : 1; +} + +int main() +{ + int Error = 0; + +# if !defined(GLM_FORCE_PLATFORM_UNKNOWN) && !defined(GLM_FORCE_COMPILER_UNKNOWN) && !defined(GLM_FORCE_ARCH_UNKNOWN) && !defined(GLM_FORCE_CXX_UNKNOWN) + + Error += test_cpp_version(); + Error += test_compiler(); + Error += test_model(); + Error += test_instruction_set(); + Error += test_operators(); + +# endif + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_setup_platform_unknown.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_setup_platform_unknown.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9feaee3943681a1efb47f697c1a6ce28dbf6d76d --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_setup_platform_unknown.cpp @@ -0,0 +1,21 @@ +#ifndef GLM_FORCE_PLATFORM_UNKNOWN +# define GLM_FORCE_PLATFORM_UNKNOWN +#endif +#ifndef GLM_FORCE_COMPILER_UNKNOWN +# define GLM_FORCE_COMPILER_UNKNOWN +#endif +#ifndef GLM_FORCE_ARCH_UNKNOWN +# define GLM_FORCE_ARCH_UNKNOWN +#endif +#ifndef GLM_FORCE_CXX_UNKNOWN +# define GLM_FORCE_CXX_UNKNOWN +#endif +#include +#include + +int main() +{ + int Error = 0; + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_setup_precision.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_setup_precision.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b44bc50e421c08eca01afa22a04fba7e5a00f182 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_setup_precision.cpp @@ -0,0 +1,58 @@ +#define GLM_FORCE_INLINE +#define GLM_PRECISION_HIGHP_FLOAT +#include +#include + +static int test_mat() +{ + int Error = 0; + + Error += sizeof(glm::mat2) == sizeof(glm::highp_mat2) ? 0 : 1; + Error += sizeof(glm::mat3) == sizeof(glm::highp_mat3) ? 0 : 1; + Error += sizeof(glm::mat4) == sizeof(glm::highp_mat4) ? 0 : 1; + + Error += sizeof(glm::mat2x2) == sizeof(glm::highp_mat2x2) ? 0 : 1; + Error += sizeof(glm::mat2x3) == sizeof(glm::highp_mat2x3) ? 0 : 1; + Error += sizeof(glm::mat2x4) == sizeof(glm::highp_mat2x4) ? 0 : 1; + Error += sizeof(glm::mat3x2) == sizeof(glm::highp_mat3x2) ? 0 : 1; + Error += sizeof(glm::mat3x3) == sizeof(glm::highp_mat3x3) ? 0 : 1; + Error += sizeof(glm::mat3x4) == sizeof(glm::highp_mat3x4) ? 0 : 1; + Error += sizeof(glm::mat4x2) == sizeof(glm::highp_mat4x2) ? 0 : 1; + Error += sizeof(glm::mat4x3) == sizeof(glm::highp_mat4x3) ? 0 : 1; + Error += sizeof(glm::mat4x4) == sizeof(glm::highp_mat4x4) ? 0 : 1; + + return Error; +} + +static int test_vec() +{ + int Error = 0; + + Error += sizeof(glm::vec2) == sizeof(glm::highp_vec2) ? 0 : 1; + Error += sizeof(glm::vec3) == sizeof(glm::highp_vec3) ? 0 : 1; + Error += sizeof(glm::vec4) == sizeof(glm::highp_vec4) ? 0 : 1; + + return Error; +} + +static int test_dvec() +{ + int Error = 0; + + Error += sizeof(glm::dvec2) == sizeof(glm::highp_dvec2) ? 0 : 1; + Error += sizeof(glm::dvec3) == sizeof(glm::highp_dvec3) ? 0 : 1; + Error += sizeof(glm::dvec4) == sizeof(glm::highp_dvec4) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_mat(); + Error += test_vec(); + Error += test_dvec(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_aligned.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_aligned.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dff0939cf7914f258502230fd86e9eb6a686bb1d --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_aligned.cpp @@ -0,0 +1,92 @@ +#define GLM_FORCE_DEFAULT_ALIGNED_GENTYPES +#include + +#if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE +#include + +static_assert(sizeof(glm::bvec4) > sizeof(glm::bvec2), "Invalid sizeof"); +static_assert(sizeof(glm::ivec4) > sizeof(glm::uvec2), "Invalid sizeof"); +static_assert(sizeof(glm::dvec4) > sizeof(glm::dvec2), "Invalid sizeof"); + +static_assert(sizeof(glm::bvec4) == sizeof(glm::bvec3), "Invalid sizeof"); +static_assert(sizeof(glm::uvec4) == sizeof(glm::uvec3), "Invalid sizeof"); +static_assert(sizeof(glm::dvec4) == sizeof(glm::dvec3), "Invalid sizeof"); + +static int test_storage_aligned() +{ + int Error = 0; + + size_t size1_aligned = sizeof(glm::detail::storage<1, int, true>::type); + Error += size1_aligned == sizeof(int) * 1 ? 0 : 1; + size_t size2_aligned = sizeof(glm::detail::storage<2, int, true>::type); + Error += size2_aligned == sizeof(int) * 2 ? 0 : 1; + size_t size4_aligned = sizeof(glm::detail::storage<4, int, true>::type); + Error += size4_aligned == sizeof(int) * 4 ? 0 : 1; + + size_t align1_aligned = alignof(glm::detail::storage<1, int, true>::type); + Error += align1_aligned == 4 ? 0 : 1; + size_t align2_aligned = alignof(glm::detail::storage<2, int, true>::type); + Error += align2_aligned == 8 ? 0 : 1; + size_t align4_aligned = alignof(glm::detail::storage<4, int, true>::type); + Error += align4_aligned == 16 ? 0 : 1; + + return Error; +} + +static int test_storage_unaligned() +{ + int Error = 0; + + size_t align1_unaligned = alignof(glm::detail::storage<1, int, false>::type); + Error += align1_unaligned == sizeof(int) ? 0 : 1; + size_t align2_unaligned = alignof(glm::detail::storage<2, int, false>::type); + Error += align2_unaligned == sizeof(int) ? 0 : 1; + size_t align3_unaligned = alignof(glm::detail::storage<3, int, false>::type); + Error += align3_unaligned == sizeof(int) ? 0 : 1; + size_t align4_unaligned = alignof(glm::detail::storage<4, int, false>::type); + Error += align4_unaligned == sizeof(int) ? 0 : 1; + + return Error; +} + +static int test_vec3_aligned() +{ + int Error = 0; + + struct Struct1 + { + glm::vec4 A; + float B; + glm::vec3 C; + }; + + std::size_t const Size1 = sizeof(Struct1); + Error += Size1 == 48 ? 0 : 1; + + struct Struct2 + { + glm::vec4 A; + glm::vec3 B; + float C; + }; + + std::size_t const Size2 = sizeof(Struct2); + Error += Size2 == 48 ? 0 : 1; + + return Error; +} + +#endif + +int main() +{ + int Error = 0; + +# if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE + Error += test_storage_aligned(); + Error += test_storage_unaligned(); + Error += test_vec3_aligned(); +# endif + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_cast.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_cast.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7ff1901e1ad2ec1ea6e876004eb5b52a9bfb256f --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_cast.cpp @@ -0,0 +1,146 @@ +#include +#include +#include +#include +#include +#include + +struct my_vec2 +{ + operator glm::vec2() { return glm::vec2(x, y); } + float x, y; +}; + +int test_vec2_cast() +{ + glm::vec2 A(1.0f, 2.0f); + glm::lowp_vec2 B(A); + glm::mediump_vec2 C(A); + glm::highp_vec2 D(A); + + glm::vec2 E = static_cast(A); + glm::lowp_vec2 F = static_cast(A); + glm::mediump_vec2 G = static_cast(A); + glm::highp_vec2 H = static_cast(A); + + my_vec2 I; + glm::vec2 J = static_cast(I); + glm::vec2 K(7.8f); + + int Error(0); + + Error += glm::all(glm::equal(A, E, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(B, F, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(C, G, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(D, H, glm::epsilon())) ? 0 : 1; + + return Error; +} + +int test_vec3_cast() +{ + glm::vec3 A(1.0f, 2.0f, 3.0f); + glm::lowp_vec3 B(A); + glm::mediump_vec3 C(A); + glm::highp_vec3 D(A); + + glm::vec3 E = static_cast(A); + glm::lowp_vec3 F = static_cast(A); + glm::mediump_vec3 G = static_cast(A); + glm::highp_vec3 H = static_cast(A); + + int Error(0); + + Error += glm::all(glm::equal(A, E, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(B, F, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(C, G, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(D, H, glm::epsilon())) ? 0 : 1; + + return Error; +} + +int test_vec4_cast() +{ + glm::vec4 A(1.0f, 2.0f, 3.0f, 4.0f); + glm::lowp_vec4 B(A); + glm::mediump_vec4 C(A); + glm::highp_vec4 D(A); + + glm::vec4 E = static_cast(A); + glm::lowp_vec4 F = static_cast(A); + glm::mediump_vec4 G = static_cast(A); + glm::highp_vec4 H = static_cast(A); + + int Error(0); + + Error += glm::all(glm::equal(A, E, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(B, F, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(C, G, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(D, H, glm::epsilon())) ? 0 : 1; + + return Error; +} + +int test_std_copy() +{ + int Error = 0; + + { + std::vector High; + High.resize(64); + std::vector Medium(High.size()); + + std::copy(High.begin(), High.end(), Medium.begin()); + + *Medium.begin() = *High.begin(); + } + + { + std::vector High4; + High4.resize(64); + std::vector Medium4(High4.size()); + + std::copy(High4.begin(), High4.end(), Medium4.begin()); + + *Medium4.begin() = *High4.begin(); + } + + { + std::vector High3; + High3.resize(64); + std::vector Medium3(High3.size()); + + std::copy(High3.begin(), High3.end(), Medium3.begin()); + + *Medium3.begin() = *High3.begin(); + } + + { + std::vector High2; + High2.resize(64); + std::vector Medium2(High2.size()); + + std::copy(High2.begin(), High2.end(), Medium2.begin()); + + *Medium2.begin() = *High2.begin(); + } + + glm::dvec4 v1; + glm::vec4 v2; + + v2 = v1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_std_copy(); + Error += test_vec2_cast(); + Error += test_vec3_cast(); + Error += test_vec4_cast(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_ctor.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_ctor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..078fcdf04185b59f93a92d8f0af924b5b3efd1dc --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_ctor.cpp @@ -0,0 +1,351 @@ +#include +#include +#include +#include +#include + +static int test_vec1_ctor() +{ + int Error = 0; + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_ENABLE + { + union pack + { + glm::vec1 f; + glm::ivec1 i; + } A, B; + + A.f = glm::vec1(0); + Error += glm::all(glm::equal(A.i, glm::ivec1(0))) ? 0 : 1; + + B.f = glm::vec1(1); + Error += glm::all(glm::equal(B.i, glm::ivec1(1065353216))) ? 0 : 1; + } +# endif//GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_ENABLE + + return Error; +} + +static int test_vec2_ctor() +{ + int Error = 0; + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_ENABLE + { + union pack + { + glm::vec2 f; + glm::ivec2 i; + } A, B; + + A.f = glm::vec2(0); + Error += glm::all(glm::equal(A.i, glm::ivec2(0))) ? 0 : 1; + + B.f = glm::vec2(1); + Error += glm::all(glm::equal(B.i, glm::ivec2(1065353216))) ? 0 : 1; + } +# endif + + return Error; +} + +static int test_vec3_ctor() +{ + int Error = 0; + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_ENABLE + { + union pack + { + glm::vec3 f; + glm::ivec3 i; + } A, B; + + A.f = glm::vec3(0); + Error += glm::all(glm::equal(A.i, glm::ivec3(0))) ? 0 : 1; + + B.f = glm::vec3(1); + Error += glm::all(glm::equal(B.i, glm::ivec3(1065353216))) ? 0 : 1; + } +# endif + + return Error; +} + +static int test_vec4_ctor() +{ + int Error = 0; + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_ENABLE + { + union pack + { + glm::vec4 f; + glm::ivec4 i; + } A, B; + + A.f = glm::vec4(0); + Error += glm::all(glm::equal(A.i, glm::ivec4(0))) ? 0 : 1; + + B.f = glm::vec4(1); + Error += glm::all(glm::equal(B.i, glm::ivec4(1065353216))) ? 0 : 1; + } +# endif + + return Error; +} + +static int test_mat2x2_ctor() +{ + int Error = 0; + +# if GLM_LANG & GLM_LANG_CXX11_FLAG + { + union pack + { + glm::mat2x2 f; + glm::mat2x2 i; + } A, B; + + A.f = glm::mat2x2(0); + Error += glm::all(glm::equal(A.i[0], glm::vec2(0), glm::epsilon())) ? 0 : 1; + + B.f = glm::mat2x2(1); + Error += glm::all(glm::equal(B.i[0], glm::vec2(1, 0), glm::epsilon())) ? 0 : 1; + } +# endif//GLM_LANG & GLM_LANG_CXX11_FLAG + + return Error; +} + +static int test_mat2x3_ctor() +{ + int Error = 0; + +# if GLM_LANG & GLM_LANG_CXX11_FLAG + { + union pack + { + glm::mat2x3 f; + glm::mat2x3 i; + } A, B; + + A.f = glm::mat2x3(0); + Error += glm::all(glm::equal(A.i[0], glm::vec3(0), glm::epsilon())) ? 0 : 1; + + B.f = glm::mat2x3(1); + Error += glm::all(glm::equal(B.i[0], glm::vec3(1, 0, 0), glm::epsilon())) ? 0 : 1; + } +# endif//GLM_LANG & GLM_LANG_CXX11_FLAG + + return Error; +} + +static int test_mat2x4_ctor() +{ + int Error = 0; + +# if GLM_LANG & GLM_LANG_CXX11_FLAG + { + union pack + { + glm::mat2x4 f; + glm::mat2x4 i; + } A, B; + + A.f = glm::mat2x4(0); + glm::vec4 const C(0, 0, 0, 0); + Error += glm::all(glm::equal(A.i[0], C, glm::epsilon())) ? 0 : 1; + + B.f = glm::mat2x4(1); + glm::vec4 const D(1, 0, 0, 0); + Error += glm::all(glm::equal(B.i[0], D, glm::epsilon())) ? 0 : 1; + } +# endif//GLM_LANG & GLM_LANG_CXX11_FLAG + + return Error; +} + +static int test_mat3x2_ctor() +{ + int Error = 0; + +# if GLM_LANG & GLM_LANG_CXX11_FLAG + { + union pack + { + glm::mat3x2 f; + glm::mat3x2 i; + } A, B; + + A.f = glm::mat3x2(0); + Error += glm::all(glm::equal(A.i[0], glm::vec2(0), glm::epsilon())) ? 0 : 1; + + B.f = glm::mat3x2(1); + Error += glm::all(glm::equal(B.i[0], glm::vec2(1, 0), glm::epsilon())) ? 0 : 1; + } +# endif//GLM_LANG & GLM_LANG_CXX11_FLAG + + return Error; +} + +static int test_mat3x3_ctor() +{ + int Error = 0; + +# if GLM_LANG & GLM_LANG_CXX11_FLAG + { + union pack + { + glm::mat3x3 f; + glm::mat3x3 i; + } A, B; + + A.f = glm::mat3x3(0); + Error += glm::all(glm::equal(A.i[0], glm::vec3(0), glm::epsilon())) ? 0 : 1; + + B.f = glm::mat3x3(1); + Error += glm::all(glm::equal(B.i[0], glm::vec3(1, 0, 0), glm::epsilon())) ? 0 : 1; + } +# endif//GLM_LANG & GLM_LANG_CXX11_FLAG + + return Error; +} + +static int test_mat3x4_ctor() +{ + int Error = 0; + +# if GLM_LANG & GLM_LANG_CXX11_FLAG + { + union pack + { + glm::mat3x4 f; + glm::mat3x4 i; + } A, B; + + A.f = glm::mat3x4(0); + Error += glm::all(glm::equal(A.i[0], glm::vec4(0), glm::epsilon())) ? 0 : 1; + + B.f = glm::mat3x4(1); + Error += glm::all(glm::equal(B.i[0], glm::vec4(1, 0, 0, 0), glm::epsilon())) ? 0 : 1; + } +# endif//GLM_LANG & GLM_LANG_CXX11_FLAG + + return Error; +} + +static int test_mat4x2_ctor() +{ + int Error = 0; + +# if GLM_LANG & GLM_LANG_CXX11_FLAG + { + union pack + { + glm::mat4x2 f; + glm::mat4x2 i; + } A, B; + + A.f = glm::mat4x2(0); + Error += glm::all(glm::equal(A.i[0], glm::vec2(0), glm::epsilon())) ? 0 : 1; + + B.f = glm::mat4x2(1); + Error += glm::all(glm::equal(B.i[0], glm::vec2(1, 0), glm::epsilon())) ? 0 : 1; + } +# endif//GLM_LANG & GLM_LANG_CXX11_FLAG + + return Error; +} + +static int test_mat4x3_ctor() +{ + int Error = 0; + +# if GLM_LANG & GLM_LANG_CXX11_FLAG + { + union pack + { + glm::mat4x3 f; + glm::mat4x3 i; + } A, B; + + A.f = glm::mat4x3(0); + Error += glm::all(glm::equal(A.i[0], glm::vec3(0), glm::epsilon())) ? 0 : 1; + + B.f = glm::mat4x3(1); + Error += glm::all(glm::equal(B.i[0], glm::vec3(1, 0, 0), glm::epsilon())) ? 0 : 1; + } +# endif//GLM_LANG & GLM_LANG_CXX11_FLAG + + return Error; +} + +static int test_mat4x4_ctor() +{ + int Error = 0; + +# if GLM_LANG & GLM_LANG_CXX11_FLAG + { + union pack + { + glm::mat4 f; + glm::mat4 i; + } A, B; + + A.f = glm::mat4(0); + Error += glm::all(glm::equal(A.i[0], glm::vec4(0), glm::epsilon())) ? 0 : 1; + + B.f = glm::mat4(1); + Error += glm::all(glm::equal(B.i[0], glm::vec4(1, 0, 0, 0), glm::epsilon())) ? 0 : 1; + } +# endif//GLM_LANG & GLM_LANG_CXX11_FLAG + + return Error; +} + +static int test_quat_ctor() +{ + int Error = 0; + +# if GLM_LANG & GLM_LANG_CXX11_FLAG + { + union pack + { + glm::quat f; + glm::quat i; + } A, B; + + A.f = glm::quat(0, 0, 0, 0); + Error += glm::all(glm::equal(A.i, glm::quat(0, 0, 0, 0), glm::epsilon())) ? 0 : 1; + + B.f = glm::quat(1, 1, 1, 1); + Error += glm::all(glm::equal(B.i, glm::quat(1, 1, 1, 1), glm::epsilon())) ? 0 : 1; + } +# endif//GLM_LANG & GLM_LANG_CXX11_FLAG + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_vec1_ctor(); + Error += test_vec2_ctor(); + Error += test_vec3_ctor(); + Error += test_vec4_ctor(); + Error += test_mat2x2_ctor(); + Error += test_mat2x3_ctor(); + Error += test_mat2x4_ctor(); + Error += test_mat3x2_ctor(); + Error += test_mat3x3_ctor(); + Error += test_mat3x4_ctor(); + Error += test_mat4x2_ctor(); + Error += test_mat4x3_ctor(); + Error += test_mat4x4_ctor(); + Error += test_quat_ctor(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_int.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_int.cpp new file mode 100644 index 0000000000000000000000000000000000000000..26315098ff50b5e3068b8128877ee69d84dff8f1 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_int.cpp @@ -0,0 +1,26 @@ +#include +#include + +static int test_bit_operator() +{ + int Error = 0; + + glm::ivec4 const a(1); + glm::ivec4 const b = ~a; + Error += glm::all(glm::equal(b, glm::ivec4(-2))) ? 0 : 1; + + glm::int32 const c(1); + glm::int32 const d = ~c; + Error += d == -2 ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_bit_operator(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_length.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_length.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f088cb3429d0d8f125c5bf22fc8fa0a2689b73f1 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_length.cpp @@ -0,0 +1,78 @@ +#include + +static int test_length_mat_non_squared() +{ + int Error = 0; + + Error += glm::mat2x3().length() == 2 ? 0 : 1; + Error += glm::mat2x4().length() == 2 ? 0 : 1; + Error += glm::mat3x2().length() == 3 ? 0 : 1; + Error += glm::mat3x4().length() == 3 ? 0 : 1; + Error += glm::mat4x2().length() == 4 ? 0 : 1; + Error += glm::mat4x3().length() == 4 ? 0 : 1; + + Error += glm::dmat2x3().length() == 2 ? 0 : 1; + Error += glm::dmat2x4().length() == 2 ? 0 : 1; + Error += glm::dmat3x2().length() == 3 ? 0 : 1; + Error += glm::dmat3x4().length() == 3 ? 0 : 1; + Error += glm::dmat4x2().length() == 4 ? 0 : 1; + Error += glm::dmat4x3().length() == 4 ? 0 : 1; + + return Error; +} + +static int test_length_mat() +{ + int Error = 0; + + Error += glm::mat2().length() == 2 ? 0 : 1; + Error += glm::mat3().length() == 3 ? 0 : 1; + Error += glm::mat4().length() == 4 ? 0 : 1; + Error += glm::mat2x2().length() == 2 ? 0 : 1; + Error += glm::mat3x3().length() == 3 ? 0 : 1; + Error += glm::mat4x4().length() == 4 ? 0 : 1; + + Error += glm::dmat2().length() == 2 ? 0 : 1; + Error += glm::dmat3().length() == 3 ? 0 : 1; + Error += glm::dmat4().length() == 4 ? 0 : 1; + Error += glm::dmat2x2().length() == 2 ? 0 : 1; + Error += glm::dmat3x3().length() == 3 ? 0 : 1; + Error += glm::dmat4x4().length() == 4 ? 0 : 1; + + return Error; +} + +static int test_length_vec() +{ + int Error = 0; + + Error += glm::vec2().length() == 2 ? 0 : 1; + Error += glm::vec3().length() == 3 ? 0 : 1; + Error += glm::vec4().length() == 4 ? 0 : 1; + + Error += glm::ivec2().length() == 2 ? 0 : 1; + Error += glm::ivec3().length() == 3 ? 0 : 1; + Error += glm::ivec4().length() == 4 ? 0 : 1; + + Error += glm::uvec2().length() == 2 ? 0 : 1; + Error += glm::uvec3().length() == 3 ? 0 : 1; + Error += glm::uvec4().length() == 4 ? 0 : 1; + + Error += glm::dvec2().length() == 2 ? 0 : 1; + Error += glm::dvec3().length() == 3 ? 0 : 1; + Error += glm::dvec4().length() == 4 ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_length_vec(); + Error += test_length_mat(); + Error += test_length_mat_non_squared(); + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_mat2x2.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_mat2x2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2f8b018f690151b789c5640b4d770ae7ba7993f2 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_mat2x2.cpp @@ -0,0 +1,177 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int test_operators() +{ + glm::mat2x2 l(1.0f); + glm::mat2x2 m(1.0f); + glm::vec2 u(1.0f); + glm::vec2 v(1.0f); + float x = 1.0f; + glm::vec2 a = m * u; + glm::vec2 b = v * m; + glm::mat2x2 n = x / m; + glm::mat2x2 o = m / x; + glm::mat2x2 p = x * m; + glm::mat2x2 q = m * x; + bool R = glm::any(glm::notEqual(m, q, glm::epsilon())); + bool S = glm::all(glm::equal(m, l, glm::epsilon())); + + return (S && !R) ? 0 : 1; +} + +int test_inverse() +{ + int Error(0); + + { + glm::mat2 const Matrix(1, 2, 3, 4); + glm::mat2 const Inverse = glm::inverse(Matrix); + glm::mat2 const Identity = Matrix * Inverse; + + Error += glm::all(glm::equal(Identity[0], glm::vec2(1.0f, 0.0f), glm::vec2(0.01f))) ? 0 : 1; + Error += glm::all(glm::equal(Identity[1], glm::vec2(0.0f, 1.0f), glm::vec2(0.01f))) ? 0 : 1; + } + + { + glm::mat2 const Matrix(1, 2, 3, 4); + glm::mat2 const Identity = Matrix / Matrix; + + Error += glm::all(glm::equal(Identity[0], glm::vec2(1.0f, 0.0f), glm::vec2(0.01f))) ? 0 : 1; + Error += glm::all(glm::equal(Identity[1], glm::vec2(0.0f, 1.0f), glm::vec2(0.01f))) ? 0 : 1; + } + + return Error; +} + +int test_ctr() +{ + int Error = 0; + + { + glm::mediump_mat2x2 const A(1.0f); + glm::highp_mat2x2 const B(A); + glm::mediump_mat2x2 const C(B); + + Error += glm::all(glm::equal(A, C, glm::epsilon())) ? 0 : 1; + } + +#if GLM_HAS_INITIALIZER_LISTS + glm::mat2x2 m0( + glm::vec2(0, 1), + glm::vec2(2, 3)); + + glm::mat2x2 m1{0, 1, 2, 3}; + + glm::mat2x2 m2{ + {0, 1}, + {2, 3}}; + + Error += glm::all(glm::equal(m0, m2, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(m1, m2, glm::epsilon())) ? 0 : 1; + + std::vector v1{ + {0, 1, 2, 3}, + {0, 1, 2, 3} + }; + + std::vector v2{ + { + { 0, 1}, + { 4, 5} + }, + { + { 0, 1}, + { 4, 5} + } + }; + +#endif//GLM_HAS_INITIALIZER_LISTS + + return Error; +} + +namespace cast +{ + template + int entry() + { + int Error = 0; + + genType A(1.0f); + glm::mat2 B(A); + glm::mat2 Identity(1.0f); + + Error += glm::all(glm::equal(B, Identity, glm::epsilon())) ? 0 : 1; + + return Error; + } + + int test() + { + int Error = 0; + + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + + return Error; + } +}//namespace cast + +int test_size() +{ + int Error = 0; + + Error += 16 == sizeof(glm::mat2x2) ? 0 : 1; + Error += 32 == sizeof(glm::dmat2x2) ? 0 : 1; + Error += glm::mat2x2().length() == 2 ? 0 : 1; + Error += glm::dmat2x2().length() == 2 ? 0 : 1; + Error += glm::mat2x2::length() == 2 ? 0 : 1; + Error += glm::dmat2x2::length() == 2 ? 0 : 1; + + return Error; +} + +int test_constexpr() +{ +#if GLM_HAS_CONSTEXPR + static_assert(glm::mat2x2::length() == 2, "GLM: Failed constexpr"); +#endif + + return 0; +} + +int main() +{ + int Error = 0; + + Error += cast::test(); + Error += test_ctr(); + Error += test_operators(); + Error += test_inverse(); + Error += test_size(); + Error += test_constexpr(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_mat2x3.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_mat2x3.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e3ad76bbca7bac856692f489c4df5e4a5ad4dbd6 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_mat2x3.cpp @@ -0,0 +1,142 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int test_operators() +{ + glm::mat2x3 l(1.0f); + glm::mat2x3 m(1.0f); + glm::vec2 u(1.0f); + glm::vec3 v(1.0f); + float x = 1.0f; + glm::vec3 a = m * u; + glm::vec2 b = v * m; + glm::mat2x3 n = x / m; + glm::mat2x3 o = m / x; + glm::mat2x3 p = x * m; + glm::mat2x3 q = m * x; + bool R = glm::any(glm::notEqual(m, q, glm::epsilon())); + bool S = glm::all(glm::equal(m, l, glm::epsilon())); + + return (S && !R) ? 0 : 1; +} + +int test_ctr() +{ + int Error(0); + +#if GLM_HAS_INITIALIZER_LISTS + glm::mat2x3 m0( + glm::vec3(0, 1, 2), + glm::vec3(3, 4, 5)); + + glm::mat2x3 m1{0, 1, 2, 3, 4, 5}; + + glm::mat2x3 m2{ + {0, 1, 2}, + {3, 4, 5}}; + + Error += glm::all(glm::equal(m0, m2, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(m1, m2, glm::epsilon())) ? 0 : 1; + + std::vector v1{ + {0, 1, 2, 3, 4, 5}, + {0, 1, 2, 3, 4, 5} + }; + + std::vector v2{ + { + { 0, 1, 2}, + { 4, 5, 6} + }, + { + { 0, 1, 2}, + { 4, 5, 6} + } + }; + +#endif//GLM_HAS_INITIALIZER_LISTS + + return Error; +} + +namespace cast +{ + template + int entry() + { + int Error = 0; + + genType A(1.0f); + glm::mat2x3 B(A); + glm::mat2x3 Identity(1.0f); + + Error += glm::all(glm::equal(B, Identity, glm::epsilon())) ? 0 : 1; + + return Error; + } + + int test() + { + int Error = 0; + + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + + return Error; + } +}//namespace cast + +int test_size() +{ + int Error = 0; + + Error += 24 == sizeof(glm::mat2x3) ? 0 : 1; + Error += 48 == sizeof(glm::dmat2x3) ? 0 : 1; + Error += glm::mat2x3().length() == 2 ? 0 : 1; + Error += glm::dmat2x3().length() == 2 ? 0 : 1; + Error += glm::mat2x3::length() == 2 ? 0 : 1; + Error += glm::dmat2x3::length() == 2 ? 0 : 1; + + return Error; +} + +int test_constexpr() +{ +#if GLM_HAS_CONSTEXPR + static_assert(glm::mat2x3::length() == 2, "GLM: Failed constexpr"); +#endif + + return 0; +} + +int main() +{ + int Error = 0; + + Error += cast::test(); + Error += test_ctr(); + Error += test_operators(); + Error += test_size(); + Error += test_constexpr(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_mat2x4.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_mat2x4.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ade3a444414a34f309bf0449767c6cf89d40e704 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_mat2x4.cpp @@ -0,0 +1,147 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int test_operators() +{ + glm::mat2x4 l(1.0f); + glm::mat2x4 m(1.0f); + glm::vec2 u(1.0f); + glm::vec4 v(1.0f); + float x = 1.0f; + glm::vec4 a = m * u; + glm::vec2 b = v * m; + glm::mat2x4 n = x / m; + glm::mat2x4 o = m / x; + glm::mat2x4 p = x * m; + glm::mat2x4 q = m * x; + bool R = glm::any(glm::notEqual(m, q, glm::epsilon())); + bool S = glm::all(glm::equal(m, l, glm::epsilon())); + + return (S && !R) ? 0 : 1; +} + +int test_ctr() +{ + int Error(0); + +#if(GLM_HAS_INITIALIZER_LISTS) + glm::mat2x4 m0( + glm::vec4(0, 1, 2, 3), + glm::vec4(4, 5, 6, 7)); + + glm::mat2x4 m1{0, 1, 2, 3, 4, 5, 6, 7}; + + glm::mat2x4 m2{ + {0, 1, 2, 3}, + {4, 5, 6, 7}}; + + Error += glm::all(glm::equal(m0, m2, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(m1, m2, glm::epsilon())) ? 0 : 1; + + std::vector v1{ + {0, 1, 2, 3, 4, 5, 6, 7}, + {0, 1, 2, 3, 4, 5, 6, 7} + }; + + std::vector v2{ + { + { 0, 1, 2, 3}, + { 4, 5, 6, 7} + }, + { + { 0, 1, 2, 3}, + { 4, 5, 6, 7} + } + }; + +#endif//GLM_HAS_INITIALIZER_LISTS + + return Error; +} + +namespace cast +{ + template + int entry() + { + int Error = 0; + + genType A(1.0f); + glm::mat2x4 B(A); + glm::mat2x4 Identity(1.0f); + + for(glm::length_t i = 0, length = B.length(); i < length; ++i) + Error += glm::all(glm::epsilonEqual(B[i], Identity[i], glm::epsilon())) ? 0 : 1; + + return Error; + } + + int test() + { + int Error = 0; + + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + + return Error; + } +}//namespace cast + +static int test_size() +{ + int Error = 0; + + Error += 32 == sizeof(glm::mat2x4) ? 0 : 1; + Error += 64 == sizeof(glm::dmat2x4) ? 0 : 1; + Error += glm::mat2x4().length() == 2 ? 0 : 1; + Error += glm::dmat2x4().length() == 2 ? 0 : 1; + Error += glm::mat2x4::length() == 2 ? 0 : 1; + Error += glm::dmat2x4::length() == 2 ? 0 : 1; + + return Error; +} + +static int test_constexpr() +{ +#if GLM_HAS_CONSTEXPR + static_assert(glm::mat2x4::length() == 2, "GLM: Failed constexpr"); +#endif + + return 0; +} + +int main() +{ + int Error = 0; + + Error += cast::test(); + Error += test_ctr(); + Error += test_operators(); + Error += test_size(); + Error += test_constexpr(); + + return Error; +} + + + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_mat3x2.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_mat3x2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7a40f90f8831a550226fa9addef6580b606417ea --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_mat3x2.cpp @@ -0,0 +1,148 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static bool test_operators() +{ + glm::mat3x2 l(1.0f); + glm::mat3x2 m(1.0f); + glm::vec3 u(1.0f); + glm::vec2 v(1.0f); + float x = 1.0f; + glm::vec2 a = m * u; + glm::vec3 b = v * m; + glm::mat3x2 n = x / m; + glm::mat3x2 o = m / x; + glm::mat3x2 p = x * m; + glm::mat3x2 q = m * x; + bool R = glm::any(glm::notEqual(m, q, glm::epsilon())); + bool S = glm::all(glm::equal(m, l, glm::epsilon())); + + return (S && !R) ? 0 : 1; +} + +int test_ctr() +{ + int Error(0); + +#if(GLM_HAS_INITIALIZER_LISTS) + glm::mat3x2 m0( + glm::vec2(0, 1), + glm::vec2(2, 3), + glm::vec2(4, 5)); + + glm::mat3x2 m1{0, 1, 2, 3, 4, 5}; + + glm::mat3x2 m2{ + {0, 1}, + {2, 3}, + {4, 5}}; + + Error += glm::all(glm::equal(m0, m2, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(m1, m2, glm::epsilon())) ? 0 : 1; + + std::vector v1{ + {0, 1, 2, 3, 4, 5}, + {0, 1, 2, 3, 4, 5} + }; + + std::vector v2{ + { + { 0, 1}, + { 2, 3}, + { 4, 5} + }, + { + { 0, 1}, + { 2, 3}, + { 4, 5} + } + }; + +#endif//GLM_HAS_INITIALIZER_LISTS + + return Error; +} + +namespace cast +{ + template + int entry() + { + int Error = 0; + + genType A(1.0f); + glm::mat3x2 B(A); + glm::mat3x2 Identity(1.0f); + + Error += glm::all(glm::equal(B, Identity, glm::epsilon())) ? 0 : 1; + + return Error; + } + + int test() + { + int Error = 0; + + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + + return Error; + } +}//namespace cast + +static int test_size() +{ + int Error = 0; + + Error += 24 == sizeof(glm::mat3x2) ? 0 : 1; + Error += 48 == sizeof(glm::dmat3x2) ? 0 : 1; + Error += glm::mat3x2().length() == 3 ? 0 : 1; + Error += glm::dmat3x2().length() == 3 ? 0 : 1; + Error += glm::mat3x2::length() == 3 ? 0 : 1; + Error += glm::dmat3x2::length() == 3 ? 0 : 1; + + return Error; +} + +static int test_constexpr() +{ +#if GLM_HAS_CONSTEXPR + static_assert(glm::mat3x2::length() == 3, "GLM: Failed constexpr"); +#endif + + return 0; +} + +int main() +{ + int Error = 0; + + Error += cast::test(); + Error += test_ctr(); + Error += test_operators(); + Error += test_size(); + Error += test_constexpr(); + + return Error; +} + + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_mat3x3.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_mat3x3.cpp new file mode 100644 index 0000000000000000000000000000000000000000..99e1f41e064325600acc41bfb48c41f5171811bf --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_mat3x3.cpp @@ -0,0 +1,197 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int test_mat3x3() +{ + glm::dmat3 Mat0( + glm::dvec3(0.6f, 0.2f, 0.3f), + glm::dvec3(0.2f, 0.7f, 0.5f), + glm::dvec3(0.3f, 0.5f, 0.7f)); + glm::dmat3 Inv0 = glm::inverse(Mat0); + glm::dmat3 Res0 = Mat0 * Inv0; + + return glm::all(glm::equal(Res0, glm::dmat3(1.0), 0.01)) ? 0 : 1; +} + +static int test_operators() +{ + glm::mat3x3 l(1.0f); + glm::mat3x3 m(1.0f); + glm::vec3 u(1.0f); + glm::vec3 v(1.0f); + float x = 1.0f; + glm::vec3 a = m * u; + glm::vec3 b = v * m; + glm::mat3x3 n = x / m; + glm::mat3x3 o = m / x; + glm::mat3x3 p = x * m; + glm::mat3x3 q = m * x; + bool R = glm::any(glm::notEqual(m, q, glm::epsilon())); + bool S = glm::all(glm::equal(m, l, glm::epsilon())); + + return (S && !R) ? 0 : 1; +} + +static int test_inverse() +{ + int Error(0); + + { + glm::mat3 const Matrix( + glm::vec3(0.6f, 0.2f, 0.3f), + glm::vec3(0.2f, 0.7f, 0.5f), + glm::vec3(0.3f, 0.5f, 0.7f)); + glm::mat3 const Inverse = glm::inverse(Matrix); + glm::mat3 const Identity = Matrix * Inverse; + + Error += glm::all(glm::equal(Identity[0], glm::vec3(1.0f, 0.0f, 0.0f), glm::vec3(0.01f))) ? 0 : 1; + Error += glm::all(glm::equal(Identity[1], glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(0.01f))) ? 0 : 1; + Error += glm::all(glm::equal(Identity[2], glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(0.01f))) ? 0 : 1; + } + + { + glm::mat3 const Matrix( + glm::vec3(0.6f, 0.2f, 0.3f), + glm::vec3(0.2f, 0.7f, 0.5f), + glm::vec3(0.3f, 0.5f, 0.7f)); + glm::mat3 const Identity = Matrix / Matrix; + + Error += glm::all(glm::equal(Identity[0], glm::vec3(1.0f, 0.0f, 0.0f), glm::vec3(0.01f))) ? 0 : 1; + Error += glm::all(glm::equal(Identity[1], glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(0.01f))) ? 0 : 1; + Error += glm::all(glm::equal(Identity[2], glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(0.01f))) ? 0 : 1; + } + + return Error; +} + +static int test_ctr() +{ + int Error(0); + +#if(GLM_HAS_INITIALIZER_LISTS) + glm::mat3x3 m0( + glm::vec3(0, 1, 2), + glm::vec3(3, 4, 5), + glm::vec3(6, 7, 8)); + + glm::mat3x3 m1{0, 1, 2, 3, 4, 5, 6, 7, 8}; + + glm::mat3x3 m2{ + {0, 1, 2}, + {3, 4, 5}, + {6, 7, 8}}; + + Error += glm::all(glm::equal(m0, m2, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(m1, m2, glm::epsilon())) ? 0 : 1; + + std::vector v1{ + {0, 1, 2, 3, 4, 5, 6, 7, 8}, + {0, 1, 2, 3, 4, 5, 6, 7, 8} + }; + + std::vector v2{ + { + { 0, 1, 2}, + { 3, 4, 5}, + { 6, 7, 8} + }, + { + { 0, 1, 2}, + { 3, 4, 5}, + { 6, 7, 8} + } + }; + +#endif//GLM_HAS_INITIALIZER_LISTS + + return Error; +} + +namespace cast +{ + template + int entry() + { + int Error = 0; + + genType A(1.0f); + glm::mat3x3 B(A); + glm::mat3x3 Identity(1.0f); + + Error += glm::all(glm::equal(B, Identity, glm::epsilon())) ? 0 : 1; + + return Error; + } + + int test() + { + int Error = 0; + + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + + return Error; + } +}//namespace cast + +static int test_size() +{ + int Error = 0; + + Error += 36 == sizeof(glm::mat3x3) ? 0 : 1; + Error += 72 == sizeof(glm::dmat3x3) ? 0 : 1; + Error += glm::mat3x3().length() == 3 ? 0 : 1; + Error += glm::dmat3x3().length() == 3 ? 0 : 1; + Error += glm::mat3x3::length() == 3 ? 0 : 1; + Error += glm::dmat3x3::length() == 3 ? 0 : 1; + + return Error; +} + +static int test_constexpr() +{ +#if GLM_HAS_CONSTEXPR + static_assert(glm::mat3x3::length() == 3, "GLM: Failed constexpr"); + + constexpr glm::mat3x3 const Z(0.0f); +#endif + + return 0; +} + +int main() +{ + int Error = 0; + + Error += cast::test(); + Error += test_ctr(); + Error += test_mat3x3(); + Error += test_operators(); + Error += test_inverse(); + Error += test_size(); + Error += test_constexpr(); + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_mat3x4.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_mat3x4.cpp new file mode 100644 index 0000000000000000000000000000000000000000..97d4574641f302195fcbd59859b27d6273b4ef4a --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_mat3x4.cpp @@ -0,0 +1,149 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static bool test_operators() +{ + glm::mat3x4 l(1.0f); + glm::mat3x4 m(1.0f); + glm::vec3 u(1.0f); + glm::vec4 v(1.0f); + float x = 1.0f; + glm::vec4 a = m * u; + glm::vec3 b = v * m; + glm::mat3x4 n = x / m; + glm::mat3x4 o = m / x; + glm::mat3x4 p = x * m; + glm::mat3x4 q = m * x; + bool R = glm::any(glm::notEqual(m, q, glm::epsilon())); + bool S = glm::all(glm::equal(m, l, glm::epsilon())); + + return (S && !R) ? 0 : 1; +} + +int test_ctr() +{ + int Error(0); + +#if(GLM_HAS_INITIALIZER_LISTS) + glm::mat3x4 m0( + glm::vec4(0, 1, 2, 3), + glm::vec4(4, 5, 6, 7), + glm::vec4(8, 9, 10, 11)); + + glm::mat3x4 m1{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + + glm::mat3x4 m2{ + {0, 1, 2, 3}, + {4, 5, 6, 7}, + {8, 9, 10, 11}}; + + Error += glm::all(glm::equal(m0, m2, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(m1, m2, glm::epsilon())) ? 0 : 1; + + std::vector v1{ + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11} + }; + + std::vector v2{ + { + { 0, 1, 2, 3}, + { 4, 5, 6, 7}, + { 8, 9, 10, 11} + }, + { + { 0, 1, 2, 3}, + { 4, 5, 6, 7}, + { 8, 9, 10, 11} + } + }; + +#endif//GLM_HAS_INITIALIZER_LISTS + + return Error; +} + +namespace cast +{ + template + int entry() + { + int Error = 0; + + genType A(1.0f); + glm::mat3x4 B(A); + glm::mat3x4 Identity(1.0f); + + for(glm::length_t i = 0, length = B.length(); i < length; ++i) + Error += glm::all(glm::epsilonEqual(B[i], Identity[i], glm::epsilon())) ? 0 : 1; + + return Error; + } + + int test() + { + int Error = 0; + + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + + return Error; + } +}//namespace cast + +static int test_size() +{ + int Error = 0; + + Error += 48 == sizeof(glm::mat3x4) ? 0 : 1; + Error += 96 == sizeof(glm::dmat3x4) ? 0 : 1; + Error += glm::mat3x4().length() == 3 ? 0 : 1; + Error += glm::dmat3x4().length() == 3 ? 0 : 1; + Error += glm::mat3x4::length() == 3 ? 0 : 1; + Error += glm::dmat3x4::length() == 3 ? 0 : 1; + + return Error; +} + +static int test_constexpr() +{ +#if GLM_HAS_CONSTEXPR + static_assert(glm::mat3x4::length() == 3, "GLM: Failed constexpr"); +#endif + + return 0; +} + +int main() +{ + int Error = 0; + + Error += cast::test(); + Error += test_ctr(); + Error += test_operators(); + Error += test_size(); + Error += test_constexpr(); + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_mat4x2.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_mat4x2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7133edc812de4b095b1207e0004c859b56c581b8 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_mat4x2.cpp @@ -0,0 +1,151 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int test_operators() +{ + glm::mat4x2 l(1.0f); + glm::mat4x2 m(1.0f); + glm::vec4 u(1.0f); + glm::vec2 v(1.0f); + float x = 1.0f; + glm::vec2 a = m * u; + glm::vec4 b = v * m; + glm::mat4x2 n = x / m; + glm::mat4x2 o = m / x; + glm::mat4x2 p = x * m; + glm::mat4x2 q = m * x; + bool R = glm::any(glm::notEqual(m, q, glm::epsilon())); + bool S = glm::all(glm::equal(m, l, glm::epsilon())); + + return (S && !R) ? 0 : 1; +} + +int test_ctr() +{ + int Error(0); + +#if(GLM_HAS_INITIALIZER_LISTS) + glm::mat4x2 m0( + glm::vec2(0, 1), + glm::vec2(2, 3), + glm::vec2(4, 5), + glm::vec2(6, 7)); + + glm::mat4x2 m1{0, 1, 2, 3, 4, 5, 6, 7}; + + glm::mat4x2 m2{ + {0, 1}, + {2, 3}, + {4, 5}, + {6, 7}}; + + Error += glm::all(glm::equal(m0, m2, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(m1, m2, glm::epsilon())) ? 0 : 1; + + std::vector v1{ + {0, 1, 2, 3, 4, 5, 6, 7}, + {0, 1, 2, 3, 4, 5, 6, 7} + }; + + std::vector v2{ + { + { 0, 1}, + { 4, 5}, + { 8, 9}, + { 12, 13} + }, + { + { 0, 1}, + { 4, 5}, + { 8, 9}, + { 12, 13} + } + }; + +#endif//GLM_HAS_INITIALIZER_LISTS + + return Error; +} + +namespace cast +{ + template + int entry() + { + int Error = 0; + + genType A(1.0f); + glm::mat4x2 B(A); + glm::mat4x2 Identity(1.0f); + + Error += glm::all(glm::equal(B, Identity, glm::epsilon())) ? 0 : 1; + + return Error; + } + + int test() + { + int Error = 0; + + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + + return Error; + } +}//namespace cast + +static int test_size() +{ + int Error = 0; + + Error += 32 == sizeof(glm::mat4x2) ? 0 : 1; + Error += 64 == sizeof(glm::dmat4x2) ? 0 : 1; + Error += glm::mat4x2().length() == 4 ? 0 : 1; + Error += glm::dmat4x2().length() == 4 ? 0 : 1; + Error += glm::mat4x2::length() == 4 ? 0 : 1; + Error += glm::dmat4x2::length() == 4 ? 0 : 1; + + return Error; +} + +static int test_constexpr() +{ +#if GLM_HAS_CONSTEXPR + static_assert(glm::mat4x2::length() == 4, "GLM: Failed constexpr"); +#endif + + return 0; +} + +int main() +{ + int Error = 0; + + Error += cast::test(); + Error += test_ctr(); + Error += test_operators(); + Error += test_size(); + Error += test_constexpr(); + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_mat4x3.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_mat4x3.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1c65e7f3ff0751a807e286498c7de61735b0efda --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_mat4x3.cpp @@ -0,0 +1,152 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int test_operators() +{ + glm::mat4x3 l(1.0f); + glm::mat4x3 m(1.0f); + glm::vec4 u(1.0f); + glm::vec3 v(1.0f); + float x = 1.0f; + glm::vec3 a = m * u; + glm::vec4 b = v * m; + glm::mat4x3 n = x / m; + glm::mat4x3 o = m / x; + glm::mat4x3 p = x * m; + glm::mat4x3 q = m * x; + bool R = glm::any(glm::notEqual(m, q, glm::epsilon())); + bool S = glm::all(glm::equal(m, l, glm::epsilon())); + + return (S && !R) ? 0 : 1; +} + +int test_ctr() +{ + int Error(0); + +#if(GLM_HAS_INITIALIZER_LISTS) + glm::mat4x3 m0( + glm::vec3(0, 1, 2), + glm::vec3(3, 4, 5), + glm::vec3(6, 7, 8), + glm::vec3(9, 10, 11)); + + glm::mat4x3 m1{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + + glm::mat4x3 m2{ + {0, 1, 2}, + {3, 4, 5}, + {6, 7, 8}, + {9, 10, 11}}; + + Error += glm::all(glm::equal(m0, m2, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(m1, m2, glm::epsilon())) ? 0 : 1; + + std::vector v1{ + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11} + }; + + std::vector v2{ + { + { 0, 1, 2 }, + { 4, 5, 6 }, + { 8, 9, 10 }, + { 12, 13, 14 } + }, + { + { 0, 1, 2 }, + { 4, 5, 6 }, + { 8, 9, 10 }, + { 12, 13, 14 } + } + }; + +#endif//GLM_HAS_INITIALIZER_LISTS + + return Error; +} + +namespace cast +{ + template + int entry() + { + int Error = 0; + + genType A(1.0f); + glm::mat4x3 B(A); + glm::mat4x3 Identity(1.0f); + + Error += glm::all(glm::equal(B, Identity, glm::epsilon())) ? 0 : 1; + + return Error; + } + + int test() + { + int Error = 0; + + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + Error += entry(); + + return Error; + } +}//namespace cast + +static int test_size() +{ + int Error = 0; + + Error += 48 == sizeof(glm::mat4x3) ? 0 : 1; + Error += 96 == sizeof(glm::dmat4x3) ? 0 : 1; + Error += glm::mat4x3().length() == 4 ? 0 : 1; + Error += glm::dmat4x3().length() == 4 ? 0 : 1; + Error += glm::mat4x3::length() == 4 ? 0 : 1; + Error += glm::dmat4x3::length() == 4 ? 0 : 1; + + return Error; +} + +static int test_constexpr() +{ +#if GLM_HAS_CONSTEXPR + static_assert(glm::mat4x3::length() == 4, "GLM: Failed constexpr"); +#endif + + return 0; +} + +int main() +{ + int Error = 0; + + Error += cast::test(); + Error += test_ctr(); + Error += test_operators(); + Error += test_size(); + Error += test_constexpr(); + + return Error; +} + + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_mat4x4.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_mat4x4.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0be87f18b56f0b651d0e56653efb2178e6288578 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_mat4x4.cpp @@ -0,0 +1,218 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +template +static int test_operators() +{ + typedef typename matType::value_type value_type; + + value_type const Epsilon = static_cast(0.001); + + int Error = 0; + + matType const M(static_cast(2.0f)); + matType const N(static_cast(1.0f)); + vecType const U(static_cast(2.0f)); + + { + matType const P = N * static_cast(2.0f); + Error += glm::all(glm::equal(P, M, Epsilon)) ? 0 : 1; + + matType const Q = M / static_cast(2.0f); + Error += glm::all(glm::equal(Q, N, Epsilon)) ? 0 : 1; + } + + { + vecType const V = M * U; + Error += glm::all(glm::equal(V, vecType(static_cast(4.f)), Epsilon)) ? 0 : 1; + + vecType const W = U / M; + Error += glm::all(glm::equal(W, vecType(static_cast(1.f)), Epsilon)) ? 0 : 1; + } + + { + matType const O = M * N; + Error += glm::all(glm::equal(O, matType(static_cast(2.f)), Epsilon)) ? 0 : 1; + } + + return Error; +} + +template +static int test_inverse() +{ + typedef typename matType::value_type value_type; + + value_type const Epsilon = static_cast(0.001); + + int Error = 0; + + matType const Identity(static_cast(1.0f)); + matType const Matrix( + glm::vec4(0.6f, 0.2f, 0.3f, 0.4f), + glm::vec4(0.2f, 0.7f, 0.5f, 0.3f), + glm::vec4(0.3f, 0.5f, 0.7f, 0.2f), + glm::vec4(0.4f, 0.3f, 0.2f, 0.6f)); + matType const Inverse = Identity / Matrix; + matType const Result = Matrix * Inverse; + + Error += glm::all(glm::equal(Identity, Result, Epsilon)) ? 0 : 1; + + return Error; +} + +static int test_ctr() +{ + int Error = 0; + +#if GLM_HAS_TRIVIAL_QUERIES + //Error += std::is_trivially_default_constructible::value ? 0 : 1; + //Error += std::is_trivially_copy_assignable::value ? 0 : 1; + Error += std::is_trivially_copyable::value ? 0 : 1; + //Error += std::is_copy_constructible::value ? 0 : 1; + //Error += std::has_trivial_copy_constructor::value ? 0 : 1; +#endif + +#if GLM_HAS_INITIALIZER_LISTS + glm::mat4 const m0( + glm::vec4(0, 1, 2, 3), + glm::vec4(4, 5, 6, 7), + glm::vec4(8, 9, 10, 11), + glm::vec4(12, 13, 14, 15)); + + assert(sizeof(m0) == 4 * 4 * 4); + + glm::vec4 const V{0, 1, 2, 3}; + + glm::mat4 const m1{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; + + glm::mat4 const m2{ + {0, 1, 2, 3}, + {4, 5, 6, 7}, + {8, 9, 10, 11}, + {12, 13, 14, 15}}; + + Error += glm::all(glm::equal(m0, m2, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(m1, m2, glm::epsilon())) ? 0 : 1; + + + std::vector const m3{ + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}}; + + glm::mat4 const m4{ + {1, 0, 0, 0}, + {0, 1, 0, 0}, + {0, 0, 1, 0}, + {0, 0, 0, 1} }; + + Error += glm::equal(m4[0][0], 1.0f, 0.0001f) ? 0 : 1; + Error += glm::equal(m4[3][3], 1.0f, 0.0001f) ? 0 : 1; + + std::vector const v1{ + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}}; + + std::vector const v2{ + { + { 0, 1, 2, 3 }, + { 4, 5, 6, 7 }, + { 8, 9, 10, 11 }, + { 12, 13, 14, 15 } + }, + { + { 0, 1, 2, 3 }, + { 4, 5, 6, 7 }, + { 8, 9, 10, 11 }, + { 12, 13, 14, 15 } + }}; + +#endif//GLM_HAS_INITIALIZER_LISTS + + return Error; +} + +static int test_member_alloc_bug() +{ + int Error = 0; + + struct repro + { + repro(){ this->matrix = new glm::mat4(); } + ~repro(){delete this->matrix;} + + glm::mat4* matrix; + }; + + repro Repro; + + return Error; +} + +static int test_size() +{ + int Error = 0; + + Error += 64 == sizeof(glm::mat4) ? 0 : 1; + Error += 128 == sizeof(glm::dmat4) ? 0 : 1; + Error += glm::mat4().length() == 4 ? 0 : 1; + Error += glm::dmat4().length() == 4 ? 0 : 1; + Error += glm::mat4::length() == 4 ? 0 : 1; + Error += glm::dmat4::length() == 4 ? 0 : 1; + + return Error; +} + +static int test_constexpr() +{ +#if GLM_HAS_CONSTEXPR + static_assert(glm::mat4::length() == 4, "GLM: Failed constexpr"); + constexpr glm::mat4 A(1.f); + constexpr glm::mat4 B(1.f); + constexpr glm::bvec4 C = glm::equal(A, B, 0.01f); + static_assert(glm::all(C), "GLM: Failed constexpr"); +#endif + + return 0; +} + +int main() +{ + int Error = 0; + + Error += test_member_alloc_bug(); + Error += test_ctr(); + + Error += test_operators(); + Error += test_operators(); + Error += test_operators(); + Error += test_operators(); + + Error += test_operators(); + Error += test_operators(); + Error += test_operators(); + Error += test_operators(); + + Error += test_inverse(); + Error += test_inverse(); + Error += test_inverse(); + Error += test_inverse(); + + Error += test_inverse(); + Error += test_inverse(); + Error += test_inverse(); + Error += test_inverse(); + + Error += test_size(); + Error += test_constexpr(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_vec1.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_vec1.cpp new file mode 100644 index 0000000000000000000000000000000000000000..77f3f84d787a8876ba67785a239a9e9a163d7732 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_vec1.cpp @@ -0,0 +1,169 @@ +#define GLM_FORCE_SWIZZLE +#include +#include +#include +#include +#include + +static glm::vec1 g1; +static glm::vec1 g2(1); + +int test_vec1_operators() +{ + int Error = 0; + + glm::ivec1 A(1); + glm::ivec1 B(1); + { + bool R = A != B; + bool S = A == B; + + Error += (S && !R) ? 0 : 1; + } + + { + A *= 1; + B *= 1; + A += 1; + B += 1; + + bool R = A != B; + bool S = A == B; + + Error += (S && !R) ? 0 : 1; + } + + return Error; +} + +int test_vec1_ctor() +{ + int Error = 0; + +# if GLM_HAS_TRIVIAL_QUERIES + // Error += std::is_trivially_default_constructible::value ? 0 : 1; + // Error += std::is_trivially_copy_assignable::value ? 0 : 1; + Error += std::is_trivially_copyable::value ? 0 : 1; + Error += std::is_trivially_copyable::value ? 0 : 1; + Error += std::is_trivially_copyable::value ? 0 : 1; + Error += std::is_trivially_copyable::value ? 0 : 1; + + Error += std::is_copy_constructible::value ? 0 : 1; +# endif + +/* +#if GLM_HAS_INITIALIZER_LISTS + { + glm::vec1 a{ 0 }; + std::vector v = { + {0.f}, + {4.f}, + {8.f}}; + } + + { + glm::dvec2 a{ 0 }; + std::vector v = { + {0.0}, + {4.0}, + {8.0}}; + } +#endif +*/ + + { + glm::vec2 A = glm::vec2(2.0f); + glm::vec2 B = glm::vec2(2.0f, 3.0f); + glm::vec2 C = glm::vec2(2.0f, 3.0); + //glm::vec2 D = glm::dvec2(2.0); // Build error TODO: What does the specification says? + glm::vec2 E(glm::dvec2(2.0)); + glm::vec2 F(glm::ivec2(2)); + } + + return Error; +} + +static int test_vec1_size() +{ + int Error = 0; + + Error += sizeof(glm::vec1) == sizeof(glm::mediump_vec1) ? 0 : 1; + Error += 4 == sizeof(glm::mediump_vec1) ? 0 : 1; + Error += sizeof(glm::dvec1) == sizeof(glm::highp_dvec1) ? 0 : 1; + Error += 8 == sizeof(glm::highp_dvec1) ? 0 : 1; + Error += glm::vec1().length() == 1 ? 0 : 1; + Error += glm::dvec1().length() == 1 ? 0 : 1; + Error += glm::vec1::length() == 1 ? 0 : 1; + Error += glm::dvec1::length() == 1 ? 0 : 1; + + return Error; +} + +static int test_vec1_operator_increment() +{ + int Error(0); + + glm::ivec1 v0(1); + glm::ivec1 v1(v0); + glm::ivec1 v2(v0); + glm::ivec1 v3 = ++v1; + glm::ivec1 v4 = v2++; + + Error += glm::all(glm::equal(v0, v4)) ? 0 : 1; + Error += glm::all(glm::equal(v1, v2)) ? 0 : 1; + Error += glm::all(glm::equal(v1, v3)) ? 0 : 1; + + int i0(1); + int i1(i0); + int i2(i0); + int i3 = ++i1; + int i4 = i2++; + + Error += i0 == i4 ? 0 : 1; + Error += i1 == i2 ? 0 : 1; + Error += i1 == i3 ? 0 : 1; + + return Error; +} + +static int test_swizzle() +{ + int Error = 0; + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + { + glm::vec1 A = glm::vec1(1.0f); + //glm::vec1 B = A.x; + glm::vec1 C(A.x); + + //Error += glm::all(glm::equal(A, B)) ? 0 : 1; + Error += glm::all(glm::equal(A, C, glm::epsilon())) ? 0 : 1; + } +# endif//GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + + return Error; +} + +static int test_constexpr() +{ +#if GLM_HAS_CONSTEXPR + static_assert(glm::vec1::length() == 1, "GLM: Failed constexpr"); + static_assert(glm::vec1(1.0f).x > 0.0f, "GLM: Failed constexpr"); +#endif + + return 0; +} + +int main() +{ + int Error = 0; + + Error += test_vec1_size(); + Error += test_vec1_ctor(); + Error += test_vec1_operators(); + Error += test_vec1_operator_increment(); + Error += test_swizzle(); + Error += test_constexpr(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_vec2.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_vec2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..308c61f0dd48cd002161fb1ee1c42899984f290c --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_vec2.cpp @@ -0,0 +1,392 @@ +#define GLM_FORCE_SWIZZLE +#include +#include +#include +#include +#include +#include +#include +#if GLM_HAS_TRIVIAL_QUERIES +# include +#endif + +static glm::ivec2 g1; +static glm::ivec2 g2(1); +static glm::ivec2 g3(1, 1); + +static int test_operators() +{ + int Error = 0; + + { + glm::ivec2 A(1); + glm::ivec2 B(1); + Error += A != B ? 1 : 0; + Error += A == B ? 0 : 1; + } + + { + glm::vec2 A(1.0f); + glm::vec2 C = A + 1.0f; + A += 1.0f; + Error += glm::all(glm::equal(A, glm::vec2(2.0f), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(A, C, glm::epsilon())) ? 0 : 1; + } + + { + glm::vec2 A(1.0f); + glm::vec2 B(2.0f,-1.0f); + glm::vec2 C = A + B; + A += B; + Error += glm::all(glm::equal(A, glm::vec2(3.0f, 0.0f), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(A, C, glm::epsilon())) ? 0 : 1; + } + + { + glm::vec2 A(1.0f); + glm::vec2 C = A - 1.0f; + A -= 1.0f; + Error += glm::all(glm::equal(A, glm::vec2(0.0f), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(A, C, glm::epsilon())) ? 0 : 1; + } + + { + glm::vec2 A(1.0f); + glm::vec2 B(2.0f,-1.0f); + glm::vec2 C = A - B; + A -= B; + Error += glm::all(glm::equal(A, glm::vec2(-1.0f, 2.0f), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(A, C, glm::epsilon())) ? 0 : 1; + } + + { + glm::vec2 A(1.0f); + glm::vec2 C = A * 2.0f; + A *= 2.0f; + Error += glm::all(glm::equal(A, glm::vec2(2.0f), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(A, C, glm::epsilon())) ? 0 : 1; + } + + { + glm::vec2 A(2.0f); + glm::vec2 B(2.0f); + glm::vec2 C = A / B; + A /= B; + Error += glm::all(glm::equal(A, glm::vec2(1.0f), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(A, C, glm::epsilon())) ? 0 : 1; + } + + { + glm::vec2 A(1.0f, 2.0f); + glm::vec2 B(4.0f, 5.0f); + + glm::vec2 C = A + B; + Error += glm::all(glm::equal(C, glm::vec2(5, 7), glm::epsilon())) ? 0 : 1; + + glm::vec2 D = B - A; + Error += glm::all(glm::equal(D, glm::vec2(3, 3), glm::epsilon())) ? 0 : 1; + + glm::vec2 E = A * B; + Error += glm::all(glm::equal(E, glm::vec2(4, 10), glm::epsilon())) ? 0 : 1; + + glm::vec2 F = B / A; + Error += glm::all(glm::equal(F, glm::vec2(4, 2.5), glm::epsilon())) ? 0 : 1; + + glm::vec2 G = A + 1.0f; + Error += glm::all(glm::equal(G, glm::vec2(2, 3), glm::epsilon())) ? 0 : 1; + + glm::vec2 H = B - 1.0f; + Error += glm::all(glm::equal(H, glm::vec2(3, 4), glm::epsilon())) ? 0 : 1; + + glm::vec2 I = A * 2.0f; + Error += glm::all(glm::equal(I, glm::vec2(2, 4), glm::epsilon())) ? 0 : 1; + + glm::vec2 J = B / 2.0f; + Error += glm::all(glm::equal(J, glm::vec2(2, 2.5), glm::epsilon())) ? 0 : 1; + + glm::vec2 K = 1.0f + A; + Error += glm::all(glm::equal(K, glm::vec2(2, 3), glm::epsilon())) ? 0 : 1; + + glm::vec2 L = 1.0f - B; + Error += glm::all(glm::equal(L, glm::vec2(-3, -4), glm::epsilon())) ? 0 : 1; + + glm::vec2 M = 2.0f * A; + Error += glm::all(glm::equal(M, glm::vec2(2, 4), glm::epsilon())) ? 0 : 1; + + glm::vec2 N = 2.0f / B; + Error += glm::all(glm::equal(N, glm::vec2(0.5, 2.0 / 5.0), glm::epsilon())) ? 0 : 1; + } + + { + glm::vec2 A(1.0f, 2.0f); + glm::vec2 B(4.0f, 5.0f); + + A += B; + Error += glm::all(glm::equal(A, glm::vec2(5, 7), glm::epsilon())) ? 0 : 1; + + A += 1.0f; + Error += glm::all(glm::equal(A, glm::vec2(6, 8), glm::epsilon())) ? 0 : 1; + } + { + glm::ivec2 A(1.0f, 2.0f); + glm::ivec2 B(4.0f, 5.0f); + + B -= A; + Error += B == glm::ivec2(3, 3) ? 0 : 1; + + B -= 1.0f; + Error += B == glm::ivec2(2, 2) ? 0 : 1; + } + { + glm::ivec2 A(1.0f, 2.0f); + glm::ivec2 B(4.0f, 5.0f); + + A *= B; + Error += A == glm::ivec2(4, 10) ? 0 : 1; + + A *= 2; + Error += A == glm::ivec2(8, 20) ? 0 : 1; + } + { + glm::ivec2 A(1.0f, 2.0f); + glm::ivec2 B(4.0f, 16.0f); + + B /= A; + Error += B == glm::ivec2(4, 8) ? 0 : 1; + + B /= 2.0f; + Error += B == glm::ivec2(2, 4) ? 0 : 1; + } + { + glm::ivec2 B(2); + + B /= B.y; + Error += B == glm::ivec2(1) ? 0 : 1; + } + + { + glm::ivec2 A(1.0f, 2.0f); + glm::ivec2 B = -A; + Error += B == glm::ivec2(-1.0f, -2.0f) ? 0 : 1; + } + + { + glm::ivec2 A(1.0f, 2.0f); + glm::ivec2 B = --A; + Error += B == glm::ivec2(0.0f, 1.0f) ? 0 : 1; + } + + { + glm::ivec2 A(1.0f, 2.0f); + glm::ivec2 B = A--; + Error += B == glm::ivec2(1.0f, 2.0f) ? 0 : 1; + Error += A == glm::ivec2(0.0f, 1.0f) ? 0 : 1; + } + + { + glm::ivec2 A(1.0f, 2.0f); + glm::ivec2 B = ++A; + Error += B == glm::ivec2(2.0f, 3.0f) ? 0 : 1; + } + + { + glm::ivec2 A(1.0f, 2.0f); + glm::ivec2 B = A++; + Error += B == glm::ivec2(1.0f, 2.0f) ? 0 : 1; + Error += A == glm::ivec2(2.0f, 3.0f) ? 0 : 1; + } + + return Error; +} + +static int test_ctor() +{ + int Error = 0; + + { + glm::ivec2 A(1); + glm::ivec2 B(A); + Error += A == B ? 0 : 1; + } + +# if GLM_HAS_TRIVIAL_QUERIES + // Error += std::is_trivially_default_constructible::value ? 0 : 1; + // Error += std::is_trivially_copy_assignable::value ? 0 : 1; + Error += std::is_trivially_copyable::value ? 0 : 1; + Error += std::is_trivially_copyable::value ? 0 : 1; + Error += std::is_trivially_copyable::value ? 0 : 1; + Error += std::is_trivially_copyable::value ? 0 : 1; + + Error += std::is_copy_constructible::value ? 0 : 1; +# endif + +#if GLM_HAS_INITIALIZER_LISTS + { + glm::vec2 a{ 0, 1 }; + std::vector v = { + {0, 1}, + {4, 5}, + {8, 9}}; + } + + { + glm::dvec2 a{ 0, 1 }; + std::vector v = { + {0, 1}, + {4, 5}, + {8, 9}}; + } +#endif + + { + glm::vec2 A = glm::vec2(2.0f); + glm::vec2 B = glm::vec2(2.0f, 3.0f); + glm::vec2 C = glm::vec2(2.0f, 3.0); + //glm::vec2 D = glm::dvec2(2.0); // Build error TODO: What does the specification says? + glm::vec2 E(glm::dvec2(2.0)); + glm::vec2 F(glm::ivec2(2)); + } + + { + glm::vec1 const R(1.0f); + glm::vec1 const S(2.0f); + glm::vec2 const O(1.0f, 2.0f); + + glm::vec2 const A(R); + glm::vec2 const B(1.0f); + Error += glm::all(glm::equal(A, B, 0.0001f)) ? 0 : 1; + + glm::vec2 const C(R, S); + Error += glm::all(glm::equal(C, O, 0.0001f)) ? 0 : 1; + + glm::vec2 const D(R, 2.0f); + Error += glm::all(glm::equal(D, O, 0.0001f)) ? 0 : 1; + + glm::vec2 const E(1.0f, S); + Error += glm::all(glm::equal(E, O, 0.0001f)) ? 0 : 1; + } + + { + glm::vec1 const R(1.0f); + glm::dvec1 const S(2.0); + glm::vec2 const O(1.0, 2.0); + + glm::vec2 const A(R); + glm::vec2 const B(1.0); + Error += glm::all(glm::equal(A, B, 0.0001f)) ? 0 : 1; + + glm::vec2 const C(R, S); + Error += glm::all(glm::equal(C, O, 0.0001f)) ? 0 : 1; + + glm::vec2 const D(R, 2.0); + Error += glm::all(glm::equal(D, O, 0.0001f)) ? 0 : 1; + + glm::vec2 const E(1.0, S); + Error += glm::all(glm::equal(E, O, 0.0001f)) ? 0 : 1; + } + + return Error; +} + +static int test_size() +{ + int Error = 0; + + Error += sizeof(glm::vec2) == sizeof(glm::mediump_vec2) ? 0 : 1; + Error += 8 == sizeof(glm::mediump_vec2) ? 0 : 1; + Error += sizeof(glm::dvec2) == sizeof(glm::highp_dvec2) ? 0 : 1; + Error += 16 == sizeof(glm::highp_dvec2) ? 0 : 1; + Error += glm::vec2().length() == 2 ? 0 : 1; + Error += glm::dvec2().length() == 2 ? 0 : 1; + Error += glm::vec2::length() == 2 ? 0 : 1; + Error += glm::dvec2::length() == 2 ? 0 : 1; + + GLM_CONSTEXPR std::size_t Length = glm::vec2::length(); + Error += Length == 2 ? 0 : 1; + + return Error; +} + +static int test_operator_increment() +{ + int Error = 0; + + glm::ivec2 v0(1); + glm::ivec2 v1(v0); + glm::ivec2 v2(v0); + glm::ivec2 v3 = ++v1; + glm::ivec2 v4 = v2++; + + Error += glm::all(glm::equal(v0, v4)) ? 0 : 1; + Error += glm::all(glm::equal(v1, v2)) ? 0 : 1; + Error += glm::all(glm::equal(v1, v3)) ? 0 : 1; + + int i0(1); + int i1(i0); + int i2(i0); + int i3 = ++i1; + int i4 = i2++; + + Error += i0 == i4 ? 0 : 1; + Error += i1 == i2 ? 0 : 1; + Error += i1 == i3 ? 0 : 1; + + return Error; +} + +static int test_constexpr() +{ +#if GLM_HAS_CONSTEXPR + static_assert(glm::vec2::length() == 2, "GLM: Failed constexpr"); + static_assert(glm::vec2(1.0f).x > 0.0f, "GLM: Failed constexpr"); + static_assert(glm::vec2(1.0f, -1.0f).x > 0.0f, "GLM: Failed constexpr"); + static_assert(glm::vec2(1.0f, -1.0f).y < 0.0f, "GLM: Failed constexpr"); +#endif + + return 0; +} + +static int test_swizzle() +{ + int Error = 0; + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + { + glm::vec2 A = glm::vec2(1.0f, 2.0f); + glm::vec2 B = A.xy; + glm::vec2 C(A.xy); + glm::vec2 D(A.xy()); + + Error += glm::all(glm::equal(A, B, 0.0001f)) ? 0 : 1; + Error += glm::all(glm::equal(A, C, 0.0001f)) ? 0 : 1; + Error += glm::all(glm::equal(A, D, 0.0001f)) ? 0 : 1; + } +# endif//GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR || GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION + { + glm::vec2 A = glm::vec2(1.0f, 2.0f); + glm::vec2 B = A.xy(); + glm::vec2 C(A.xy()); + + Error += glm::all(glm::equal(A, B, 0.0001f)) ? 0 : 1; + Error += glm::all(glm::equal(A, C, 0.0001f)) ? 0 : 1; + } +# endif//GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR || GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_size(); + Error += test_ctor(); + Error += test_operators(); + Error += test_operator_increment(); + Error += test_swizzle(); + Error += test_constexpr(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_vec3.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_vec3.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4da8187db95e5245f36701ca1c33d36cb8fedf6b --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_vec3.cpp @@ -0,0 +1,628 @@ +#define GLM_FORCE_SWIZZLE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static glm::vec3 g1; +static glm::vec3 g2(1); +static glm::vec3 g3(1, 1, 1); + +int test_vec3_ctor() +{ + int Error = 0; + +# if GLM_HAS_TRIVIAL_QUERIES + // Error += std::is_trivially_default_constructible::value ? 0 : 1; + // Error += std::is_trivially_copy_assignable::value ? 0 : 1; + Error += std::is_trivially_copyable::value ? 0 : 1; + Error += std::is_trivially_copyable::value ? 0 : 1; + Error += std::is_trivially_copyable::value ? 0 : 1; + Error += std::is_trivially_copyable::value ? 0 : 1; + + Error += std::is_copy_constructible::value ? 0 : 1; +# endif + +# if GLM_HAS_INITIALIZER_LISTS + { + glm::vec3 a{ 0, 1, 2 }; + std::vector v = { + {0, 1, 2}, + {4, 5, 6}, + {8, 9, 0}}; + } + + { + glm::dvec3 a{ 0, 1, 2 }; + std::vector v = { + {0, 1, 2}, + {4, 5, 6}, + {8, 9, 0}}; + } +# endif + + { + glm::ivec3 A(1); + glm::ivec3 B(1, 1, 1); + + Error += A == B ? 0 : 1; + } + + { + std::vector Tests; + Tests.push_back(glm::ivec3(glm::ivec2(1, 2), 3)); + Tests.push_back(glm::ivec3(1, glm::ivec2(2, 3))); + Tests.push_back(glm::ivec3(1, 2, 3)); + Tests.push_back(glm::ivec3(glm::ivec4(1, 2, 3, 4))); + + for(std::size_t i = 0; i < Tests.size(); ++i) + Error += Tests[i] == glm::ivec3(1, 2, 3) ? 0 : 1; + } + + { + glm::vec1 const R(1.0f); + glm::vec1 const S(2.0f); + glm::vec1 const T(3.0f); + glm::vec3 const O(1.0f, 2.0f, 3.0f); + + glm::vec3 const A(R); + glm::vec3 const B(1.0f); + Error += glm::all(glm::equal(A, B, glm::epsilon())) ? 0 : 1; + + glm::vec3 const C(R, S, T); + Error += glm::all(glm::equal(C, O, glm::epsilon())) ? 0 : 1; + + glm::vec3 const D(R, 2.0f, 3.0f); + Error += glm::all(glm::equal(D, O, glm::epsilon())) ? 0 : 1; + + glm::vec3 const E(1.0f, S, 3.0f); + Error += glm::all(glm::equal(E, O, glm::epsilon())) ? 0 : 1; + + glm::vec3 const F(1.0f, S, T); + Error += glm::all(glm::equal(F, O, glm::epsilon())) ? 0 : 1; + + glm::vec3 const G(R, 2.0f, T); + Error += glm::all(glm::equal(G, O, glm::epsilon())) ? 0 : 1; + + glm::vec3 const H(R, S, 3.0f); + Error += glm::all(glm::equal(H, O, glm::epsilon())) ? 0 : 1; + } + + { + glm::vec1 const R(1.0); + glm::dvec1 const S(2.0); + glm::vec1 const T(3.0); + glm::vec3 const O(1.0f, 2.0f, 3.0f); + + glm::vec3 const A(R); + glm::vec3 const B(1.0); + Error += glm::all(glm::equal(A, B, glm::epsilon())) ? 0 : 1; + + glm::vec3 const C(R, S, T); + Error += glm::all(glm::equal(C, O, glm::epsilon())) ? 0 : 1; + + glm::vec3 const D(R, 2.0, 3.0); + Error += glm::all(glm::equal(D, O, glm::epsilon())) ? 0 : 1; + + glm::vec3 const E(1.0f, S, 3.0); + Error += glm::all(glm::equal(E, O, glm::epsilon())) ? 0 : 1; + + glm::vec3 const F(1.0, S, T); + Error += glm::all(glm::equal(F, O, glm::epsilon())) ? 0 : 1; + + glm::vec3 const G(R, 2.0, T); + Error += glm::all(glm::equal(G, O, glm::epsilon())) ? 0 : 1; + + glm::vec3 const H(R, S, 3.0); + Error += glm::all(glm::equal(H, O, glm::epsilon())) ? 0 : 1; + } + + return Error; +} + +float foo() +{ + glm::vec3 bar = glm::vec3(0.0f, 1.0f, 1.0f); + + return glm::length(bar); +} + +static int test_bvec3_ctor() +{ + int Error = 0; + + glm::bvec3 const A(true); + glm::bvec3 const B(true); + glm::bvec3 const C(false); + glm::bvec3 const D = A && B; + glm::bvec3 const E = A && C; + glm::bvec3 const F = A || C; + + Error += D == glm::bvec3(true) ? 0 : 1; + Error += E == glm::bvec3(false) ? 0 : 1; + Error += F == glm::bvec3(true) ? 0 : 1; + + bool const G = A == C; + bool const H = A != C; + Error += !G ? 0 : 1; + Error += H ? 0 : 1; + + return Error; +} + +static int test_vec3_operators() +{ + int Error = 0; + + { + glm::ivec3 A(1); + glm::ivec3 B(1); + bool R = A != B; + bool S = A == B; + + Error += (S && !R) ? 0 : 1; + } + + { + glm::vec3 const A(1.0f, 2.0f, 3.0f); + glm::vec3 const B(4.0f, 5.0f, 6.0f); + + glm::vec3 const C = A + B; + Error += glm::all(glm::equal(C, glm::vec3(5, 7, 9), glm::epsilon())) ? 0 : 1; + + glm::vec3 const D = B - A; + Error += glm::all(glm::equal(D, glm::vec3(3, 3, 3), glm::epsilon())) ? 0 : 1; + + glm::vec3 const E = A * B; + Error += glm::all(glm::equal(E, glm::vec3(4, 10, 18), glm::epsilon())) ? 0 : 1; + + glm::vec3 const F = B / A; + Error += glm::all(glm::equal(F, glm::vec3(4, 2.5, 2), glm::epsilon())) ? 0 : 1; + + glm::vec3 const G = A + 1.0f; + Error += glm::all(glm::equal(G, glm::vec3(2, 3, 4), glm::epsilon())) ? 0 : 1; + + glm::vec3 const H = B - 1.0f; + Error += glm::all(glm::equal(H, glm::vec3(3, 4, 5), glm::epsilon())) ? 0 : 1; + + glm::vec3 const I = A * 2.0f; + Error += glm::all(glm::equal(I, glm::vec3(2, 4, 6), glm::epsilon())) ? 0 : 1; + + glm::vec3 const J = B / 2.0f; + Error += glm::all(glm::equal(J, glm::vec3(2, 2.5, 3), glm::epsilon())) ? 0 : 1; + + glm::vec3 const K = 1.0f + A; + Error += glm::all(glm::equal(K, glm::vec3(2, 3, 4), glm::epsilon())) ? 0 : 1; + + glm::vec3 const L = 1.0f - B; + Error += glm::all(glm::equal(L, glm::vec3(-3, -4, -5), glm::epsilon())) ? 0 : 1; + + glm::vec3 const M = 2.0f * A; + Error += glm::all(glm::equal(M, glm::vec3(2, 4, 6), glm::epsilon())) ? 0 : 1; + + glm::vec3 const N = 2.0f / B; + Error += glm::all(glm::equal(N, glm::vec3(0.5, 2.0 / 5.0, 2.0 / 6.0), glm::epsilon())) ? 0 : 1; + } + + { + glm::ivec3 A(1.0f, 2.0f, 3.0f); + glm::ivec3 B(4.0f, 5.0f, 6.0f); + + A += B; + Error += A == glm::ivec3(5, 7, 9) ? 0 : 1; + + A += 1; + Error += A == glm::ivec3(6, 8, 10) ? 0 : 1; + } + { + glm::ivec3 A(1.0f, 2.0f, 3.0f); + glm::ivec3 B(4.0f, 5.0f, 6.0f); + + B -= A; + Error += B == glm::ivec3(3, 3, 3) ? 0 : 1; + + B -= 1; + Error += B == glm::ivec3(2, 2, 2) ? 0 : 1; + } + { + glm::ivec3 A(1.0f, 2.0f, 3.0f); + glm::ivec3 B(4.0f, 5.0f, 6.0f); + + A *= B; + Error += A == glm::ivec3(4, 10, 18) ? 0 : 1; + + A *= 2; + Error += A == glm::ivec3(8, 20, 36) ? 0 : 1; + } + { + glm::ivec3 A(1.0f, 2.0f, 3.0f); + glm::ivec3 B(4.0f, 4.0f, 6.0f); + + B /= A; + Error += B == glm::ivec3(4, 2, 2) ? 0 : 1; + + B /= 2; + Error += B == glm::ivec3(2, 1, 1) ? 0 : 1; + } + { + glm::ivec3 B(2); + + B /= B.y; + Error += B == glm::ivec3(1) ? 0 : 1; + } + + { + glm::ivec3 A(1.0f, 2.0f, 3.0f); + glm::ivec3 B = -A; + Error += B == glm::ivec3(-1.0f, -2.0f, -3.0f) ? 0 : 1; + } + + { + glm::ivec3 A(1.0f, 2.0f, 3.0f); + glm::ivec3 B = --A; + Error += B == glm::ivec3(0.0f, 1.0f, 2.0f) ? 0 : 1; + } + + { + glm::ivec3 A(1.0f, 2.0f, 3.0f); + glm::ivec3 B = A--; + Error += B == glm::ivec3(1.0f, 2.0f, 3.0f) ? 0 : 1; + Error += A == glm::ivec3(0.0f, 1.0f, 2.0f) ? 0 : 1; + } + + { + glm::ivec3 A(1.0f, 2.0f, 3.0f); + glm::ivec3 B = ++A; + Error += B == glm::ivec3(2.0f, 3.0f, 4.0f) ? 0 : 1; + } + + { + glm::ivec3 A(1.0f, 2.0f, 3.0f); + glm::ivec3 B = A++; + Error += B == glm::ivec3(1.0f, 2.0f, 3.0f) ? 0 : 1; + Error += A == glm::ivec3(2.0f, 3.0f, 4.0f) ? 0 : 1; + } + + return Error; +} + +int test_vec3_size() +{ + int Error = 0; + + Error += sizeof(glm::vec3) == sizeof(glm::lowp_vec3) ? 0 : 1; + Error += sizeof(glm::vec3) == sizeof(glm::mediump_vec3) ? 0 : 1; + Error += sizeof(glm::vec3) == sizeof(glm::highp_vec3) ? 0 : 1; + Error += 12 == sizeof(glm::mediump_vec3) ? 0 : 1; + Error += sizeof(glm::dvec3) == sizeof(glm::lowp_dvec3) ? 0 : 1; + Error += sizeof(glm::dvec3) == sizeof(glm::mediump_dvec3) ? 0 : 1; + Error += sizeof(glm::dvec3) == sizeof(glm::highp_dvec3) ? 0 : 1; + Error += 24 == sizeof(glm::highp_dvec3) ? 0 : 1; + Error += glm::vec3().length() == 3 ? 0 : 1; + Error += glm::dvec3().length() == 3 ? 0 : 1; + Error += glm::vec3::length() == 3 ? 0 : 1; + Error += glm::dvec3::length() == 3 ? 0 : 1; + + GLM_CONSTEXPR std::size_t Length = glm::vec3::length(); + Error += Length == 3 ? 0 : 1; + + return Error; +} + +int test_vec3_swizzle3_2() +{ + int Error = 0; + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + { + glm::ivec3 v(1, 2, 3); + glm::ivec2 u; + + // Can not assign a vec3 swizzle to a vec2 + //u = v.xyz; //Illegal + //u = v.rgb; //Illegal + //u = v.stp; //Illegal + + u = v.xx; Error += (u.x == 1 && u.y == 1) ? 0 : 1; + u = v.xy; Error += (u.x == 1 && u.y == 2) ? 0 : 1; + u = v.xz; Error += (u.x == 1 && u.y == 3) ? 0 : 1; + u = v.yx; Error += (u.x == 2 && u.y == 1) ? 0 : 1; + u = v.yy; Error += (u.x == 2 && u.y == 2) ? 0 : 1; + u = v.yz; Error += (u.x == 2 && u.y == 3) ? 0 : 1; + u = v.zx; Error += (u.x == 3 && u.y == 1) ? 0 : 1; + u = v.zy; Error += (u.x == 3 && u.y == 2) ? 0 : 1; + u = v.zz; Error += (u.x == 3 && u.y == 3) ? 0 : 1; + + u = v.rr; Error += (u.r == 1 && u.g == 1) ? 0 : 1; + u = v.rg; Error += (u.r == 1 && u.g == 2) ? 0 : 1; + u = v.rb; Error += (u.r == 1 && u.g == 3) ? 0 : 1; + u = v.gr; Error += (u.r == 2 && u.g == 1) ? 0 : 1; + u = v.gg; Error += (u.r == 2 && u.g == 2) ? 0 : 1; + u = v.gb; Error += (u.r == 2 && u.g == 3) ? 0 : 1; + u = v.br; Error += (u.r == 3 && u.g == 1) ? 0 : 1; + u = v.bg; Error += (u.r == 3 && u.g == 2) ? 0 : 1; + u = v.bb; Error += (u.r == 3 && u.g == 3) ? 0 : 1; + + u = v.ss; Error += (u.s == 1 && u.t == 1) ? 0 : 1; + u = v.st; Error += (u.s == 1 && u.t == 2) ? 0 : 1; + u = v.sp; Error += (u.s == 1 && u.t == 3) ? 0 : 1; + u = v.ts; Error += (u.s == 2 && u.t == 1) ? 0 : 1; + u = v.tt; Error += (u.s == 2 && u.t == 2) ? 0 : 1; + u = v.tp; Error += (u.s == 2 && u.t == 3) ? 0 : 1; + u = v.ps; Error += (u.s == 3 && u.t == 1) ? 0 : 1; + u = v.pt; Error += (u.s == 3 && u.t == 2) ? 0 : 1; + u = v.pp; Error += (u.s == 3 && u.t == 3) ? 0 : 1; + // Mixed member aliases are not valid + //u = v.rx; //Illegal + //u = v.sy; //Illegal + + u = glm::ivec2(1, 2); + v = glm::ivec3(1, 2, 3); + //v.xx = u; //Illegal + v.xy = u; Error += (v.x == 1 && v.y == 2 && v.z == 3) ? 0 : 1; + v.xz = u; Error += (v.x == 1 && v.y == 2 && v.z == 2) ? 0 : 1; + v.yx = u; Error += (v.x == 2 && v.y == 1 && v.z == 2) ? 0 : 1; + //v.yy = u; //Illegal + v.yz = u; Error += (v.x == 2 && v.y == 1 && v.z == 2) ? 0 : 1; + v.zx = u; Error += (v.x == 2 && v.y == 1 && v.z == 1) ? 0 : 1; + v.zy = u; Error += (v.x == 2 && v.y == 2 && v.z == 1) ? 0 : 1; + //v.zz = u; //Illegal + } +# endif//GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + + return Error; +} + +int test_vec3_swizzle3_3() +{ + int Error = 0; + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + { + glm::ivec3 v(1, 2, 3); + glm::ivec3 u; + + u = v; Error += (u.x == 1 && u.y == 2 && u.z == 3) ? 0 : 1; + + u = v.xyz; Error += (u.x == 1 && u.y == 2 && u.z == 3) ? 0 : 1; + u = v.zyx; Error += (u.x == 3 && u.y == 2 && u.z == 1) ? 0 : 1; + u.zyx = v; Error += (u.x == 3 && u.y == 2 && u.z == 1) ? 0 : 1; + + u = v.rgb; Error += (u.x == 1 && u.y == 2 && u.z == 3) ? 0 : 1; + u = v.bgr; Error += (u.x == 3 && u.y == 2 && u.z == 1) ? 0 : 1; + u.bgr = v; Error += (u.x == 3 && u.y == 2 && u.z == 1) ? 0 : 1; + + u = v.stp; Error += (u.x == 1 && u.y == 2 && u.z == 3) ? 0 : 1; + u = v.pts; Error += (u.x == 3 && u.y == 2 && u.z == 1) ? 0 : 1; + u.pts = v; Error += (u.x == 3 && u.y == 2 && u.z == 1) ? 0 : 1; + } +# endif//GLM_LANG + + return Error; +} + +int test_vec3_swizzle_operators() +{ + int Error = 0; + + glm::ivec3 const u = glm::ivec3(1, 2, 3); + glm::ivec3 const v = glm::ivec3(10, 20, 30); + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + { + glm::ivec3 q; + + // Swizzle, swizzle binary operators + q = u.xyz + v.xyz; Error += (q == (u + v)) ? 0 : 1; + q = (u.zyx + v.zyx).zyx; Error += (q == (u + v)) ? 0 : 1; + q = (u.xyz - v.xyz); Error += (q == (u - v)) ? 0 : 1; + q = (u.xyz * v.xyz); Error += (q == (u * v)) ? 0 : 1; + q = (u.xxx * v.xxx); Error += (q == glm::ivec3(u.x * v.x)) ? 0 : 1; + q = (u.xyz / v.xyz); Error += (q == (u / v)) ? 0 : 1; + + // vec, swizzle binary operators + q = u + v.xyz; Error += (q == (u + v)) ? 0 : 1; + q = (u - v.xyz); Error += (q == (u - v)) ? 0 : 1; + q = (u * v.xyz); Error += (q == (u * v)) ? 0 : 1; + q = (u * v.xxx); Error += (q == v.x * u) ? 0 : 1; + q = (u / v.xyz); Error += (q == (u / v)) ? 0 : 1; + + // swizzle,vec binary operators + q = u.xyz + v; Error += (q == (u + v)) ? 0 : 1; + q = (u.xyz - v); Error += (q == (u - v)) ? 0 : 1; + q = (u.xyz * v); Error += (q == (u * v)) ? 0 : 1; + q = (u.xxx * v); Error += (q == u.x * v) ? 0 : 1; + q = (u.xyz / v); Error += (q == (u / v)) ? 0 : 1; + } +# endif//GLM_LANG + + // Compile errors + //q = (u.yz * v.xyz); + //q = (u * v.xy); + + return Error; +} + +int test_vec3_swizzle_functions() +{ + int Error = 0; + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR || GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION + { + // NOTE: template functions cannot pick up the implicit conversion from + // a swizzle to the unswizzled type, therefore the operator() must be + // used. E.g.: + // + // glm::dot(u.xy, v.xy); <--- Compile error + // glm::dot(u.xy(), v.xy()); <--- Compiles correctly + + float r; + + // vec2 + glm::vec2 a(1, 2); + glm::vec2 b(10, 20); + r = glm::dot(a, b); Error += (int(r) == 50) ? 0 : 1; + r = glm::dot(glm::vec2(a.xy()), glm::vec2(b.xy())); Error += (int(r) == 50) ? 0 : 1; + r = glm::dot(glm::vec2(a.xy()), glm::vec2(b.yy())); Error += (int(r) == 60) ? 0 : 1; + + // vec3 + glm::vec3 u = glm::vec3(1, 2, 3); + glm::vec3 v = glm::vec3(10, 20, 30); + r = glm::dot(u, v); Error += (int(r) == 140) ? 0 : 1; + r = glm::dot(u.xyz(), v.zyz()); Error += (int(r) == 160) ? 0 : 1; + r = glm::dot(u, v.zyx()); Error += (int(r) == 100) ? 0 : 1; + r = glm::dot(u.xyz(), v); Error += (int(r) == 140) ? 0 : 1; + r = glm::dot(u.xy(), v.xy()); Error += (int(r) == 50) ? 0 : 1; + + // vec4 + glm::vec4 s = glm::vec4(1, 2, 3, 4); + glm::vec4 t = glm::vec4(10, 20, 30, 40); + r = glm::dot(s, t); Error += (int(r) == 300) ? 0 : 1; + r = glm::dot(s.xyzw(), t.xyzw()); Error += (int(r) == 300) ? 0 : 1; + r = glm::dot(s.xyz(), t.xyz()); Error += (int(r) == 140) ? 0 : 1; + } +# endif//GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR || GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION + + return Error; +} + +int test_vec3_swizzle_partial() +{ + int Error = 0; + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + { + glm::vec3 const A(1, 2, 3); + glm::vec3 B(A.xy, 3); + Error += glm::all(glm::equal(A, B, glm::epsilon())) ? 0 : 1; + } + + { + glm::ivec3 const A(1, 2, 3); + glm::ivec3 const B(1, A.yz); + Error += A == B ? 0 : 1; + } + + { + glm::ivec3 const A(1, 2, 3); + glm::ivec3 const B(A.xyz); + Error += A == B ? 0 : 1; + } +# endif//GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + + return Error; +} + +static int test_operator_increment() +{ + int Error = 0; + + glm::ivec3 v0(1); + glm::ivec3 v1(v0); + glm::ivec3 v2(v0); + glm::ivec3 v3 = ++v1; + glm::ivec3 v4 = v2++; + + Error += glm::all(glm::equal(v0, v4)) ? 0 : 1; + Error += glm::all(glm::equal(v1, v2)) ? 0 : 1; + Error += glm::all(glm::equal(v1, v3)) ? 0 : 1; + + int i0(1); + int i1(i0); + int i2(i0); + int i3 = ++i1; + int i4 = i2++; + + Error += i0 == i4 ? 0 : 1; + Error += i1 == i2 ? 0 : 1; + Error += i1 == i3 ? 0 : 1; + + return Error; +} + +static int test_swizzle() +{ + int Error = 0; + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + { + glm::vec3 A = glm::vec3(1.0f, 2.0f, 3.0f); + glm::vec3 B = A.xyz; + glm::vec3 C(A.xyz); + glm::vec3 D(A.xyz()); + glm::vec3 E(A.x, A.yz); + glm::vec3 F(A.x, A.yz()); + glm::vec3 G(A.xy, A.z); + glm::vec3 H(A.xy(), A.z); + + Error += glm::all(glm::equal(A, B, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(A, C, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(A, D, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(A, E, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(A, F, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(A, G, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(A, H, glm::epsilon())) ? 0 : 1; + } +# endif//GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR || GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION + { + glm::vec3 A = glm::vec3(1.0f, 2.0f, 3.0f); + glm::vec3 B = A.xyz(); + glm::vec3 C(A.xyz()); + glm::vec3 D(A.xyz()); + glm::vec3 E(A.x, A.yz()); + glm::vec3 F(A.x, A.yz()); + glm::vec3 G(A.xy(), A.z); + glm::vec3 H(A.xy(), A.z); + + Error += glm::all(glm::equal(A, B, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(A, C, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(A, D, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(A, E, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(A, F, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(A, G, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(A, H, glm::epsilon())) ? 0 : 1; + } +# endif//GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR || GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION + + return Error; +} + +static int test_constexpr() +{ +#if GLM_HAS_CONSTEXPR + static_assert(glm::vec3::length() == 3, "GLM: Failed constexpr"); + static_assert(glm::vec3(1.0f).x > 0.0f, "GLM: Failed constexpr"); + static_assert(glm::vec3(1.0f, -1.0f, -1.0f).x > 0.0f, "GLM: Failed constexpr"); + static_assert(glm::vec3(1.0f, -1.0f, -1.0f).y < 0.0f, "GLM: Failed constexpr"); +#endif + + return 0; +} + +int main() +{ + int Error = 0; + + Error += test_vec3_ctor(); + Error += test_bvec3_ctor(); + Error += test_vec3_operators(); + Error += test_vec3_size(); + Error += test_operator_increment(); + Error += test_constexpr(); + + Error += test_swizzle(); + Error += test_vec3_swizzle3_2(); + Error += test_vec3_swizzle3_3(); + Error += test_vec3_swizzle_partial(); + Error += test_vec3_swizzle_operators(); + Error += test_vec3_swizzle_functions(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_vec4.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_vec4.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5d65259f57b0587e5023b5bda85449c9b73abe52 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/core/core_type_vec4.cpp @@ -0,0 +1,850 @@ +#define GLM_FORCE_SWIZZLE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static glm::vec4 g1; +static glm::vec4 g2(1); +static glm::vec4 g3(1, 1, 1, 1); + +template +struct mask +{ + enum{value = Value}; +}; + +enum comp +{ + X, + Y, + Z, + W +}; + +//template +//__m128 swizzle(glm::vec4 const& v) +//{ +// __m128 Src = _mm_set_ps(v.w, v.z, v.y, v.x); +// return _mm_shuffle_ps(Src, Src, mask<(int(W) << 6) | (int(Z) << 4) | (int(Y) << 2) | (int(X) << 0)>::value); +//} + +static int test_vec4_ctor() +{ + int Error = 0; + + { + glm::ivec4 A(1, 2, 3, 4); + glm::ivec4 B(A); + Error += glm::all(glm::equal(A, B)) ? 0 : 1; + } + +# if GLM_HAS_TRIVIAL_QUERIES + // Error += std::is_trivially_default_constructible::value ? 0 : 1; + // Error += std::is_trivially_copy_assignable::value ? 0 : 1; + Error += std::is_trivially_copyable::value ? 0 : 1; + Error += std::is_trivially_copyable::value ? 0 : 1; + Error += std::is_trivially_copyable::value ? 0 : 1; + Error += std::is_trivially_copyable::value ? 0 : 1; + + Error += std::is_copy_constructible::value ? 0 : 1; +# endif + +#if GLM_HAS_INITIALIZER_LISTS + { + glm::vec4 a{ 0, 1, 2, 3 }; + std::vector v = { + {0, 1, 2, 3}, + {4, 5, 6, 7}, + {8, 9, 0, 1}}; + } + + { + glm::dvec4 a{ 0, 1, 2, 3 }; + std::vector v = { + {0, 1, 2, 3}, + {4, 5, 6, 7}, + {8, 9, 0, 1}}; + } +#endif + + { + glm::ivec4 const A(1); + glm::ivec4 const B(1, 1, 1, 1); + + Error += A == B ? 0 : 1; + } + + { + std::vector Tests; + Tests.push_back(glm::ivec4(glm::ivec2(1, 2), 3, 4)); + Tests.push_back(glm::ivec4(1, glm::ivec2(2, 3), 4)); + Tests.push_back(glm::ivec4(1, 2, glm::ivec2(3, 4))); + Tests.push_back(glm::ivec4(glm::ivec3(1, 2, 3), 4)); + Tests.push_back(glm::ivec4(1, glm::ivec3(2, 3, 4))); + Tests.push_back(glm::ivec4(glm::ivec2(1, 2), glm::ivec2(3, 4))); + Tests.push_back(glm::ivec4(1, 2, 3, 4)); + Tests.push_back(glm::ivec4(glm::ivec4(1, 2, 3, 4))); + + for(std::size_t i = 0; i < Tests.size(); ++i) + Error += Tests[i] == glm::ivec4(1, 2, 3, 4) ? 0 : 1; + } + + { + glm::vec1 const R(1.0f); + glm::vec1 const S(2.0f); + glm::vec1 const T(3.0f); + glm::vec1 const U(4.0f); + glm::vec4 const O(1.0f, 2.0f, 3.0f, 4.0f); + + glm::vec4 const A(R); + glm::vec4 const B(1.0f); + Error += glm::all(glm::equal(A, B, glm::epsilon())) ? 0 : 1; + + glm::vec4 const C(R, S, T, U); + Error += glm::all(glm::equal(C, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const D(R, 2.0f, 3.0f, 4.0f); + Error += glm::all(glm::equal(D, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const E(1.0f, S, 3.0f, 4.0f); + Error += glm::all(glm::equal(E, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const F(R, S, 3.0f, 4.0f); + Error += glm::all(glm::equal(F, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const G(1.0f, 2.0f, T, 4.0f); + Error += glm::all(glm::equal(G, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const H(R, 2.0f, T, 4.0f); + Error += glm::all(glm::equal(H, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const I(1.0f, S, T, 4.0f); + Error += glm::all(glm::equal(I, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const J(R, S, T, 4.0f); + Error += glm::all(glm::equal(J, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const K(R, 2.0f, 3.0f, U); + Error += glm::all(glm::equal(K, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const L(1.0f, S, 3.0f, U); + Error += glm::all(glm::equal(L, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const M(R, S, 3.0f, U); + Error += glm::all(glm::equal(M, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const N(1.0f, 2.0f, T, U); + Error += glm::all(glm::equal(N, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const P(R, 2.0f, T, U); + Error += glm::all(glm::equal(P, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const Q(1.0f, S, T, U); + Error += glm::all(glm::equal(Q, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const V(R, S, T, U); + Error += glm::all(glm::equal(V, O, glm::epsilon())) ? 0 : 1; + } + + { + glm::vec1 const R(1.0f); + glm::dvec1 const S(2.0); + glm::vec1 const T(3.0); + glm::dvec1 const U(4.0); + glm::vec4 const O(1.0f, 2.0, 3.0f, 4.0); + + glm::vec4 const A(R); + glm::vec4 const B(1.0); + Error += glm::all(glm::equal(A, B, glm::epsilon())) ? 0 : 1; + + glm::vec4 const C(R, S, T, U); + Error += glm::all(glm::equal(C, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const D(R, 2.0f, 3.0, 4.0f); + Error += glm::all(glm::equal(D, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const E(1.0, S, 3.0f, 4.0); + Error += glm::all(glm::equal(E, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const F(R, S, 3.0, 4.0f); + Error += glm::all(glm::equal(F, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const G(1.0f, 2.0, T, 4.0); + Error += glm::all(glm::equal(G, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const H(R, 2.0, T, 4.0); + Error += glm::all(glm::equal(H, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const I(1.0, S, T, 4.0f); + Error += glm::all(glm::equal(I, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const J(R, S, T, 4.0f); + Error += glm::all(glm::equal(J, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const K(R, 2.0f, 3.0, U); + Error += glm::all(glm::equal(K, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const L(1.0f, S, 3.0, U); + Error += glm::all(glm::equal(L, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const M(R, S, 3.0, U); + Error += glm::all(glm::equal(M, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const N(1.0f, 2.0, T, U); + Error += glm::all(glm::equal(N, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const P(R, 2.0, T, U); + Error += glm::all(glm::equal(P, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const Q(1.0f, S, T, U); + Error += glm::all(glm::equal(Q, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const V(R, S, T, U); + Error += glm::all(glm::equal(V, O, glm::epsilon())) ? 0 : 1; + } + + { + glm::vec1 const v1_0(1.0f); + glm::vec1 const v1_1(2.0f); + glm::vec1 const v1_2(3.0f); + glm::vec1 const v1_3(4.0f); + + glm::vec2 const v2_0(1.0f, 2.0f); + glm::vec2 const v2_1(2.0f, 3.0f); + glm::vec2 const v2_2(3.0f, 4.0f); + + glm::vec3 const v3_0(1.0f, 2.0f, 3.0f); + glm::vec3 const v3_1(2.0f, 3.0f, 4.0f); + + glm::vec4 const O(1.0f, 2.0, 3.0f, 4.0); + + glm::vec4 const A(v1_0, v1_1, v2_2); + Error += glm::all(glm::equal(A, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const B(1.0f, 2.0f, v2_2); + Error += glm::all(glm::equal(B, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const C(v1_0, 2.0f, v2_2); + Error += glm::all(glm::equal(C, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const D(1.0f, v1_1, v2_2); + Error += glm::all(glm::equal(D, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const E(v2_0, v1_2, v1_3); + Error += glm::all(glm::equal(E, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const F(v2_0, 3.0, v1_3); + Error += glm::all(glm::equal(F, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const G(v2_0, v1_2, 4.0); + Error += glm::all(glm::equal(G, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const H(v2_0, 3.0f, 4.0); + Error += glm::all(glm::equal(H, O, glm::epsilon())) ? 0 : 1; + } + + { + glm::vec1 const v1_0(1.0f); + glm::vec1 const v1_1(2.0f); + glm::vec1 const v1_2(3.0f); + glm::vec1 const v1_3(4.0f); + + glm::vec2 const v2(2.0f, 3.0f); + + glm::vec4 const O(1.0f, 2.0, 3.0f, 4.0); + + glm::vec4 const A(v1_0, v2, v1_3); + Error += glm::all(glm::equal(A, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const B(v1_0, v2, 4.0); + Error += glm::all(glm::equal(B, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const C(1.0, v2, v1_3); + Error += glm::all(glm::equal(C, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const D(1.0f, v2, 4.0); + Error += glm::all(glm::equal(D, O, glm::epsilon())) ? 0 : 1; + + glm::vec4 const E(1.0, v2, 4.0f); + Error += glm::all(glm::equal(E, O, glm::epsilon())) ? 0 : 1; + } + + return Error; +} + +static int test_bvec4_ctor() +{ + int Error = 0; + + glm::bvec4 const A(true); + glm::bvec4 const B(true); + glm::bvec4 const C(false); + glm::bvec4 const D = A && B; + glm::bvec4 const E = A && C; + glm::bvec4 const F = A || C; + + Error += D == glm::bvec4(true) ? 0 : 1; + Error += E == glm::bvec4(false) ? 0 : 1; + Error += F == glm::bvec4(true) ? 0 : 1; + + bool const G = A == C; + bool const H = A != C; + Error += !G ? 0 : 1; + Error += H ? 0 : 1; + + return Error; +} + +static int test_operators() +{ + int Error = 0; + + { + glm::ivec4 A(1); + glm::ivec4 B(1); + bool R = A != B; + bool S = A == B; + + Error += (S && !R) ? 0 : 1; + } + + { + glm::vec4 const A(1.0f, 2.0f, 3.0f, 4.0f); + glm::vec4 const B(4.0f, 5.0f, 6.0f, 7.0f); + + glm::vec4 const C = A + B; + Error += glm::all(glm::equal(C, glm::vec4(5, 7, 9, 11), glm::epsilon())) ? 0 : 1; + + glm::vec4 const D = B - A; + Error += glm::all(glm::equal(D, glm::vec4(3, 3, 3, 3), glm::epsilon())) ? 0 : 1; + + glm::vec4 const E = A * B; + Error += glm::all(glm::equal(E, glm::vec4(4, 10, 18, 28), glm::epsilon()) )? 0 : 1; + + glm::vec4 const F = B / A; + Error += glm::all(glm::equal(F, glm::vec4(4, 2.5, 2, 7.0f / 4.0f), glm::epsilon())) ? 0 : 1; + + glm::vec4 const G = A + 1.0f; + Error += glm::all(glm::equal(G, glm::vec4(2, 3, 4, 5), glm::epsilon())) ? 0 : 1; + + glm::vec4 const H = B - 1.0f; + Error += glm::all(glm::equal(H, glm::vec4(3, 4, 5, 6), glm::epsilon())) ? 0 : 1; + + glm::vec4 const I = A * 2.0f; + Error += glm::all(glm::equal(I, glm::vec4(2, 4, 6, 8), glm::epsilon())) ? 0 : 1; + + glm::vec4 const J = B / 2.0f; + Error += glm::all(glm::equal(J, glm::vec4(2, 2.5, 3, 3.5), glm::epsilon())) ? 0 : 1; + + glm::vec4 const K = 1.0f + A; + Error += glm::all(glm::equal(K, glm::vec4(2, 3, 4, 5), glm::epsilon())) ? 0 : 1; + + glm::vec4 const L = 1.0f - B; + Error += glm::all(glm::equal(L, glm::vec4(-3, -4, -5, -6), glm::epsilon())) ? 0 : 1; + + glm::vec4 const M = 2.0f * A; + Error += glm::all(glm::equal(M, glm::vec4(2, 4, 6, 8), glm::epsilon())) ? 0 : 1; + + glm::vec4 const N = 2.0f / B; + Error += glm::all(glm::equal(N, glm::vec4(0.5, 2.0 / 5.0, 2.0 / 6.0, 2.0 / 7.0), glm::epsilon())) ? 0 : 1; + } + + { + glm::ivec4 A(1.0f, 2.0f, 3.0f, 4.0f); + glm::ivec4 B(4.0f, 5.0f, 6.0f, 7.0f); + + A += B; + Error += A == glm::ivec4(5, 7, 9, 11) ? 0 : 1; + + A += 1; + Error += A == glm::ivec4(6, 8, 10, 12) ? 0 : 1; + } + { + glm::ivec4 A(1.0f, 2.0f, 3.0f, 4.0f); + glm::ivec4 B(4.0f, 5.0f, 6.0f, 7.0f); + + B -= A; + Error += B == glm::ivec4(3, 3, 3, 3) ? 0 : 1; + + B -= 1; + Error += B == glm::ivec4(2, 2, 2, 2) ? 0 : 1; + } + { + glm::ivec4 A(1.0f, 2.0f, 3.0f, 4.0f); + glm::ivec4 B(4.0f, 5.0f, 6.0f, 7.0f); + + A *= B; + Error += A == glm::ivec4(4, 10, 18, 28) ? 0 : 1; + + A *= 2; + Error += A == glm::ivec4(8, 20, 36, 56) ? 0 : 1; + } + { + glm::ivec4 A(1.0f, 2.0f, 2.0f, 4.0f); + glm::ivec4 B(4.0f, 4.0f, 8.0f, 8.0f); + + B /= A; + Error += B == glm::ivec4(4, 2, 4, 2) ? 0 : 1; + + B /= 2; + Error += B == glm::ivec4(2, 1, 2, 1) ? 0 : 1; + } + { + glm::ivec4 B(2); + + B /= B.y; + Error += B == glm::ivec4(1) ? 0 : 1; + } + + { + glm::ivec4 A(1.0f, 2.0f, 3.0f, 4.0f); + glm::ivec4 B = -A; + Error += B == glm::ivec4(-1.0f, -2.0f, -3.0f, -4.0f) ? 0 : 1; + } + + { + glm::ivec4 A(1.0f, 2.0f, 3.0f, 4.0f); + glm::ivec4 B = --A; + Error += B == glm::ivec4(0.0f, 1.0f, 2.0f, 3.0f) ? 0 : 1; + } + + { + glm::ivec4 A(1.0f, 2.0f, 3.0f, 4.0f); + glm::ivec4 B = A--; + Error += B == glm::ivec4(1.0f, 2.0f, 3.0f, 4.0f) ? 0 : 1; + Error += A == glm::ivec4(0.0f, 1.0f, 2.0f, 3.0f) ? 0 : 1; + } + + { + glm::ivec4 A(1.0f, 2.0f, 3.0f, 4.0f); + glm::ivec4 B = ++A; + Error += B == glm::ivec4(2.0f, 3.0f, 4.0f, 5.0f) ? 0 : 1; + } + + { + glm::ivec4 A(1.0f, 2.0f, 3.0f, 4.0f); + glm::ivec4 B = A++; + Error += B == glm::ivec4(1.0f, 2.0f, 3.0f, 4.0f) ? 0 : 1; + Error += A == glm::ivec4(2.0f, 3.0f, 4.0f, 5.0f) ? 0 : 1; + } + + return Error; +} + +static int test_equal() +{ + int Error = 0; + + { + glm::uvec4 const A(1, 2, 3, 4); + glm::uvec4 const B(1, 2, 3, 4); + Error += A == B ? 0 : 1; + Error += A != B ? 1 : 0; + } + + { + glm::ivec4 const A(1, 2, 3, 4); + glm::ivec4 const B(1, 2, 3, 4); + Error += A == B ? 0 : 1; + Error += A != B ? 1 : 0; + } + + return Error; +} + +static int test_size() +{ + int Error = 0; + + Error += sizeof(glm::vec4) == sizeof(glm::lowp_vec4) ? 0 : 1; + Error += sizeof(glm::vec4) == sizeof(glm::mediump_vec4) ? 0 : 1; + Error += sizeof(glm::vec4) == sizeof(glm::highp_vec4) ? 0 : 1; + Error += 16 == sizeof(glm::mediump_vec4) ? 0 : 1; + Error += sizeof(glm::dvec4) == sizeof(glm::lowp_dvec4) ? 0 : 1; + Error += sizeof(glm::dvec4) == sizeof(glm::mediump_dvec4) ? 0 : 1; + Error += sizeof(glm::dvec4) == sizeof(glm::highp_dvec4) ? 0 : 1; + Error += 32 == sizeof(glm::highp_dvec4) ? 0 : 1; + Error += glm::vec4().length() == 4 ? 0 : 1; + Error += glm::dvec4().length() == 4 ? 0 : 1; + Error += glm::vec4::length() == 4 ? 0 : 1; + Error += glm::dvec4::length() == 4 ? 0 : 1; + + return Error; +} + +static int test_swizzle_partial() +{ + int Error = 0; + + glm::vec4 const A(1, 2, 3, 4); + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + { + glm::vec4 B(A.xy, A.zw); + Error += glm::all(glm::equal(A, B, glm::epsilon())) ? 0 : 1; + } + { + glm::vec4 B(A.xy, 3.0f, 4.0f); + Error += glm::all(glm::equal(A, B, glm::epsilon())) ? 0 : 1; + } + { + glm::vec4 B(1.0f, A.yz, 4.0f); + Error += glm::all(glm::equal(A, B, glm::epsilon())) ? 0 : 1; + } + { + glm::vec4 B(1.0f, 2.0f, A.zw); + Error += glm::all(glm::equal(A, B, glm::epsilon())) ? 0 : 1; + } + + { + glm::vec4 B(A.xyz, 4.0f); + Error += glm::all(glm::equal(A, B, glm::epsilon())) ? 0 : 1; + } + { + glm::vec4 B(1.0f, A.yzw); + Error += glm::all(glm::equal(A, B, glm::epsilon())) ? 0 : 1; + } +# endif//GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR || GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION + + return Error; +} + +static int test_swizzle() +{ + int Error = 0; + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + { + glm::ivec4 A = glm::ivec4(1.0f, 2.0f, 3.0f, 4.0f); + glm::ivec4 B = A.xyzw; + glm::ivec4 C(A.xyzw); + glm::ivec4 D(A.xyzw()); + glm::ivec4 E(A.x, A.yzw); + glm::ivec4 F(A.x, A.yzw()); + glm::ivec4 G(A.xyz, A.w); + glm::ivec4 H(A.xyz(), A.w); + glm::ivec4 I(A.xy, A.zw); + glm::ivec4 J(A.xy(), A.zw()); + glm::ivec4 K(A.x, A.y, A.zw); + glm::ivec4 L(A.x, A.yz, A.w); + glm::ivec4 M(A.xy, A.z, A.w); + + Error += glm::all(glm::equal(A, B)) ? 0 : 1; + Error += glm::all(glm::equal(A, C)) ? 0 : 1; + Error += glm::all(glm::equal(A, D)) ? 0 : 1; + Error += glm::all(glm::equal(A, E)) ? 0 : 1; + Error += glm::all(glm::equal(A, F)) ? 0 : 1; + Error += glm::all(glm::equal(A, G)) ? 0 : 1; + Error += glm::all(glm::equal(A, H)) ? 0 : 1; + Error += glm::all(glm::equal(A, I)) ? 0 : 1; + Error += glm::all(glm::equal(A, J)) ? 0 : 1; + Error += glm::all(glm::equal(A, K)) ? 0 : 1; + Error += glm::all(glm::equal(A, L)) ? 0 : 1; + Error += glm::all(glm::equal(A, M)) ? 0 : 1; + } +# endif//GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR || GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION + { + glm::vec4 A = glm::vec4(1.0f, 2.0f, 3.0f, 4.0f); + glm::vec4 B = A.xyzw(); + glm::vec4 C(A.xyzw()); + glm::vec4 D(A.xyzw()); + glm::vec4 E(A.x, A.yzw()); + glm::vec4 F(A.x, A.yzw()); + glm::vec4 G(A.xyz(), A.w); + glm::vec4 H(A.xyz(), A.w); + glm::vec4 I(A.xy(), A.zw()); + glm::vec4 J(A.xy(), A.zw()); + glm::vec4 K(A.x, A.y, A.zw()); + glm::vec4 L(A.x, A.yz(), A.w); + glm::vec4 M(A.xy(), A.z, A.w); + + Error += glm::all(glm::equal(A, B, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(A, C, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(A, D, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(A, E, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(A, F, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(A, G, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(A, H, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(A, I, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(A, J, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(A, K, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(A, L, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(A, M, glm::epsilon())) ? 0 : 1; + } +# endif//GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR || GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION + + return Error; +} + +static int test_operator_increment() +{ + int Error = 0; + + glm::ivec4 v0(1); + glm::ivec4 v1(v0); + glm::ivec4 v2(v0); + glm::ivec4 v3 = ++v1; + glm::ivec4 v4 = v2++; + + Error += glm::all(glm::equal(v0, v4)) ? 0 : 1; + Error += glm::all(glm::equal(v1, v2)) ? 0 : 1; + Error += glm::all(glm::equal(v1, v3)) ? 0 : 1; + + int i0(1); + int i1(i0); + int i2(i0); + int i3 = ++i1; + int i4 = i2++; + + Error += i0 == i4 ? 0 : 1; + Error += i1 == i2 ? 0 : 1; + Error += i1 == i3 ? 0 : 1; + + return Error; +} + +struct AoS +{ + glm::vec4 A; + glm::vec3 B; + glm::vec3 C; + glm::vec2 D; +}; + +static int test_perf_AoS(std::size_t Size) +{ + int Error = 0; + + std::vector In; + std::vector Out; + In.resize(Size); + Out.resize(Size); + + std::clock_t StartTime = std::clock(); + + for(std::size_t i = 0; i < In.size(); ++i) + Out[i] = In[i]; + + std::clock_t EndTime = std::clock(); + + std::printf("AoS: %d\n", static_cast(EndTime - StartTime)); + + return Error; +} + +static int test_perf_SoA(std::size_t Size) +{ + int Error = 0; + + std::vector InA; + std::vector InB; + std::vector InC; + std::vector InD; + std::vector OutA; + std::vector OutB; + std::vector OutC; + std::vector OutD; + + InA.resize(Size); + InB.resize(Size); + InC.resize(Size); + InD.resize(Size); + OutA.resize(Size); + OutB.resize(Size); + OutC.resize(Size); + OutD.resize(Size); + + std::clock_t StartTime = std::clock(); + + for(std::size_t i = 0; i < InA.size(); ++i) + { + OutA[i] = InA[i]; + OutB[i] = InB[i]; + OutC[i] = InC[i]; + OutD[i] = InD[i]; + } + + std::clock_t EndTime = std::clock(); + + std::printf("SoA: %d\n", static_cast(EndTime - StartTime)); + + return Error; +} + +namespace heap +{ + struct A + { + float f; + }; + + struct B : public A + { + float g; + glm::vec4 v; + }; + + static int test() + { + int Error = 0; + + A* p = new B; + p->f = 0.0f; + delete p; + + Error += sizeof(B) == sizeof(glm::vec4) + sizeof(float) * 2 ? 0 : 1; + + return Error; + } +}//namespace heap + +static int test_simd() +{ + int Error = 0; + + glm::vec4 const a(std::clock(), std::clock(), std::clock(), std::clock()); + glm::vec4 const b(std::clock(), std::clock(), std::clock(), std::clock()); + + glm::vec4 const c(b * a); + glm::vec4 const d(a + c); + + Error += glm::all(glm::greaterThanEqual(d, glm::vec4(0))) ? 0 : 1; + + return Error; +} + +static int test_inheritance() +{ + struct my_vec4 : public glm::vec4 + { + my_vec4() + : glm::vec4(76.f, 75.f, 74.f, 73.f) + , member(82) + {} + + int member; + }; + + int Error = 0; + + my_vec4 v; + + Error += v.member == 82 ? 0 : 1; + Error += glm::equal(v.x, 76.f, glm::epsilon()) ? 0 : 1; + Error += glm::equal(v.y, 75.f, glm::epsilon()) ? 0 : 1; + Error += glm::equal(v.z, 74.f, glm::epsilon()) ? 0 : 1; + Error += glm::equal(v.w, 73.f, glm::epsilon()) ? 0 : 1; + + return Error; +} + +static int test_constexpr() +{ +#if GLM_HAS_CONSTEXPR + static_assert(glm::vec4::length() == 4, "GLM: Failed constexpr"); + static_assert(glm::vec4(1.0f).x > 0.0f, "GLM: Failed constexpr"); + static_assert(glm::vec4(1.0f, -1.0f, -1.0f, -1.0f).x > 0.0f, "GLM: Failed constexpr"); + static_assert(glm::vec4(1.0f, -1.0f, -1.0f, -1.0f).y < 0.0f, "GLM: Failed constexpr"); +#endif + + return 0; +} +/* +static int test_simd_gen() +{ + int Error = 0; + + int const C = static_cast(std::clock()); + int const D = static_cast(std::clock()); + + glm::ivec4 const A(C); + glm::ivec4 const B(D); + + Error += A != B ? 0 : 1; + + return Error; +} +*/ +int main() +{ + int Error = 0; + + //Error += test_simd_gen(); + +/* + { + glm::ivec4 const a1(2); + glm::ivec4 const b1 = a1 >> 1; + + __m128i const e1 = _mm_set1_epi32(2); + __m128i const f1 = _mm_srli_epi32(e1, 1); + + glm::ivec4 const g1 = *reinterpret_cast(&f1); + + glm::ivec4 const a2(-2); + glm::ivec4 const b2 = a2 >> 1; + + __m128i const e2 = _mm_set1_epi32(-1); + __m128i const f2 = _mm_srli_epi32(e2, 1); + + glm::ivec4 const g2 = *reinterpret_cast(&f2); + + std::printf("GNI\n"); + } + + { + glm::uvec4 const a1(2); + glm::uvec4 const b1 = a1 >> 1u; + + __m128i const e1 = _mm_set1_epi32(2); + __m128i const f1 = _mm_srli_epi32(e1, 1); + + glm::uvec4 const g1 = *reinterpret_cast(&f1); + + glm::uvec4 const a2(-1); + glm::uvec4 const b2 = a2 >> 1u; + + __m128i const e2 = _mm_set1_epi32(-1); + __m128i const f2 = _mm_srli_epi32(e2, 1); + + glm::uvec4 const g2 = *reinterpret_cast(&f2); + + std::printf("GNI\n"); + } +*/ + +# ifdef NDEBUG + std::size_t const Size(1000000); +# else + std::size_t const Size(1); +# endif//NDEBUG + + Error += test_perf_AoS(Size); + Error += test_perf_SoA(Size); + + Error += test_vec4_ctor(); + Error += test_bvec4_ctor(); + Error += test_size(); + Error += test_operators(); + Error += test_equal(); + Error += test_swizzle(); + Error += test_swizzle_partial(); + Error += test_simd(); + Error += test_operator_increment(); + Error += heap::test(); + Error += test_inheritance(); + Error += test_constexpr(); + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/CMakeLists.txt b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..40c91bac7b2997606d1f48d20e3a15f4fbcf7f8e --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/CMakeLists.txt @@ -0,0 +1,55 @@ +glmCreateTestGTC(ext_matrix_relational) +glmCreateTestGTC(ext_matrix_transform) +glmCreateTestGTC(ext_matrix_common) +glmCreateTestGTC(ext_matrix_integer) +glmCreateTestGTC(ext_matrix_int2x2_sized) +glmCreateTestGTC(ext_matrix_int2x3_sized) +glmCreateTestGTC(ext_matrix_int2x4_sized) +glmCreateTestGTC(ext_matrix_int3x2_sized) +glmCreateTestGTC(ext_matrix_int3x3_sized) +glmCreateTestGTC(ext_matrix_int3x4_sized) +glmCreateTestGTC(ext_matrix_int4x2_sized) +glmCreateTestGTC(ext_matrix_int4x3_sized) +glmCreateTestGTC(ext_matrix_int4x4_sized) +glmCreateTestGTC(ext_matrix_uint2x2_sized) +glmCreateTestGTC(ext_matrix_uint2x3_sized) +glmCreateTestGTC(ext_matrix_uint2x4_sized) +glmCreateTestGTC(ext_matrix_uint3x2_sized) +glmCreateTestGTC(ext_matrix_uint3x3_sized) +glmCreateTestGTC(ext_matrix_uint3x4_sized) +glmCreateTestGTC(ext_matrix_uint4x2_sized) +glmCreateTestGTC(ext_matrix_uint4x3_sized) +glmCreateTestGTC(ext_matrix_uint4x4_sized) +glmCreateTestGTC(ext_quaternion_common) +glmCreateTestGTC(ext_quaternion_exponential) +glmCreateTestGTC(ext_quaternion_geometric) +glmCreateTestGTC(ext_quaternion_relational) +glmCreateTestGTC(ext_quaternion_transform) +glmCreateTestGTC(ext_quaternion_trigonometric) +glmCreateTestGTC(ext_quaternion_type) +glmCreateTestGTC(ext_scalar_common) +glmCreateTestGTC(ext_scalar_constants) +glmCreateTestGTC(ext_scalar_int_sized) +glmCreateTestGTC(ext_scalar_uint_sized) +glmCreateTestGTC(ext_scalar_integer) +glmCreateTestGTC(ext_scalar_ulp) +glmCreateTestGTC(ext_scalar_reciprocal) +glmCreateTestGTC(ext_scalar_relational) +glmCreateTestGTC(ext_vec1) +glmCreateTestGTC(ext_vector_bool1) +glmCreateTestGTC(ext_vector_common) +glmCreateTestGTC(ext_vector_iec559) +glmCreateTestGTC(ext_vector_int1_sized) +glmCreateTestGTC(ext_vector_int2_sized) +glmCreateTestGTC(ext_vector_int3_sized) +glmCreateTestGTC(ext_vector_int4_sized) +glmCreateTestGTC(ext_vector_integer) +glmCreateTestGTC(ext_vector_integer_sized) +glmCreateTestGTC(ext_vector_uint1_sized) +glmCreateTestGTC(ext_vector_uint2_sized) +glmCreateTestGTC(ext_vector_uint3_sized) +glmCreateTestGTC(ext_vector_uint4_sized) +glmCreateTestGTC(ext_vector_reciprocal) +glmCreateTestGTC(ext_vector_relational) +glmCreateTestGTC(ext_vector_ulp) + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_clip_space.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_clip_space.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ca84c19b92dba4c6c3290b0d9ceafb7225e434a1 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_clip_space.cpp @@ -0,0 +1,13 @@ +#include +#include +#include +#include +#include +#include + +int main() +{ + int Error = 0; + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_common.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_common.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8895892a2e9a2fcc898157013a65b5e9e672a474 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_common.cpp @@ -0,0 +1,236 @@ +#include +#include +#include +#include +#include +#include + +static int test_mix() +{ + int Error = 0; + + { + glm::mat4 A(2); + glm::mat4 B(4); + glm::mat4 C = glm::mix(A, B, 0.5f); + glm::bvec4 const D = glm::equal(C, glm::mat4(3), 1); + Error += glm::all(D) ? 0 : 1; + } + + { + glm::mat4 A(2); + glm::mat4 B(4); + glm::mat4 C = glm::mix(A, B, 0.5); + glm::bvec4 const D = glm::equal(C, glm::mat4(3), 1); + Error += glm::all(D) ? 0 : 1; + } + + { + glm::dmat4 A(2); + glm::dmat4 B(4); + glm::dmat4 C = glm::mix(A, B, 0.5); + glm::bvec4 const D = glm::equal(C, glm::dmat4(3), 1); + Error += glm::all(D) ? 0 : 1; + } + + { + glm::dmat4 A(2); + glm::dmat4 B(4); + glm::dmat4 C = glm::mix(A, B, 0.5f); + glm::bvec4 const D = glm::equal(C, glm::dmat4(3), 1); + Error += glm::all(D) ? 0 : 1; + } + + return Error; +} + +static int test_abs() +{ + int Error = 0; + + // -------------------- // + // glm::mat4 variants : // + // -------------------- // + { + glm::mat4 A( + 3.0f, 1.0f, 5.2f, 4.9f, + 1.4f, 0.5f, 9.3f, 3.7f, + 6.8f, 8.4f, 4.3f, 3.9f, + 5.6f, 7.2f, 1.1f, 4.4f + ); + glm::mat4 B( + 1.0,-1.0, 1.0, 1.0, + -1.0, 1.0, 1.0,-1.0, + 1.0,-1.0,-1.0,-1.0, + -1.0,-1.0, 1.0, 1.0 + ); + glm::mat4 C = glm::matrixCompMult(A, B); // Not * to avoid matrix product. + glm::mat4 D = glm::abs(C); + glm::bvec4 const col1 = glm::equal(D[0], A[0]); + glm::bvec4 const col2 = glm::equal(D[1], A[1]); + glm::bvec4 const col3 = glm::equal(D[2], A[2]); + glm::bvec4 const col4 = glm::equal(D[3], A[3]); + Error += glm::all(glm::bvec4{glm::all(col1), glm::all(col2), glm::all(col3), glm::all(col4)}) ? 0 : 1; + } + { + glm::mat4x3 A( + 3.0f, 1.0f, 5.2f, + 4.9f, 1.4f, 0.5f, + 9.3f, 3.7f, 6.8f, + 8.4f, 4.3f, 3.9f + ); + glm::mat4x3 B( + 1.0,-1.0, 1.0, + 1.0,-1.0, 1.0, + 1.0,-1.0, 1.0, + -1.0,-1.0,-1.0 + ); + glm::mat4x3 C = glm::matrixCompMult(A, B); // Not * to avoid matrix product. + glm::mat4x3 D = glm::abs(C); + glm::bvec3 const col1 = glm::equal(D[0], A[0]); + glm::bvec3 const col2 = glm::equal(D[1], A[1]); + glm::bvec3 const col3 = glm::equal(D[2], A[2]); + glm::bvec3 const col4 = glm::equal(D[3], A[3]); + Error += glm::all(glm::bvec4{glm::all(col1), glm::all(col2), glm::all(col3), glm::all(col4)}) ? 0 : 1; + } + { + glm::mat4x2 A( + 3.0f, 1.0f, + 1.4f, 0.5f, + 6.8f, 8.4f, + 5.6f, 7.2f + ); + glm::mat4x2 B( + 1.0,-1.0, + -1.0, 1.0, + 1.0,-1.0, + -1.0,-1.0 + ); + glm::mat4x2 C = glm::matrixCompMult(A, B); // Not * to avoid matrix product. + glm::mat4x2 D = glm::abs(C); + glm::bvec2 const col1 = glm::equal(D[0], A[0]); + glm::bvec2 const col2 = glm::equal(D[1], A[1]); + glm::bvec2 const col3 = glm::equal(D[2], A[2]); + glm::bvec2 const col4 = glm::equal(D[3], A[3]); + Error += glm::all(glm::bvec4{glm::all(col1), glm::all(col2), glm::all(col3), glm::all(col4)}) ? 0 : 1; + } + + // -------------------- // + // glm::mat3 variants : // + // -------------------- // + { + glm::mat3x4 A( + 3.0f, 1.0f, 5.2f, 4.9f, + 1.4f, 0.5f, 9.3f, 3.7f, + 6.8f, 8.4f, 4.3f, 3.9f + ); + glm::mat3x4 B( + 1.0,-1.0, 1.0, 1.0, + -1.0, 1.0, 1.0,-1.0, + 1.0,-1.0,-1.0,-1.0 + ); + glm::mat3x4 C = glm::matrixCompMult(A, B); // Not * to avoid matrix product. + glm::mat3x4 D = glm::abs(C); + glm::bvec4 const col1 = glm::equal(D[0], A[0]); + glm::bvec4 const col2 = glm::equal(D[1], A[1]); + glm::bvec4 const col3 = glm::equal(D[2], A[2]); + Error += glm::all(glm::bvec3{glm::all(col1), glm::all(col2), glm::all(col3)}) ? 0 : 1; + } + { + glm::mat3 A( + 3.0f, 1.0f, 5.2f, + 1.4f, 0.5f, 9.3f, + 6.8f, 8.4f, 4.3f + ); + glm::mat3 B( + 1.0,-1.0, 1.0, + -1.0, 1.0, 1.0, + 1.0,-1.0,-1.0 + ); + glm::mat3 C = glm::matrixCompMult(A, B); // Not * to avoid matrix product. + glm::mat3 D = glm::abs(C); + glm::bvec3 const col1 = glm::equal(D[0], A[0]); + glm::bvec3 const col2 = glm::equal(D[1], A[1]); + glm::bvec3 const col3 = glm::equal(D[2], A[2]); + Error += glm::all(glm::bvec3{glm::all(col1), glm::all(col2), glm::all(col3)}) ? 0 : 1; + } + { + glm::mat3x2 A( + 5.2f, 4.9f, + 9.3f, 3.7f, + 4.3f, 3.9f + ); + glm::mat3x2 B( + 1.0, 1.0, + 1.0,-1.0, + -1.0,-1.0 + ); + glm::mat3x2 C = glm::matrixCompMult(A, B); // Not * to avoid matrix product. + glm::mat3x2 D = glm::abs(C); + glm::bvec2 const col1 = glm::equal(D[0], A[0]); + glm::bvec2 const col2 = glm::equal(D[1], A[1]); + glm::bvec2 const col3 = glm::equal(D[2], A[2]); + Error += glm::all(glm::bvec3{glm::all(col1), glm::all(col2), glm::all(col3)}) ? 0 : 1; + } + + // -------------------- // + // glm::mat2 variants : // + // -------------------- // + { + glm::mat2x4 A( + 3.0f, 1.0f, 5.2f, 4.9f, + 5.6f, 7.2f, 1.1f, 4.4f + ); + glm::mat2x4 B( + 1.0,-1.0, 1.0, 1.0, + -1.0,-1.0, 1.0, 1.0 + ); + glm::mat2x4 C = glm::matrixCompMult(A, B); // Not * to avoid matrix product. + glm::mat2x4 D = glm::abs(C); + glm::bvec4 const col1 = glm::equal(D[0], A[0]); + glm::bvec4 const col2 = glm::equal(D[1], A[1]); + Error += glm::all(glm::bvec2{glm::all(col1), glm::all(col2)}) ? 0 : 1; + } + { + glm::mat2x3 A( + 3.0f, 1.0f, 5.2f, + 8.4f, 4.3f, 3.9f + ); + glm::mat2x3 B( + 1.0,-1.0, 1.0, + -1.0,-1.0,-1.0 + ); + glm::mat2x3 C = glm::matrixCompMult(A, B); // Not * to avoid matrix product. + glm::mat2x3 D = glm::abs(C); + glm::bvec3 const col1 = glm::equal(D[0], A[0]); + glm::bvec3 const col2 = glm::equal(D[1], A[1]); + Error += glm::all(glm::bvec2{glm::all(col1), glm::all(col2)}) ? 0 : 1; + } + { + glm::mat2 A( + 3.0f, 1.0f, + 5.6f, 7.2f + ); + glm::mat2 B( + 1.0,-1.0, + -1.0,-1.0 + ); + glm::mat2 C = glm::matrixCompMult(A, B); // Not * to avoid matrix product. + glm::mat2 D = glm::abs(C); + glm::bvec2 const col1 = glm::equal(D[0], A[0]); + glm::bvec2 const col2 = glm::equal(D[1], A[1]); + Error += glm::all(glm::bvec2{glm::all(col1), glm::all(col2)}) ? 0 : 1; + } + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_mix(); + Error += test_abs(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_int2x2_sized.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_int2x2_sized.cpp new file mode 100644 index 0000000000000000000000000000000000000000..93b6e8662c46d65991b435033157ebfaff742dab --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_int2x2_sized.cpp @@ -0,0 +1,28 @@ +#include + +#if GLM_HAS_STATIC_ASSERT + static_assert(sizeof(glm::i8mat2x2) == 4, "int8 size isn't 1 byte on this platform"); + static_assert(sizeof(glm::i16mat2x2) == 8, "int16 size isn't 2 bytes on this platform"); + static_assert(sizeof(glm::i32mat2x2) == 16, "int32 size isn't 4 bytes on this platform"); + static_assert(sizeof(glm::i64mat2x2) == 32, "int64 size isn't 8 bytes on this platform"); +#endif + +static int test_comp() +{ + int Error = 0; + + Error += sizeof(glm::i8mat2x2) < sizeof(glm::i16mat2x2) ? 0 : 1; + Error += sizeof(glm::i16mat2x2) < sizeof(glm::i32mat2x2) ? 0 : 1; + Error += sizeof(glm::i32mat2x2) < sizeof(glm::i64mat2x2) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_comp(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_int2x3_sized.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_int2x3_sized.cpp new file mode 100644 index 0000000000000000000000000000000000000000..058f57be491554a752ec095e62f8fc8d4c6a7625 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_int2x3_sized.cpp @@ -0,0 +1,28 @@ +#include + +#if GLM_HAS_STATIC_ASSERT +static_assert(sizeof(glm::i8mat2x3) == 6, "int8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::i16mat2x3) == 12, "int16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::i32mat2x3) == 24, "int32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::i64mat2x3) == 48, "int64 size isn't 8 bytes on this platform"); +#endif + +static int test_comp() +{ + int Error = 0; + + Error += sizeof(glm::i8mat2x3) < sizeof(glm::i16mat2x3) ? 0 : 1; + Error += sizeof(glm::i16mat2x3) < sizeof(glm::i32mat2x3) ? 0 : 1; + Error += sizeof(glm::i32mat2x3) < sizeof(glm::i64mat2x3) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_comp(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_int2x4_sized.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_int2x4_sized.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c20198daee5cdb926ef301c0dca2cb811f8cb8ae --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_int2x4_sized.cpp @@ -0,0 +1,28 @@ +#include + +#if GLM_HAS_STATIC_ASSERT +static_assert(sizeof(glm::i8mat2x4) == 8, "int8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::i16mat2x4) == 16, "int16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::i32mat2x4) == 32, "int32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::i64mat2x4) == 64, "int64 size isn't 8 bytes on this platform"); +#endif + +static int test_comp() +{ + int Error = 0; + + Error += sizeof(glm::i8mat2x4) < sizeof(glm::i16mat2x4) ? 0 : 1; + Error += sizeof(glm::i16mat2x4) < sizeof(glm::i32mat2x4) ? 0 : 1; + Error += sizeof(glm::i32mat2x4) < sizeof(glm::i64mat2x4) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_comp(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_int3x2_sized.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_int3x2_sized.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1d14029eef282513f96875afe25e44769258071c --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_int3x2_sized.cpp @@ -0,0 +1,28 @@ +#include + +#if GLM_HAS_STATIC_ASSERT +static_assert(sizeof(glm::i8mat3x2) == 6, "int8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::i16mat3x2) == 12, "int16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::i32mat3x2) == 24, "int32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::i64mat3x2) == 48, "int64 size isn't 8 bytes on this platform"); +#endif + +static int test_comp() +{ + int Error = 0; + + Error += sizeof(glm::i8mat3x2) < sizeof(glm::i16mat3x2) ? 0 : 1; + Error += sizeof(glm::i16mat3x2) < sizeof(glm::i32mat3x2) ? 0 : 1; + Error += sizeof(glm::i32mat3x2) < sizeof(glm::i64mat3x2) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_comp(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_int3x3_sized.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_int3x3_sized.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d82836c49c5f7729d28d4e498d4b33b15435b0df --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_int3x3_sized.cpp @@ -0,0 +1,28 @@ +#include + +#if GLM_HAS_STATIC_ASSERT +static_assert(sizeof(glm::i8mat3x3) == 9, "int8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::i16mat3x3) == 18, "int16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::i32mat3x3) == 36, "int32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::i64mat3x3) == 72, "int64 size isn't 8 bytes on this platform"); +#endif + +static int test_comp() +{ + int Error = 0; + + Error += sizeof(glm::i8mat3x3) < sizeof(glm::i16mat3x3) ? 0 : 1; + Error += sizeof(glm::i16mat3x3) < sizeof(glm::i32mat3x3) ? 0 : 1; + Error += sizeof(glm::i32mat3x3) < sizeof(glm::i64mat3x3) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_comp(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_int3x4_sized.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_int3x4_sized.cpp new file mode 100644 index 0000000000000000000000000000000000000000..52b7d52b86c1fe3240afcb0fdacfe938b279d661 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_int3x4_sized.cpp @@ -0,0 +1,28 @@ +#include + +#if GLM_HAS_STATIC_ASSERT +static_assert(sizeof(glm::i8mat3x4) == 12, "int8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::i16mat3x4) == 24, "int16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::i32mat3x4) == 48, "int32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::i64mat3x4) == 96, "int64 size isn't 8 bytes on this platform"); +#endif + +static int test_comp() +{ + int Error = 0; + + Error += sizeof(glm::i8mat3x4) < sizeof(glm::i16mat3x4) ? 0 : 1; + Error += sizeof(glm::i16mat3x4) < sizeof(glm::i32mat3x4) ? 0 : 1; + Error += sizeof(glm::i32mat3x4) < sizeof(glm::i64mat3x4) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_comp(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_int4x2_sized.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_int4x2_sized.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3c4566f9ff656b23c463a2b80432fbf68e7979e9 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_int4x2_sized.cpp @@ -0,0 +1,28 @@ +#include + +#if GLM_HAS_STATIC_ASSERT +static_assert(sizeof(glm::i8mat4x2) == 8, "int8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::i16mat4x2) == 16, "int16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::i32mat4x2) == 32, "int32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::i64mat4x2) == 64, "int64 size isn't 8 bytes on this platform"); +#endif + +static int test_comp() +{ + int Error = 0; + + Error += sizeof(glm::i8mat4x2) < sizeof(glm::i16mat4x2) ? 0 : 1; + Error += sizeof(glm::i16mat4x2) < sizeof(glm::i32mat4x2) ? 0 : 1; + Error += sizeof(glm::i32mat4x2) < sizeof(glm::i64mat4x2) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_comp(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_int4x3_sized.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_int4x3_sized.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fb882af7e832917ee2c15264f8bfff0f2b844964 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_int4x3_sized.cpp @@ -0,0 +1,28 @@ +#include + +#if GLM_HAS_STATIC_ASSERT +static_assert(sizeof(glm::i8mat4x3) == 12, "int8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::i16mat4x3) == 24, "int16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::i32mat4x3) == 48, "int32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::i64mat4x3) == 96, "int64 size isn't 8 bytes on this platform"); +#endif + +static int test_comp() +{ + int Error = 0; + + Error += sizeof(glm::i8mat4x3) < sizeof(glm::i16mat4x3) ? 0 : 1; + Error += sizeof(glm::i16mat4x3) < sizeof(glm::i32mat4x3) ? 0 : 1; + Error += sizeof(glm::i32mat4x3) < sizeof(glm::i64mat4x3) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_comp(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_int4x4_sized.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_int4x4_sized.cpp new file mode 100644 index 0000000000000000000000000000000000000000..02769ea986d1d3832ffd7829aa8006f4fd01b924 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_int4x4_sized.cpp @@ -0,0 +1,28 @@ +#include + +#if GLM_HAS_STATIC_ASSERT +static_assert(sizeof(glm::i8mat4x4) == 16, "int8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::i16mat4x4) == 32, "int16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::i32mat4x4) == 64, "int32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::i64mat4x4) == 128, "int64 size isn't 8 bytes on this platform"); +#endif + +static int test_comp() +{ + int Error = 0; + + Error += sizeof(glm::i8mat4x4) < sizeof(glm::i16mat4x4) ? 0 : 1; + Error += sizeof(glm::i16mat4x4) < sizeof(glm::i32mat4x4) ? 0 : 1; + Error += sizeof(glm::i32mat4x4) < sizeof(glm::i64mat4x4) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_comp(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_integer.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_integer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c26d557f5fc6a8720d4918b50b0b0ae9e93aa7a2 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_integer.cpp @@ -0,0 +1,237 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace glm; + +int test_matrixCompMult() +{ + int Error = 0; + + { + imat2 m(0, 1, 2, 3); + imat2 n = matrixCompMult(m, m); + imat2 expected = imat2(0, 1, 4, 9); + Error += all(equal(n, expected)) ? 0 : 1; + } + + { + imat2x3 m(0, 1, 2, 3, 4, 5); + imat2x3 n = matrixCompMult(m, m); + imat2x3 expected = imat2x3(0, 1, 4, 9, 16, 25); + Error += all(equal(n, expected)) ? 0 : 1; + } + + { + imat2x4 m(0, 1, 2, 3, 4, 5, 6, 7); + imat2x4 n = matrixCompMult(m, m); + imat2x4 expected = imat2x4(0, 1, 4, 9, 16, 25, 36, 49); + Error += all(equal(n, expected)) ? 0 : 1; + } + + { + imat3 m(0, 1, 2, 3, 4, 5, 6, 7, 8); + imat3 n = matrixCompMult(m, m); + imat3 expected = imat3(0, 1, 4, 9, 16, 25, 36, 49, 64); + Error += all(equal(n, expected)) ? 0 : 1; + } + + { + imat3x2 m(0, 1, 2, 3, 4, 5); + imat3x2 n = matrixCompMult(m, m); + imat3x2 expected = imat3x2(0, 1, 4, 9, 16, 25); + Error += all(equal(n, expected)) ? 0 : 1; + } + + { + imat3x4 m(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11); + imat3x4 n = matrixCompMult(m, m); + imat3x4 expected = imat3x4(0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121); + Error += all(equal(n, expected)) ? 0 : 1; + } + + { + imat4 m(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + imat4 n = matrixCompMult(m, m); + imat4 expected = imat4(0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225); + Error += all(equal(n, expected)) ? 0 : 1; + } + + { + imat4x2 m(0, 1, 2, 3, 4, 5, 6, 7); + imat4x2 n = matrixCompMult(m, m); + imat4x2 expected = imat4x2(0, 1, 4, 9, 16, 25, 36, 49); + Error += all(equal(n, expected)) ? 0 : 1; + } + + { + imat4x3 m(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11); + imat4x3 n = matrixCompMult(m, m); + imat4x3 expected = imat4x3(0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121); + Error += all(equal(n, expected)) ? 0 : 1; + } + + return Error; +} + +int test_outerProduct() +{ + int Error = 0; + + { + glm::imat2x2 const m = glm::outerProduct(glm::ivec2(1), glm::ivec2(1)); + Error += all(equal(m, glm::imat2x2(1, 1, 1, 1))) ? 0 : 1; + } + { + glm::imat2x3 const m = glm::outerProduct(glm::ivec3(1), glm::ivec2(1)); + Error += all(equal(m, glm::imat2x3(1, 1, 1, 1, 1, 1))) ? 0 : 1; + } + { + glm::imat2x4 const m = glm::outerProduct(glm::ivec4(1), glm::ivec2(1)); + Error += all(equal(m, glm::imat2x4(1, 1, 1, 1, 1, 1, 1, 1))) ? 0 : 1; + } + + { + glm::imat3x2 const m = glm::outerProduct(glm::ivec2(1), glm::ivec3(1)); + Error += all(equal(m, glm::imat3x2(1, 1, 1, 1, 1, 1))) ? 0 : 1; + } + { + glm::imat3x3 const m = glm::outerProduct(glm::ivec3(1), glm::ivec3(1)); + Error += all(equal(m, glm::imat3x3(1, 1, 1, 1, 1, 1, 1, 1, 1))) ? 0 : 1; + } + { + glm::imat3x4 const m = glm::outerProduct(glm::ivec4(1), glm::ivec3(1)); + Error += all(equal(m, glm::imat3x4(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1))) ? 0 : 1; + } + + + { + glm::imat4x2 const m = glm::outerProduct(glm::ivec2(1), glm::ivec4(1)); + Error += all(equal(m, glm::imat4x2(1, 1, 1, 1, 1, 1, 1, 1))) ? 0 : 1; + } + { + glm::imat4x3 const m = glm::outerProduct(glm::ivec3(1), glm::ivec4(1)); + Error += all(equal(m, glm::imat4x3(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1))) ? 0 : 1; + } + { + glm::imat4x4 const m = glm::outerProduct(glm::ivec4(1), glm::ivec4(1)); + Error += all(equal(m, glm::imat4x4(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1))) ? 0 : 1; + } + + return Error; +} + +int test_transpose() +{ + int Error = 0; + + { + imat2 const m(0, 1, 2, 3); + imat2 const t = transpose(m); + imat2 const expected = imat2(0, 2, 1, 3); + Error += all(equal(t, expected)) ? 0 : 1; + } + + { + imat2x3 m(0, 1, 2, 3, 4, 5); + imat3x2 t = transpose(m); + imat3x2 const expected = imat3x2(0, 3, 1, 4, 2, 5); + Error += all(equal(t, expected)) ? 0 : 1; + } + + { + imat2x4 m(0, 1, 2, 3, 4, 5, 6, 7); + imat4x2 t = transpose(m); + imat4x2 const expected = imat4x2(0, 4, 1, 5, 2, 6, 3, 7); + Error += all(equal(t, expected)) ? 0 : 1; + } + + { + imat3 m(0, 1, 2, 3, 4, 5, 6, 7, 8); + imat3 t = transpose(m); + imat3 const expected = imat3(0, 3, 6, 1, 4, 7, 2, 5, 8); + Error += all(equal(t, expected)) ? 0 : 1; + } + + { + imat3x2 m(0, 1, 2, 3, 4, 5); + imat2x3 t = transpose(m); + imat2x3 const expected = imat2x3(0, 2, 4, 1, 3, 5); + Error += all(equal(t, expected)) ? 0 : 1; + } + + { + imat3x4 m(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11); + imat4x3 t = transpose(m); + imat4x3 const expected = imat4x3(0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11); + Error += all(equal(t, expected)) ? 0 : 1; + } + + { + imat4 m(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + imat4 t = transpose(m); + imat4 const expected = imat4(0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15); + Error += all(equal(t, expected)) ? 0 : 1; + } + + { + imat4x2 m(0, 1, 2, 3, 4, 5, 6, 7); + imat2x4 t = transpose(m); + imat2x4 const expected = imat2x4(0, 2, 4, 6, 1, 3, 5, 7); + Error += all(equal(t, expected)) ? 0 : 1; + } + + { + imat4x3 m(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11); + imat3x4 t = transpose(m); + imat3x4 const expected = imat3x4(0, 3, 6, 9, 1, 4, 7, 10, 2, 5, 8, 11); + Error += all(equal(t, expected)) ? 0 : 1; + } + + return Error; +} + +int test_determinant() +{ + int Error = 0; + + { + imat2 const m(1, 1, 1, 1); + int const t = determinant(m); + Error += t == 0 ? 0 : 1; + } + + { + imat3 m(1, 1, 1, 1, 1, 1, 1, 1, 1); + int t = determinant(m); + Error += t == 0 ? 0 : 1; + } + + { + imat4 m(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + int t = determinant(m); + Error += t == 0 ? 0 : 1; + } + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_matrixCompMult(); + Error += test_outerProduct(); + Error += test_transpose(); + Error += test_determinant(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_projection.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_projection.cpp new file mode 100644 index 0000000000000000000000000000000000000000..88f6ae9c7b5ea85a32f309dd1cd710033f182af2 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_projection.cpp @@ -0,0 +1,13 @@ +#include +#include +#include +#include +#include +#include + +int main() +{ + int Error = 0; + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_relational.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_relational.cpp new file mode 100644 index 0000000000000000000000000000000000000000..64c0dae578eda64aeef7a413a26d82121c8e9221 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_relational.cpp @@ -0,0 +1,163 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +template +static int test_equal() +{ + typedef typename matType::value_type valType; + + valType const Epsilon = static_cast(0.001f); + valType const One = static_cast(1); + valType const Two = static_cast(2); + + int Error = 0; + + Error += glm::all(glm::equal(matType(One), matType(One), Epsilon)) ? 0 : 1; + Error += glm::all(glm::equal(matType(One), matType(Two), vecType(Epsilon))) ? 1 : 0; + + return Error; +} + +template +static int test_notEqual() +{ + typedef typename matType::value_type valType; + + valType const Epsilon = static_cast(0.001f); + valType const One = static_cast(1); + valType const Two = static_cast(2); + + int Error = 0; + + Error += !glm::any(glm::notEqual(matType(One), matType(One), Epsilon)) ? 0 : 1; + Error += !glm::any(glm::notEqual(matType(One), matType(Two), vecType(Epsilon))) ? 1 : 0; + + return Error; +} + + +template +static int test_equal_ulps() +{ + typedef glm::mat<4, 4, T, glm::defaultp> mat4; + + T const One(1); + mat4 const Ones(1); + + int Error = 0; + + T const ULP1Plus = glm::nextFloat(One); + Error += glm::all(glm::equal(Ones, mat4(ULP1Plus), 1)) ? 0 : 1; + + T const ULP2Plus = glm::nextFloat(ULP1Plus); + Error += !glm::all(glm::equal(Ones, mat4(ULP2Plus), 1)) ? 0 : 1; + + T const ULP1Minus = glm::prevFloat(One); + Error += glm::all(glm::equal(Ones, mat4(ULP1Minus), 1)) ? 0 : 1; + + T const ULP2Minus = glm::prevFloat(ULP1Minus); + Error += !glm::all(glm::equal(Ones, mat4(ULP2Minus), 1)) ? 0 : 1; + + return Error; +} + +template +static int test_notEqual_ulps() +{ + typedef glm::mat<4, 4, T, glm::defaultp> mat4; + + T const One(1); + mat4 const Ones(1); + + int Error = 0; + + T const ULP1Plus = glm::nextFloat(One); + Error += !glm::all(glm::notEqual(Ones, mat4(ULP1Plus), 1)) ? 0 : 1; + + T const ULP2Plus = glm::nextFloat(ULP1Plus); + Error += glm::all(glm::notEqual(Ones, mat4(ULP2Plus), 1)) ? 0 : 1; + + T const ULP1Minus = glm::prevFloat(One); + Error += !glm::all(glm::notEqual(Ones, mat4(ULP1Minus), 1)) ? 0 : 1; + + T const ULP2Minus = glm::prevFloat(ULP1Minus); + Error += glm::all(glm::notEqual(Ones, mat4(ULP2Minus), 1)) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_equal_ulps(); + Error += test_equal_ulps(); + Error += test_notEqual_ulps(); + Error += test_notEqual_ulps(); + + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_transform.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_transform.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cf653b7df0556118c1be324a7ddf7cab46e21d0b --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_transform.cpp @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include +#include + +static int test_translate() +{ + int Error = 0; + + glm::mat4 const M(1.0f); + glm::vec3 const V(1.0f); + + glm::mat4 const T = glm::translate(M, V); + Error += glm::all(glm::equal(T[3], glm::vec4(1.0f), glm::epsilon())) ? 0 : 1; + + return Error; +} + +static int test_scale() +{ + int Error = 0; + + glm::mat4 const M(1.0f); + glm::vec3 const V(2.0f); + + glm::mat4 const S = glm::scale(M, V); + glm::mat4 const R = glm::mat4( + glm::vec4(2, 0, 0, 0), + glm::vec4(0, 2, 0, 0), + glm::vec4(0, 0, 2, 0), + glm::vec4(0, 0, 0, 1)); + Error += glm::all(glm::equal(S, R, glm::epsilon())) ? 0 : 1; + + return Error; +} + +static int test_rotate() +{ + int Error = 0; + + glm::vec4 const A(1.0f, 0.0f, 0.0f, 1.0f); + + glm::mat4 const R = glm::rotate(glm::mat4(1.0f), glm::radians(90.f), glm::vec3(0, 0, 1)); + glm::vec4 const B = R * A; + Error += glm::all(glm::equal(B, glm::vec4(0.0f, 1.0f, 0.0f, 1.0f), 0.0001f)) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_translate(); + Error += test_scale(); + Error += test_rotate(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_uint2x2_sized.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_uint2x2_sized.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a9bd49c73f0d861373d84eb0e2716127e10fb493 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_uint2x2_sized.cpp @@ -0,0 +1,28 @@ +#include + +#if GLM_HAS_STATIC_ASSERT + static_assert(sizeof(glm::u8mat2x2) == 4, "uint8 size isn't 1 byte on this platform"); + static_assert(sizeof(glm::u16mat2x2) == 8, "uint16 size isn't 2 bytes on this platform"); + static_assert(sizeof(glm::u32mat2x2) == 16, "uint32 size isn't 4 bytes on this platform"); + static_assert(sizeof(glm::u64mat2x2) == 32, "uint64 size isn't 8 bytes on this platform"); +#endif + +static int test_comp() +{ + int Error = 0; + + Error += sizeof(glm::u8mat2x2) < sizeof(glm::u16mat2x2) ? 0 : 1; + Error += sizeof(glm::u16mat2x2) < sizeof(glm::u32mat2x2) ? 0 : 1; + Error += sizeof(glm::u32mat2x2) < sizeof(glm::u64mat2x2) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_comp(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_uint2x3_sized.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_uint2x3_sized.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0b7589385696d0114c0aa0532a9c351d116164e6 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_uint2x3_sized.cpp @@ -0,0 +1,28 @@ +#include + +#if GLM_HAS_STATIC_ASSERT +static_assert(sizeof(glm::u8mat2x3) == 6, "uint8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::u16mat2x3) == 12, "uint16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::u32mat2x3) == 24, "uint32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::u64mat2x3) == 48, "uint64 size isn't 8 bytes on this platform"); +#endif + +static int test_comp() +{ + int Error = 0; + + Error += sizeof(glm::u8mat2x3) < sizeof(glm::u16mat2x3) ? 0 : 1; + Error += sizeof(glm::u16mat2x3) < sizeof(glm::u32mat2x3) ? 0 : 1; + Error += sizeof(glm::u32mat2x3) < sizeof(glm::u64mat2x3) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_comp(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_uint2x4_sized.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_uint2x4_sized.cpp new file mode 100644 index 0000000000000000000000000000000000000000..84af4dd11f340b8a3d3c29a8fa07f9466c966350 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_uint2x4_sized.cpp @@ -0,0 +1,28 @@ +#include + +#if GLM_HAS_STATIC_ASSERT +static_assert(sizeof(glm::u8mat2x4) == 8, "uint8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::u16mat2x4) == 16, "uint16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::u32mat2x4) == 32, "uint32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::u64mat2x4) == 64, "uint64 size isn't 8 bytes on this platform"); +#endif + +static int test_comp() +{ + int Error = 0; + + Error += sizeof(glm::u8mat2x4) < sizeof(glm::u16mat2x4) ? 0 : 1; + Error += sizeof(glm::u16mat2x4) < sizeof(glm::u32mat2x4) ? 0 : 1; + Error += sizeof(glm::u32mat2x4) < sizeof(glm::u64mat2x4) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_comp(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_uint3x2_sized.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_uint3x2_sized.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3c035e23ce7e180c8087bfc634ee139a3bcacfcb --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_uint3x2_sized.cpp @@ -0,0 +1,28 @@ +#include + +#if GLM_HAS_STATIC_ASSERT +static_assert(sizeof(glm::u8mat3x2) == 6, "uint8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::u16mat3x2) == 12, "uint16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::u32mat3x2) == 24, "uint32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::u64mat3x2) == 48, "uint64 size isn't 8 bytes on this platform"); +#endif + +static int test_comp() +{ + int Error = 0; + + Error += sizeof(glm::u8mat3x2) < sizeof(glm::u16mat3x2) ? 0 : 1; + Error += sizeof(glm::u16mat3x2) < sizeof(glm::u32mat3x2) ? 0 : 1; + Error += sizeof(glm::u32mat3x2) < sizeof(glm::u64mat3x2) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_comp(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_uint3x3_sized.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_uint3x3_sized.cpp new file mode 100644 index 0000000000000000000000000000000000000000..64384ede30331395ea3ce4ec3f64220a6b72d4fd --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_uint3x3_sized.cpp @@ -0,0 +1,28 @@ +#include + +#if GLM_HAS_STATIC_ASSERT +static_assert(sizeof(glm::u8mat3x3) == 9, "uint8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::u16mat3x3) == 18, "uint16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::u32mat3x3) == 36, "uint32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::u64mat3x3) == 72, "uint64 size isn't 8 bytes on this platform"); +#endif + +static int test_comp() +{ + int Error = 0; + + Error += sizeof(glm::u8mat3x3) < sizeof(glm::u16mat3x3) ? 0 : 1; + Error += sizeof(glm::u16mat3x3) < sizeof(glm::u32mat3x3) ? 0 : 1; + Error += sizeof(glm::u32mat3x3) < sizeof(glm::u64mat3x3) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_comp(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_uint3x4_sized.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_uint3x4_sized.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7f743dfe168e766a1d80f2c2215e2e35266084da --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_uint3x4_sized.cpp @@ -0,0 +1,28 @@ +#include + +#if GLM_HAS_STATIC_ASSERT +static_assert(sizeof(glm::u8mat3x4) == 12, "uint8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::u16mat3x4) == 24, "uint16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::u32mat3x4) == 48, "uint32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::u64mat3x4) == 96, "uint64 size isn't 8 bytes on this platform"); +#endif + +static int test_comp() +{ + int Error = 0; + + Error += sizeof(glm::u8mat3x4) < sizeof(glm::u16mat3x4) ? 0 : 1; + Error += sizeof(glm::u16mat3x4) < sizeof(glm::u32mat3x4) ? 0 : 1; + Error += sizeof(glm::u32mat3x4) < sizeof(glm::u64mat3x4) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_comp(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_uint4x2_sized.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_uint4x2_sized.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2b4453f95c6dac0afd30a07e252c023d0dc38f45 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_uint4x2_sized.cpp @@ -0,0 +1,28 @@ +#include + +#if GLM_HAS_STATIC_ASSERT +static_assert(sizeof(glm::u8mat4x2) == 8, "uint8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::u16mat4x2) == 16, "uint16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::u32mat4x2) == 32, "uint32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::u64mat4x2) == 64, "uint64 size isn't 8 bytes on this platform"); +#endif + +static int test_comp() +{ + int Error = 0; + + Error += sizeof(glm::u8mat4x2) < sizeof(glm::u16mat4x2) ? 0 : 1; + Error += sizeof(glm::u16mat4x2) < sizeof(glm::u32mat4x2) ? 0 : 1; + Error += sizeof(glm::u32mat4x2) < sizeof(glm::u64mat4x2) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_comp(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_uint4x3_sized.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_uint4x3_sized.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2820bde1985d363bbe8a6e91c8982b4f40a11287 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_uint4x3_sized.cpp @@ -0,0 +1,28 @@ +#include + +#if GLM_HAS_STATIC_ASSERT +static_assert(sizeof(glm::u8mat4x3) == 12, "uint8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::u16mat4x3) == 24, "uint16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::u32mat4x3) == 48, "uint32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::u64mat4x3) == 96, "uint64 size isn't 8 bytes on this platform"); +#endif + +static int test_comp() +{ + int Error = 0; + + Error += sizeof(glm::u8mat4x3) < sizeof(glm::u16mat4x3) ? 0 : 1; + Error += sizeof(glm::u16mat4x3) < sizeof(glm::u32mat4x3) ? 0 : 1; + Error += sizeof(glm::u32mat4x3) < sizeof(glm::u64mat4x3) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_comp(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_uint4x4_sized.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_uint4x4_sized.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8f9e239cf478d2b9045178865333edf814710468 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_matrix_uint4x4_sized.cpp @@ -0,0 +1,28 @@ +#include + +#if GLM_HAS_STATIC_ASSERT +static_assert(sizeof(glm::u8mat4x4) == 16, "uint8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::u16mat4x4) == 32, "uint16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::u32mat4x4) == 64, "uint32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::u64mat4x4) == 128, "uint64 size isn't 8 bytes on this platform"); +#endif + +static int test_comp() +{ + int Error = 0; + + Error += sizeof(glm::u8mat4x4) < sizeof(glm::u16mat4x4) ? 0 : 1; + Error += sizeof(glm::u16mat4x4) < sizeof(glm::u32mat4x4) ? 0 : 1; + Error += sizeof(glm::u32mat4x4) < sizeof(glm::u64mat4x4) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_comp(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_quaternion_common.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_quaternion_common.cpp new file mode 100644 index 0000000000000000000000000000000000000000..861aa65fd60371e2a57d433ee33ad2823e26a89e --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_quaternion_common.cpp @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include +#include +#include + +static int test_conjugate() +{ + int Error = 0; + + glm::quat const A(glm::vec3(1, 0, 0), glm::vec3(0, 1, 0)); + glm::quat const C = glm::conjugate(A); + Error += glm::any(glm::notEqual(A, C, glm::epsilon())) ? 0 : 1; + + glm::quat const B = glm::conjugate(C); + Error += glm::all(glm::equal(A, B, glm::epsilon())) ? 0 : 1; + + return Error; +} + +static int test_mix() +{ + int Error = 0; + + glm::quat const Q1(glm::vec3(1, 0, 0), glm::vec3(1, 0, 0)); + glm::quat const Q2(glm::vec3(1, 0, 0), glm::vec3(0, 1, 0)); + + { + glm::quat const Q3 = glm::mix(Q1, Q2, 0.5f); + float const F3 = glm::degrees(glm::angle(Q3)); + Error += glm::equal(F3, 45.0f, 0.001f) ? 0 : 1; + + glm::quat const Q4 = glm::mix(Q2, Q1, 0.5f); + float const F4 = glm::degrees(glm::angle(Q4)); + Error += glm::equal(F4, 45.0f, 0.001f) ? 0 : 1; + } + + { + glm::quat const Q3 = glm::slerp(Q1, Q2, 0.5f); + float const F3 = glm::degrees(glm::angle(Q3)); + Error += glm::equal(F3, 45.0f, 0.001f) ? 0 : 1; + + glm::quat const Q4 = glm::slerp(Q2, Q1, 0.5f); + float const F4 = glm::degrees(glm::angle(Q4)); + Error += glm::equal(F4, 45.0f, 0.001f) ? 0 : 1; + } + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_conjugate(); + Error += test_mix(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_quaternion_exponential.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_quaternion_exponential.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fbcdbeff745c40c0b014263aaf42d56d379fb6ae --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_quaternion_exponential.cpp @@ -0,0 +1,87 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +template +int test_log() +{ + typedef typename quaType::value_type T; + + T const Epsilon = static_cast(0.001f); + + int Error = 0; + + quaType const Q(vecType(1, 0, 0), vecType(0, 1, 0)); + quaType const P = glm::log(Q); + Error += glm::any(glm::notEqual(Q, P, Epsilon)) ? 0 : 1; + + quaType const R = glm::exp(P); + Error += glm::all(glm::equal(Q, R, Epsilon)) ? 0 : 1; + + return Error; +} + +template +int test_pow() +{ + typedef typename quaType::value_type T; + + T const Epsilon = static_cast(0.001f); + + int Error = 0; + + quaType const Q(vecType(1, 0, 0), vecType(0, 1, 0)); + + { + T const One = static_cast(1.0f); + quaType const P = glm::pow(Q, One); + Error += glm::all(glm::equal(Q, P, Epsilon)) ? 0 : 1; + } + + { + T const Two = static_cast(2.0f); + quaType const P = glm::pow(Q, Two); + quaType const R = Q * Q; + Error += glm::all(glm::equal(P, R, Epsilon)) ? 0 : 1; + + quaType const U = glm::sqrt(P); + Error += glm::all(glm::equal(Q, U, Epsilon)) ? 0 : 1; + } + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_log(); + Error += test_log(); + Error += test_log(); + Error += test_log(); + + Error += test_log(); + Error += test_log(); + Error += test_log(); + Error += test_log(); + + Error += test_pow(); + Error += test_pow(); + Error += test_pow(); + Error += test_pow(); + + Error += test_pow(); + Error += test_pow(); + Error += test_pow(); + Error += test_pow(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_quaternion_geometric.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_quaternion_geometric.cpp new file mode 100644 index 0000000000000000000000000000000000000000..73b5dea7115d0c704093fb3c51c51afd8dd19378 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_quaternion_geometric.cpp @@ -0,0 +1,88 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +float const Epsilon = 0.001f; + +static int test_length() +{ + int Error = 0; + + { + float const A = glm::length(glm::quat(1, 0, 0, 0)); + Error += glm::equal(A, 1.0f, Epsilon) ? 0 : 1; + } + + { + float const A = glm::length(glm::quat(1, glm::vec3(0))); + Error += glm::equal(A, 1.0f, Epsilon) ? 0 : 1; + } + + { + float const A = glm::length(glm::quat(glm::vec3(1, 0, 0), glm::vec3(0, 1, 0))); + Error += glm::equal(A, 1.0f, Epsilon) ? 0 : 1; + } + + return Error; +} + +static int test_normalize() +{ + int Error = 0; + + { + glm::quat const A = glm::quat(1, 0, 0, 0); + glm::quat const N = glm::normalize(A); + Error += glm::all(glm::equal(A, N, Epsilon)) ? 0 : 1; + } + + { + glm::quat const A = glm::quat(1, glm::vec3(0)); + glm::quat const N = glm::normalize(A); + Error += glm::all(glm::equal(A, N, Epsilon)) ? 0 : 1; + } + + return Error; +} + +static int test_dot() +{ + int Error = 0; + + { + glm::quat const A = glm::quat(1, 0, 0, 0); + glm::quat const B = glm::quat(1, 0, 0, 0); + float const C = glm::dot(A, B); + Error += glm::equal(C, 1.0f, Epsilon) ? 0 : 1; + } + + return Error; +} + +static int test_cross() +{ + int Error = 0; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_length(); + Error += test_normalize(); + Error += test_dot(); + Error += test_cross(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_quaternion_relational.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_quaternion_relational.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7f51fdc9d76c12afc1817ef044b4856507c25c57 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_quaternion_relational.cpp @@ -0,0 +1,51 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +template +static int test_equal() +{ + int Error = 0; + + quaType const Q(1, 0, 0, 0); + quaType const P(1, 0, 0, 0); + Error += glm::all(glm::equal(Q, P, glm::epsilon())) ? 0 : 1; + + return Error; +} + +template +static int test_notEqual() +{ + int Error = 0; + + quaType const Q(1, 0, 0, 0); + quaType const P(1, 0, 0, 0); + Error += glm::any(glm::notEqual(Q, P, glm::epsilon())) ? 1 : 0; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_quaternion_transform.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_quaternion_transform.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fefe88e827a18ae979cd4e466978fe1c1d8524a6 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_quaternion_transform.cpp @@ -0,0 +1,45 @@ +#include +#include +#include +#include + +#define GLM_ENABLE_EXPERIMENTAL +#include + +static int test_lookAt() +{ + int Error(0); + + glm::vec3 eye(0.0f); + glm::vec3 center(1.1f, -2.0f, 3.1416f); + glm::vec3 up(-0.17f, 7.23f, -1.744f); + + glm::quat test_quat = glm::quatLookAt(glm::normalize(center - eye), up); + glm::quat test_mat = glm::conjugate(glm::quat_cast(glm::lookAt(eye, center, up))); + + Error += static_cast(glm::abs(glm::length(test_quat) - 1.0f) > glm::epsilon()); + Error += static_cast(glm::min(glm::length(test_quat + (-test_mat)), glm::length(test_quat + test_mat)) > glm::epsilon()); + + // Test left-handed implementation + glm::quat test_quatLH = glm::quatLookAtLH(glm::normalize(center - eye), up); + glm::quat test_matLH = glm::conjugate(glm::quat_cast(glm::lookAtLH(eye, center, up))); + Error += static_cast(glm::abs(glm::length(test_quatLH) - 1.0f) > glm::epsilon()); + Error += static_cast(glm::min(glm::length(test_quatLH - test_matLH), glm::length(test_quatLH + test_matLH)) > glm::epsilon()); + + // Test right-handed implementation + glm::quat test_quatRH = glm::quatLookAtRH(glm::normalize(center - eye), up); + glm::quat test_matRH = glm::conjugate(glm::quat_cast(glm::lookAtRH(eye, center, up))); + Error += static_cast(glm::abs(glm::length(test_quatRH) - 1.0f) > glm::epsilon()); + Error += static_cast(glm::min(glm::length(test_quatRH - test_matRH), glm::length(test_quatRH + test_matRH)) > glm::epsilon()); + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_lookAt(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_quaternion_trigonometric.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_quaternion_trigonometric.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d2371252f2021b9e319423c5bfe7d6139316354c --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_quaternion_trigonometric.cpp @@ -0,0 +1,40 @@ +#include +#include +#include +#include + +float const Epsilon = 0.001f; + +static int test_angle() +{ + int Error = 0; + + { + glm::quat const Q = glm::quat(glm::vec3(1, 0, 0), glm::vec3(0, 1, 0)); + float const A = glm::degrees(glm::angle(Q)); + Error += glm::equal(A, 90.0f, Epsilon) ? 0 : 1; + } + + { + glm::quat const Q = glm::quat(glm::vec3(0, 1, 0), glm::vec3(1, 0, 0)); + float const A = glm::degrees(glm::angle(Q)); + Error += glm::equal(A, 90.0f, Epsilon) ? 0 : 1; + } + + { + glm::quat const Q = glm::angleAxis(glm::two_pi() - 1.0f, glm::vec3(1, 0, 0)); + float const A = glm::angle(Q); + Error += glm::equal(A, 1.0f, Epsilon) ? 1 : 0; + } + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_angle(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_quaternion_type.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_quaternion_type.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7e6114966b255f7e74f26fab708193d39e1033ff --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_quaternion_type.cpp @@ -0,0 +1,113 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +static int test_ctr() +{ + int Error(0); + +# if GLM_HAS_TRIVIAL_QUERIES + // Error += std::is_trivially_default_constructible::value ? 0 : 1; + // Error += std::is_trivially_default_constructible::value ? 0 : 1; + // Error += std::is_trivially_copy_assignable::value ? 0 : 1; + // Error += std::is_trivially_copy_assignable::value ? 0 : 1; + Error += std::is_trivially_copyable::value ? 0 : 1; + Error += std::is_trivially_copyable::value ? 0 : 1; + + Error += std::is_copy_constructible::value ? 0 : 1; + Error += std::is_copy_constructible::value ? 0 : 1; +# endif + +# if GLM_HAS_INITIALIZER_LISTS + { + glm::quat A{0, 1, 2, 3}; + + std::vector B{ + {0, 1, 2, 3}, + {0, 1, 2, 3}}; + } +# endif//GLM_HAS_INITIALIZER_LISTS + + return Error; +} + +static int test_two_axis_ctr() +{ + int Error = 0; + + glm::quat const q1(glm::vec3(1, 0, 0), glm::vec3(0, 1, 0)); + glm::vec3 const v1 = q1 * glm::vec3(1, 0, 0); + Error += glm::all(glm::equal(v1, glm::vec3(0, 1, 0), 0.0001f)) ? 0 : 1; + + glm::quat const q2 = q1 * q1; + glm::vec3 const v2 = q2 * glm::vec3(1, 0, 0); + Error += glm::all(glm::equal(v2, glm::vec3(-1, 0, 0), 0.0001f)) ? 0 : 1; + + glm::quat const q3(glm::vec3(1, 0, 0), glm::vec3(-1, 0, 0)); + glm::vec3 const v3 = q3 * glm::vec3(1, 0, 0); + Error += glm::all(glm::equal(v3, glm::vec3(-1, 0, 0), 0.0001f)) ? 0 : 1; + + glm::quat const q4(glm::vec3(0, 1, 0), glm::vec3(0, -1, 0)); + glm::vec3 const v4 = q4 * glm::vec3(0, 1, 0); + Error += glm::all(glm::equal(v4, glm::vec3(0, -1, 0), 0.0001f)) ? 0 : 1; + + glm::quat const q5(glm::vec3(0, 0, 1), glm::vec3(0, 0, -1)); + glm::vec3 const v5 = q5 * glm::vec3(0, 0, 1); + Error += glm::all(glm::equal(v5, glm::vec3(0, 0, -1), 0.0001f)) ? 0 : 1; + + return Error; +} + +static int test_size() +{ + int Error = 0; + + std::size_t const A = sizeof(glm::quat); + Error += 16 == A ? 0 : 1; + std::size_t const B = sizeof(glm::dquat); + Error += 32 == B ? 0 : 1; + Error += glm::quat().length() == 4 ? 0 : 1; + Error += glm::dquat().length() == 4 ? 0 : 1; + Error += glm::quat::length() == 4 ? 0 : 1; + Error += glm::dquat::length() == 4 ? 0 : 1; + + return Error; +} + +static int test_precision() +{ + int Error = 0; + + Error += sizeof(glm::lowp_quat) <= sizeof(glm::mediump_quat) ? 0 : 1; + Error += sizeof(glm::mediump_quat) <= sizeof(glm::highp_quat) ? 0 : 1; + + return Error; +} + +static int test_constexpr() +{ +#if GLM_HAS_CONSTEXPR + static_assert(glm::quat::length() == 4, "GLM: Failed constexpr"); + static_assert(glm::quat(1.0f, glm::vec3(0.0f)).w > 0.0f, "GLM: Failed constexpr"); +#endif + + return 0; +} + +int main() +{ + int Error = 0; + + Error += test_ctr(); + Error += test_two_axis_ctr(); + Error += test_size(); + Error += test_precision(); + Error += test_constexpr(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_scalar_common.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_scalar_common.cpp new file mode 100644 index 0000000000000000000000000000000000000000..917a242ee185c52a84b4d631b9a1e284737a4372 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_scalar_common.cpp @@ -0,0 +1,360 @@ +#include +#include +#include +#include + +#if ((GLM_LANG & GLM_LANG_CXX11_FLAG) || (GLM_COMPILER & GLM_COMPILER_VC)) +# define GLM_NAN(T) NAN +#else +# define GLM_NAN(T) (static_cast(0.0f) / static_cast(0.0f)) +#endif + +template +static int test_min() +{ + int Error = 0; + + T const N = static_cast(0); + T const B = static_cast(1); + Error += glm::equal(glm::min(N, B), N, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::min(B, N), N, glm::epsilon()) ? 0 : 1; + + T const C = static_cast(2); + Error += glm::equal(glm::min(N, B, C), N, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::min(B, N, C), N, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::min(C, N, B), N, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::min(C, B, N), N, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::min(B, C, N), N, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::min(N, C, B), N, glm::epsilon()) ? 0 : 1; + + T const D = static_cast(3); + Error += glm::equal(glm::min(D, N, B, C), N, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::min(B, D, N, C), N, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::min(C, N, D, B), N, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::min(C, B, D, N), N, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::min(B, C, N, D), N, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::min(N, C, B, D), N, glm::epsilon()) ? 0 : 1; + + return Error; +} + +template +static int test_min_nan() +{ + int Error = 0; + + T const B = static_cast(1); + T const N = static_cast(GLM_NAN(T)); + Error += glm::isnan(glm::min(N, B)) ? 0 : 1; + Error += !glm::isnan(glm::min(B, N)) ? 0 : 1; + + T const C = static_cast(2); + Error += glm::isnan(glm::min(N, B, C)) ? 0 : 1; + Error += !glm::isnan(glm::min(B, N, C)) ? 0 : 1; + Error += !glm::isnan(glm::min(C, N, B)) ? 0 : 1; + Error += !glm::isnan(glm::min(C, B, N)) ? 0 : 1; + Error += !glm::isnan(glm::min(B, C, N)) ? 0 : 1; + Error += glm::isnan(glm::min(N, C, B)) ? 0 : 1; + + T const D = static_cast(3); + Error += !glm::isnan(glm::min(D, N, B, C)) ? 0 : 1; + Error += !glm::isnan(glm::min(B, D, N, C)) ? 0 : 1; + Error += !glm::isnan(glm::min(C, N, D, B)) ? 0 : 1; + Error += !glm::isnan(glm::min(C, B, D, N)) ? 0 : 1; + Error += !glm::isnan(glm::min(B, C, N, D)) ? 0 : 1; + Error += glm::isnan(glm::min(N, C, B, D)) ? 0 : 1; + + return Error; +} + +template +static int test_max() +{ + int Error = 0; + + T const N = static_cast(0); + T const B = static_cast(1); + Error += glm::equal(glm::max(N, B), B, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::max(B, N), B, glm::epsilon()) ? 0 : 1; + + T const C = static_cast(2); + Error += glm::equal(glm::max(N, B, C), C, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::max(B, N, C), C, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::max(C, N, B), C, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::max(C, B, N), C, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::max(B, C, N), C, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::max(N, C, B), C, glm::epsilon()) ? 0 : 1; + + T const D = static_cast(3); + Error += glm::equal(glm::max(D, N, B, C), D, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::max(B, D, N, C), D, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::max(C, N, D, B), D, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::max(C, B, D, N), D, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::max(B, C, N, D), D, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::max(N, C, B, D), D, glm::epsilon()) ? 0 : 1; + + return Error; +} + +template +static int test_max_nan() +{ + int Error = 0; + + T const B = static_cast(1); + T const N = static_cast(GLM_NAN(T)); + Error += glm::isnan(glm::max(N, B)) ? 0 : 1; + Error += !glm::isnan(glm::max(B, N)) ? 0 : 1; + + T const C = static_cast(2); + Error += glm::isnan(glm::max(N, B, C)) ? 0 : 1; + Error += !glm::isnan(glm::max(B, N, C)) ? 0 : 1; + Error += !glm::isnan(glm::max(C, N, B)) ? 0 : 1; + Error += !glm::isnan(glm::max(C, B, N)) ? 0 : 1; + Error += !glm::isnan(glm::max(B, C, N)) ? 0 : 1; + Error += glm::isnan(glm::max(N, C, B)) ? 0 : 1; + + T const D = static_cast(3); + Error += !glm::isnan(glm::max(D, N, B, C)) ? 0 : 1; + Error += !glm::isnan(glm::max(B, D, N, C)) ? 0 : 1; + Error += !glm::isnan(glm::max(C, N, D, B)) ? 0 : 1; + Error += !glm::isnan(glm::max(C, B, D, N)) ? 0 : 1; + Error += !glm::isnan(glm::max(B, C, N, D)) ? 0 : 1; + Error += glm::isnan(glm::max(N, C, B, D)) ? 0 : 1; + + return Error; +} + +template +static int test_fmin() +{ + int Error = 0; + + T const B = static_cast(1); + T const N = static_cast(GLM_NAN(T)); + Error += glm::equal(glm::fmin(N, B), B, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::fmin(B, N), B, glm::epsilon()) ? 0 : 1; + + T const C = static_cast(2); + Error += glm::equal(glm::fmin(N, B, C), B, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::fmin(B, N, C), B, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::fmin(C, N, B), B, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::fmin(C, B, N), B, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::fmin(B, C, N), B, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::fmin(N, C, B), B, glm::epsilon()) ? 0 : 1; + + T const D = static_cast(3); + Error += glm::equal(glm::fmin(D, N, B, C), B, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::fmin(B, D, N, C), B, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::fmin(C, N, D, B), B, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::fmin(C, B, D, N), B, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::fmin(B, C, N, D), B, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::fmin(N, C, B, D), B, glm::epsilon()) ? 0 : 1; + + return Error; +} + +template +static int test_fmax() +{ + int Error = 0; + + T const B = static_cast(1); + T const N = static_cast(GLM_NAN(T)); + Error += glm::equal(glm::fmax(N, B), B, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::fmax(B, N), B, glm::epsilon()) ? 0 : 1; + + T const C = static_cast(2); + Error += glm::equal(glm::fmax(N, B, C), C, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::fmax(B, N, C), C, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::fmax(C, N, B), C, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::fmax(C, B, N), C, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::fmax(B, C, N), C, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::fmax(N, C, B), C, glm::epsilon()) ? 0 : 1; + + T const D = static_cast(3); + Error += glm::equal(glm::fmax(D, N, B, C), D, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::fmax(B, D, N, C), D, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::fmax(C, N, D, B), D, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::fmax(C, B, D, N), D, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::fmax(B, C, N, D), D, glm::epsilon()) ? 0 : 1; + Error += glm::equal(glm::fmax(N, C, B, D), D, glm::epsilon()) ? 0 : 1; + + return Error; +} + +static int test_clamp() +{ + int Error = 0; + + float A = glm::clamp(0.5f); + Error += glm::equal(A, 0.5f, 0.00001f) ? 0 : 1; + + float B = glm::clamp(0.0f); + Error += glm::equal(B, 0.0f, 0.00001f) ? 0 : 1; + + float C = glm::clamp(1.0f); + Error += glm::equal(C, 1.0f, 0.00001f) ? 0 : 1; + + float D = glm::clamp(-0.5f); + Error += glm::equal(D, 0.0f, 0.00001f) ? 0 : 1; + + float E = glm::clamp(1.5f); + Error += glm::equal(E, 1.0f, 0.00001f) ? 0 : 1; + + return Error; +} + +static int test_repeat() +{ + int Error = 0; + + float A = glm::repeat(0.5f); + Error += glm::equal(A, 0.5f, 0.00001f) ? 0 : 1; + + float B = glm::repeat(0.0f); + Error += glm::equal(B, 0.0f, 0.00001f) ? 0 : 1; + + float C = glm::repeat(1.0f); + Error += glm::equal(C, 0.0f, 0.00001f) ? 0 : 1; + + float D = glm::repeat(-0.5f); + Error += glm::equal(D, 0.5f, 0.00001f) ? 0 : 1; + + float E = glm::repeat(1.5f); + Error += glm::equal(E, 0.5f, 0.00001f) ? 0 : 1; + + float F = glm::repeat(0.9f); + Error += glm::equal(F, 0.9f, 0.00001f) ? 0 : 1; + + return Error; +} + +static int test_mirrorClamp() +{ + int Error = 0; + + float A = glm::mirrorClamp(0.5f); + Error += glm::equal(A, 0.5f, 0.00001f) ? 0 : 1; + + float B = glm::mirrorClamp(0.0f); + Error += glm::equal(B, 0.0f, 0.00001f) ? 0 : 1; + + float C = glm::mirrorClamp(1.1f); + Error += glm::equal(C, 0.1f, 0.00001f) ? 0 : 1; + + float D = glm::mirrorClamp(-0.5f); + Error += glm::equal(D, 0.5f, 0.00001f) ? 0 : 1; + + float E = glm::mirrorClamp(1.5f); + Error += glm::equal(E, 0.5f, 0.00001f) ? 0 : 1; + + float F = glm::mirrorClamp(0.9f); + Error += glm::equal(F, 0.9f, 0.00001f) ? 0 : 1; + + float G = glm::mirrorClamp(3.1f); + Error += glm::equal(G, 0.1f, 0.00001f) ? 0 : 1; + + float H = glm::mirrorClamp(-3.1f); + Error += glm::equal(H, 0.1f, 0.00001f) ? 0 : 1; + + float I = glm::mirrorClamp(-0.9f); + Error += glm::equal(I, 0.9f, 0.00001f) ? 0 : 1; + + return Error; +} + +static int test_mirrorRepeat() +{ + int Error = 0; + + float A = glm::mirrorRepeat(0.5f); + Error += glm::equal(A, 0.5f, 0.00001f) ? 0 : 1; + + float B = glm::mirrorRepeat(0.0f); + Error += glm::equal(B, 0.0f, 0.00001f) ? 0 : 1; + + float C = glm::mirrorRepeat(1.0f); + Error += glm::equal(C, 1.0f, 0.00001f) ? 0 : 1; + + float D = glm::mirrorRepeat(-0.5f); + Error += glm::equal(D, 0.5f, 0.00001f) ? 0 : 1; + + float E = glm::mirrorRepeat(1.5f); + Error += glm::equal(E, 0.5f, 0.00001f) ? 0 : 1; + + float F = glm::mirrorRepeat(0.9f); + Error += glm::equal(F, 0.9f, 0.00001f) ? 0 : 1; + + float G = glm::mirrorRepeat(3.0f); + Error += glm::equal(G, 1.0f, 0.00001f) ? 0 : 1; + + float H = glm::mirrorRepeat(-3.0f); + Error += glm::equal(H, 1.0f, 0.00001f) ? 0 : 1; + + float I = glm::mirrorRepeat(-1.0f); + Error += glm::equal(I, 1.0f, 0.00001f) ? 0 : 1; + + return Error; +} + +static int test_iround() +{ + int Error = 0; + + for(float f = 0.0f; f < 3.1f; f += 0.05f) + { + int RoundFast = static_cast(glm::iround(f)); + int RoundSTD = static_cast(glm::round(f)); + Error += RoundFast == RoundSTD ? 0 : 1; + assert(!Error); + } + + return Error; +} + +static int test_uround() +{ + int Error = 0; + + for(float f = 0.0f; f < 3.1f; f += 0.05f) + { + int RoundFast = static_cast(glm::uround(f)); + int RoundSTD = static_cast(glm::round(f)); + Error += RoundFast == RoundSTD ? 0 : 1; + assert(!Error); + } + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_min(); + Error += test_min(); + Error += test_min_nan(); + Error += test_min_nan(); + + Error += test_max(); + Error += test_max(); + Error += test_max_nan(); + Error += test_max_nan(); + + Error += test_fmin(); + Error += test_fmin(); + + Error += test_fmax(); + Error += test_fmax(); + + Error += test_clamp(); + Error += test_repeat(); + Error += test_mirrorClamp(); + Error += test_mirrorRepeat(); + + Error += test_iround(); + Error += test_uround(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_scalar_constants.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_scalar_constants.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3af7099877708eb16a3c47240b08dd2d6265d674 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_scalar_constants.cpp @@ -0,0 +1,36 @@ +#include + +template +static int test_epsilon() +{ + int Error = 0; + + valType const Test = glm::epsilon(); + Error += Test > static_cast(0) ? 0 : 1; + + return Error; +} + +template +static int test_pi() +{ + int Error = 0; + + valType const Test = glm::pi(); + Error += Test > static_cast(3.14) ? 0 : 1; + Error += Test < static_cast(3.15) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_epsilon(); + Error += test_epsilon(); + Error += test_pi(); + Error += test_pi(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_scalar_int_sized.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_scalar_int_sized.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b55c6ca7f11fba0eb61426710b4bbe9434a58313 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_scalar_int_sized.cpp @@ -0,0 +1,43 @@ +#include + +#if GLM_HAS_STATIC_ASSERT + static_assert(sizeof(glm::int8) == 1, "int8 size isn't 1 byte on this platform"); + static_assert(sizeof(glm::int16) == 2, "int16 size isn't 2 bytes on this platform"); + static_assert(sizeof(glm::int32) == 4, "int32 size isn't 4 bytes on this platform"); + static_assert(sizeof(glm::int64) == 8, "int64 size isn't 8 bytes on this platform"); + static_assert(sizeof(glm::int16) == sizeof(short), "signed short size isn't 4 bytes on this platform"); + static_assert(sizeof(glm::int32) == sizeof(int), "signed int size isn't 4 bytes on this platform"); +#endif + +static int test_size() +{ + int Error = 0; + + Error += sizeof(glm::int8) == 1 ? 0 : 1; + Error += sizeof(glm::int16) == 2 ? 0 : 1; + Error += sizeof(glm::int32) == 4 ? 0 : 1; + Error += sizeof(glm::int64) == 8 ? 0 : 1; + + return Error; +} + +static int test_comp() +{ + int Error = 0; + + Error += sizeof(glm::int8) < sizeof(glm::int16) ? 0 : 1; + Error += sizeof(glm::int16) < sizeof(glm::int32) ? 0 : 1; + Error += sizeof(glm::int32) < sizeof(glm::int64) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_size(); + Error += test_comp(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_scalar_integer.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_scalar_integer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f169e8a303c074bb1914102048496af4831ea60b --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_scalar_integer.cpp @@ -0,0 +1,686 @@ +#include +#include +#include +#include +#include +#include + +#if GLM_LANG & GLM_LANG_CXX11_FLAG +#include + +namespace isPowerOfTwo +{ + template + struct type + { + genType Value; + bool Return; + }; + + int test_int16() + { + type const Data[] = + { + {0x0001, true}, + {0x0002, true}, + {0x0004, true}, + {0x0080, true}, + {0x0000, true}, + {0x0003, false} + }; + + int Error = 0; + + for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + bool Result = glm::isPowerOfTwo(Data[i].Value); + Error += Data[i].Return == Result ? 0 : 1; + } + + return Error; + } + + int test_uint16() + { + type const Data[] = + { + {0x0001, true}, + {0x0002, true}, + {0x0004, true}, + {0x0000, true}, + {0x0000, true}, + {0x0003, false} + }; + + int Error = 0; + + for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + bool Result = glm::isPowerOfTwo(Data[i].Value); + Error += Data[i].Return == Result ? 0 : 1; + } + + return Error; + } + + int test_int32() + { + type const Data[] = + { + {0x00000001, true}, + {0x00000002, true}, + {0x00000004, true}, + {0x0000000f, false}, + {0x00000000, true}, + {0x00000003, false} + }; + + int Error = 0; + + for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + bool Result = glm::isPowerOfTwo(Data[i].Value); + Error += Data[i].Return == Result ? 0 : 1; + } + + return Error; + } + + int test_uint32() + { + type const Data[] = + { + {0x00000001, true}, + {0x00000002, true}, + {0x00000004, true}, + {0x80000000, true}, + {0x00000000, true}, + {0x00000003, false} + }; + + int Error = 0; + + for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + bool Result = glm::isPowerOfTwo(Data[i].Value); + Error += Data[i].Return == Result ? 0 : 1; + } + + return Error; + } + + int test() + { + int Error = 0; + + Error += test_int16(); + Error += test_uint16(); + Error += test_int32(); + Error += test_uint32(); + + return Error; + } +}//isPowerOfTwo + +namespace nextPowerOfTwo_advanced +{ + template + GLM_FUNC_QUALIFIER genIUType highestBitValue(genIUType Value) + { + genIUType tmp = Value; + genIUType result = genIUType(0); + while(tmp) + { + result = (tmp & (~tmp + 1)); // grab lowest bit + tmp &= ~result; // clear lowest bit + } + return result; + } + + template + GLM_FUNC_QUALIFIER genType nextPowerOfTwo_loop(genType value) + { + return glm::isPowerOfTwo(value) ? value : highestBitValue(value) << 1; + } + + template + struct type + { + genType Value; + genType Return; + }; + + int test_int32() + { + type const Data[] = + { + {0x0000ffff, 0x00010000}, + {-3, -4}, + {-8, -8}, + {0x00000001, 0x00000001}, + {0x00000002, 0x00000002}, + {0x00000004, 0x00000004}, + {0x00000007, 0x00000008}, + {0x0000fff0, 0x00010000}, + {0x0000f000, 0x00010000}, + {0x08000000, 0x08000000}, + {0x00000000, 0x00000000}, + {0x00000003, 0x00000004} + }; + + int Error(0); + + for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + glm::int32 Result = glm::nextPowerOfTwo(Data[i].Value); + Error += Data[i].Return == Result ? 0 : 1; + } + + return Error; + } + + int test_uint32() + { + type const Data[] = + { + {0x00000001, 0x00000001}, + {0x00000002, 0x00000002}, + {0x00000004, 0x00000004}, + {0x00000007, 0x00000008}, + {0x0000ffff, 0x00010000}, + {0x0000fff0, 0x00010000}, + {0x0000f000, 0x00010000}, + {0x80000000, 0x80000000}, + {0x00000000, 0x00000000}, + {0x00000003, 0x00000004} + }; + + int Error(0); + + for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + glm::uint32 Result = glm::nextPowerOfTwo(Data[i].Value); + Error += Data[i].Return == Result ? 0 : 1; + } + + return Error; + } + + int perf() + { + int Error(0); + + std::vector v; + v.resize(100000000); + + std::clock_t Timestramp0 = std::clock(); + + for(glm::uint32 i = 0, n = static_cast(v.size()); i < n; ++i) + v[i] = nextPowerOfTwo_loop(i); + + std::clock_t Timestramp1 = std::clock(); + + for(glm::uint32 i = 0, n = static_cast(v.size()); i < n; ++i) + v[i] = glm::nextPowerOfTwo(i); + + std::clock_t Timestramp2 = std::clock(); + + std::printf("nextPowerOfTwo_loop: %d clocks\n", static_cast(Timestramp1 - Timestramp0)); + std::printf("glm::nextPowerOfTwo: %d clocks\n", static_cast(Timestramp2 - Timestramp1)); + + return Error; + } + + int test() + { + int Error(0); + + Error += test_int32(); + Error += test_uint32(); + + return Error; + } +}//namespace nextPowerOfTwo_advanced + +namespace prevPowerOfTwo +{ + template + int run() + { + int Error = 0; + + T const A = glm::prevPowerOfTwo(static_cast(7)); + Error += A == static_cast(4) ? 0 : 1; + + T const B = glm::prevPowerOfTwo(static_cast(15)); + Error += B == static_cast(8) ? 0 : 1; + + T const C = glm::prevPowerOfTwo(static_cast(31)); + Error += C == static_cast(16) ? 0 : 1; + + T const D = glm::prevPowerOfTwo(static_cast(32)); + Error += D == static_cast(32) ? 0 : 1; + + return Error; + } + + int test() + { + int Error = 0; + + Error += run(); + Error += run(); + Error += run(); + Error += run(); + + Error += run(); + Error += run(); + Error += run(); + Error += run(); + + return Error; + } +}//namespace prevPowerOfTwo + +namespace nextPowerOfTwo +{ + template + int run() + { + int Error = 0; + + T const A = glm::nextPowerOfTwo(static_cast(7)); + Error += A == static_cast(8) ? 0 : 1; + + T const B = glm::nextPowerOfTwo(static_cast(15)); + Error += B == static_cast(16) ? 0 : 1; + + T const C = glm::nextPowerOfTwo(static_cast(31)); + Error += C == static_cast(32) ? 0 : 1; + + T const D = glm::nextPowerOfTwo(static_cast(32)); + Error += D == static_cast(32) ? 0 : 1; + + return Error; + } + + int test() + { + int Error = 0; + + Error += run(); + Error += run(); + Error += run(); + Error += run(); + + Error += run(); + Error += run(); + Error += run(); + Error += run(); + + return Error; + } +}//namespace nextPowerOfTwo + +namespace prevMultiple +{ + template + struct type + { + genIUType Source; + genIUType Multiple; + genIUType Return; + }; + + template + int run() + { + type const Data[] = + { + {8, 3, 6}, + {7, 7, 7} + }; + + int Error = 0; + + for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + T const Result = glm::prevMultiple(Data[i].Source, Data[i].Multiple); + Error += Data[i].Return == Result ? 0 : 1; + } + + return Error; + } + + int test() + { + int Error = 0; + + Error += run(); + Error += run(); + Error += run(); + Error += run(); + + Error += run(); + Error += run(); + Error += run(); + Error += run(); + + return Error; + } +}//namespace prevMultiple + +namespace nextMultiple +{ + static glm::uint const Multiples = 128; + + int perf_nextMultiple(glm::uint Samples) + { + std::vector Results(Samples * Multiples); + + std::chrono::high_resolution_clock::time_point t0 = std::chrono::high_resolution_clock::now(); + + for(glm::uint Source = 0; Source < Samples; ++Source) + for(glm::uint Multiple = 0; Multiple < Multiples; ++Multiple) + { + Results[Source * Multiples + Multiple] = glm::nextMultiple(Source, Multiples); + } + + std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now(); + + std::printf("- glm::nextMultiple Time %d microseconds\n", static_cast(std::chrono::duration_cast(t1 - t0).count())); + + glm::uint Result = 0; + for(std::size_t i = 0, n = Results.size(); i < n; ++i) + Result += Results[i]; + + return Result > 0 ? 0 : 1; + } + + template + GLM_FUNC_QUALIFIER T nextMultipleMod(T Source, T Multiple) + { + T const Tmp = Source - static_cast(1); + return Tmp + (Multiple - (Tmp % Multiple)); + } + + int perf_nextMultipleMod(glm::uint Samples) + { + std::vector Results(Samples * Multiples); + + std::chrono::high_resolution_clock::time_point t0 = std::chrono::high_resolution_clock::now(); + + for(glm::uint Multiple = 0; Multiple < Multiples; ++Multiple) + for (glm::uint Source = 0; Source < Samples; ++Source) + { + Results[Source * Multiples + Multiple] = nextMultipleMod(Source, Multiples); + } + + std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now(); + + std::printf("- nextMultipleMod Time %d microseconds\n", static_cast(std::chrono::duration_cast(t1 - t0).count())); + + glm::uint Result = 0; + for(std::size_t i = 0, n = Results.size(); i < n; ++i) + Result += Results[i]; + + return Result > 0 ? 0 : 1; + } + + template + GLM_FUNC_QUALIFIER T nextMultipleNeg(T Source, T Multiple) + { + if(Source > static_cast(0)) + { + T const Tmp = Source - static_cast(1); + return Tmp + (Multiple - (Tmp % Multiple)); + } + else + return Source + (-Source % Multiple); + } + + int perf_nextMultipleNeg(glm::uint Samples) + { + std::vector Results(Samples * Multiples); + + std::chrono::high_resolution_clock::time_point t0 = std::chrono::high_resolution_clock::now(); + + for(glm::uint Source = 0; Source < Samples; ++Source) + for(glm::uint Multiple = 0; Multiple < Multiples; ++Multiple) + { + Results[Source * Multiples + Multiple] = nextMultipleNeg(Source, Multiples); + } + + std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now(); + + std::printf("- nextMultipleNeg Time %d microseconds\n", static_cast(std::chrono::duration_cast(t1 - t0).count())); + + glm::uint Result = 0; + for (std::size_t i = 0, n = Results.size(); i < n; ++i) + Result += Results[i]; + + return Result > 0 ? 0 : 1; + } + + template + GLM_FUNC_QUALIFIER T nextMultipleUFloat(T Source, T Multiple) + { + return Source + (Multiple - std::fmod(Source, Multiple)); + } + + int perf_nextMultipleUFloat(glm::uint Samples) + { + std::vector Results(Samples * Multiples); + + std::chrono::high_resolution_clock::time_point t0 = std::chrono::high_resolution_clock::now(); + + for(glm::uint Source = 0; Source < Samples; ++Source) + for(glm::uint Multiple = 0; Multiple < Multiples; ++Multiple) + { + Results[Source * Multiples + Multiple] = nextMultipleUFloat(static_cast(Source), static_cast(Multiples)); + } + + std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now(); + + std::printf("- nextMultipleUFloat Time %d microseconds\n", static_cast(std::chrono::duration_cast(t1 - t0).count())); + + float Result = 0; + for (std::size_t i = 0, n = Results.size(); i < n; ++i) + Result += Results[i]; + + return Result > 0.0f ? 0 : 1; + } + + template + GLM_FUNC_QUALIFIER T nextMultipleFloat(T Source, T Multiple) + { + if(Source > static_cast(0)) + return Source + (Multiple - std::fmod(Source, Multiple)); + else + return Source + std::fmod(-Source, Multiple); + } + + int perf_nextMultipleFloat(glm::uint Samples) + { + std::vector Results(Samples * Multiples); + + std::chrono::high_resolution_clock::time_point t0 = std::chrono::high_resolution_clock::now(); + + for(glm::uint Source = 0; Source < Samples; ++Source) + for(glm::uint Multiple = 0; Multiple < Multiples; ++Multiple) + { + Results[Source * Multiples + Multiple] = nextMultipleFloat(static_cast(Source), static_cast(Multiples)); + } + + std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now(); + + std::printf("- nextMultipleFloat Time %d microseconds\n", static_cast(std::chrono::duration_cast(t1 - t0).count())); + + float Result = 0; + for (std::size_t i = 0, n = Results.size(); i < n; ++i) + Result += Results[i]; + + return Result > 0.0f ? 0 : 1; + } + + template + struct type + { + genIUType Source; + genIUType Multiple; + genIUType Return; + }; + + template + int test_uint() + { + type const Data[] = + { + { 3, 4, 4 }, + { 6, 3, 6 }, + { 5, 3, 6 }, + { 7, 7, 7 }, + { 0, 1, 0 }, + { 8, 3, 9 } + }; + + int Error = 0; + + for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + T const Result0 = glm::nextMultiple(Data[i].Source, Data[i].Multiple); + Error += Data[i].Return == Result0 ? 0 : 1; + assert(!Error); + + T const Result1 = nextMultipleMod(Data[i].Source, Data[i].Multiple); + Error += Data[i].Return == Result1 ? 0 : 1; + assert(!Error); + } + + return Error; + } + + int perf() + { + int Error = 0; + + glm::uint const Samples = 10000; + + for(int i = 0; i < 4; ++i) + { + std::printf("Run %d :\n", i); + Error += perf_nextMultiple(Samples); + Error += perf_nextMultipleMod(Samples); + Error += perf_nextMultipleNeg(Samples); + Error += perf_nextMultipleUFloat(Samples); + Error += perf_nextMultipleFloat(Samples); + std::printf("\n"); + } + + return Error; + } + + int test() + { + int Error = 0; + + Error += test_uint(); + Error += test_uint(); + Error += test_uint(); + Error += test_uint(); + + Error += test_uint(); + Error += test_uint(); + Error += test_uint(); + Error += test_uint(); + + return Error; + } +}//namespace nextMultiple + +namespace findNSB +{ + template + struct type + { + T Source; + int SignificantBitCount; + int Return; + }; + + template + int run() + { + type const Data[] = + { + { 0x00, 1,-1 }, + { 0x01, 2,-1 }, + { 0x02, 2,-1 }, + { 0x06, 3,-1 }, + { 0x01, 1, 0 }, + { 0x03, 1, 0 }, + { 0x03, 2, 1 }, + { 0x07, 2, 1 }, + { 0x05, 2, 2 }, + { 0x0D, 2, 2 } + }; + + int Error = 0; + + for (std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + int const Result0 = glm::findNSB(Data[i].Source, Data[i].SignificantBitCount); + Error += Data[i].Return == Result0 ? 0 : 1; + assert(!Error); + } + + return Error; + } + + int test() + { + int Error = 0; + + Error += run(); + Error += run(); + Error += run(); + Error += run(); + + Error += run(); + Error += run(); + Error += run(); + Error += run(); + + return Error; + } +}//namespace findNSB + +int main() +{ + int Error = 0; + + Error += findNSB::test(); + + Error += isPowerOfTwo::test(); + Error += prevPowerOfTwo::test(); + Error += nextPowerOfTwo::test(); + Error += nextPowerOfTwo_advanced::test(); + Error += prevMultiple::test(); + Error += nextMultiple::test(); + +# ifdef NDEBUG + Error += nextPowerOfTwo_advanced::perf(); + Error += nextMultiple::perf(); +# endif//NDEBUG + + return Error; +} + +#else + +int main() +{ + return 0; +} + +#endif diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_scalar_packing.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_scalar_packing.cpp new file mode 100644 index 0000000000000000000000000000000000000000..77616e3f78dfa0545ac7edb881642dc36530eb55 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_scalar_packing.cpp @@ -0,0 +1,28 @@ +#include +#include + +int test_packUnorm() +{ + int Error = 0; + + + return Error; +} + +int test_packSnorm() +{ + int Error = 0; + + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_packUnorm(); + Error += test_packSnorm(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_scalar_reciprocal.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_scalar_reciprocal.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ebba10d73f9593accb11938b46374339e9c4e11f --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_scalar_reciprocal.cpp @@ -0,0 +1,171 @@ +#include +#include +#include + +static int test_sec() +{ + int Error = 0; + + Error += glm::equal(glm::sec(0.0), 1.0, 0.01) ? 0 : 1; + Error += glm::equal(glm::sec(glm::pi() * 2.0), 1.0, 0.01) ? 0 : 1; + Error += glm::equal(glm::sec(glm::pi() * -2.0), 1.0, 0.01) ? 0 : 1; + Error += glm::equal(glm::sec(glm::pi() * 1.0), -1.0, 0.01) ? 0 : 1; + Error += glm::equal(glm::sec(glm::pi() * -1.0), -1.0, 0.01) ? 0 : 1; + + return Error; +} + +static int test_csc() +{ + int Error = 0; + + double const a = glm::csc(glm::pi() * 0.5); + Error += glm::equal(a, 1.0, 0.01) ? 0 : 1; + double const b = glm::csc(glm::pi() * -0.5); + Error += glm::equal(b, -1.0, 0.01) ? 0 : 1; + + return Error; +} + +static int test_cot() +{ + int Error = 0; + + double const a = glm::cot(glm::pi() * 0.5); + Error += glm::equal(a, 0.0, 0.01) ? 0 : 1; + double const b = glm::cot(glm::pi() * -0.5); + Error += glm::equal(b, 0.0, 0.01) ? 0 : 1; + + return Error; +} + +static int test_asec() +{ + int Error = 0; + + Error += glm::equal(glm::asec(100000.0), glm::pi() * 0.5, 0.01) ? 0 : 1; + Error += glm::equal(glm::asec(-100000.0), glm::pi() * 0.5, 0.01) ? 0 : 1; + + return Error; +} + +static int test_acsc() +{ + int Error = 0; + + Error += glm::equal(glm::acsc(100000.0), 0.0, 0.01) ? 0 : 1; + Error += glm::equal(glm::acsc(-100000.0), 0.0, 0.01) ? 0 : 1; + + return Error; +} + +static int test_acot() +{ + int Error = 0; + + Error += glm::equal(glm::acot(100000.0), 0.0, 0.01) ? 0 : 1; + Error += glm::equal(glm::acot(-100000.0), glm::pi(), 0.01) ? 0 : 1; + Error += glm::equal(glm::acot(0.0), glm::pi() * 0.5, 0.01) ? 0 : 1; + + return Error; +} + +static int test_sech() +{ + int Error = 0; + + Error += glm::equal(glm::sech(100000.0), 0.0, 0.01) ? 0 : 1; + Error += glm::equal(glm::sech(-100000.0), 0.0, 0.01) ? 0 : 1; + Error += glm::equal(glm::sech(0.0), 1.0, 0.01) ? 0 : 1; + + return Error; +} + +static int test_csch() +{ + int Error = 0; + + Error += glm::equal(glm::csch(100000.0), 0.0, 0.01) ? 0 : 1; + Error += glm::equal(glm::csch(-100000.0), 0.0, 0.01) ? 0 : 1; + + return Error; +} + +static int test_coth() +{ + int Error = 0; + + double const a = glm::coth(100.0); + Error += glm::equal(a, 1.0, 0.01) ? 0 : 1; + + double const b = glm::coth(-100.0); + Error += glm::equal(b, -1.0, 0.01) ? 0 : 1; + + return Error; +} + +static int test_asech() +{ + int Error = 0; + + double const a = glm::asech(1.0); + Error += glm::equal(a, 0.0, 0.01) ? 0 : 1; + + return Error; +} + +static int test_acsch() +{ + int Error = 0; + + Error += glm::acsch(0.01) > 1.0 ? 0 : 1; + Error += glm::acsch(-0.01) < -1.0 ? 0 : 1; + + Error += glm::equal(glm::acsch(100.0), 0.0, 0.01) ? 0 : 1; + Error += glm::equal(glm::acsch(-100.0), 0.0, 0.01) ? 0 : 1; + + return Error; +} + +static int test_acoth() +{ + int Error = 0; + + double const a = glm::acoth(1.00001); + Error += a > 6.0 ? 0 : 1; + + double const b = glm::acoth(-1.00001); + Error += b < -6.0 ? 0 : 1; + + double const c = glm::acoth(10000.0); + Error += glm::equal(c, 0.0, 0.01) ? 0 : 1; + + double const d = glm::acoth(-10000.0); + Error += glm::equal(d, 0.0, 0.01) ? 0 : 1; + + return Error; +} + + +int main() +{ + int Error = 0; + + Error += test_sec(); + Error += test_csc(); + Error += test_cot(); + + Error += test_asec(); + Error += test_acsc(); + Error += test_acot(); + + Error += test_sech(); + Error += test_csch(); + Error += test_coth(); + + Error += test_asech(); + Error += test_acsch(); + Error += test_acoth(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_scalar_relational.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_scalar_relational.cpp new file mode 100644 index 0000000000000000000000000000000000000000..61f1999aaeeb0cde08e288eedb530fd0bd63fe6e --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_scalar_relational.cpp @@ -0,0 +1,106 @@ +#include +#include +#include +#include + +static int test_equal_epsilon() +{ +# if GLM_CONFIG_CONSTEXP == GLM_ENABLE + static_assert(glm::equal(1.01f, 1.02f, 0.1f), "GLM: Failed constexpr"); + static_assert(!glm::equal(1.01f, 1.02f, 0.001f), "GLM: Failed constexpr"); +# endif + + int Error = 0; + + Error += glm::equal(1.01f, 1.02f, 0.1f) ? 0 : 1; + Error += !glm::equal(1.01f, 1.02f, 0.001f) ? 0 : 1; + + return Error; +} + +static int test_notEqual_epsilon() +{ +# if GLM_CONFIG_CONSTEXP == GLM_ENABLE + static_assert(glm::notEqual(1.01f, 1.02f, 0.001f), "GLM: Failed constexpr"); + static_assert(!glm::notEqual(1.01f, 1.02f, 0.1f), "GLM: Failed constexpr"); +# endif + + int Error = 0; + + Error += glm::notEqual(1.01f, 1.02f, 0.001f) ? 0 : 1; + Error += !glm::notEqual(1.01f, 1.02f, 0.1f) ? 0 : 1; + + return Error; +} + +static int test_equal_ulps() +{ + int Error = 0; + + float const ULP1Plus = glm::nextFloat(1.0f); + Error += glm::equal(1.0f, ULP1Plus, 1) ? 0 : 1; + + float const ULP2Plus = glm::nextFloat(ULP1Plus); + Error += !glm::equal(1.0f, ULP2Plus, 1) ? 0 : 1; + + float const ULP1Minus = glm::prevFloat(1.0f); + Error += glm::equal(1.0f, ULP1Minus, 1) ? 0 : 1; + + float const ULP2Minus = glm::prevFloat(ULP1Minus); + Error += !glm::equal(1.0f, ULP2Minus, 1) ? 0 : 1; + + return Error; +} + +static int test_notEqual_ulps() +{ + int Error = 0; + + float const ULP1Plus = glm::nextFloat(1.0f); + Error += !glm::notEqual(1.0f, ULP1Plus, 1) ? 0 : 1; + + float const ULP2Plus = glm::nextFloat(ULP1Plus); + Error += glm::notEqual(1.0f, ULP2Plus, 1) ? 0 : 1; + + float const ULP1Minus = glm::prevFloat(1.0f); + Error += !glm::notEqual(1.0f, ULP1Minus, 1) ? 0 : 1; + + float const ULP2Minus = glm::prevFloat(ULP1Minus); + Error += glm::notEqual(1.0f, ULP2Minus, 1) ? 0 : 1; + + return Error; +} + +static int test_equal_sign() +{ + int Error = 0; + + Error += !glm::equal(-0.0f, 0.0f, 2) ? 0 : 1; + Error += !glm::equal(-0.0, 0.0, 2) ? 0 : 1; + + Error += !glm::equal(-1.0f, 2.0f, 2) ? 0 : 1; + Error += !glm::equal(-1.0, 2.0, 2) ? 0 : 1; + + Error += !glm::equal(-0.00001f, 1.00000f, 2) ? 0 : 1; + Error += !glm::equal(-0.00001, 1.00000, 2) ? 0 : 1; + + Error += !glm::equal(-1.0f, 1.0f, 2) ? 0 : 1; + Error += !glm::equal(-1.0, 1.0, 2) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_equal_epsilon(); + Error += test_notEqual_epsilon(); + + Error += test_equal_ulps(); + Error += test_notEqual_ulps(); + + Error += test_equal_sign(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_scalar_uint_sized.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_scalar_uint_sized.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1122947d42496d8f91807e80e5c1315b7371ae9b --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_scalar_uint_sized.cpp @@ -0,0 +1,43 @@ +#include + +#if GLM_HAS_STATIC_ASSERT + static_assert(sizeof(glm::uint8) == 1, "uint8 size isn't 1 byte on this platform"); + static_assert(sizeof(glm::uint16) == 2, "uint16 size isn't 2 bytes on this platform"); + static_assert(sizeof(glm::uint32) == 4, "uint32 size isn't 4 bytes on this platform"); + static_assert(sizeof(glm::uint64) == 8, "uint64 size isn't 8 bytes on this platform"); + static_assert(sizeof(glm::uint16) == sizeof(unsigned short), "unsigned short size isn't 4 bytes on this platform"); + static_assert(sizeof(glm::uint32) == sizeof(unsigned int), "unsigned int size isn't 4 bytes on this platform"); +#endif + +static int test_size() +{ + int Error = 0; + + Error += sizeof(glm::uint8) == 1 ? 0 : 1; + Error += sizeof(glm::uint16) == 2 ? 0 : 1; + Error += sizeof(glm::uint32) == 4 ? 0 : 1; + Error += sizeof(glm::uint64) == 8 ? 0 : 1; + + return Error; +} + +static int test_comp() +{ + int Error = 0; + + Error += sizeof(glm::uint8) < sizeof(glm::uint16) ? 0 : 1; + Error += sizeof(glm::uint16) < sizeof(glm::uint32) ? 0 : 1; + Error += sizeof(glm::uint32) < sizeof(glm::uint64) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_size(); + Error += test_comp(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_scalar_ulp.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_scalar_ulp.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a19b77432d91977ed6a5c11fd8be6717cb5ba97a --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_scalar_ulp.cpp @@ -0,0 +1,96 @@ +#include +#include + +static int test_ulp_float_dist() +{ + int Error = 0; + + float A = 1.0f; + + float B = glm::nextFloat(A); + Error += glm::notEqual(A, B, 0) ? 0 : 1; + float C = glm::prevFloat(B); + Error += glm::equal(A, C, 0) ? 0 : 1; + + int D = glm::floatDistance(A, B); + Error += D == 1 ? 0 : 1; + int E = glm::floatDistance(A, C); + Error += E == 0 ? 0 : 1; + + return Error; +} + +static int test_ulp_float_step() +{ + int Error = 0; + + float A = 1.0f; + + for(int i = 10; i < 1000; i *= 10) + { + float B = glm::nextFloat(A, i); + Error += glm::notEqual(A, B, 0) ? 0 : 1; + float C = glm::prevFloat(B, i); + Error += glm::equal(A, C, 0) ? 0 : 1; + + int D = glm::floatDistance(A, B); + Error += D == i ? 0 : 1; + int E = glm::floatDistance(A, C); + Error += E == 0 ? 0 : 1; + } + + return Error; +} + +static int test_ulp_double_dist() +{ + int Error = 0; + + double A = 1.0; + + double B = glm::nextFloat(A); + Error += glm::notEqual(A, B, 0) ? 0 : 1; + double C = glm::prevFloat(B); + Error += glm::equal(A, C, 0) ? 0 : 1; + + glm::int64 const D = glm::floatDistance(A, B); + Error += D == 1 ? 0 : 1; + glm::int64 const E = glm::floatDistance(A, C); + Error += E == 0 ? 0 : 1; + + return Error; +} + +static int test_ulp_double_step() +{ + int Error = 0; + + double A = 1.0; + + for(int i = 10; i < 1000; i *= 10) + { + double B = glm::nextFloat(A, i); + Error += glm::notEqual(A, B, 0) ? 0 : 1; + double C = glm::prevFloat(B, i); + Error += glm::equal(A, C, 0) ? 0 : 1; + + glm::int64 const D = glm::floatDistance(A, B); + Error += D == i ? 0 : 1; + glm::int64 const E = glm::floatDistance(A, C); + Error += E == 0 ? 0 : 1; + } + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_ulp_float_dist(); + Error += test_ulp_float_step(); + Error += test_ulp_double_dist(); + Error += test_ulp_double_step(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vec1.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vec1.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fc0b931878bc918c8a2dbbb5ab88068acf73b1aa --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vec1.cpp @@ -0,0 +1,157 @@ +#define GLM_FORCE_SWIZZLE +#include +#include +#include + +static glm::vec1 g1; +static glm::vec1 g2(1); + +static int test_vec1_operators() +{ + int Error(0); + + glm::ivec1 A(1); + glm::ivec1 B(1); + { + bool R = A != B; + bool S = A == B; + + Error += (S && !R) ? 0 : 1; + } + + { + A *= 1; + B *= 1; + A += 1; + B += 1; + + bool R = A != B; + bool S = A == B; + + Error += (S && !R) ? 0 : 1; + } + + return Error; +} + +static int test_vec1_ctor() +{ + int Error = 0; + +# if GLM_HAS_TRIVIAL_QUERIES + // Error += std::is_trivially_default_constructible::value ? 0 : 1; + // Error += std::is_trivially_copy_assignable::value ? 0 : 1; + Error += std::is_trivially_copyable::value ? 0 : 1; + Error += std::is_trivially_copyable::value ? 0 : 1; + Error += std::is_trivially_copyable::value ? 0 : 1; + Error += std::is_trivially_copyable::value ? 0 : 1; + + Error += std::is_copy_constructible::value ? 0 : 1; +# endif + + + { + glm::ivec1 A = glm::vec1(2.0f); + + glm::ivec1 E(glm::dvec1(2.0)); + Error += A == E ? 0 : 1; + + glm::ivec1 F(glm::ivec1(2)); + Error += A == F ? 0 : 1; + } + + return Error; +} + +static int test_vec1_size() +{ + int Error = 0; + + Error += sizeof(glm::vec1) == sizeof(glm::mediump_vec1) ? 0 : 1; + Error += 4 == sizeof(glm::mediump_vec1) ? 0 : 1; + Error += sizeof(glm::dvec1) == sizeof(glm::highp_dvec1) ? 0 : 1; + Error += 8 == sizeof(glm::highp_dvec1) ? 0 : 1; + Error += glm::vec1().length() == 1 ? 0 : 1; + Error += glm::dvec1().length() == 1 ? 0 : 1; + Error += glm::vec1::length() == 1 ? 0 : 1; + Error += glm::dvec1::length() == 1 ? 0 : 1; + + GLM_CONSTEXPR std::size_t Length = glm::vec1::length(); + Error += Length == 1 ? 0 : 1; + + return Error; +} + +static int test_vec1_operator_increment() +{ + int Error(0); + + glm::ivec1 v0(1); + glm::ivec1 v1(v0); + glm::ivec1 v2(v0); + glm::ivec1 v3 = ++v1; + glm::ivec1 v4 = v2++; + + Error += glm::all(glm::equal(v0, v4)) ? 0 : 1; + Error += glm::all(glm::equal(v1, v2)) ? 0 : 1; + Error += glm::all(glm::equal(v1, v3)) ? 0 : 1; + + int i0(1); + int i1(i0); + int i2(i0); + int i3 = ++i1; + int i4 = i2++; + + Error += i0 == i4 ? 0 : 1; + Error += i1 == i2 ? 0 : 1; + Error += i1 == i3 ? 0 : 1; + + return Error; +} + +static int test_bvec1_ctor() +{ + int Error = 0; + + glm::bvec1 const A(true); + glm::bvec1 const B(true); + glm::bvec1 const C(false); + glm::bvec1 const D = A && B; + glm::bvec1 const E = A && C; + glm::bvec1 const F = A || C; + + Error += D == glm::bvec1(true) ? 0 : 1; + Error += E == glm::bvec1(false) ? 0 : 1; + Error += F == glm::bvec1(true) ? 0 : 1; + + bool const G = A == C; + bool const H = A != C; + Error += !G ? 0 : 1; + Error += H ? 0 : 1; + + return Error; +} + +static int test_constexpr() +{ +#if GLM_HAS_CONSTEXPR + static_assert(glm::vec1::length() == 1, "GLM: Failed constexpr"); + static_assert(glm::vec1(1.0f).x > 0.0f, "GLM: Failed constexpr"); +#endif + + return 0; +} + +int main() +{ + int Error = 0; + + Error += test_vec1_size(); + Error += test_vec1_ctor(); + Error += test_bvec1_ctor(); + Error += test_vec1_operators(); + Error += test_vec1_operator_increment(); + Error += test_constexpr(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_bool1.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_bool1.cpp new file mode 100644 index 0000000000000000000000000000000000000000..43eed57b1e0913452edfcad9e4f0f189ff0723da --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_bool1.cpp @@ -0,0 +1,104 @@ +#include +#include + +template +static int test_operators() +{ + int Error = 0; + + genType const A(true); + genType const B(true); + { + bool const R = A != B; + bool const S = A == B; + Error += (S && !R) ? 0 : 1; + } + + return Error; +} + +template +static int test_ctor() +{ + int Error = 0; + + glm::bvec1 const A = genType(true); + + glm::bvec1 const E(genType(true)); + Error += A == E ? 0 : 1; + + glm::bvec1 const F(E); + Error += A == F ? 0 : 1; + + return Error; +} + +template +static int test_size() +{ + int Error = 0; + + Error += sizeof(glm::bvec1) == sizeof(genType) ? 0 : 1; + Error += genType().length() == 1 ? 0 : 1; + Error += genType::length() == 1 ? 0 : 1; + + return Error; +} + +template +static int test_relational() +{ + int Error = 0; + + genType const A(true); + genType const B(true); + genType const C(false); + + Error += A == B ? 0 : 1; + Error += (A && B) == A ? 0 : 1; + Error += (A || C) == A ? 0 : 1; + + return Error; +} + +template +static int test_constexpr() +{ +# if GLM_HAS_CONSTEXPR + static_assert(genType::length() == 1, "GLM: Failed constexpr"); +# endif + + return 0; +} + +int main() +{ + int Error = 0; + + Error += test_operators(); + Error += test_operators(); + Error += test_operators(); + Error += test_operators(); + + Error += test_ctor(); + Error += test_ctor(); + Error += test_ctor(); + Error += test_ctor(); + + Error += test_size(); + Error += test_size(); + Error += test_size(); + Error += test_size(); + + Error += test_relational(); + Error += test_relational(); + Error += test_relational(); + Error += test_relational(); + + Error += test_constexpr(); + Error += test_constexpr(); + Error += test_constexpr(); + Error += test_constexpr(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_common.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_common.cpp new file mode 100644 index 0000000000000000000000000000000000000000..211003fcabc813993663355611da2213ec3748b4 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_common.cpp @@ -0,0 +1,365 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if ((GLM_LANG & GLM_LANG_CXX11_FLAG) || (GLM_COMPILER & GLM_COMPILER_VC)) +# define GLM_NAN(T) NAN +#else +# define GLM_NAN(T) (static_cast(0.0f) / static_cast(0.0f)) +#endif + +template +static int test_min() +{ + typedef typename vecType::value_type T; + + int Error = 0; + + vecType const N(static_cast(0)); + vecType const B(static_cast(1)); + + Error += glm::all(glm::equal(glm::min(N, B), N, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::min(B, N), N, glm::epsilon())) ? 0 : 1; + + vecType const C(static_cast(2)); + Error += glm::all(glm::equal(glm::min(N, B, C), N, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::min(B, N, C), N, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::min(C, N, B), N, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::min(C, B, N), N, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::min(B, C, N), N, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::min(N, C, B), N, glm::epsilon())) ? 0 : 1; + + vecType const D(static_cast(3)); + Error += glm::all(glm::equal(glm::min(D, N, B, C), N, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::min(B, D, N, C), N, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::min(C, N, D, B), N, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::min(C, B, D, N), N, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::min(B, C, N, D), N, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::min(N, C, B, D), N, glm::epsilon())) ? 0 : 1; + + return Error; +} + +template +static int test_min_nan() +{ + typedef typename vecType::value_type T; + + int Error = 0; + + vecType const B(static_cast(1)); + vecType const N(GLM_NAN(T)); + + Error += glm::all(glm::isnan(glm::min(N, B))) ? 0 : 1; + Error += !glm::all(glm::isnan(glm::min(B, N))) ? 0 : 1; + + vecType const C(static_cast(2)); + Error += glm::all(glm::isnan(glm::min(N, B, C))) ? 0 : 1; + Error += !glm::all(glm::isnan(glm::min(B, N, C))) ? 0 : 1; + Error += !glm::all(glm::isnan(glm::min(C, N, B))) ? 0 : 1; + Error += !glm::all(glm::isnan(glm::min(C, B, N))) ? 0 : 1; + Error += !glm::all(glm::isnan(glm::min(B, C, N))) ? 0 : 1; + Error += glm::all(glm::isnan(glm::min(N, C, B))) ? 0 : 1; + + vecType const D(static_cast(3)); + Error += !glm::all(glm::isnan(glm::min(D, N, B, C))) ? 0 : 1; + Error += !glm::all(glm::isnan(glm::min(B, D, N, C))) ? 0 : 1; + Error += !glm::all(glm::isnan(glm::min(C, N, D, B))) ? 0 : 1; + Error += !glm::all(glm::isnan(glm::min(C, B, D, N))) ? 0 : 1; + Error += !glm::all(glm::isnan(glm::min(B, C, N, D))) ? 0 : 1; + Error += glm::all(glm::isnan(glm::min(N, C, B, D))) ? 0 : 1; + + return Error; +} + +template +static int test_max() +{ + typedef typename vecType::value_type T; + + int Error = 0; + + vecType const N(static_cast(0)); + vecType const B(static_cast(1)); + Error += glm::all(glm::equal(glm::max(N, B), B, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::max(B, N), B, glm::epsilon())) ? 0 : 1; + + vecType const C(static_cast(2)); + Error += glm::all(glm::equal(glm::max(N, B, C), C, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::max(B, N, C), C, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::max(C, N, B), C, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::max(C, B, N), C, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::max(B, C, N), C, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::max(N, C, B), C, glm::epsilon())) ? 0 : 1; + + vecType const D(static_cast(3)); + Error += glm::all(glm::equal(glm::max(D, N, B, C), D, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::max(B, D, N, C), D, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::max(C, N, D, B), D, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::max(C, B, D, N), D, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::max(B, C, N, D), D, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::max(N, C, B, D), D, glm::epsilon())) ? 0 : 1; + + return Error; +} + +template +static int test_max_nan() +{ + typedef typename vecType::value_type T; + + int Error = 0; + + vecType const B(static_cast(1)); + vecType const N(GLM_NAN(T)); + + Error += glm::all(glm::isnan(glm::max(N, B))) ? 0 : 1; + Error += !glm::all(glm::isnan(glm::max(B, N))) ? 0 : 1; + + vecType const C(static_cast(2)); + Error += glm::all(glm::isnan(glm::max(N, B, C))) ? 0 : 1; + Error += !glm::all(glm::isnan(glm::max(B, N, C))) ? 0 : 1; + Error += !glm::all(glm::isnan(glm::max(C, N, B))) ? 0 : 1; + Error += !glm::all(glm::isnan(glm::max(C, B, N))) ? 0 : 1; + Error += !glm::all(glm::isnan(glm::max(B, C, N))) ? 0 : 1; + Error += glm::all(glm::isnan(glm::max(N, C, B))) ? 0 : 1; + + vecType const D(static_cast(3)); + Error += !glm::all(glm::isnan(glm::max(D, N, B, C))) ? 0 : 1; + Error += !glm::all(glm::isnan(glm::max(B, D, N, C))) ? 0 : 1; + Error += !glm::all(glm::isnan(glm::max(C, N, D, B))) ? 0 : 1; + Error += !glm::all(glm::isnan(glm::max(C, B, D, N))) ? 0 : 1; + Error += !glm::all(glm::isnan(glm::max(B, C, N, D))) ? 0 : 1; + Error += glm::all(glm::isnan(glm::max(N, C, B, D))) ? 0 : 1; + + return Error; +} + +template +static int test_fmin() +{ + typedef typename vecType::value_type T; + + int Error = 0; + + vecType const B(static_cast(1)); + vecType const N(GLM_NAN(T)); + + Error += glm::all(glm::equal(glm::fmin(N, B), B, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::fmin(B, N), B, glm::epsilon())) ? 0 : 1; + + vecType const C(static_cast(2)); + Error += glm::all(glm::equal(glm::fmin(N, B, C), B, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::fmin(B, N, C), B, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::fmin(C, N, B), B, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::fmin(C, B, N), B, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::fmin(B, C, N), B, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::fmin(N, C, B), B, glm::epsilon())) ? 0 : 1; + + vecType const D(static_cast(3)); + Error += glm::all(glm::equal(glm::fmin(D, N, B, C), B, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::fmin(B, D, N, C), B, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::fmin(C, N, D, B), B, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::fmin(C, B, D, N), B, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::fmin(B, C, N, D), B, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::fmin(N, C, B, D), B, glm::epsilon())) ? 0 : 1; + + return Error; +} + +template +static int test_fmax() +{ + typedef typename vecType::value_type T; + + int Error = 0; + + vecType const B(static_cast(1)); + vecType const N(GLM_NAN(T)); + + Error += glm::all(glm::equal(glm::fmax(N, B), B, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::fmax(B, N), B, glm::epsilon())) ? 0 : 1; + + vecType const C(static_cast(2)); + Error += glm::all(glm::equal(glm::fmax(N, B, C), C, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::fmax(B, N, C), C, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::fmax(C, N, B), C, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::fmax(C, B, N), C, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::fmax(B, C, N), C, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::fmax(N, C, B), C, glm::epsilon())) ? 0 : 1; + + vecType const D(static_cast(3)); + Error += glm::all(glm::equal(glm::fmax(D, N, B, C), D, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::fmax(B, D, N, C), D, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::fmax(C, N, D, B), D, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::fmax(C, B, D, N), D, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::fmax(B, C, N, D), D, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::fmax(N, C, B, D), D, glm::epsilon())) ? 0 : 1; + + return Error; +} + +static int test_clamp() +{ + int Error = 0; + + glm::vec2 K = glm::clamp(glm::vec2(0.5f)); + Error += glm::all(glm::equal(K, glm::vec2(0.5f), glm::vec2(0.00001f))) ? 0 : 1; + + glm::vec3 L = glm::clamp(glm::vec3(0.5f)); + Error += glm::all(glm::equal(L, glm::vec3(0.5f), glm::vec3(0.00001f))) ? 0 : 1; + + glm::vec4 M = glm::clamp(glm::vec4(0.5f)); + Error += glm::all(glm::equal(M, glm::vec4(0.5f), glm::vec4(0.00001f))) ? 0 : 1; + + glm::vec1 N = glm::clamp(glm::vec1(0.5f)); + Error += glm::all(glm::equal(N, glm::vec1(0.5f), glm::vec1(0.00001f))) ? 0 : 1; + + return Error; +} + +static int test_repeat() +{ + int Error = 0; + + glm::vec2 K = glm::repeat(glm::vec2(0.5f)); + Error += glm::all(glm::equal(K, glm::vec2(0.5f), glm::vec2(0.00001f))) ? 0 : 1; + + glm::vec3 L = glm::repeat(glm::vec3(0.5f)); + Error += glm::all(glm::equal(L, glm::vec3(0.5f), glm::vec3(0.00001f))) ? 0 : 1; + + glm::vec4 M = glm::repeat(glm::vec4(0.5f)); + Error += glm::all(glm::equal(M, glm::vec4(0.5f), glm::vec4(0.00001f))) ? 0 : 1; + + glm::vec1 N = glm::repeat(glm::vec1(0.5f)); + Error += glm::all(glm::equal(N, glm::vec1(0.5f), glm::vec1(0.00001f))) ? 0 : 1; + + return Error; +} + +static int test_mirrorClamp() +{ + int Error = 0; + + glm::vec2 K = glm::mirrorClamp(glm::vec2(0.5f)); + Error += glm::all(glm::equal(K, glm::vec2(0.5f), glm::vec2(0.00001f))) ? 0 : 1; + + glm::vec3 L = glm::mirrorClamp(glm::vec3(0.5f)); + Error += glm::all(glm::equal(L, glm::vec3(0.5f), glm::vec3(0.00001f))) ? 0 : 1; + + glm::vec4 M = glm::mirrorClamp(glm::vec4(0.5f)); + Error += glm::all(glm::equal(M, glm::vec4(0.5f), glm::vec4(0.00001f))) ? 0 : 1; + + glm::vec1 N = glm::mirrorClamp(glm::vec1(0.5f)); + Error += glm::all(glm::equal(N, glm::vec1(0.5f), glm::vec1(0.00001f))) ? 0 : 1; + + return Error; +} + +static int test_mirrorRepeat() +{ + int Error = 0; + + glm::vec2 K = glm::mirrorRepeat(glm::vec2(0.5f)); + Error += glm::all(glm::equal(K, glm::vec2(0.5f), glm::vec2(0.00001f))) ? 0 : 1; + + glm::vec3 L = glm::mirrorRepeat(glm::vec3(0.5f)); + Error += glm::all(glm::equal(L, glm::vec3(0.5f), glm::vec3(0.00001f))) ? 0 : 1; + + glm::vec4 M = glm::mirrorRepeat(glm::vec4(0.5f)); + Error += glm::all(glm::equal(M, glm::vec4(0.5f), glm::vec4(0.00001f))) ? 0 : 1; + + glm::vec1 N = glm::mirrorRepeat(glm::vec1(0.5f)); + Error += glm::all(glm::equal(N, glm::vec1(0.5f), glm::vec1(0.00001f))) ? 0 : 1; + + return Error; +} + +static int test_iround() +{ + int Error = 0; + + for(float f = 0.0f; f < 3.1f; f += 0.05f) + { + int RoundFast = static_cast(glm::iround(f)); + int RoundSTD = static_cast(glm::round(f)); + Error += RoundFast == RoundSTD ? 0 : 1; + assert(!Error); + } + + return Error; +} + +static int test_uround() +{ + int Error = 0; + + for(float f = 0.0f; f < 3.1f; f += 0.05f) + { + int RoundFast = static_cast(glm::uround(f)); + int RoundSTD = static_cast(glm::round(f)); + Error += RoundFast == RoundSTD ? 0 : 1; + assert(!Error); + } + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_min(); + Error += test_min(); + Error += test_min_nan(); + Error += test_min_nan(); + + Error += test_max(); + Error += test_max(); + Error += test_max_nan(); + Error += test_max_nan(); + + Error += test_fmin(); + Error += test_fmin(); + + Error += test_fmax(); + Error += test_fmax(); + + Error += test_clamp(); + Error += test_repeat(); + Error += test_mirrorClamp(); + Error += test_mirrorRepeat(); + + Error += test_iround(); + Error += test_uround(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_iec559.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_iec559.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5a9da506931490576fc260840b0fde162fab0047 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_iec559.cpp @@ -0,0 +1,166 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +template +static int test_operators() +{ + typedef typename genType::value_type valType; + + int Error = 0; + + { + genType const A(1); + genType const B(1); + + genType const C = A + B; + Error += glm::all(glm::equal(C, genType(2), glm::epsilon())) ? 0 : 1; + + genType const D = A - B; + Error += glm::all(glm::equal(D, genType(0), glm::epsilon())) ? 0 : 1; + + genType const E = A * B; + Error += glm::all(glm::equal(E, genType(1), glm::epsilon())) ? 0 : 1; + + genType const F = A / B; + Error += glm::all(glm::equal(F, genType(1), glm::epsilon())) ? 0 : 1; + } + + return Error; +} + +template +static int test_ctor() +{ + typedef typename genType::value_type T; + + int Error = 0; + + glm::vec<1, T> const A = genType(1); + + glm::vec<1, T> const E(genType(1)); + Error += glm::all(glm::equal(A, E, glm::epsilon())) ? 0 : 1; + + glm::vec<1, T> const F(E); + Error += glm::all(glm::equal(A, F, glm::epsilon())) ? 0 : 1; + + genType const B = genType(1); + genType const G(glm::vec<2, T>(1)); + Error += glm::all(glm::equal(B, G, glm::epsilon())) ? 0 : 1; + + genType const H(glm::vec<3, T>(1)); + Error += glm::all(glm::equal(B, H, glm::epsilon())) ? 0 : 1; + + genType const I(glm::vec<4, T>(1)); + Error += glm::all(glm::equal(B, I, glm::epsilon())) ? 0 : 1; + + return Error; +} + +template +static int test_size() +{ + typedef typename genType::value_type T; + + int Error = 0; + + Error += sizeof(glm::vec<1, T>) == sizeof(genType) ? 0 : 1; + Error += genType().length() == 1 ? 0 : 1; + Error += genType::length() == 1 ? 0 : 1; + + return Error; +} + +template +static int test_relational() +{ + typedef typename genType::value_type valType; + + int Error = 0; + + genType const A(1); + genType const B(1); + genType const C(0); + + Error += all(equal(A, B, glm::epsilon())) ? 0 : 1; + Error += any(notEqual(A, C, glm::epsilon())) ? 0 : 1; + + return Error; +} + +template +static int test_constexpr() +{ +# if GLM_CONFIG_CONSTEXP == GLM_ENABLE + static_assert(genType::length() == 1, "GLM: Failed constexpr"); +# endif + + return 0; +} + +int main() +{ + int Error = 0; + + Error += test_operators(); + Error += test_operators(); + Error += test_operators(); + Error += test_operators(); + + Error += test_ctor(); + Error += test_ctor(); + Error += test_ctor(); + Error += test_ctor(); + + Error += test_size(); + Error += test_size(); + Error += test_size(); + Error += test_size(); + + Error += test_relational(); + Error += test_relational(); + Error += test_relational(); + Error += test_relational(); + + Error += test_constexpr(); + Error += test_constexpr(); + Error += test_constexpr(); + Error += test_constexpr(); + + Error += test_operators(); + Error += test_operators(); + Error += test_operators(); + Error += test_operators(); + + Error += test_ctor(); + Error += test_ctor(); + Error += test_ctor(); + Error += test_ctor(); + + Error += test_size(); + Error += test_size(); + Error += test_size(); + Error += test_size(); + + Error += test_relational(); + Error += test_relational(); + Error += test_relational(); + Error += test_relational(); + + Error += test_constexpr(); + Error += test_constexpr(); + Error += test_constexpr(); + Error += test_constexpr(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_int1_sized.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_int1_sized.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c262f495d516537e4cf2fddf155b9cabe3a26cda --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_int1_sized.cpp @@ -0,0 +1,41 @@ +#include + +#if GLM_HAS_STATIC_ASSERT + static_assert(sizeof(glm::i8vec1) == 1, "int8 size isn't 1 byte on this platform"); + static_assert(sizeof(glm::i16vec1) == 2, "int16 size isn't 2 bytes on this platform"); + static_assert(sizeof(glm::i32vec1) == 4, "int32 size isn't 4 bytes on this platform"); + static_assert(sizeof(glm::i64vec1) == 8, "int64 size isn't 8 bytes on this platform"); +#endif + +static int test_size() +{ + int Error = 0; + + Error += sizeof(glm::i8vec1) == 1 ? 0 : 1; + Error += sizeof(glm::i16vec1) == 2 ? 0 : 1; + Error += sizeof(glm::i32vec1) == 4 ? 0 : 1; + Error += sizeof(glm::i64vec1) == 8 ? 0 : 1; + + return Error; +} + +static int test_comp() +{ + int Error = 0; + + Error += sizeof(glm::i8vec1) < sizeof(glm::i16vec1) ? 0 : 1; + Error += sizeof(glm::i16vec1) < sizeof(glm::i32vec1) ? 0 : 1; + Error += sizeof(glm::i32vec1) < sizeof(glm::i64vec1) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_size(); + Error += test_comp(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_int2_sized.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_int2_sized.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f4ad8b6be58998697a32a34ff08252367714517e --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_int2_sized.cpp @@ -0,0 +1,41 @@ +#include + +#if GLM_HAS_STATIC_ASSERT + static_assert(sizeof(glm::i8vec2) == 2, "int8 size isn't 1 byte on this platform"); + static_assert(sizeof(glm::i16vec2) == 4, "int16 size isn't 2 bytes on this platform"); + static_assert(sizeof(glm::i32vec2) == 8, "int32 size isn't 4 bytes on this platform"); + static_assert(sizeof(glm::i64vec2) == 16, "int64 size isn't 8 bytes on this platform"); +#endif + +static int test_size() +{ + int Error = 0; + + Error += sizeof(glm::i8vec2) == 2 ? 0 : 1; + Error += sizeof(glm::i16vec2) == 4 ? 0 : 1; + Error += sizeof(glm::i32vec2) == 8 ? 0 : 1; + Error += sizeof(glm::i64vec2) == 16 ? 0 : 1; + + return Error; +} + +static int test_comp() +{ + int Error = 0; + + Error += sizeof(glm::i8vec2) < sizeof(glm::i16vec2) ? 0 : 1; + Error += sizeof(glm::i16vec2) < sizeof(glm::i32vec2) ? 0 : 1; + Error += sizeof(glm::i32vec2) < sizeof(glm::i64vec2) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_size(); + Error += test_comp(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_int3_sized.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_int3_sized.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c51bfe71222f4827955cba5e80d3e7a954f5ce5a --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_int3_sized.cpp @@ -0,0 +1,41 @@ +#include + +#if GLM_HAS_STATIC_ASSERT + static_assert(sizeof(glm::i8vec3) == 3, "int8 size isn't 1 byte on this platform"); + static_assert(sizeof(glm::i16vec3) == 6, "int16 size isn't 2 bytes on this platform"); + static_assert(sizeof(glm::i32vec3) == 12, "int32 size isn't 4 bytes on this platform"); + static_assert(sizeof(glm::i64vec3) == 24, "int64 size isn't 8 bytes on this platform"); +#endif + +static int test_size() +{ + int Error = 0; + + Error += sizeof(glm::i8vec3) == 3 ? 0 : 1; + Error += sizeof(glm::i16vec3) == 6 ? 0 : 1; + Error += sizeof(glm::i32vec3) == 12 ? 0 : 1; + Error += sizeof(glm::i64vec3) == 24 ? 0 : 1; + + return Error; +} + +static int test_comp() +{ + int Error = 0; + + Error += sizeof(glm::i8vec3) < sizeof(glm::i16vec3) ? 0 : 1; + Error += sizeof(glm::i16vec3) < sizeof(glm::i32vec3) ? 0 : 1; + Error += sizeof(glm::i32vec3) < sizeof(glm::i64vec3) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_size(); + Error += test_comp(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_int4_sized.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_int4_sized.cpp new file mode 100644 index 0000000000000000000000000000000000000000..93fd9ed2fcdf8f482ccb3426b3909c329273f98c --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_int4_sized.cpp @@ -0,0 +1,41 @@ +#include + +#if GLM_HAS_STATIC_ASSERT +static_assert(sizeof(glm::i8vec4) == 4, "int8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::i16vec4) == 8, "int16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::i32vec4) == 16, "int32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::i64vec4) == 32, "int64 size isn't 8 bytes on this platform"); +#endif + +static int test_size() +{ + int Error = 0; + + Error += sizeof(glm::i8vec4) == 4 ? 0 : 1; + Error += sizeof(glm::i16vec4) == 8 ? 0 : 1; + Error += sizeof(glm::i32vec4) == 16 ? 0 : 1; + Error += sizeof(glm::i64vec4) == 32 ? 0 : 1; + + return Error; +} + +static int test_comp() +{ + int Error = 0; + + Error += sizeof(glm::i8vec4) < sizeof(glm::i16vec4) ? 0 : 1; + Error += sizeof(glm::i16vec4) < sizeof(glm::i32vec4) ? 0 : 1; + Error += sizeof(glm::i32vec4) < sizeof(glm::i64vec4) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_size(); + Error += test_comp(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_integer.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_integer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d7278d38462d5e2bc92cb3988e5f30fa3d132ca5 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_integer.cpp @@ -0,0 +1,547 @@ +#include +#include +#include +#include +#include +#include + +namespace isPowerOfTwo +{ + template + struct type + { + genType Value; + bool Return; + }; + + template + int test_int16() + { + type const Data[] = + { + { 0x0001, true }, + { 0x0002, true }, + { 0x0004, true }, + { 0x0080, true }, + { 0x0000, true }, + { 0x0003, false } + }; + + int Error = 0; + + for (std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + glm::vec const Result = glm::isPowerOfTwo(glm::vec(Data[i].Value)); + Error += glm::vec(Data[i].Return) == Result ? 0 : 1; + } + + return Error; + } + + template + int test_uint16() + { + type const Data[] = + { + { 0x0001, true }, + { 0x0002, true }, + { 0x0004, true }, + { 0x0000, true }, + { 0x0000, true }, + { 0x0003, false } + }; + + int Error = 0; + + for (std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + glm::vec const Result = glm::isPowerOfTwo(glm::vec(Data[i].Value)); + Error += glm::vec(Data[i].Return) == Result ? 0 : 1; + } + + return Error; + } + + template + int test_int32() + { + type const Data[] = + { + { 0x00000001, true }, + { 0x00000002, true }, + { 0x00000004, true }, + { 0x0000000f, false }, + { 0x00000000, true }, + { 0x00000003, false } + }; + + int Error = 0; + + for (std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + glm::vec const Result = glm::isPowerOfTwo(glm::vec(Data[i].Value)); + Error += glm::vec(Data[i].Return) == Result ? 0 : 1; + } + + return Error; + } + + template + int test_uint32() + { + type const Data[] = + { + { 0x00000001, true }, + { 0x00000002, true }, + { 0x00000004, true }, + { 0x80000000, true }, + { 0x00000000, true }, + { 0x00000003, false } + }; + + int Error = 0; + + for (std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + glm::vec const Result = glm::isPowerOfTwo(glm::vec(Data[i].Value)); + Error += glm::vec(Data[i].Return) == Result ? 0 : 1; + } + + return Error; + } + + int test() + { + int Error = 0; + + Error += test_int16<1>(); + Error += test_int16<2>(); + Error += test_int16<3>(); + Error += test_int16<4>(); + + Error += test_uint16<1>(); + Error += test_uint16<2>(); + Error += test_uint16<3>(); + Error += test_uint16<4>(); + + Error += test_int32<1>(); + Error += test_int32<2>(); + Error += test_int32<3>(); + Error += test_int32<4>(); + + Error += test_uint32<1>(); + Error += test_uint32<2>(); + Error += test_uint32<3>(); + Error += test_uint32<4>(); + + return Error; + } +}//isPowerOfTwo + +namespace prevPowerOfTwo +{ + template + int run() + { + int Error = 0; + + glm::vec const A = glm::prevPowerOfTwo(glm::vec(7)); + Error += A == glm::vec(4) ? 0 : 1; + + glm::vec const B = glm::prevPowerOfTwo(glm::vec(15)); + Error += B == glm::vec(8) ? 0 : 1; + + glm::vec const C = glm::prevPowerOfTwo(glm::vec(31)); + Error += C == glm::vec(16) ? 0 : 1; + + glm::vec const D = glm::prevPowerOfTwo(glm::vec(32)); + Error += D == glm::vec(32) ? 0 : 1; + + return Error; + } + + int test() + { + int Error = 0; + + Error += run<1, glm::int8>(); + Error += run<2, glm::int8>(); + Error += run<3, glm::int8>(); + Error += run<4, glm::int8>(); + + Error += run<1, glm::int16>(); + Error += run<2, glm::int16>(); + Error += run<3, glm::int16>(); + Error += run<4, glm::int16>(); + + Error += run<1, glm::int32>(); + Error += run<2, glm::int32>(); + Error += run<3, glm::int32>(); + Error += run<4, glm::int32>(); + + Error += run<1, glm::int64>(); + Error += run<2, glm::int64>(); + Error += run<3, glm::int64>(); + Error += run<4, glm::int64>(); + + Error += run<1, glm::uint8>(); + Error += run<2, glm::uint8>(); + Error += run<3, glm::uint8>(); + Error += run<4, glm::uint8>(); + + Error += run<1, glm::uint16>(); + Error += run<2, glm::uint16>(); + Error += run<3, glm::uint16>(); + Error += run<4, glm::uint16>(); + + Error += run<1, glm::uint32>(); + Error += run<2, glm::uint32>(); + Error += run<3, glm::uint32>(); + Error += run<4, glm::uint32>(); + + Error += run<1, glm::uint64>(); + Error += run<2, glm::uint64>(); + Error += run<3, glm::uint64>(); + Error += run<4, glm::uint64>(); + + return Error; + } +}//namespace prevPowerOfTwo + +namespace nextPowerOfTwo +{ + template + int run() + { + int Error = 0; + + glm::vec const A = glm::nextPowerOfTwo(glm::vec(7)); + Error += A == glm::vec(8) ? 0 : 1; + + glm::vec const B = glm::nextPowerOfTwo(glm::vec(15)); + Error += B == glm::vec(16) ? 0 : 1; + + glm::vec const C = glm::nextPowerOfTwo(glm::vec(31)); + Error += C == glm::vec(32) ? 0 : 1; + + glm::vec const D = glm::nextPowerOfTwo(glm::vec(32)); + Error += D == glm::vec(32) ? 0 : 1; + + return Error; + } + + int test() + { + int Error = 0; + + Error += run<1, glm::int8>(); + Error += run<2, glm::int8>(); + Error += run<3, glm::int8>(); + Error += run<4, glm::int8>(); + + Error += run<1, glm::int16>(); + Error += run<2, glm::int16>(); + Error += run<3, glm::int16>(); + Error += run<4, glm::int16>(); + + Error += run<1, glm::int32>(); + Error += run<2, glm::int32>(); + Error += run<3, glm::int32>(); + Error += run<4, glm::int32>(); + + Error += run<1, glm::int64>(); + Error += run<2, glm::int64>(); + Error += run<3, glm::int64>(); + Error += run<4, glm::int64>(); + + Error += run<1, glm::uint8>(); + Error += run<2, glm::uint8>(); + Error += run<3, glm::uint8>(); + Error += run<4, glm::uint8>(); + + Error += run<1, glm::uint16>(); + Error += run<2, glm::uint16>(); + Error += run<3, glm::uint16>(); + Error += run<4, glm::uint16>(); + + Error += run<1, glm::uint32>(); + Error += run<2, glm::uint32>(); + Error += run<3, glm::uint32>(); + Error += run<4, glm::uint32>(); + + Error += run<1, glm::uint64>(); + Error += run<2, glm::uint64>(); + Error += run<3, glm::uint64>(); + Error += run<4, glm::uint64>(); + + return Error; + } +}//namespace nextPowerOfTwo + +namespace prevMultiple +{ + template + struct type + { + genIUType Source; + genIUType Multiple; + genIUType Return; + }; + + template + int run() + { + type const Data[] = + { + { 8, 3, 6 }, + { 7, 7, 7 } + }; + + int Error = 0; + + for (std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + glm::vec const Result0 = glm::prevMultiple(glm::vec(Data[i].Source), Data[i].Multiple); + Error += glm::vec(Data[i].Return) == Result0 ? 0 : 1; + + glm::vec const Result1 = glm::prevMultiple(glm::vec(Data[i].Source), glm::vec(Data[i].Multiple)); + Error += glm::vec(Data[i].Return) == Result1 ? 0 : 1; + } + + return Error; + } + + int test() + { + int Error = 0; + + Error += run<1, glm::int8>(); + Error += run<2, glm::int8>(); + Error += run<3, glm::int8>(); + Error += run<4, glm::int8>(); + + Error += run<1, glm::int16>(); + Error += run<2, glm::int16>(); + Error += run<3, glm::int16>(); + Error += run<4, glm::int16>(); + + Error += run<1, glm::int32>(); + Error += run<2, glm::int32>(); + Error += run<3, glm::int32>(); + Error += run<4, glm::int32>(); + + Error += run<1, glm::int64>(); + Error += run<2, glm::int64>(); + Error += run<3, glm::int64>(); + Error += run<4, glm::int64>(); + + Error += run<1, glm::uint8>(); + Error += run<2, glm::uint8>(); + Error += run<3, glm::uint8>(); + Error += run<4, glm::uint8>(); + + Error += run<1, glm::uint16>(); + Error += run<2, glm::uint16>(); + Error += run<3, glm::uint16>(); + Error += run<4, glm::uint16>(); + + Error += run<1, glm::uint32>(); + Error += run<2, glm::uint32>(); + Error += run<3, glm::uint32>(); + Error += run<4, glm::uint32>(); + + Error += run<1, glm::uint64>(); + Error += run<2, glm::uint64>(); + Error += run<3, glm::uint64>(); + Error += run<4, glm::uint64>(); + + return Error; + } +}//namespace prevMultiple + +namespace nextMultiple +{ + template + struct type + { + genIUType Source; + genIUType Multiple; + genIUType Return; + }; + + template + int run() + { + type const Data[] = + { + { 3, 4, 4 }, + { 6, 3, 6 }, + { 5, 3, 6 }, + { 7, 7, 7 }, + { 0, 1, 0 }, + { 8, 3, 9 } + }; + + int Error = 0; + + for (std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + glm::vec const Result0 = glm::nextMultiple(glm::vec(Data[i].Source), glm::vec(Data[i].Multiple)); + Error += glm::vec(Data[i].Return) == Result0 ? 0 : 1; + + glm::vec const Result1 = glm::nextMultiple(glm::vec(Data[i].Source), Data[i].Multiple); + Error += glm::vec(Data[i].Return) == Result1 ? 0 : 1; + } + + return Error; + } + + int test() + { + int Error = 0; + + Error += run<1, glm::int8>(); + Error += run<2, glm::int8>(); + Error += run<3, glm::int8>(); + Error += run<4, glm::int8>(); + + Error += run<1, glm::int16>(); + Error += run<2, glm::int16>(); + Error += run<3, glm::int16>(); + Error += run<4, glm::int16>(); + + Error += run<1, glm::int32>(); + Error += run<2, glm::int32>(); + Error += run<3, glm::int32>(); + Error += run<4, glm::int32>(); + + Error += run<1, glm::int64>(); + Error += run<2, glm::int64>(); + Error += run<3, glm::int64>(); + Error += run<4, glm::int64>(); + + Error += run<1, glm::uint8>(); + Error += run<2, glm::uint8>(); + Error += run<3, glm::uint8>(); + Error += run<4, glm::uint8>(); + + Error += run<1, glm::uint16>(); + Error += run<2, glm::uint16>(); + Error += run<3, glm::uint16>(); + Error += run<4, glm::uint16>(); + + Error += run<1, glm::uint32>(); + Error += run<2, glm::uint32>(); + Error += run<3, glm::uint32>(); + Error += run<4, glm::uint32>(); + + Error += run<1, glm::uint64>(); + Error += run<2, glm::uint64>(); + Error += run<3, glm::uint64>(); + Error += run<4, glm::uint64>(); + + return Error; + } +}//namespace nextMultiple + +namespace findNSB +{ + template + struct type + { + T Source; + int SignificantBitCount; + int Return; + }; + + template + int run() + { + type const Data[] = + { + { 0x00, 1,-1 }, + { 0x01, 2,-1 }, + { 0x02, 2,-1 }, + { 0x06, 3,-1 }, + { 0x01, 1, 0 }, + { 0x03, 1, 0 }, + { 0x03, 2, 1 }, + { 0x07, 2, 1 }, + { 0x05, 2, 2 }, + { 0x0D, 2, 2 } + }; + + int Error = 0; + + for (std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + glm::vec const Result0 = glm::findNSB(glm::vec(Data[i].Source), glm::vec(Data[i].SignificantBitCount)); + Error += glm::vec(Data[i].Return) == Result0 ? 0 : 1; + assert(!Error); + } + + return Error; + } + + int test() + { + int Error = 0; + + Error += run<1, glm::uint8>(); + Error += run<2, glm::uint8>(); + Error += run<3, glm::uint8>(); + Error += run<4, glm::uint8>(); + + Error += run<1, glm::uint16>(); + Error += run<2, glm::uint16>(); + Error += run<3, glm::uint16>(); + Error += run<4, glm::uint16>(); + + Error += run<1, glm::uint32>(); + Error += run<2, glm::uint32>(); + Error += run<3, glm::uint32>(); + Error += run<4, glm::uint32>(); + + Error += run<1, glm::uint64>(); + Error += run<2, glm::uint64>(); + Error += run<3, glm::uint64>(); + Error += run<4, glm::uint64>(); + + Error += run<1, glm::int8>(); + Error += run<2, glm::int8>(); + Error += run<3, glm::int8>(); + Error += run<4, glm::int8>(); + + Error += run<1, glm::int16>(); + Error += run<2, glm::int16>(); + Error += run<3, glm::int16>(); + Error += run<4, glm::int16>(); + + Error += run<1, glm::int32>(); + Error += run<2, glm::int32>(); + Error += run<3, glm::int32>(); + Error += run<4, glm::int32>(); + + Error += run<1, glm::int64>(); + Error += run<2, glm::int64>(); + Error += run<3, glm::int64>(); + Error += run<4, glm::int64>(); + + + return Error; + } +}//namespace findNSB + +int main() +{ + int Error = 0; + + Error += isPowerOfTwo::test(); + Error += prevPowerOfTwo::test(); + Error += nextPowerOfTwo::test(); + Error += prevMultiple::test(); + Error += nextMultiple::test(); + Error += findNSB::test(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_integer_sized.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_integer_sized.cpp new file mode 100644 index 0000000000000000000000000000000000000000..52b3f4ef86363bf3ee62253e219c25c15035cd27 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_integer_sized.cpp @@ -0,0 +1,216 @@ +#include +#include +#include +#include +#include + +template +static int test_operators() +{ + int Error = 0; + + { + genType const A(1); + genType const B(1); + + bool const R = A != B; + bool const S = A == B; + Error += (S && !R) ? 0 : 1; + } + + { + genType const A(1); + genType const B(1); + + genType const C = A + B; + Error += C == genType(2) ? 0 : 1; + + genType const D = A - B; + Error += D == genType(0) ? 0 : 1; + + genType const E = A * B; + Error += E == genType(1) ? 0 : 1; + + genType const F = A / B; + Error += F == genType(1) ? 0 : 1; + } + + { + genType const A(3); + genType const B(2); + + genType const C = A % B; + Error += C == genType(1) ? 0 : 1; + } + + { + genType const A(1); + genType const B(1); + genType const C(0); + + genType const I = A & B; + Error += I == genType(1) ? 0 : 1; + genType const D = A & C; + Error += D == genType(0) ? 0 : 1; + + genType const E = A | B; + Error += E == genType(1) ? 0 : 1; + genType const F = A | C; + Error += F == genType(1) ? 0 : 1; + + genType const G = A ^ B; + Error += G == genType(0) ? 0 : 1; + genType const H = A ^ C; + Error += H == genType(1) ? 0 : 1; + } + + { + genType const A(0); + genType const B(1); + genType const C(2); + + genType const D = B << B; + Error += D == genType(2) ? 0 : 1; + genType const E = C >> B; + Error += E == genType(1) ? 0 : 1; + } + + return Error; +} + +template +static int test_ctor() +{ + typedef typename genType::value_type T; + + int Error = 0; + + genType const A = genType(1); + + genType const E(genType(1)); + Error += A == E ? 0 : 1; + + genType const F(E); + Error += A == F ? 0 : 1; + + genType const B = genType(1); + genType const G(glm::vec<2, T>(1)); + Error += B == G ? 0 : 1; + + genType const H(glm::vec<3, T>(1)); + Error += B == H ? 0 : 1; + + genType const I(glm::vec<4, T>(1)); + Error += B == I ? 0 : 1; + + return Error; +} + +template +static int test_size() +{ + int Error = 0; + + Error += sizeof(typename genType::value_type) == sizeof(genType) ? 0 : 1; + Error += genType().length() == 1 ? 0 : 1; + Error += genType::length() == 1 ? 0 : 1; + + return Error; +} + +template +static int test_relational() +{ + int Error = 0; + + genType const A(1); + genType const B(1); + genType const C(0); + + Error += A == B ? 0 : 1; + Error += A != C ? 0 : 1; + Error += all(equal(A, B)) ? 0 : 1; + Error += any(notEqual(A, C)) ? 0 : 1; + + return Error; +} + +template +static int test_constexpr() +{ +# if GLM_CONFIG_CONSTEXP == GLM_ENABLE + static_assert(genType::length() == 1, "GLM: Failed constexpr"); + static_assert(genType(1)[0] == 1, "GLM: Failed constexpr"); + static_assert(genType(1) == genType(1), "GLM: Failed constexpr"); + static_assert(genType(1) != genType(0), "GLM: Failed constexpr"); +# endif + + return 0; +} + +int main() +{ + int Error = 0; + + Error += test_operators(); + Error += test_operators(); + Error += test_operators(); + Error += test_operators(); + Error += test_operators(); + + Error += test_ctor(); + Error += test_ctor(); + Error += test_ctor(); + Error += test_ctor(); + Error += test_ctor(); + + Error += test_size(); + Error += test_size(); + Error += test_size(); + Error += test_size(); + Error += test_size(); + + Error += test_relational(); + Error += test_relational(); + Error += test_relational(); + Error += test_relational(); + Error += test_relational(); + + Error += test_constexpr(); + Error += test_constexpr(); + Error += test_constexpr(); + Error += test_constexpr(); + Error += test_constexpr(); + + Error += test_operators(); + Error += test_operators(); + Error += test_operators(); + Error += test_operators(); + Error += test_operators(); + + Error += test_ctor(); + Error += test_ctor(); + Error += test_ctor(); + Error += test_ctor(); + Error += test_ctor(); + + Error += test_size(); + Error += test_size(); + Error += test_size(); + Error += test_size(); + Error += test_size(); + + Error += test_relational(); + Error += test_relational(); + Error += test_relational(); + Error += test_relational(); + Error += test_relational(); + + Error += test_constexpr(); + Error += test_constexpr(); + Error += test_constexpr(); + Error += test_constexpr(); + Error += test_constexpr(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_packing.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_packing.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d7cbce21e84c56f91888f6cc1c7fa01570155334 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_packing.cpp @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include +#include +#include + +int test_packUnorm() +{ + int Error = 0; + + std::vector A; + A.push_back(glm::vec2(1.0f, 0.7f)); + A.push_back(glm::vec2(0.5f, 0.1f)); + + for (std::size_t i = 0; i < A.size(); ++i) + { + glm::vec2 B(A[i]); + glm::u16vec2 C = glm::packUnorm(B); + glm::vec2 D = glm::unpackUnorm(C); + Error += glm::all(glm::equal(B, D, 1.0f / 255.f)) ? 0 : 1; + assert(!Error); + } + + return Error; +} + +int test_packSnorm() +{ + int Error = 0; + + std::vector A; + A.push_back(glm::vec2(1.0f, 0.0f)); + A.push_back(glm::vec2(-0.5f, -0.7f)); + A.push_back(glm::vec2(-0.1f, 0.1f)); + + for (std::size_t i = 0; i < A.size(); ++i) + { + glm::vec2 B(A[i]); + glm::i16vec2 C = glm::packSnorm(B); + glm::vec2 D = glm::unpackSnorm(C); + Error += glm::all(glm::equal(B, D, 1.0f / 32767.0f * 2.0f)) ? 0 : 1; + assert(!Error); + } + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_packUnorm(); + Error += test_packSnorm(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_reciprocal.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_reciprocal.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f4b9f18b88fe0f3a270f64aa744979fe72caf7ca --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_reciprocal.cpp @@ -0,0 +1,186 @@ +#include +#include +#include +#include + +static int test_sec() +{ + int Error = 0; + + glm::dvec1 const a = glm::sec(glm::dvec1(0.0)); + Error += glm::all(glm::equal(a, glm::dvec1(1.0), 0.01)) ? 0 : 1; + + glm::dvec1 const b = glm::sec(glm::dvec1(glm::pi() * 2.0)); + Error += glm::all(glm::equal(b, glm::dvec1(1.0), 0.01)) ? 0 : 1; + + glm::dvec1 const c = glm::sec(glm::dvec1(glm::pi() * -2.0)); + Error += glm::all(glm::equal(c, glm::dvec1(1.0), 0.01)) ? 0 : 1; + + glm::dvec1 const d = glm::sec(glm::dvec1(glm::pi() * 1.0)); + Error += glm::all(glm::equal(d, -glm::dvec1(1.0), 0.01)) ? 0 : 1; + + glm::dvec1 const e = glm::sec(glm::dvec1(glm::pi() * -1.0)); + Error += glm::all(glm::equal(e, -glm::dvec1(1.0), 0.01)) ? 0 : 1; + + return Error; +} + +static int test_csc() +{ + int Error = 0; + + glm::dvec1 const a = glm::csc(glm::dvec1(glm::pi() * 0.5)); + Error += glm::all(glm::equal(a, glm::dvec1(1.0), 0.01)) ? 0 : 1; + + glm::dvec1 const b = glm::csc(glm::dvec1(glm::pi() * -0.5)); + Error += glm::all(glm::equal(b, glm::dvec1(-1.0), 0.01)) ? 0 : 1; + + return Error; +} + +static int test_cot() +{ + int Error = 0; + + glm::dvec1 const a = glm::cot(glm::dvec1(glm::pi() * 0.5)); + Error += glm::all(glm::equal(a, glm::dvec1(0.0), 0.01)) ? 0 : 1; + + glm::dvec1 const b = glm::cot(glm::dvec1(glm::pi() * -0.5)); + Error += glm::all(glm::equal(b, glm::dvec1(0.0), 0.01)) ? 0 : 1; + + return Error; +} + +static int test_asec() +{ + int Error = 0; + + Error += glm::all(glm::equal(glm::asec(glm::dvec1(100000.0)), glm::dvec1(glm::pi() * 0.5), 0.01)) ? 0 : 1; + Error += glm::all(glm::equal(glm::asec(glm::dvec1(-100000.0)), glm::dvec1(glm::pi() * 0.5), 0.01)) ? 0 : 1; + + return Error; +} + +static int test_acsc() +{ + int Error = 0; + + Error += glm::all(glm::equal(glm::acsc(glm::dvec1(100000.0)), glm::dvec1(0.0), 0.01)) ? 0 : 1; + Error += glm::all(glm::equal(glm::acsc(glm::dvec1(-100000.0)), glm::dvec1(0.0), 0.01)) ? 0 : 1; + + return Error; +} + +static int test_acot() +{ + int Error = 0; + + Error += glm::all(glm::equal(glm::acot(glm::dvec1(100000.0)), glm::dvec1(0.0), 0.01)) ? 0 : 1; + Error += glm::all(glm::equal(glm::acot(glm::dvec1(-100000.0)), glm::dvec1(glm::pi()), 0.01)) ? 0 : 1; + Error += glm::all(glm::equal(glm::acot(glm::dvec1(0.0)), glm::dvec1(glm::pi() * 0.5), 0.01)) ? 0 : 1; + + return Error; +} + +static int test_sech() +{ + int Error = 0; + + Error += glm::all(glm::equal(glm::sech(glm::dvec1(100000.0)), glm::dvec1(0.0), 0.01)) ? 0 : 1; + Error += glm::all(glm::equal(glm::sech(glm::dvec1(-100000.0)), glm::dvec1(0.0), 0.01)) ? 0 : 1; + Error += glm::all(glm::equal(glm::sech(glm::dvec1(0.0)), glm::dvec1(1.0), 0.01)) ? 0 : 1; + + return Error; +} + +static int test_csch() +{ + int Error = 0; + + Error += glm::all(glm::equal(glm::csch(glm::dvec1(100000.0)), glm::dvec1(0.0), 0.01)) ? 0 : 1; + Error += glm::all(glm::equal(glm::csch(glm::dvec1(-100000.0)), glm::dvec1(0.0), 0.01)) ? 0 : 1; + + return Error; +} + +static int test_coth() +{ + int Error = 0; + + glm::dvec1 const a = glm::coth(glm::dvec1(100.0)); + Error += glm::all(glm::equal(a, glm::dvec1(1.0), 0.01)) ? 0 : 1; + + glm::dvec1 const b = glm::coth(glm::dvec1(-100.0)); + Error += glm::all(glm::equal(b, glm::dvec1(-1.0), 0.01)) ? 0 : 1; + + return Error; +} + +static int test_asech() +{ + int Error = 0; + + glm::dvec1 const a = glm::asech(glm::dvec1(1.0)); + Error += glm::all(glm::equal(a, glm::dvec1(0.0), 0.01)) ? 0 : 1; + + return Error; +} + +static int test_acsch() +{ + int Error = 0; + + glm::dvec1 const a(glm::acsch(glm::dvec1(0.01))); + Error += a.x > 1.0 ? 0 : 1; + + glm::dvec1 const b(glm::acsch(glm::dvec1(-0.01))); + Error += b.x < -1.0 ? 0 : 1; + + Error += glm::all(glm::equal(glm::acsch(glm::dvec1(100.0)), glm::dvec1(0.0), 0.01)) ? 0 : 1; + Error += glm::all(glm::equal(glm::acsch(glm::dvec1(-100.0)), glm::dvec1(0.0), 0.01)) ? 0 : 1; + + return Error; +} + +static int test_acoth() +{ + int Error = 0; + + glm::dvec1 const a = glm::acoth(glm::dvec1(1.00001)); + Error += a.x > 6.0 ? 0 : 1; + + glm::dvec1 const b = glm::acoth(glm::dvec1(-1.00001)); + Error += b.x < -6.0 ? 0 : 1; + + glm::dvec1 const c = glm::acoth(glm::dvec1(10000.0)); + Error += glm::all(glm::equal(c, glm::dvec1(0.0), 0.01)) ? 0 : 1; + + glm::dvec1 const d = glm::acoth(glm::dvec1(-10000.0)); + Error += glm::all(glm::equal(d, glm::dvec1(0.0), 0.01)) ? 0 : 1; + + return Error; +} + + +int main() +{ + int Error = 0; + + Error += test_sec(); + Error += test_csc(); + Error += test_cot(); + + Error += test_asec(); + Error += test_acsc(); + Error += test_acot(); + + Error += test_sech(); + Error += test_csch(); + Error += test_coth(); + + Error += test_asech(); + Error += test_acsch(); + Error += test_acoth(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_relational.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_relational.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f6cd307144f9b96f01cc03c705d1793fbed44129 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_relational.cpp @@ -0,0 +1,205 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +template +static int test_equal() +{ + typedef typename vecType::value_type valType; + + valType const A = static_cast(1.01f); + valType const B = static_cast(1.02f); + valType const Epsilon1 = static_cast(0.1f); + valType const Epsilon2 = static_cast(0.001f); + + int Error = 0; + + Error += glm::all(glm::equal(vecType(A), vecType(B), Epsilon1)) ? 0 : 1; + Error += glm::all(glm::equal(vecType(A), vecType(B), vecType(Epsilon1))) ? 0 : 1; + + Error += !glm::any(glm::equal(vecType(A), vecType(B), Epsilon2)) ? 0 : 1; + Error += !glm::any(glm::equal(vecType(A), vecType(B), vecType(Epsilon2))) ? 0 : 1; + + return Error; +} + +template +static int test_notEqual() +{ + typedef typename vecType::value_type valType; + + valType const A = static_cast(1.01f); + valType const B = static_cast(1.02f); + valType const Epsilon1 = static_cast(0.1f); + valType const Epsilon2 = static_cast(0.001f); + + int Error = 0; + + Error += glm::all(glm::notEqual(vecType(A), vecType(B), Epsilon2)) ? 0 : 1; + Error += glm::all(glm::notEqual(vecType(A), vecType(B), vecType(Epsilon2))) ? 0 : 1; + + Error += !glm::any(glm::notEqual(vecType(A), vecType(B), Epsilon1)) ? 0 : 1; + Error += !glm::any(glm::notEqual(vecType(A), vecType(B), vecType(Epsilon1))) ? 0 : 1; + + return Error; +} + +template +static int test_constexpr() +{ +# if GLM_CONFIG_CONSTEXP == GLM_ENABLE + static_assert(glm::all(glm::equal(genType(static_cast(1.01f)), genType(static_cast(1.02f)), static_cast(0.1f))), "GLM: Failed constexpr"); +# endif + + return 0; +} + +template +static int test_equal_ulps() +{ + typedef glm::vec<4, T, glm::defaultp> vec4; + + T const One(1); + vec4 const Ones(1); + + int Error = 0; + + T const ULP1Plus = glm::nextFloat(One); + Error += glm::all(glm::equal(Ones, vec4(ULP1Plus), 1)) ? 0 : 1; + + T const ULP2Plus = glm::nextFloat(ULP1Plus); + Error += !glm::all(glm::equal(Ones, vec4(ULP2Plus), 1)) ? 0 : 1; + + T const ULP1Minus = glm::prevFloat(One); + Error += glm::all(glm::equal(Ones, vec4(ULP1Minus), 1)) ? 0 : 1; + + T const ULP2Minus = glm::prevFloat(ULP1Minus); + Error += !glm::all(glm::equal(Ones, vec4(ULP2Minus), 1)) ? 0 : 1; + + return Error; +} + +template +static int test_notEqual_ulps() +{ + typedef glm::vec<4, T, glm::defaultp> vec4; + + T const One(1); + vec4 const Ones(1); + + int Error = 0; + + T const ULP1Plus = glm::nextFloat(One); + Error += !glm::all(glm::notEqual(Ones, vec4(ULP1Plus), 1)) ? 0 : 1; + + T const ULP2Plus = glm::nextFloat(ULP1Plus); + Error += glm::all(glm::notEqual(Ones, vec4(ULP2Plus), 1)) ? 0 : 1; + + T const ULP1Minus = glm::prevFloat(One); + Error += !glm::all(glm::notEqual(Ones, vec4(ULP1Minus), 1)) ? 0 : 1; + + T const ULP2Minus = glm::prevFloat(ULP1Minus); + Error += glm::all(glm::notEqual(Ones, vec4(ULP2Minus), 1)) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_equal_ulps(); + Error += test_equal_ulps(); + Error += test_notEqual_ulps(); + Error += test_notEqual_ulps(); + + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + Error += test_equal(); + + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + Error += test_notEqual(); + + Error += test_constexpr(); + Error += test_constexpr(); + Error += test_constexpr(); + Error += test_constexpr(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_uint1_sized.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_uint1_sized.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f2e4624f86337e6007ec18c21329ca29848113db --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_uint1_sized.cpp @@ -0,0 +1,41 @@ +#include + +#if GLM_HAS_STATIC_ASSERT + static_assert(sizeof(glm::u8vec1) == 1, "uint8 size isn't 1 byte on this platform"); + static_assert(sizeof(glm::u16vec1) == 2, "uint16 size isn't 2 bytes on this platform"); + static_assert(sizeof(glm::u32vec1) == 4, "uint32 size isn't 4 bytes on this platform"); + static_assert(sizeof(glm::u64vec1) == 8, "uint64 size isn't 8 bytes on this platform"); +#endif + +static int test_size() +{ + int Error = 0; + + Error += sizeof(glm::u8vec1) == 1 ? 0 : 1; + Error += sizeof(glm::u16vec1) == 2 ? 0 : 1; + Error += sizeof(glm::u32vec1) == 4 ? 0 : 1; + Error += sizeof(glm::u64vec1) == 8 ? 0 : 1; + + return Error; +} + +static int test_comp() +{ + int Error = 0; + + Error += sizeof(glm::u8vec1) < sizeof(glm::u16vec1) ? 0 : 1; + Error += sizeof(glm::u16vec1) < sizeof(glm::u32vec1) ? 0 : 1; + Error += sizeof(glm::u32vec1) < sizeof(glm::u64vec1) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_size(); + Error += test_comp(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_uint2_sized.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_uint2_sized.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9c0977ee27c75db9f0d36bc719536c3f560d48be --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_uint2_sized.cpp @@ -0,0 +1,41 @@ +#include + +#if GLM_HAS_STATIC_ASSERT +static_assert(sizeof(glm::u8vec2) == 2, "int8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::u16vec2) == 4, "int16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::u32vec2) == 8, "int32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::u64vec2) == 16, "int64 size isn't 8 bytes on this platform"); +#endif + +static int test_size() +{ + int Error = 0; + + Error += sizeof(glm::u8vec2) == 2 ? 0 : 1; + Error += sizeof(glm::u16vec2) == 4 ? 0 : 1; + Error += sizeof(glm::u32vec2) == 8 ? 0 : 1; + Error += sizeof(glm::u64vec2) == 16 ? 0 : 1; + + return Error; +} + +static int test_comp() +{ + int Error = 0; + + Error += sizeof(glm::u8vec2) < sizeof(glm::u16vec2) ? 0 : 1; + Error += sizeof(glm::u16vec2) < sizeof(glm::u32vec2) ? 0 : 1; + Error += sizeof(glm::u32vec2) < sizeof(glm::u64vec2) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_size(); + Error += test_comp(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_uint3_sized.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_uint3_sized.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4cc2e4487a8b0e9390b5d3cc19bc3250ef3d61f6 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_uint3_sized.cpp @@ -0,0 +1,41 @@ +#include + +#if GLM_HAS_STATIC_ASSERT +static_assert(sizeof(glm::u8vec3) == 3, "int8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::u16vec3) == 6, "int16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::u32vec3) == 12, "int32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::u64vec3) == 24, "int64 size isn't 8 bytes on this platform"); +#endif + +static int test_size() +{ + int Error = 0; + + Error += sizeof(glm::u8vec3) == 3 ? 0 : 1; + Error += sizeof(glm::u16vec3) == 6 ? 0 : 1; + Error += sizeof(glm::u32vec3) == 12 ? 0 : 1; + Error += sizeof(glm::u64vec3) == 24 ? 0 : 1; + + return Error; +} + +static int test_comp() +{ + int Error = 0; + + Error += sizeof(glm::u8vec3) < sizeof(glm::u16vec3) ? 0 : 1; + Error += sizeof(glm::u16vec3) < sizeof(glm::u32vec3) ? 0 : 1; + Error += sizeof(glm::u32vec3) < sizeof(glm::u64vec3) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_size(); + Error += test_comp(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_uint4_sized.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_uint4_sized.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9e7ffe750584828ece3ecd599506150c99c598a5 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_uint4_sized.cpp @@ -0,0 +1,41 @@ +#include + +#if GLM_HAS_STATIC_ASSERT +static_assert(sizeof(glm::u8vec4) == 4, "int8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::u16vec4) == 8, "int16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::u32vec4) == 16, "int32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::u64vec4) == 32, "int64 size isn't 8 bytes on this platform"); +#endif + +static int test_size() +{ + int Error = 0; + + Error += sizeof(glm::u8vec4) == 4 ? 0 : 1; + Error += sizeof(glm::u16vec4) == 8 ? 0 : 1; + Error += sizeof(glm::u32vec4) == 16 ? 0 : 1; + Error += sizeof(glm::u64vec4) == 32 ? 0 : 1; + + return Error; +} + +static int test_comp() +{ + int Error = 0; + + Error += sizeof(glm::u8vec4) < sizeof(glm::u16vec4) ? 0 : 1; + Error += sizeof(glm::u16vec4) < sizeof(glm::u32vec4) ? 0 : 1; + Error += sizeof(glm::u32vec4) < sizeof(glm::u64vec4) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_size(); + Error += test_comp(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_ulp.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_ulp.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6ebd1a1007132ba1321e8322447b57feb49cebf8 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/ext/ext_vector_ulp.cpp @@ -0,0 +1,99 @@ +#include +#include +#include +#include +#include + +static int test_ulp_float_dist() +{ + int Error = 0; + + glm::vec4 const A(1.0f); + + glm::vec4 const B = glm::nextFloat(A); + Error += glm::any(glm::notEqual(A, B, 0)) ? 0 : 1; + glm::vec4 const C = glm::prevFloat(B); + Error += glm::all(glm::equal(A, C, 0)) ? 0 : 1; + + glm::ivec4 const D = glm::floatDistance(A, B); + Error += D == glm::ivec4(1) ? 0 : 1; + glm::ivec4 const E = glm::floatDistance(A, C); + Error += E == glm::ivec4(0) ? 0 : 1; + + return Error; +} + +static int test_ulp_float_step() +{ + int Error = 0; + + glm::vec4 const A(1.0f); + + for(int i = 10; i < 1000; i *= 10) + { + glm::vec4 const B = glm::nextFloat(A, i); + Error += glm::any(glm::notEqual(A, B, 0)) ? 0 : 1; + glm::vec4 const C = glm::prevFloat(B, i); + Error += glm::all(glm::equal(A, C, 0)) ? 0 : 1; + + glm::ivec4 const D = glm::floatDistance(A, B); + Error += D == glm::ivec4(i) ? 0 : 1; + glm::ivec4 const E = glm::floatDistance(A, C); + Error += E == glm::ivec4(0) ? 0 : 1; + } + + return Error; +} + +static int test_ulp_double_dist() +{ + int Error = 0; + + glm::dvec4 const A(1.0); + + glm::dvec4 const B = glm::nextFloat(A); + Error += glm::any(glm::notEqual(A, B, 0)) ? 0 : 1; + glm::dvec4 const C = glm::prevFloat(B); + Error += glm::all(glm::equal(A, C, 0)) ? 0 : 1; + + glm::ivec4 const D(glm::floatDistance(A, B)); + Error += D == glm::ivec4(1) ? 0 : 1; + glm::ivec4 const E = glm::floatDistance(A, C); + Error += E == glm::ivec4(0) ? 0 : 1; + + return Error; +} + +static int test_ulp_double_step() +{ + int Error = 0; + + glm::dvec4 const A(1.0); + + for(int i = 10; i < 1000; i *= 10) + { + glm::dvec4 const B = glm::nextFloat(A, i); + Error += glm::any(glm::notEqual(A, B, 0)) ? 0 : 1; + glm::dvec4 const C = glm::prevFloat(B, i); + Error += glm::all(glm::equal(A, C, 0)) ? 0 : 1; + + glm::ivec4 const D(glm::floatDistance(A, B)); + Error += D == glm::ivec4(i) ? 0 : 1; + glm::ivec4 const E(glm::floatDistance(A, C)); + Error += E == glm::ivec4(0) ? 0 : 1; + } + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_ulp_float_dist(); + Error += test_ulp_float_step(); + Error += test_ulp_double_dist(); + Error += test_ulp_double_step(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/glm.cppcheck b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/glm.cppcheck new file mode 100644 index 0000000000000000000000000000000000000000..12081fe17985562a56e402a07ec0f9d00569e75f --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/glm.cppcheck @@ -0,0 +1,6 @@ + + + + + + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/CMakeLists.txt b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..4aef24a897f91343f784176ced2064a26d9c0d1d --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/CMakeLists.txt @@ -0,0 +1,20 @@ +glmCreateTestGTC(gtc_bitfield) +glmCreateTestGTC(gtc_color_space) +glmCreateTestGTC(gtc_constants) +glmCreateTestGTC(gtc_epsilon) +glmCreateTestGTC(gtc_integer) +glmCreateTestGTC(gtc_matrix_access) +glmCreateTestGTC(gtc_matrix_integer) +glmCreateTestGTC(gtc_matrix_inverse) +glmCreateTestGTC(gtc_matrix_transform) +glmCreateTestGTC(gtc_noise) +glmCreateTestGTC(gtc_packing) +glmCreateTestGTC(gtc_quaternion) +glmCreateTestGTC(gtc_random) +glmCreateTestGTC(gtc_round) +glmCreateTestGTC(gtc_reciprocal) +glmCreateTestGTC(gtc_type_aligned) +glmCreateTestGTC(gtc_type_precision) +glmCreateTestGTC(gtc_type_ptr) +glmCreateTestGTC(gtc_ulp) +glmCreateTestGTC(gtc_vec1) diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_bitfield.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_bitfield.cpp new file mode 100644 index 0000000000000000000000000000000000000000..95c41f1ffc6c4a552aebf13d46953248bd6a97bd --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_bitfield.cpp @@ -0,0 +1,936 @@ +#include +#include +#include +#include +#include +#include +#include + +namespace mask +{ + template + struct type + { + genType Value; + genType Return; + }; + + inline int mask_zero(int Bits) + { + return ~((~0) << Bits); + } + + inline int mask_mix(int Bits) + { + return Bits >= sizeof(int) * 8 ? 0xffffffff : (static_cast(1) << Bits) - static_cast(1); + } + + inline int mask_half(int Bits) + { + // We do the shift in two steps because 1 << 32 on an int is undefined. + + int const Half = Bits >> 1; + int const Fill = ~0; + int const ShiftHaft = (Fill << Half); + int const Rest = Bits - Half; + int const Reversed = ShiftHaft << Rest; + + return ~Reversed; + } + + inline int mask_loop(int Bits) + { + int Mask = 0; + for(int Bit = 0; Bit < Bits; ++Bit) + Mask |= (static_cast(1) << Bit); + return Mask; + } + + int perf() + { + int const Count = 100000000; + + std::clock_t Timestamp1 = std::clock(); + + { + std::vector Mask; + Mask.resize(Count); + for(int i = 0; i < Count; ++i) + Mask[i] = mask_mix(i % 32); + } + + std::clock_t Timestamp2 = std::clock(); + + { + std::vector Mask; + Mask.resize(Count); + for(int i = 0; i < Count; ++i) + Mask[i] = mask_loop(i % 32); + } + + std::clock_t Timestamp3 = std::clock(); + + { + std::vector Mask; + Mask.resize(Count); + for(int i = 0; i < Count; ++i) + Mask[i] = glm::mask(i % 32); + } + + std::clock_t Timestamp4 = std::clock(); + + { + std::vector Mask; + Mask.resize(Count); + for(int i = 0; i < Count; ++i) + Mask[i] = mask_zero(i % 32); + } + + std::clock_t Timestamp5 = std::clock(); + + { + std::vector Mask; + Mask.resize(Count); + for(int i = 0; i < Count; ++i) + Mask[i] = mask_half(i % 32); + } + + std::clock_t Timestamp6 = std::clock(); + + std::clock_t TimeMix = Timestamp2 - Timestamp1; + std::clock_t TimeLoop = Timestamp3 - Timestamp2; + std::clock_t TimeDefault = Timestamp4 - Timestamp3; + std::clock_t TimeZero = Timestamp5 - Timestamp4; + std::clock_t TimeHalf = Timestamp6 - Timestamp5; + + std::printf("mask[mix]: %d\n", static_cast(TimeMix)); + std::printf("mask[loop]: %d\n", static_cast(TimeLoop)); + std::printf("mask[default]: %d\n", static_cast(TimeDefault)); + std::printf("mask[zero]: %d\n", static_cast(TimeZero)); + std::printf("mask[half]: %d\n", static_cast(TimeHalf)); + + return TimeDefault < TimeLoop ? 0 : 1; + } + + int test_uint() + { + type const Data[] = + { + { 0, 0x00000000}, + { 1, 0x00000001}, + { 2, 0x00000003}, + { 3, 0x00000007}, + {31, 0x7fffffff}, + {32, 0xffffffff} + }; + + int Error = 0; +/* mask_zero is sadly not a correct code + for(std::size_t i = 0; i < sizeof(Data) / sizeof(type); ++i) + { + int Result = mask_zero(Data[i].Value); + Error += Data[i].Return == Result ? 0 : 1; + } +*/ + for(std::size_t i = 0; i < sizeof(Data) / sizeof(type); ++i) + { + int Result = mask_mix(Data[i].Value); + Error += Data[i].Return == Result ? 0 : 1; + } + + for(std::size_t i = 0; i < sizeof(Data) / sizeof(type); ++i) + { + int Result = mask_half(Data[i].Value); + Error += Data[i].Return == Result ? 0 : 1; + } + + for(std::size_t i = 0; i < sizeof(Data) / sizeof(type); ++i) + { + int Result = mask_loop(Data[i].Value); + Error += Data[i].Return == Result ? 0 : 1; + } + + for(std::size_t i = 0; i < sizeof(Data) / sizeof(type); ++i) + { + int Result = glm::mask(Data[i].Value); + Error += Data[i].Return == Result ? 0 : 1; + } + + return Error; + } + + int test_uvec4() + { + type const Data[] = + { + {glm::ivec4( 0), glm::ivec4(0x00000000)}, + {glm::ivec4( 1), glm::ivec4(0x00000001)}, + {glm::ivec4( 2), glm::ivec4(0x00000003)}, + {glm::ivec4( 3), glm::ivec4(0x00000007)}, + {glm::ivec4(31), glm::ivec4(0x7fffffff)}, + {glm::ivec4(32), glm::ivec4(0xffffffff)} + }; + + int Error(0); + + for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + glm::ivec4 Result = glm::mask(Data[i].Value); + Error += glm::all(glm::equal(Data[i].Return, Result)) ? 0 : 1; + } + + return Error; + } + + int test() + { + int Error(0); + + Error += test_uint(); + Error += test_uvec4(); + + return Error; + } +}//namespace mask + +namespace bitfieldInterleave3 +{ + template + inline RET refBitfieldInterleave(PARAM x, PARAM y, PARAM z) + { + RET Result = 0; + for(RET i = 0; i < sizeof(PARAM) * 8; ++i) + { + Result |= ((RET(x) & (RET(1U) << i)) << ((i << 1) + 0)); + Result |= ((RET(y) & (RET(1U) << i)) << ((i << 1) + 1)); + Result |= ((RET(z) & (RET(1U) << i)) << ((i << 1) + 2)); + } + return Result; + } + + int test() + { + int Error(0); + + glm::uint16 x_max = 1 << 11; + glm::uint16 y_max = 1 << 11; + glm::uint16 z_max = 1 << 11; + + for(glm::uint16 z = 0; z < z_max; z += 27) + for(glm::uint16 y = 0; y < y_max; y += 27) + for(glm::uint16 x = 0; x < x_max; x += 27) + { + glm::uint64 ResultA = refBitfieldInterleave(x, y, z); + glm::uint64 ResultB = glm::bitfieldInterleave(x, y, z); + Error += ResultA == ResultB ? 0 : 1; + } + + return Error; + } +} + +namespace bitfieldInterleave4 +{ + template + inline RET loopBitfieldInterleave(PARAM x, PARAM y, PARAM z, PARAM w) + { + RET const v[4] = {x, y, z, w}; + RET Result = 0; + for(RET i = 0; i < sizeof(PARAM) * 8; i++) + { + Result |= ((((v[0] >> i) & 1U)) << ((i << 2) + 0)); + Result |= ((((v[1] >> i) & 1U)) << ((i << 2) + 1)); + Result |= ((((v[2] >> i) & 1U)) << ((i << 2) + 2)); + Result |= ((((v[3] >> i) & 1U)) << ((i << 2) + 3)); + } + return Result; + } + + int test() + { + int Error(0); + + glm::uint16 x_max = 1 << 11; + glm::uint16 y_max = 1 << 11; + glm::uint16 z_max = 1 << 11; + glm::uint16 w_max = 1 << 11; + + for(glm::uint16 w = 0; w < w_max; w += 27) + for(glm::uint16 z = 0; z < z_max; z += 27) + for(glm::uint16 y = 0; y < y_max; y += 27) + for(glm::uint16 x = 0; x < x_max; x += 27) + { + glm::uint64 ResultA = loopBitfieldInterleave(x, y, z, w); + glm::uint64 ResultB = glm::bitfieldInterleave(x, y, z, w); + Error += ResultA == ResultB ? 0 : 1; + } + + return Error; + } +} + +namespace bitfieldInterleave +{ + inline glm::uint64 fastBitfieldInterleave(glm::uint32 x, glm::uint32 y) + { + glm::uint64 REG1; + glm::uint64 REG2; + + REG1 = x; + REG1 = ((REG1 << 16) | REG1) & glm::uint64(0x0000FFFF0000FFFF); + REG1 = ((REG1 << 8) | REG1) & glm::uint64(0x00FF00FF00FF00FF); + REG1 = ((REG1 << 4) | REG1) & glm::uint64(0x0F0F0F0F0F0F0F0F); + REG1 = ((REG1 << 2) | REG1) & glm::uint64(0x3333333333333333); + REG1 = ((REG1 << 1) | REG1) & glm::uint64(0x5555555555555555); + + REG2 = y; + REG2 = ((REG2 << 16) | REG2) & glm::uint64(0x0000FFFF0000FFFF); + REG2 = ((REG2 << 8) | REG2) & glm::uint64(0x00FF00FF00FF00FF); + REG2 = ((REG2 << 4) | REG2) & glm::uint64(0x0F0F0F0F0F0F0F0F); + REG2 = ((REG2 << 2) | REG2) & glm::uint64(0x3333333333333333); + REG2 = ((REG2 << 1) | REG2) & glm::uint64(0x5555555555555555); + + return REG1 | (REG2 << 1); + } + + inline glm::uint64 interleaveBitfieldInterleave(glm::uint32 x, glm::uint32 y) + { + glm::uint64 REG1; + glm::uint64 REG2; + + REG1 = x; + REG2 = y; + + REG1 = ((REG1 << 16) | REG1) & glm::uint64(0x0000FFFF0000FFFF); + REG2 = ((REG2 << 16) | REG2) & glm::uint64(0x0000FFFF0000FFFF); + + REG1 = ((REG1 << 8) | REG1) & glm::uint64(0x00FF00FF00FF00FF); + REG2 = ((REG2 << 8) | REG2) & glm::uint64(0x00FF00FF00FF00FF); + + REG1 = ((REG1 << 4) | REG1) & glm::uint64(0x0F0F0F0F0F0F0F0F); + REG2 = ((REG2 << 4) | REG2) & glm::uint64(0x0F0F0F0F0F0F0F0F); + + REG1 = ((REG1 << 2) | REG1) & glm::uint64(0x3333333333333333); + REG2 = ((REG2 << 2) | REG2) & glm::uint64(0x3333333333333333); + + REG1 = ((REG1 << 1) | REG1) & glm::uint64(0x5555555555555555); + REG2 = ((REG2 << 1) | REG2) & glm::uint64(0x5555555555555555); + + return REG1 | (REG2 << 1); + } +/* + inline glm::uint64 loopBitfieldInterleave(glm::uint32 x, glm::uint32 y) + { + static glm::uint64 const Mask[5] = + { + 0x5555555555555555, + 0x3333333333333333, + 0x0F0F0F0F0F0F0F0F, + 0x00FF00FF00FF00FF, + 0x0000FFFF0000FFFF + }; + + glm::uint64 REG1 = x; + glm::uint64 REG2 = y; + for(int i = 4; i >= 0; --i) + { + REG1 = ((REG1 << (1 << i)) | REG1) & Mask[i]; + REG2 = ((REG2 << (1 << i)) | REG2) & Mask[i]; + } + + return REG1 | (REG2 << 1); + } +*/ +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + inline glm::uint64 sseBitfieldInterleave(glm::uint32 x, glm::uint32 y) + { + __m128i const Array = _mm_set_epi32(0, y, 0, x); + + __m128i const Mask4 = _mm_set1_epi32(0x0000FFFF); + __m128i const Mask3 = _mm_set1_epi32(0x00FF00FF); + __m128i const Mask2 = _mm_set1_epi32(0x0F0F0F0F); + __m128i const Mask1 = _mm_set1_epi32(0x33333333); + __m128i const Mask0 = _mm_set1_epi32(0x55555555); + + __m128i Reg1; + __m128i Reg2; + + // REG1 = x; + // REG2 = y; + Reg1 = _mm_load_si128(&Array); + + //REG1 = ((REG1 << 16) | REG1) & glm::uint64(0x0000FFFF0000FFFF); + //REG2 = ((REG2 << 16) | REG2) & glm::uint64(0x0000FFFF0000FFFF); + Reg2 = _mm_slli_si128(Reg1, 2); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask4); + + //REG1 = ((REG1 << 8) | REG1) & glm::uint64(0x00FF00FF00FF00FF); + //REG2 = ((REG2 << 8) | REG2) & glm::uint64(0x00FF00FF00FF00FF); + Reg2 = _mm_slli_si128(Reg1, 1); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask3); + + //REG1 = ((REG1 << 4) | REG1) & glm::uint64(0x0F0F0F0F0F0F0F0F); + //REG2 = ((REG2 << 4) | REG2) & glm::uint64(0x0F0F0F0F0F0F0F0F); + Reg2 = _mm_slli_epi32(Reg1, 4); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask2); + + //REG1 = ((REG1 << 2) | REG1) & glm::uint64(0x3333333333333333); + //REG2 = ((REG2 << 2) | REG2) & glm::uint64(0x3333333333333333); + Reg2 = _mm_slli_epi32(Reg1, 2); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask1); + + //REG1 = ((REG1 << 1) | REG1) & glm::uint64(0x5555555555555555); + //REG2 = ((REG2 << 1) | REG2) & glm::uint64(0x5555555555555555); + Reg2 = _mm_slli_epi32(Reg1, 1); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask0); + + //return REG1 | (REG2 << 1); + Reg2 = _mm_slli_epi32(Reg1, 1); + Reg2 = _mm_srli_si128(Reg2, 8); + Reg1 = _mm_or_si128(Reg1, Reg2); + + __m128i Result; + _mm_store_si128(&Result, Reg1); + return *reinterpret_cast(&Result); + } + + inline glm::uint64 sseUnalignedBitfieldInterleave(glm::uint32 x, glm::uint32 y) + { + __m128i const Array = _mm_set_epi32(0, y, 0, x); + + __m128i const Mask4 = _mm_set1_epi32(0x0000FFFF); + __m128i const Mask3 = _mm_set1_epi32(0x00FF00FF); + __m128i const Mask2 = _mm_set1_epi32(0x0F0F0F0F); + __m128i const Mask1 = _mm_set1_epi32(0x33333333); + __m128i const Mask0 = _mm_set1_epi32(0x55555555); + + __m128i Reg1; + __m128i Reg2; + + // REG1 = x; + // REG2 = y; + Reg1 = _mm_loadu_si128(&Array); + + //REG1 = ((REG1 << 16) | REG1) & glm::uint64(0x0000FFFF0000FFFF); + //REG2 = ((REG2 << 16) | REG2) & glm::uint64(0x0000FFFF0000FFFF); + Reg2 = _mm_slli_si128(Reg1, 2); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask4); + + //REG1 = ((REG1 << 8) | REG1) & glm::uint64(0x00FF00FF00FF00FF); + //REG2 = ((REG2 << 8) | REG2) & glm::uint64(0x00FF00FF00FF00FF); + Reg2 = _mm_slli_si128(Reg1, 1); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask3); + + //REG1 = ((REG1 << 4) | REG1) & glm::uint64(0x0F0F0F0F0F0F0F0F); + //REG2 = ((REG2 << 4) | REG2) & glm::uint64(0x0F0F0F0F0F0F0F0F); + Reg2 = _mm_slli_epi32(Reg1, 4); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask2); + + //REG1 = ((REG1 << 2) | REG1) & glm::uint64(0x3333333333333333); + //REG2 = ((REG2 << 2) | REG2) & glm::uint64(0x3333333333333333); + Reg2 = _mm_slli_epi32(Reg1, 2); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask1); + + //REG1 = ((REG1 << 1) | REG1) & glm::uint64(0x5555555555555555); + //REG2 = ((REG2 << 1) | REG2) & glm::uint64(0x5555555555555555); + Reg2 = _mm_slli_epi32(Reg1, 1); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask0); + + //return REG1 | (REG2 << 1); + Reg2 = _mm_slli_epi32(Reg1, 1); + Reg2 = _mm_srli_si128(Reg2, 8); + Reg1 = _mm_or_si128(Reg1, Reg2); + + __m128i Result; + _mm_store_si128(&Result, Reg1); + return *reinterpret_cast(&Result); + } +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT + + int test() + { + int Error = 0; + +/* + { + for(glm::uint32 y = 0; y < (1 << 10); ++y) + for(glm::uint32 x = 0; x < (1 << 10); ++x) + { + glm::uint64 A = glm::bitfieldInterleave(x, y); + glm::uint64 B = fastBitfieldInterleave(x, y); + //glm::uint64 C = loopBitfieldInterleave(x, y); + glm::uint64 D = interleaveBitfieldInterleave(x, y); + + assert(A == B); + //assert(A == C); + assert(A == D); + +# if GLM_ARCH & GLM_ARCH_SSE2_BIT + glm::uint64 E = sseBitfieldInterleave(x, y); + glm::uint64 F = sseUnalignedBitfieldInterleave(x, y); + assert(A == E); + assert(A == F); + + __m128i G = glm_i128_interleave(_mm_set_epi32(0, y, 0, x)); + glm::uint64 Result[2]; + _mm_storeu_si128((__m128i*)Result, G); + assert(A == Result[0]); +# endif//GLM_ARCH & GLM_ARCH_SSE2_BIT + } + } +*/ + { + for(glm::uint8 y = 0; y < 127; ++y) + for(glm::uint8 x = 0; x < 127; ++x) + { + glm::uint64 A(glm::bitfieldInterleave(glm::u8vec2(x, y))); + glm::uint64 B(glm::bitfieldInterleave(glm::u16vec2(x, y))); + glm::uint64 C(glm::bitfieldInterleave(glm::u32vec2(x, y))); + + Error += A == B ? 0 : 1; + Error += A == C ? 0 : 1; + + glm::u32vec2 const& D = glm::bitfieldDeinterleave(C); + Error += D.x == x ? 0 : 1; + Error += D.y == y ? 0 : 1; + } + } + + { + for(glm::uint8 y = 0; y < 127; ++y) + for(glm::uint8 x = 0; x < 127; ++x) + { + glm::int64 A(glm::bitfieldInterleave(glm::int8(x), glm::int8(y))); + glm::int64 B(glm::bitfieldInterleave(glm::int16(x), glm::int16(y))); + glm::int64 C(glm::bitfieldInterleave(glm::int32(x), glm::int32(y))); + + Error += A == B ? 0 : 1; + Error += A == C ? 0 : 1; + } + } + + return Error; + } + + int perf() + { + glm::uint32 x_max = 1 << 11; + glm::uint32 y_max = 1 << 10; + + // ALU + std::vector Data(x_max * y_max); + std::vector Param(x_max * y_max); + for(glm::uint32 i = 0; i < Param.size(); ++i) + Param[i] = glm::u32vec2(i % x_max, i / y_max); + + { + std::clock_t LastTime = std::clock(); + + for(std::size_t i = 0; i < Data.size(); ++i) + Data[i] = glm::bitfieldInterleave(Param[i].x, Param[i].y); + + std::clock_t Time = std::clock() - LastTime; + + std::printf("glm::bitfieldInterleave Time %d clocks\n", static_cast(Time)); + } + + { + std::clock_t LastTime = std::clock(); + + for(std::size_t i = 0; i < Data.size(); ++i) + Data[i] = fastBitfieldInterleave(Param[i].x, Param[i].y); + + std::clock_t Time = std::clock() - LastTime; + + std::printf("fastBitfieldInterleave Time %d clocks\n", static_cast(Time)); + } +/* + { + std::clock_t LastTime = std::clock(); + + for(std::size_t i = 0; i < Data.size(); ++i) + Data[i] = loopBitfieldInterleave(Param[i].x, Param[i].y); + + std::clock_t Time = std::clock() - LastTime; + + std::printf("loopBitfieldInterleave Time %d clocks\n", static_cast(Time)); + } +*/ + { + std::clock_t LastTime = std::clock(); + + for(std::size_t i = 0; i < Data.size(); ++i) + Data[i] = interleaveBitfieldInterleave(Param[i].x, Param[i].y); + + std::clock_t Time = std::clock() - LastTime; + + std::printf("interleaveBitfieldInterleave Time %d clocks\n", static_cast(Time)); + } + +# if GLM_ARCH & GLM_ARCH_SSE2_BIT + { + std::clock_t LastTime = std::clock(); + + for(std::size_t i = 0; i < Data.size(); ++i) + Data[i] = sseBitfieldInterleave(Param[i].x, Param[i].y); + + std::clock_t Time = std::clock() - LastTime; + + std::printf("sseBitfieldInterleave Time %d clocks\n", static_cast(Time)); + } + + { + std::clock_t LastTime = std::clock(); + + for(std::size_t i = 0; i < Data.size(); ++i) + Data[i] = sseUnalignedBitfieldInterleave(Param[i].x, Param[i].y); + + std::clock_t Time = std::clock() - LastTime; + + std::printf("sseUnalignedBitfieldInterleave Time %d clocks\n", static_cast(Time)); + } +# endif//GLM_ARCH & GLM_ARCH_SSE2_BIT + + { + std::clock_t LastTime = std::clock(); + + for(std::size_t i = 0; i < Data.size(); ++i) + Data[i] = glm::bitfieldInterleave(Param[i].x, Param[i].y, Param[i].x); + + std::clock_t Time = std::clock() - LastTime; + + std::printf("glm::detail::bitfieldInterleave Time %d clocks\n", static_cast(Time)); + } + +# if(GLM_ARCH & GLM_ARCH_SSE2_BIT && !(GLM_COMPILER & GLM_COMPILER_GCC)) + { + // SIMD + std::vector<__m128i> SimdData; + SimdData.resize(static_cast(x_max * y_max)); + std::vector<__m128i> SimdParam; + SimdParam.resize(static_cast(x_max * y_max)); + for(std::size_t i = 0; i < SimdParam.size(); ++i) + SimdParam[i] = _mm_set_epi32(static_cast(i % static_cast(x_max)), 0, static_cast(i / static_cast(y_max)), 0); + + std::clock_t LastTime = std::clock(); + + for(std::size_t i = 0; i < SimdData.size(); ++i) + SimdData[i] = glm_i128_interleave(SimdParam[i]); + + std::clock_t Time = std::clock() - LastTime; + + std::printf("_mm_bit_interleave_si128 Time %d clocks\n", static_cast(Time)); + } +# endif//GLM_ARCH & GLM_ARCH_SSE2_BIT + + return 0; + } +}//namespace bitfieldInterleave + +namespace bitfieldInterleave5 +{ + GLM_FUNC_QUALIFIER glm::uint16 bitfieldInterleave_u8vec2(glm::uint8 x, glm::uint8 y) + { + glm::uint32 Result = (glm::uint32(y) << 16) | glm::uint32(x); + Result = ((Result << 4) | Result) & 0x0F0F0F0F; + Result = ((Result << 2) | Result) & 0x33333333; + Result = ((Result << 1) | Result) & 0x55555555; + return static_cast((Result & 0x0000FFFF) | (Result >> 15)); + } + + GLM_FUNC_QUALIFIER glm::u8vec2 bitfieldDeinterleave_u8vec2(glm::uint16 InterleavedBitfield) + { + glm::uint32 Result(InterleavedBitfield); + Result = ((Result << 15) | Result) & 0x55555555; + Result = ((Result >> 1) | Result) & 0x33333333; + Result = ((Result >> 2) | Result) & 0x0F0F0F0F; + Result = ((Result >> 4) | Result) & 0x00FF00FF; + return glm::u8vec2(Result & 0x0000FFFF, Result >> 16); + } + + GLM_FUNC_QUALIFIER glm::uint32 bitfieldInterleave_u8vec4(glm::uint8 x, glm::uint8 y, glm::uint8 z, glm::uint8 w) + { + glm::uint64 Result = (glm::uint64(w) << 48) | (glm::uint64(z) << 32) | (glm::uint64(y) << 16) | glm::uint64(x); + Result = ((Result << 12) | Result) & 0x000F000F000F000Full; + Result = ((Result << 6) | Result) & 0x0303030303030303ull; + Result = ((Result << 3) | Result) & 0x1111111111111111ull; + + const glm::uint32 a = static_cast((Result & 0x000000000000FFFF) >> ( 0 - 0)); + const glm::uint32 b = static_cast((Result & 0x00000000FFFF0000) >> (16 - 3)); + const glm::uint32 c = static_cast((Result & 0x0000FFFF00000000) >> (32 - 6)); + const glm::uint32 d = static_cast((Result & 0xFFFF000000000000) >> (48 - 12)); + + return a | b | c | d; + } + + GLM_FUNC_QUALIFIER glm::u8vec4 bitfieldDeinterleave_u8vec4(glm::uint32 InterleavedBitfield) + { + glm::uint64 Result(InterleavedBitfield); + Result = ((Result << 15) | Result) & 0x9249249249249249ull; + Result = ((Result >> 1) | Result) & 0x30C30C30C30C30C3ull; + Result = ((Result >> 2) | Result) & 0xF00F00F00F00F00Full; + Result = ((Result >> 4) | Result) & 0x00FF0000FF0000FFull; + return glm::u8vec4( + (Result >> 0) & 0x000000000000FFFFull, + (Result >> 16) & 0x00000000FFFF0000ull, + (Result >> 32) & 0x0000FFFF00000000ull, + (Result >> 48) & 0xFFFF000000000000ull); + } + + GLM_FUNC_QUALIFIER glm::uint32 bitfieldInterleave_u16vec2(glm::uint16 x, glm::uint16 y) + { + glm::uint64 Result = (glm::uint64(y) << 32) | glm::uint64(x); + Result = ((Result << 8) | Result) & static_cast(0x00FF00FF00FF00FFull); + Result = ((Result << 4) | Result) & static_cast(0x0F0F0F0F0F0F0F0Full); + Result = ((Result << 2) | Result) & static_cast(0x3333333333333333ull); + Result = ((Result << 1) | Result) & static_cast(0x5555555555555555ull); + return static_cast((Result & 0x00000000FFFFFFFFull) | (Result >> 31)); + } + + GLM_FUNC_QUALIFIER glm::u16vec2 bitfieldDeinterleave_u16vec2(glm::uint32 InterleavedBitfield) + { + glm::uint64 Result(InterleavedBitfield); + Result = ((Result << 31) | Result) & 0x5555555555555555ull; + Result = ((Result >> 1) | Result) & 0x3333333333333333ull; + Result = ((Result >> 2) | Result) & 0x0F0F0F0F0F0F0F0Full; + Result = ((Result >> 4) | Result) & 0x00FF00FF00FF00FFull; + Result = ((Result >> 8) | Result) & 0x0000FFFF0000FFFFull; + return glm::u16vec2(Result & 0x00000000FFFFFFFFull, Result >> 32); + } + + int test() + { + int Error = 0; + + for(glm::size_t j = 0; j < 256; ++j) + for(glm::size_t i = 0; i < 256; ++i) + { + glm::uint16 A = bitfieldInterleave_u8vec2(glm::uint8(i), glm::uint8(j)); + glm::uint16 B = glm::bitfieldInterleave(glm::uint8(i), glm::uint8(j)); + Error += A == B ? 0 : 1; + + glm::u8vec2 C = bitfieldDeinterleave_u8vec2(A); + Error += C.x == glm::uint8(i) ? 0 : 1; + Error += C.y == glm::uint8(j) ? 0 : 1; + } + + for(glm::size_t j = 0; j < 256; ++j) + for(glm::size_t i = 0; i < 256; ++i) + { + glm::uint32 A = bitfieldInterleave_u8vec4(glm::uint8(i), glm::uint8(j), glm::uint8(i), glm::uint8(j)); + glm::uint32 B = glm::bitfieldInterleave(glm::uint8(i), glm::uint8(j), glm::uint8(i), glm::uint8(j)); + Error += A == B ? 0 : 1; +/* + glm::u8vec4 C = bitfieldDeinterleave_u8vec4(A); + Error += C.x == glm::uint8(i) ? 0 : 1; + Error += C.y == glm::uint8(j) ? 0 : 1; + Error += C.z == glm::uint8(i) ? 0 : 1; + Error += C.w == glm::uint8(j) ? 0 : 1; +*/ + } + + for(glm::size_t j = 0; j < 256; ++j) + for(glm::size_t i = 0; i < 256; ++i) + { + glm::uint32 A = bitfieldInterleave_u16vec2(glm::uint16(i), glm::uint16(j)); + glm::uint32 B = glm::bitfieldInterleave(glm::uint16(i), glm::uint16(j)); + Error += A == B ? 0 : 1; + } + + return Error; + } + + int perf_old_u8vec2(std::vector& Result) + { + int Error = 0; + + const std::clock_t BeginTime = std::clock(); + + for(glm::size_t k = 0; k < 10000; ++k) + for(glm::size_t j = 0; j < 256; ++j) + for(glm::size_t i = 0; i < 256; ++i) + Error += Result[j * 256 + i] == glm::bitfieldInterleave(glm::uint8(i), glm::uint8(j)) ? 0 : 1; + + const std::clock_t EndTime = std::clock(); + + std::printf("glm::bitfieldInterleave Time %d clocks\n", static_cast(EndTime - BeginTime)); + + return Error; + } + + int perf_new_u8vec2(std::vector& Result) + { + int Error = 0; + + const std::clock_t BeginTime = std::clock(); + + for(glm::size_t k = 0; k < 10000; ++k) + for(glm::size_t j = 0; j < 256; ++j) + for(glm::size_t i = 0; i < 256; ++i) + Error += Result[j * 256 + i] == bitfieldInterleave_u8vec2(glm::uint8(i), glm::uint8(j)) ? 0 : 1; + + const std::clock_t EndTime = std::clock(); + + std::printf("bitfieldInterleave_u8vec2 Time %d clocks\n", static_cast(EndTime - BeginTime)); + + return Error; + } + + int perf_old_u8vec4(std::vector& Result) + { + int Error = 0; + + const std::clock_t BeginTime = std::clock(); + + for(glm::size_t k = 0; k < 10000; ++k) + for(glm::size_t j = 0; j < 256; ++j) + for(glm::size_t i = 0; i < 256; ++i) + Error += Result[j * 256 + i] == glm::bitfieldInterleave(glm::uint8(i), glm::uint8(j), glm::uint8(i), glm::uint8(j)) ? 0 : 1; + + const std::clock_t EndTime = std::clock(); + + std::printf("glm::bitfieldInterleave Time %d clocks\n", static_cast(EndTime - BeginTime)); + + return Error; + } + + int perf_new_u8vec4(std::vector& Result) + { + int Error = 0; + + const std::clock_t BeginTime = std::clock(); + + for(glm::size_t k = 0; k < 10000; ++k) + for(glm::size_t j = 0; j < 256; ++j) + for(glm::size_t i = 0; i < 256; ++i) + Error += Result[j * 256 + i] == bitfieldInterleave_u8vec4(glm::uint8(i), glm::uint8(j), glm::uint8(i), glm::uint8(j)) ? 0 : 1; + + const std::clock_t EndTime = std::clock(); + + std::printf("bitfieldInterleave_u8vec4 Time %d clocks\n", static_cast(EndTime - BeginTime)); + + return Error; + } + + int perf_old_u16vec2(std::vector& Result) + { + int Error = 0; + + const std::clock_t BeginTime = std::clock(); + + for(glm::size_t k = 0; k < 10000; ++k) + for(glm::size_t j = 0; j < 256; ++j) + for(glm::size_t i = 0; i < 256; ++i) + Error += Result[j * 256 + i] == glm::bitfieldInterleave(glm::uint16(i), glm::uint16(j)) ? 0 : 1; + + const std::clock_t EndTime = std::clock(); + + std::printf("glm::bitfieldInterleave Time %d clocks\n", static_cast(EndTime - BeginTime)); + + return Error; + } + + int perf_new_u16vec2(std::vector& Result) + { + int Error = 0; + + const std::clock_t BeginTime = std::clock(); + + for(glm::size_t k = 0; k < 10000; ++k) + for(glm::size_t j = 0; j < 256; ++j) + for(glm::size_t i = 0; i < 256; ++i) + Error += Result[j * 256 + i] == bitfieldInterleave_u16vec2(glm::uint16(i), glm::uint16(j)) ? 0 : 1; + + const std::clock_t EndTime = std::clock(); + + std::printf("bitfieldInterleave_u16vec2 Time %d clocks\n", static_cast(EndTime - BeginTime)); + + return Error; + } + + int perf() + { + int Error = 0; + + std::printf("bitfieldInterleave perf: init\r"); + + std::vector Result_u8vec2(256 * 256, 0); + for(glm::size_t j = 0; j < 256; ++j) + for(glm::size_t i = 0; i < 256; ++i) + Result_u8vec2[j * 256 + i] = glm::bitfieldInterleave(glm::uint8(i), glm::uint8(j)); + + Error += perf_old_u8vec2(Result_u8vec2); + Error += perf_new_u8vec2(Result_u8vec2); + + std::vector Result_u8vec4(256 * 256, 0); + for(glm::size_t j = 0; j < 256; ++j) + for(glm::size_t i = 0; i < 256; ++i) + Result_u8vec4[j * 256 + i] = glm::bitfieldInterleave(glm::uint8(i), glm::uint8(j), glm::uint8(i), glm::uint8(j)); + + Error += perf_old_u8vec4(Result_u8vec4); + Error += perf_new_u8vec4(Result_u8vec4); + + std::vector Result_u16vec2(256 * 256, 0); + for(glm::size_t j = 0; j < 256; ++j) + for(glm::size_t i = 0; i < 256; ++i) + Result_u16vec2[j * 256 + i] = glm::bitfieldInterleave(glm::uint16(i), glm::uint16(j)); + + Error += perf_old_u16vec2(Result_u16vec2); + Error += perf_new_u16vec2(Result_u16vec2); + + std::printf("bitfieldInterleave perf: %d Errors\n", Error); + + return Error; + } + +}//namespace bitfieldInterleave5 + +static int test_bitfieldRotateRight() +{ + glm::ivec4 const A = glm::bitfieldRotateRight(glm::ivec4(2), 1); + glm::ivec4 const B = glm::ivec4(2) >> 1; + + return A == B; +} + +static int test_bitfieldRotateLeft() +{ + glm::ivec4 const A = glm::bitfieldRotateLeft(glm::ivec4(2), 1); + glm::ivec4 const B = glm::ivec4(2) << 1; + + return A == B; +} + +int main() +{ + int Error = 0; + +/* Tests for a faster and to reserve bitfieldInterleave + Error += ::bitfieldInterleave5::test(); + Error += ::bitfieldInterleave5::perf(); +*/ + Error += ::mask::test(); + Error += ::bitfieldInterleave3::test(); + Error += ::bitfieldInterleave4::test(); + Error += ::bitfieldInterleave::test(); + + Error += test_bitfieldRotateRight(); + Error += test_bitfieldRotateLeft(); + +# ifdef NDEBUG + Error += ::mask::perf(); + Error += ::bitfieldInterleave::perf(); +# endif//NDEBUG + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_color_space.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_color_space.cpp new file mode 100644 index 0000000000000000000000000000000000000000..67650c5eef00586d7555ab10c336c28e7aff0e9b --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_color_space.cpp @@ -0,0 +1,78 @@ +#include +#include +#include + +namespace srgb +{ + int test() + { + int Error(0); + + glm::vec3 const ColorSourceRGB(1.0, 0.5, 0.0); + + { + glm::vec3 const ColorSRGB = glm::convertLinearToSRGB(ColorSourceRGB); + glm::vec3 const ColorRGB = glm::convertSRGBToLinear(ColorSRGB); + Error += glm::all(glm::epsilonEqual(ColorSourceRGB, ColorRGB, 0.00001f)) ? 0 : 1; + } + + { + glm::vec3 const ColorSRGB = glm::convertLinearToSRGB(ColorSourceRGB, 2.8f); + glm::vec3 const ColorRGB = glm::convertSRGBToLinear(ColorSRGB, 2.8f); + Error += glm::all(glm::epsilonEqual(ColorSourceRGB, ColorRGB, 0.00001f)) ? 0 : 1; + } + + glm::vec4 const ColorSourceRGBA(1.0, 0.5, 0.0, 1.0); + + { + glm::vec4 const ColorSRGB = glm::convertLinearToSRGB(ColorSourceRGBA); + glm::vec4 const ColorRGB = glm::convertSRGBToLinear(ColorSRGB); + Error += glm::all(glm::epsilonEqual(ColorSourceRGBA, ColorRGB, 0.00001f)) ? 0 : 1; + } + + { + glm::vec4 const ColorSRGB = glm::convertLinearToSRGB(ColorSourceRGBA, 2.8f); + glm::vec4 const ColorRGB = glm::convertSRGBToLinear(ColorSRGB, 2.8f); + Error += glm::all(glm::epsilonEqual(ColorSourceRGBA, ColorRGB, 0.00001f)) ? 0 : 1; + } + + glm::vec4 const ColorSourceGNI = glm::vec4(107, 107, 104, 131) / glm::vec4(255); + + { + glm::vec4 const ColorGNA = glm::convertSRGBToLinear(ColorSourceGNI) * glm::vec4(255); + glm::vec4 const ColorGNE = glm::convertLinearToSRGB(ColorSourceGNI) * glm::vec4(255); + glm::vec4 const ColorSRGB = glm::convertLinearToSRGB(ColorSourceGNI); + glm::vec4 const ColorRGB = glm::convertSRGBToLinear(ColorSRGB); + Error += glm::all(glm::epsilonEqual(ColorSourceGNI, ColorRGB, 0.00001f)) ? 0 : 1; + } + + return Error; + } +}//namespace srgb + +namespace srgb_lowp +{ + int test() + { + int Error(0); + + for(float Color = 0.0f; Color < 1.0f; Color += 0.01f) + { + glm::highp_vec3 const HighpSRGB = glm::convertLinearToSRGB(glm::highp_vec3(Color)); + glm::lowp_vec3 const LowpSRGB = glm::convertLinearToSRGB(glm::lowp_vec3(Color)); + Error += glm::all(glm::epsilonEqual(glm::abs(HighpSRGB - glm::highp_vec3(LowpSRGB)), glm::highp_vec3(0), 0.1f)) ? 0 : 1; + } + + return Error; + } +}//namespace srgb_lowp + +int main() +{ + int Error(0); + + Error += srgb::test(); + Error += srgb_lowp::test(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_constants.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_constants.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3897cd080b0cd415ba9ddb9085e36db3be877d2b --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_constants.cpp @@ -0,0 +1,30 @@ +#include + +int test_epsilon() +{ + int Error = 0; + + { + float Test = glm::epsilon(); + Error += Test > 0.0f ? 0 : 1; + } + + { + double Test = glm::epsilon(); + Error += Test > 0.0 ? 0 : 1; + } + + return Error; +} + +int main() +{ + int Error(0); + + //float MinHalf = 0.0f; + //while (glm::half(MinHalf) == glm::half(0.0f)) + // MinHalf += std::numeric_limits::epsilon(); + Error += test_epsilon(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_epsilon.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_epsilon.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f0e6c8a479252cb5aaec8426f05d3010261bbd2f --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_epsilon.cpp @@ -0,0 +1,78 @@ +#include +#include +#include +#include + +int test_defined() +{ + glm::epsilonEqual(glm::vec2(), glm::vec2(), glm::vec2()); + glm::epsilonEqual(glm::vec3(), glm::vec3(), glm::vec3()); + glm::epsilonEqual(glm::vec4(), glm::vec4(), glm::vec4()); + + glm::epsilonNotEqual(glm::vec2(), glm::vec2(), glm::vec2()); + glm::epsilonNotEqual(glm::vec3(), glm::vec3(), glm::vec3()); + glm::epsilonNotEqual(glm::vec4(), glm::vec4(), glm::vec4()); + + glm::epsilonEqual(glm::vec2(), glm::vec2(), 0.0f); + glm::epsilonEqual(glm::vec3(), glm::vec3(), 0.0f); + glm::epsilonEqual(glm::vec4(), glm::vec4(), 0.0f); + glm::epsilonEqual(glm::quat(), glm::quat(), 0.0f); + + glm::epsilonNotEqual(glm::vec2(), glm::vec2(), 0.0f); + glm::epsilonNotEqual(glm::vec3(), glm::vec3(), 0.0f); + glm::epsilonNotEqual(glm::vec4(), glm::vec4(), 0.0f); + glm::epsilonNotEqual(glm::quat(), glm::quat(), 0.0f); + + return 0; +} + +template +int test_equal() +{ + int Error(0); + + { + T A = glm::epsilon(); + T B = glm::epsilon(); + Error += glm::epsilonEqual(A, B, glm::epsilon() * T(2)) ? 0 : 1; + } + + { + T A(0); + T B = static_cast(0) + glm::epsilon(); + Error += glm::epsilonEqual(A, B, glm::epsilon() * T(2)) ? 0 : 1; + } + + { + T A(0); + T B = static_cast(0) - glm::epsilon(); + Error += glm::epsilonEqual(A, B, glm::epsilon() * T(2)) ? 0 : 1; + } + + { + T A = static_cast(0) + glm::epsilon(); + T B = static_cast(0); + Error += glm::epsilonEqual(A, B, glm::epsilon() * T(2)) ? 0 : 1; + } + + { + T A = static_cast(0) - glm::epsilon(); + T B = static_cast(0); + Error += glm::epsilonEqual(A, B, glm::epsilon() * T(2)) ? 0 : 1; + } + + return Error; +} + +int main() +{ + int Error(0); + + Error += test_defined(); + Error += test_equal(); + Error += test_equal(); + + return Error; +} + + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_integer.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_integer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..769d969033c284725bfc6891072a6f04bc41c5a8 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_integer.cpp @@ -0,0 +1,233 @@ +#define GLM_ENABLE_EXPERIMENTAL +#define GLM_FORCE_INLINE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace log2_ +{ + int test() + { + int Error = 0; + + int A0 = static_cast(glm::log2(16.f)); + glm::ivec1 B0(glm::log2(glm::vec1(16.f))); + glm::ivec2 C0(glm::log2(glm::vec2(16.f))); + glm::ivec3 D0(glm::log2(glm::vec3(16.f))); + glm::ivec4 E0(glm::log2(glm::vec4(16.f))); + + int A1 = glm::log2(int(16)); + glm::ivec1 B1 = glm::log2(glm::ivec1(16)); + glm::ivec2 C1 = glm::log2(glm::ivec2(16)); + glm::ivec3 D1 = glm::log2(glm::ivec3(16)); + glm::ivec4 E1 = glm::log2(glm::ivec4(16)); + + Error += A0 == A1 ? 0 : 1; + Error += glm::all(glm::equal(B0, B1)) ? 0 : 1; + Error += glm::all(glm::equal(C0, C1)) ? 0 : 1; + Error += glm::all(glm::equal(D0, D1)) ? 0 : 1; + Error += glm::all(glm::equal(E0, E1)) ? 0 : 1; + + glm::uint64 A2 = glm::log2(glm::uint64(16)); + glm::u64vec1 B2 = glm::log2(glm::u64vec1(16)); + glm::u64vec2 C2 = glm::log2(glm::u64vec2(16)); + glm::u64vec3 D2 = glm::log2(glm::u64vec3(16)); + glm::u64vec4 E2 = glm::log2(glm::u64vec4(16)); + + Error += A2 == glm::uint64(4) ? 0 : 1; + Error += glm::all(glm::equal(B2, glm::u64vec1(4))) ? 0 : 1; + Error += glm::all(glm::equal(C2, glm::u64vec2(4))) ? 0 : 1; + Error += glm::all(glm::equal(D2, glm::u64vec3(4))) ? 0 : 1; + Error += glm::all(glm::equal(E2, glm::u64vec4(4))) ? 0 : 1; + + return Error; + } + + int perf(std::size_t Count) + { + int Error = 0; + + { + std::vector Result; + Result.resize(Count); + + std::clock_t Begin = clock(); + + for(int i = 0; i < static_cast(Count); ++i) + Result[i] = glm::log2(static_cast(i)); + + std::clock_t End = clock(); + + std::printf("glm::log2: %d clocks\n", static_cast(End - Begin)); + } + + { + std::vector Result; + Result.resize(Count); + + std::clock_t Begin = clock(); + + for(int i = 0; i < static_cast(Count); ++i) + Result[i] = glm::log2(glm::ivec4(i)); + + std::clock_t End = clock(); + + std::printf("glm::log2: %d clocks\n", static_cast(End - Begin)); + } + +# if GLM_HAS_BITSCAN_WINDOWS + { + std::vector Result; + Result.resize(Count); + + std::clock_t Begin = clock(); + + for(std::size_t i = 0; i < Count; ++i) + { + glm::vec<4, unsigned long, glm::defaultp> Tmp; + _BitScanReverse(&Tmp.x, i); + _BitScanReverse(&Tmp.y, i); + _BitScanReverse(&Tmp.z, i); + _BitScanReverse(&Tmp.w, i); + Result[i] = glm::ivec4(Tmp); + } + + std::clock_t End = clock(); + + std::printf("glm::log2 inlined: %d clocks\n", static_cast(End - Begin)); + } + + + { + std::vector > Result; + Result.resize(Count); + + std::clock_t Begin = clock(); + + for(std::size_t i = 0; i < Count; ++i) + { + _BitScanReverse(&Result[i].x, i); + _BitScanReverse(&Result[i].y, i); + _BitScanReverse(&Result[i].z, i); + _BitScanReverse(&Result[i].w, i); + } + + std::clock_t End = clock(); + + std::printf("glm::log2 inlined no cast: %d clocks\n", static_cast(End - Begin)); + } + + + { + std::vector Result; + Result.resize(Count); + + std::clock_t Begin = clock(); + + for(std::size_t i = 0; i < Count; ++i) + { + _BitScanReverse(reinterpret_cast(&Result[i].x), i); + _BitScanReverse(reinterpret_cast(&Result[i].y), i); + _BitScanReverse(reinterpret_cast(&Result[i].z), i); + _BitScanReverse(reinterpret_cast(&Result[i].w), i); + } + + std::clock_t End = clock(); + + std::printf("glm::log2 reinterpret: %d clocks\n", static_cast(End - Begin)); + } +# endif//GLM_HAS_BITSCAN_WINDOWS + + { + std::vector Result; + Result.resize(Count); + + std::clock_t Begin = clock(); + + for(std::size_t i = 0; i < Count; ++i) + Result[i] = glm::log2(static_cast(i)); + + std::clock_t End = clock(); + + std::printf("glm::log2: %d clocks\n", static_cast(End - Begin)); + } + + { + std::vector Result; + Result.resize(Count); + + std::clock_t Begin = clock(); + + for(int i = 0; i < static_cast(Count); ++i) + Result[i] = glm::log2(glm::vec4(static_cast(i))); + + std::clock_t End = clock(); + + std::printf("glm::log2: %d clocks\n", static_cast(End - Begin)); + } + + return Error; + } +}//namespace log2_ + +namespace iround +{ + int test() + { + int Error = 0; + + for(float f = 0.0f; f < 3.1f; f += 0.05f) + { + int RoundFast = static_cast(glm::iround(f)); + int RoundSTD = static_cast(glm::round(f)); + Error += RoundFast == RoundSTD ? 0 : 1; + assert(!Error); + } + + return Error; + } +}//namespace iround + +namespace uround +{ + int test() + { + int Error = 0; + + for(float f = 0.0f; f < 3.1f; f += 0.05f) + { + int RoundFast = static_cast(glm::uround(f)); + int RoundSTD = static_cast(glm::round(f)); + Error += RoundFast == RoundSTD ? 0 : 1; + assert(!Error); + } + + return Error; + } +}//namespace uround + +int main() +{ + int Error(0); + + Error += ::log2_::test(); + Error += ::iround::test(); + Error += ::uround::test(); + +# ifdef NDEBUG + std::size_t const Samples(1000); + Error += ::log2_::perf(Samples); +# endif//NDEBUG + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_matrix_access.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_matrix_access.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1b966e2288ea68563cae27c7575f5c8ab4d3be13 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_matrix_access.cpp @@ -0,0 +1,383 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int test_mat2x2_row_set() +{ + int Error = 0; + + glm::mat2x2 m(1); + + m = glm::row(m, 0, glm::vec2( 0, 1)); + m = glm::row(m, 1, glm::vec2( 4, 5)); + + Error += glm::all(glm::equal(glm::row(m, 0), glm::vec2( 0, 1), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::row(m, 1), glm::vec2( 4, 5), glm::epsilon())) ? 0 : 1; + + return Error; +} + +int test_mat2x2_col_set() +{ + int Error = 0; + + glm::mat2x2 m(1); + + m = glm::column(m, 0, glm::vec2( 0, 1)); + m = glm::column(m, 1, glm::vec2( 4, 5)); + + Error += glm::all(glm::equal(glm::column(m, 0), glm::vec2( 0, 1), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::column(m, 1), glm::vec2( 4, 5), glm::epsilon())) ? 0 : 1; + + return Error; +} + +int test_mat2x3_row_set() +{ + int Error = 0; + + glm::mat2x3 m(1); + + m = glm::row(m, 0, glm::vec2( 0, 1)); + m = glm::row(m, 1, glm::vec2( 4, 5)); + m = glm::row(m, 2, glm::vec2( 8, 9)); + + Error += glm::all(glm::equal(glm::row(m, 0), glm::vec2( 0, 1), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::row(m, 1), glm::vec2( 4, 5), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::row(m, 2), glm::vec2( 8, 9), glm::epsilon())) ? 0 : 1; + + return Error; +} + +int test_mat2x3_col_set() +{ + int Error = 0; + + glm::mat2x3 m(1); + + m = glm::column(m, 0, glm::vec3( 0, 1, 2)); + m = glm::column(m, 1, glm::vec3( 4, 5, 6)); + + Error += glm::all(glm::equal(glm::column(m, 0), glm::vec3( 0, 1, 2), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::column(m, 1), glm::vec3( 4, 5, 6), glm::epsilon())) ? 0 : 1; + + return Error; +} + +int test_mat2x4_row_set() +{ + int Error = 0; + + glm::mat2x4 m(1); + + m = glm::row(m, 0, glm::vec2( 0, 1)); + m = glm::row(m, 1, glm::vec2( 4, 5)); + m = glm::row(m, 2, glm::vec2( 8, 9)); + m = glm::row(m, 3, glm::vec2(12, 13)); + + Error += glm::all(glm::equal(glm::row(m, 0), glm::vec2( 0, 1), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::row(m, 1), glm::vec2( 4, 5), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::row(m, 2), glm::vec2( 8, 9), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::row(m, 3), glm::vec2(12, 13), glm::epsilon())) ? 0 : 1; + + return Error; +} + +int test_mat2x4_col_set() +{ + int Error = 0; + + glm::mat2x4 m(1); + + m = glm::column(m, 0, glm::vec4( 0, 1, 2, 3)); + m = glm::column(m, 1, glm::vec4( 4, 5, 6, 7)); + + Error += glm::all(glm::equal(glm::column(m, 0), glm::vec4( 0, 1, 2, 3), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::column(m, 1), glm::vec4( 4, 5, 6, 7), glm::epsilon())) ? 0 : 1; + + return Error; +} + +int test_mat3x2_row_set() +{ + int Error = 0; + + glm::mat3x2 m(1); + + m = glm::row(m, 0, glm::vec3( 0, 1, 2)); + m = glm::row(m, 1, glm::vec3( 4, 5, 6)); + + Error += glm::all(glm::equal(glm::row(m, 0), glm::vec3( 0, 1, 2), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::row(m, 1), glm::vec3( 4, 5, 6), glm::epsilon())) ? 0 : 1; + + return Error; +} + +int test_mat3x2_col_set() +{ + int Error = 0; + + glm::mat3x2 m(1); + + m = glm::column(m, 0, glm::vec2( 0, 1)); + m = glm::column(m, 1, glm::vec2( 4, 5)); + m = glm::column(m, 2, glm::vec2( 8, 9)); + + Error += glm::all(glm::equal(glm::column(m, 0), glm::vec2( 0, 1), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::column(m, 1), glm::vec2( 4, 5), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::column(m, 2), glm::vec2( 8, 9), glm::epsilon())) ? 0 : 1; + + return Error; +} + +int test_mat3x3_row_set() +{ + int Error = 0; + + glm::mat3x3 m(1); + + m = glm::row(m, 0, glm::vec3( 0, 1, 2)); + m = glm::row(m, 1, glm::vec3( 4, 5, 6)); + m = glm::row(m, 2, glm::vec3( 8, 9, 10)); + + Error += glm::all(glm::equal(glm::row(m, 0), glm::vec3( 0, 1, 2), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::row(m, 1), glm::vec3( 4, 5, 6), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::row(m, 2), glm::vec3( 8, 9, 10), glm::epsilon())) ? 0 : 1; + + return Error; +} + +int test_mat3x3_col_set() +{ + int Error = 0; + + glm::mat3x3 m(1); + + m = glm::column(m, 0, glm::vec3( 0, 1, 2)); + m = glm::column(m, 1, glm::vec3( 4, 5, 6)); + m = glm::column(m, 2, glm::vec3( 8, 9, 10)); + + Error += glm::all(glm::equal(glm::column(m, 0), glm::vec3( 0, 1, 2), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::column(m, 1), glm::vec3( 4, 5, 6), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::column(m, 2), glm::vec3( 8, 9, 10), glm::epsilon())) ? 0 : 1; + + return Error; +} + +int test_mat3x4_row_set() +{ + int Error = 0; + + glm::mat3x4 m(1); + + m = glm::row(m, 0, glm::vec3( 0, 1, 2)); + m = glm::row(m, 1, glm::vec3( 4, 5, 6)); + m = glm::row(m, 2, glm::vec3( 8, 9, 10)); + m = glm::row(m, 3, glm::vec3(12, 13, 14)); + + Error += glm::all(glm::equal(glm::row(m, 0), glm::vec3( 0, 1, 2), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::row(m, 1), glm::vec3( 4, 5, 6), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::row(m, 2), glm::vec3( 8, 9, 10), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::row(m, 3), glm::vec3(12, 13, 14), glm::epsilon())) ? 0 : 1; + + return Error; +} + +int test_mat3x4_col_set() +{ + int Error = 0; + + glm::mat3x4 m(1); + + m = glm::column(m, 0, glm::vec4( 0, 1, 2, 3)); + m = glm::column(m, 1, glm::vec4( 4, 5, 6, 7)); + m = glm::column(m, 2, glm::vec4( 8, 9, 10, 11)); + + Error += glm::all(glm::equal(glm::column(m, 0), glm::vec4( 0, 1, 2, 3), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::column(m, 1), glm::vec4( 4, 5, 6, 7), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::column(m, 2), glm::vec4( 8, 9, 10, 11), glm::epsilon())) ? 0 : 1; + + return Error; +} + +int test_mat4x2_row_set() +{ + int Error = 0; + + glm::mat4x2 m(1); + + m = glm::row(m, 0, glm::vec4( 0, 1, 2, 3)); + m = glm::row(m, 1, glm::vec4( 4, 5, 6, 7)); + + Error += glm::all(glm::equal(glm::row(m, 0), glm::vec4( 0, 1, 2, 3), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::row(m, 1), glm::vec4( 4, 5, 6, 7), glm::epsilon())) ? 0 : 1; + + return Error; +} + +int test_mat4x2_col_set() +{ + int Error = 0; + + glm::mat4x2 m(1); + + m = glm::column(m, 0, glm::vec2( 0, 1)); + m = glm::column(m, 1, glm::vec2( 4, 5)); + m = glm::column(m, 2, glm::vec2( 8, 9)); + m = glm::column(m, 3, glm::vec2(12, 13)); + + Error += glm::all(glm::equal(glm::column(m, 0), glm::vec2( 0, 1), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::column(m, 1), glm::vec2( 4, 5), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::column(m, 2), glm::vec2( 8, 9), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::column(m, 3), glm::vec2(12, 13), glm::epsilon())) ? 0 : 1; + + return Error; +} + +int test_mat4x3_row_set() +{ + int Error = 0; + + glm::mat4x3 m(1); + + m = glm::row(m, 0, glm::vec4( 0, 1, 2, 3)); + m = glm::row(m, 1, glm::vec4( 4, 5, 6, 7)); + m = glm::row(m, 2, glm::vec4( 8, 9, 10, 11)); + + Error += glm::all(glm::equal(glm::row(m, 0), glm::vec4( 0, 1, 2, 3), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::row(m, 1), glm::vec4( 4, 5, 6, 7), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::row(m, 2), glm::vec4( 8, 9, 10, 11), glm::epsilon())) ? 0 : 1; + + return Error; +} + +int test_mat4x3_col_set() +{ + int Error = 0; + + glm::mat4x3 m(1); + + m = glm::column(m, 0, glm::vec3( 0, 1, 2)); + m = glm::column(m, 1, glm::vec3( 4, 5, 6)); + m = glm::column(m, 2, glm::vec3( 8, 9, 10)); + m = glm::column(m, 3, glm::vec3(12, 13, 14)); + + Error += glm::all(glm::equal(glm::column(m, 0), glm::vec3( 0, 1, 2), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::column(m, 1), glm::vec3( 4, 5, 6), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::column(m, 2), glm::vec3( 8, 9, 10), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::column(m, 3), glm::vec3(12, 13, 14), glm::epsilon())) ? 0 : 1; + + return Error; +} + +int test_mat4x4_row_set() +{ + int Error = 0; + + glm::mat4 m(1); + + m = glm::row(m, 0, glm::vec4( 0, 1, 2, 3)); + m = glm::row(m, 1, glm::vec4( 4, 5, 6, 7)); + m = glm::row(m, 2, glm::vec4( 8, 9, 10, 11)); + m = glm::row(m, 3, glm::vec4(12, 13, 14, 15)); + + Error += glm::all(glm::equal(glm::row(m, 0), glm::vec4( 0, 1, 2, 3), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::row(m, 1), glm::vec4( 4, 5, 6, 7), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::row(m, 2), glm::vec4( 8, 9, 10, 11), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::row(m, 3), glm::vec4(12, 13, 14, 15), glm::epsilon())) ? 0 : 1; + + return Error; +} + +int test_mat4x4_col_set() +{ + int Error = 0; + + glm::mat4 m(1); + + m = glm::column(m, 0, glm::vec4( 0, 1, 2, 3)); + m = glm::column(m, 1, glm::vec4( 4, 5, 6, 7)); + m = glm::column(m, 2, glm::vec4( 8, 9, 10, 11)); + m = glm::column(m, 3, glm::vec4(12, 13, 14, 15)); + + Error += glm::all(glm::equal(glm::column(m, 0), glm::vec4( 0, 1, 2, 3), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::column(m, 1), glm::vec4( 4, 5, 6, 7), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::column(m, 2), glm::vec4( 8, 9, 10, 11), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(glm::column(m, 3), glm::vec4(12, 13, 14, 15), glm::epsilon())) ? 0 : 1; + + return Error; +} + +int test_mat4x4_row_get() +{ + int Error = 0; + + glm::mat4 m(1); + + glm::vec4 A = glm::row(m, 0); + Error += glm::all(glm::equal(A, glm::vec4(1, 0, 0, 0), glm::epsilon())) ? 0 : 1; + glm::vec4 B = glm::row(m, 1); + Error += glm::all(glm::equal(B, glm::vec4(0, 1, 0, 0), glm::epsilon())) ? 0 : 1; + glm::vec4 C = glm::row(m, 2); + Error += glm::all(glm::equal(C, glm::vec4(0, 0, 1, 0), glm::epsilon())) ? 0 : 1; + glm::vec4 D = glm::row(m, 3); + Error += glm::all(glm::equal(D, glm::vec4(0, 0, 0, 1), glm::epsilon())) ? 0 : 1; + + return Error; +} + +int test_mat4x4_col_get() +{ + int Error = 0; + + glm::mat4 m(1); + + glm::vec4 A = glm::column(m, 0); + Error += glm::all(glm::equal(A, glm::vec4(1, 0, 0, 0), glm::epsilon())) ? 0 : 1; + glm::vec4 B = glm::column(m, 1); + Error += glm::all(glm::equal(B, glm::vec4(0, 1, 0, 0), glm::epsilon())) ? 0 : 1; + glm::vec4 C = glm::column(m, 2); + Error += glm::all(glm::equal(C, glm::vec4(0, 0, 1, 0), glm::epsilon())) ? 0 : 1; + glm::vec4 D = glm::column(m, 3); + Error += glm::all(glm::equal(D, glm::vec4(0, 0, 0, 1), glm::epsilon())) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_mat2x2_row_set(); + Error += test_mat2x2_col_set(); + Error += test_mat2x3_row_set(); + Error += test_mat2x3_col_set(); + Error += test_mat2x4_row_set(); + Error += test_mat2x4_col_set(); + Error += test_mat3x2_row_set(); + Error += test_mat3x2_col_set(); + Error += test_mat3x3_row_set(); + Error += test_mat3x3_col_set(); + Error += test_mat3x4_row_set(); + Error += test_mat3x4_col_set(); + Error += test_mat4x2_row_set(); + Error += test_mat4x2_col_set(); + Error += test_mat4x3_row_set(); + Error += test_mat4x3_col_set(); + Error += test_mat4x4_row_set(); + Error += test_mat4x4_col_set(); + + Error += test_mat4x4_row_get(); + Error += test_mat4x4_col_get(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_matrix_integer.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_matrix_integer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..108016a8da88637dec0dd7c6033474b214aa31eb --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_matrix_integer.cpp @@ -0,0 +1,8 @@ +#include + +int main() +{ + int Error = 0; + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_matrix_inverse.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_matrix_inverse.cpp new file mode 100644 index 0000000000000000000000000000000000000000..eaec6e17d13d41351cc35716e195d41732d075a1 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_matrix_inverse.cpp @@ -0,0 +1,51 @@ +#include +#include + +int test_affine() +{ + int Error = 0; + + { + glm::mat3 const M( + 2.f, 0.f, 0.f, + 0.f, 2.f, 0.f, + 0.f, 0.f, 1.f); + glm::mat3 const A = glm::affineInverse(M); + glm::mat3 const I = glm::inverse(M); + glm::mat3 const R = glm::affineInverse(A); + + for(glm::length_t i = 0; i < A.length(); ++i) + { + Error += glm::all(glm::epsilonEqual(M[i], R[i], 0.01f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(A[i], I[i], 0.01f)) ? 0 : 1; + } + } + + { + glm::mat4 const M( + 2.f, 0.f, 0.f, 0.f, + 0.f, 2.f, 0.f, 0.f, + 0.f, 0.f, 2.f, 0.f, + 0.f, 0.f, 0.f, 1.f); + glm::mat4 const A = glm::affineInverse(M); + glm::mat4 const I = glm::inverse(M); + glm::mat4 const R = glm::affineInverse(A); + + for(glm::length_t i = 0; i < A.length(); ++i) + { + Error += glm::all(glm::epsilonEqual(M[i], R[i], 0.01f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(A[i], I[i], 0.01f)) ? 0 : 1; + } + } + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_affine(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_matrix_transform.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_matrix_transform.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b50666e728cb9b81420a05e5cffc7d21880b7949 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_matrix_transform.cpp @@ -0,0 +1,55 @@ +#include +#include +#include + +int test_perspective() +{ + int Error = 0; + + glm::mat4 Projection = glm::perspective(glm::pi() * 0.25f, 4.0f / 3.0f, 0.1f, 100.0f); + + return Error; +} + +int test_pick() +{ + int Error = 0; + + glm::mat4 Pick = glm::pickMatrix(glm::vec2(1, 2), glm::vec2(3, 4), glm::ivec4(0, 0, 320, 240)); + + return Error; +} + +int test_tweakedInfinitePerspective() +{ + int Error = 0; + + glm::mat4 ProjectionA = glm::tweakedInfinitePerspective(45.f, 640.f/480.f, 1.0f); + glm::mat4 ProjectionB = glm::tweakedInfinitePerspective(45.f, 640.f/480.f, 1.0f, 0.001f); + + + return Error; +} + +int test_translate() +{ + int Error = 0; + + glm::lowp_vec3 v(1.0); + glm::lowp_mat4 m(0); + glm::lowp_mat4 t = glm::translate(m, v); + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_translate(); + Error += test_tweakedInfinitePerspective(); + Error += test_pick(); + Error += test_perspective(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_noise.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_noise.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6ecec22eef29073ccc6989dd97026cef4301b5f7 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_noise.cpp @@ -0,0 +1,86 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include +#include +#include + +static int test_simplex_float() +{ + int Error = 0; + + glm::u8vec4 const PixelSimplex2D(glm::byte(glm::abs(glm::simplex(glm::vec2(0.f, 0.f))) * 255.f)); + glm::u8vec4 const PixelSimplex3D(glm::byte(glm::abs(glm::simplex(glm::vec3(0.f, 0.f, 0.f))) * 255.f)); + glm::u8vec4 const PixelSimplex4D(glm::byte(glm::abs(glm::simplex(glm::vec4(0.f, 0.f, 0.f, 0.f))) * 255.f)); + + return Error; +} + +static int test_simplex_double() +{ + int Error = 0; + + glm::u8vec4 const PixelSimplex2D(glm::byte(glm::abs(glm::simplex(glm::dvec2(0.f, 0.f))) * 255.)); + glm::u8vec4 const PixelSimplex3D(glm::byte(glm::abs(glm::simplex(glm::dvec3(0.f, 0.f, 0.f))) * 255.)); + glm::u8vec4 const PixelSimplex4D(glm::byte(glm::abs(glm::simplex(glm::dvec4(0.f, 0.f, 0.f, 0.f))) * 255.)); + + return Error; +} + +static int test_perlin_float() +{ + int Error = 0; + + glm::u8vec4 const PixelPerlin2D(glm::byte(glm::abs(glm::perlin(glm::vec2(0.f, 0.f))) * 255.f)); + glm::u8vec4 const PixelPerlin3D(glm::byte(glm::abs(glm::perlin(glm::vec3(0.f, 0.f, 0.f))) * 255.f)); + glm::u8vec4 const PixelPerlin4D(glm::byte(glm::abs(glm::perlin(glm::vec4(0.f, 0.f, 0.f, 0.f))) * 255.f)); + + return Error; +} + +static int test_perlin_double() +{ + int Error = 0; + + glm::u8vec4 const PixelPerlin2D(glm::byte(glm::abs(glm::perlin(glm::dvec2(0.f, 0.f))) * 255.)); + glm::u8vec4 const PixelPerlin3D(glm::byte(glm::abs(glm::perlin(glm::dvec3(0.f, 0.f, 0.f))) * 255.)); + glm::u8vec4 const PixelPerlin4D(glm::byte(glm::abs(glm::perlin(glm::dvec4(0.f, 0.f, 0.f, 0.f))) * 255.)); + + return Error; +} + +static int test_perlin_pedioric_float() +{ + int Error = 0; + + glm::u8vec4 const PixelPeriodic2D(glm::byte(glm::abs(glm::perlin(glm::vec2(0.f, 0.f), glm::vec2(2.0f))) * 255.f)); + glm::u8vec4 const PixelPeriodic3D(glm::byte(glm::abs(glm::perlin(glm::vec3(0.f, 0.f, 0.f), glm::vec3(2.0f))) * 255.f)); + glm::u8vec4 const PixelPeriodic4D(glm::byte(glm::abs(glm::perlin(glm::vec4(0.f, 0.f, 0.f, 0.f), glm::vec4(2.0f))) * 255.f)); + + return Error; +} + +static int test_perlin_pedioric_double() +{ + int Error = 0; + + glm::u8vec4 const PixelPeriodic2D(glm::byte(glm::abs(glm::perlin(glm::dvec2(0.f, 0.f), glm::dvec2(2.0))) * 255.)); + glm::u8vec4 const PixelPeriodic3D(glm::byte(glm::abs(glm::perlin(glm::dvec3(0.f, 0.f, 0.f), glm::dvec3(2.0))) * 255.)); + glm::u8vec4 const PixelPeriodic4D(glm::byte(glm::abs(glm::perlin(glm::dvec4(0.f, 0.f, 0.f, 0.f), glm::dvec4(2.0))) * 255.)); + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_simplex_float(); + Error += test_simplex_double(); + + Error += test_perlin_float(); + Error += test_perlin_double(); + + Error += test_perlin_pedioric_float(); + Error += test_perlin_pedioric_double(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_packing.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_packing.cpp new file mode 100644 index 0000000000000000000000000000000000000000..df5b3bb1a90747b9fcaae0fc7309803ab5a1ca7d --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_packing.cpp @@ -0,0 +1,878 @@ +#include +#include +#include +#include +#include +#include + +void print_bits(float const& s) +{ + union + { + float f; + unsigned int i; + } uif; + + uif.f = s; + + std::printf("f32: "); + for(std::size_t j = sizeof(s) * 8; j > 0; --j) + { + if(j == 23 || j == 31) + std::printf(" "); + std::printf("%d", (uif.i & (1 << (j - 1))) ? 1 : 0); + } +} + +void print_10bits(glm::uint const& s) +{ + std::printf("10b: "); + for(std::size_t j = 10; j > 0; --j) + { + if(j == 5) + std::printf(" "); + std::printf("%d", (s & (1 << (j - 1))) ? 1 : 0); + } +} + +void print_11bits(glm::uint const& s) +{ + std::printf("11b: "); + for(std::size_t j = 11; j > 0; --j) + { + if(j == 6) + std::printf(" "); + std::printf("%d", (s & (1 << (j - 1))) ? 1 : 0); + } +} + +void print_value(float const& s) +{ + std::printf("%2.5f, ", static_cast(s)); + print_bits(s); + std::printf(", "); +// print_11bits(detail::floatTo11bit(s)); +// std::printf(", "); +// print_10bits(detail::floatTo10bit(s)); + std::printf("\n"); +} + +int test_Half1x16() +{ + int Error = 0; + + std::vector Tests; + Tests.push_back(0.0f); + Tests.push_back(1.0f); + Tests.push_back(-1.0f); + Tests.push_back(2.0f); + Tests.push_back(-2.0f); + Tests.push_back(1.9f); + + for(std::size_t i = 0; i < Tests.size(); ++i) + { + glm::uint16 p0 = glm::packHalf1x16(Tests[i]); + float v0 = glm::unpackHalf1x16(p0); + glm::uint16 p1 = glm::packHalf1x16(v0); + float v1 = glm::unpackHalf1x16(p1); + Error += glm::epsilonEqual(v0, v1, glm::epsilon()) ? 0 : 1; + } + + return Error; +} + +int test_Half4x16() +{ + int Error = 0; + + std::vector Tests; + Tests.push_back(glm::vec4(1.0f)); + Tests.push_back(glm::vec4(0.0f)); + Tests.push_back(glm::vec4(2.0f)); + Tests.push_back(glm::vec4(0.1f)); + Tests.push_back(glm::vec4(0.5f)); + Tests.push_back(glm::vec4(-0.9f)); + + for(std::size_t i = 0; i < Tests.size(); ++i) + { + glm::uint64 p0 = glm::packHalf4x16(Tests[i]); + glm::vec4 v0 = glm::unpackHalf4x16(p0); + glm::uint64 p1 = glm::packHalf4x16(v0); + glm::vec4 v1 = glm::unpackHalf4x16(p1); + glm::u16vec4 p2 = glm::packHalf(v0); + glm::vec4 v2 = glm::unpackHalf(p2); + + Error += glm::all(glm::equal(v0, v1, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(v0, v2, glm::epsilon())) ? 0 : 1; + } + + return Error; +} + +int test_I3x10_1x2() +{ + int Error = 0; + + std::vector Tests; + Tests.push_back(glm::ivec4(0)); + Tests.push_back(glm::ivec4(1)); + Tests.push_back(glm::ivec4(-1)); + Tests.push_back(glm::ivec4(2)); + Tests.push_back(glm::ivec4(-2)); + Tests.push_back(glm::ivec4(3)); + + for(std::size_t i = 0; i < Tests.size(); ++i) + { + glm::uint32 p0 = glm::packI3x10_1x2(Tests[i]); + glm::ivec4 v0 = glm::unpackI3x10_1x2(p0); + glm::uint32 p1 = glm::packI3x10_1x2(v0); + glm::ivec4 v1 = glm::unpackI3x10_1x2(p1); + Error += glm::all(glm::equal(v0, v1)) ? 0 : 1; + } + + return Error; +} + +int test_U3x10_1x2() +{ + int Error = 0; + + std::vector Tests; + Tests.push_back(glm::uvec4(0)); + Tests.push_back(glm::uvec4(1)); + Tests.push_back(glm::uvec4(2)); + Tests.push_back(glm::uvec4(3)); + Tests.push_back(glm::uvec4(4)); + Tests.push_back(glm::uvec4(5)); + + for(std::size_t i = 0; i < Tests.size(); ++i) + { + glm::uint32 p0 = glm::packU3x10_1x2(Tests[i]); + glm::uvec4 v0 = glm::unpackU3x10_1x2(p0); + glm::uint32 p1 = glm::packU3x10_1x2(v0); + glm::uvec4 v1 = glm::unpackU3x10_1x2(p1); + Error += glm::all(glm::equal(v0, v1)) ? 0 : 1; + } + + glm::u8vec4 const v0(0xff, 0x77, 0x0, 0x33); + glm::uint32 const p0 = *reinterpret_cast(&v0[0]); + glm::uint32 const r0 = 0x330077ff; + + Error += p0 == r0 ? 0 : 1; + + glm::uvec4 const v1(0xff, 0x77, 0x0, 0x33); + glm::uint32 const p1 = glm::packU3x10_1x2(v1); + glm::uint32 const r1 = 0xc001dcff; + + Error += p1 == r1 ? 0 : 1; + + return Error; +} + +int test_Snorm3x10_1x2() +{ + int Error = 0; + + std::vector Tests; + Tests.push_back(glm::vec4(1.0f)); + Tests.push_back(glm::vec4(0.0f)); + Tests.push_back(glm::vec4(2.0f)); + Tests.push_back(glm::vec4(0.1f)); + Tests.push_back(glm::vec4(0.5f)); + Tests.push_back(glm::vec4(0.9f)); + + for(std::size_t i = 0; i < Tests.size(); ++i) + { + glm::uint32 p0 = glm::packSnorm3x10_1x2(Tests[i]); + glm::vec4 v0 = glm::unpackSnorm3x10_1x2(p0); + glm::uint32 p1 = glm::packSnorm3x10_1x2(v0); + glm::vec4 v1 = glm::unpackSnorm3x10_1x2(p1); + + Error += glm::all(glm::epsilonEqual(v0, v1, 0.01f)) ? 0 : 1; + } + + return Error; +} + +int test_Unorm3x10_1x2() +{ + int Error = 0; + + std::vector Tests; + Tests.push_back(glm::vec4(1.0f)); + Tests.push_back(glm::vec4(0.0f)); + Tests.push_back(glm::vec4(2.0f)); + Tests.push_back(glm::vec4(0.1f)); + Tests.push_back(glm::vec4(0.5f)); + Tests.push_back(glm::vec4(0.9f)); + + for(std::size_t i = 0; i < Tests.size(); ++i) + { + glm::uint32 p0 = glm::packUnorm3x10_1x2(Tests[i]); + glm::vec4 v0 = glm::unpackUnorm3x10_1x2(p0); + glm::uint32 p1 = glm::packUnorm3x10_1x2(v0); + glm::vec4 v1 = glm::unpackUnorm3x10_1x2(p1); + + Error += glm::all(glm::epsilonEqual(v0, v1, 0.001f)) ? 0 : 1; + } + + return Error; +} + +int test_F2x11_1x10() +{ + int Error = 0; + + std::vector Tests; + Tests.push_back(glm::vec3(1.0f)); + Tests.push_back(glm::vec3(0.0f)); + Tests.push_back(glm::vec3(2.0f)); + Tests.push_back(glm::vec3(0.1f)); + Tests.push_back(glm::vec3(0.5f)); + Tests.push_back(glm::vec3(0.9f)); + + for(std::size_t i = 0; i < Tests.size(); ++i) + { + glm::uint32 p0 = glm::packF2x11_1x10(Tests[i]); + glm::vec3 v0 = glm::unpackF2x11_1x10(p0); + glm::uint32 p1 = glm::packF2x11_1x10(v0); + glm::vec3 v1 = glm::unpackF2x11_1x10(p1); + Error += glm::all(glm::equal(v0, v1, glm::epsilon())) ? 0 : 1; + } + + return Error; +} + +int test_F3x9_E1x5() +{ + int Error = 0; + + std::vector Tests; + Tests.push_back(glm::vec3(1.0f)); + Tests.push_back(glm::vec3(0.0f)); + Tests.push_back(glm::vec3(2.0f)); + Tests.push_back(glm::vec3(0.1f)); + Tests.push_back(glm::vec3(0.5f)); + Tests.push_back(glm::vec3(0.9f)); + + for(std::size_t i = 0; i < Tests.size(); ++i) + { + glm::uint32 p0 = glm::packF3x9_E1x5(Tests[i]); + glm::vec3 v0 = glm::unpackF3x9_E1x5(p0); + glm::uint32 p1 = glm::packF3x9_E1x5(v0); + glm::vec3 v1 = glm::unpackF3x9_E1x5(p1); + Error += glm::all(glm::equal(v0, v1, glm::epsilon())) ? 0 : 1; + } + + return Error; +} + +int test_RGBM() +{ + int Error = 0; + + for(std::size_t i = 0; i < 1024; ++i) + { + glm::vec3 const Color(static_cast(i)); + glm::vec4 const RGBM = glm::packRGBM(Color); + glm::vec3 const Result= glm::unpackRGBM(RGBM); + + Error += glm::all(glm::equal(Color, Result, 0.01f)) ? 0 : 1; + } + + return Error; +} + +int test_packUnorm1x16() +{ + int Error = 0; + + std::vector A; + A.push_back(glm::vec1(1.0f)); + A.push_back(glm::vec1(0.5f)); + A.push_back(glm::vec1(0.1f)); + A.push_back(glm::vec1(0.0f)); + + for(std::size_t i = 0; i < A.size(); ++i) + { + glm::vec1 B(A[i]); + glm::uint16 C = glm::packUnorm1x16(B.x); + glm::vec1 D(glm::unpackUnorm1x16(C)); + Error += glm::all(glm::epsilonEqual(B, D, 1.0f / 65535.f)) ? 0 : 1; + assert(!Error); + } + + return Error; +} + +int test_packSnorm1x16() +{ + int Error = 0; + + std::vector A; + A.push_back(glm::vec1( 1.0f)); + A.push_back(glm::vec1( 0.0f)); + A.push_back(glm::vec1(-0.5f)); + A.push_back(glm::vec1(-0.1f)); + + for(std::size_t i = 0; i < A.size(); ++i) + { + glm::vec1 B(A[i]); + glm::uint16 C = glm::packSnorm1x16(B.x); + glm::vec1 D(glm::unpackSnorm1x16(C)); + Error += glm::all(glm::epsilonEqual(B, D, 1.0f / 32767.0f * 2.0f)) ? 0 : 1; + } + + return Error; +} + +int test_packUnorm2x16() +{ + int Error = 0; + + std::vector A; + A.push_back(glm::vec2(1.0f, 0.0f)); + A.push_back(glm::vec2(0.5f, 0.7f)); + A.push_back(glm::vec2(0.1f, 0.2f)); + + for(std::size_t i = 0; i < A.size(); ++i) + { + glm::vec2 B(A[i]); + glm::uint32 C = glm::packUnorm2x16(B); + glm::vec2 D = glm::unpackUnorm2x16(C); + Error += glm::all(glm::epsilonEqual(B, D, 1.0f / 65535.f)) ? 0 : 1; + assert(!Error); + } + + return Error; +} + +int test_packSnorm2x16() +{ + int Error = 0; + + std::vector A; + A.push_back(glm::vec2( 1.0f, 0.0f)); + A.push_back(glm::vec2(-0.5f,-0.7f)); + A.push_back(glm::vec2(-0.1f, 0.1f)); + + for(std::size_t i = 0; i < A.size(); ++i) + { + glm::vec2 B(A[i]); + glm::uint32 C = glm::packSnorm2x16(B); + glm::vec2 D = glm::unpackSnorm2x16(C); + Error += glm::all(glm::epsilonEqual(B, D, 1.0f / 32767.0f * 2.0f)) ? 0 : 1; + assert(!Error); + } + + return Error; +} + +int test_packUnorm4x16() +{ + int Error = 0; + + std::vector A; + A.push_back(glm::vec4(1.0f)); + A.push_back(glm::vec4(0.5f)); + A.push_back(glm::vec4(0.1f)); + A.push_back(glm::vec4(0.0f)); + + for(std::size_t i = 0; i < A.size(); ++i) + { + glm::vec4 B(A[i]); + glm::uint64 C = glm::packUnorm4x16(B); + glm::vec4 D(glm::unpackUnorm4x16(C)); + Error += glm::all(glm::epsilonEqual(B, D, 1.0f / 65535.f)) ? 0 : 1; + assert(!Error); + } + + return Error; +} + +int test_packSnorm4x16() +{ + int Error = 0; + + std::vector A; + A.push_back(glm::vec4( 1.0f, 0.0f, -0.5f, 0.5f)); + A.push_back(glm::vec4(-0.3f,-0.7f, 0.3f, 0.7f)); + A.push_back(glm::vec4(-0.1f, 0.1f, -0.2f, 0.2f)); + + for(std::size_t i = 0; i < A.size(); ++i) + { + glm::vec4 B(A[i]); + glm::uint64 C = glm::packSnorm4x16(B); + glm::vec4 D(glm::unpackSnorm4x16(C)); + Error += glm::all(glm::epsilonEqual(B, D, 1.0f / 32767.0f * 2.0f)) ? 0 : 1; + assert(!Error); + } + + return Error; +} + +int test_packUnorm1x8() +{ + int Error = 0; + + std::vector A; + A.push_back(glm::vec1(1.0f)); + A.push_back(glm::vec1(0.5f)); + A.push_back(glm::vec1(0.0f)); + + for(std::size_t i = 0; i < A.size(); ++i) + { + glm::vec1 B(A[i]); + glm::uint8 C = glm::packUnorm1x8(B.x); + glm::vec1 D(glm::unpackUnorm1x8(C)); + Error += glm::all(glm::epsilonEqual(B, D, 1.0f / 255.f)) ? 0 : 1; + assert(!Error); + } + + return Error; +} + +int test_packSnorm1x8() +{ + int Error = 0; + + std::vector A; + A.push_back(glm::vec1( 1.0f)); + A.push_back(glm::vec1(-0.7f)); + A.push_back(glm::vec1(-1.0f)); + + for(std::size_t i = 0; i < A.size(); ++i) + { + glm::vec1 B(A[i]); + glm::uint8 C = glm::packSnorm1x8(B.x); + glm::vec1 D(glm::unpackSnorm1x8(C)); + Error += glm::all(glm::epsilonEqual(B, D, 1.0f / 127.f)) ? 0 : 1; + } + + return Error; +} + +int test_packUnorm2x8() +{ + int Error = 0; + + std::vector A; + A.push_back(glm::vec2(1.0f, 0.7f)); + A.push_back(glm::vec2(0.5f, 0.1f)); + + for(std::size_t i = 0; i < A.size(); ++i) + { + glm::vec2 B(A[i]); + glm::uint16 C = glm::packUnorm2x8(B); + glm::vec2 D = glm::unpackUnorm2x8(C); + Error += glm::all(glm::epsilonEqual(B, D, 1.0f / 255.f)) ? 0 : 1; + assert(!Error); + } + + return Error; +} + +int test_packSnorm2x8() +{ + int Error = 0; + + std::vector A; + A.push_back(glm::vec2( 1.0f, 0.0f)); + A.push_back(glm::vec2(-0.7f,-0.1f)); + + for(std::size_t i = 0; i < A.size(); ++i) + { + glm::vec2 B(A[i]); + glm::uint16 C = glm::packSnorm2x8(B); + glm::vec2 D = glm::unpackSnorm2x8(C); + Error += glm::all(glm::epsilonEqual(B, D, 1.0f / 127.f)) ? 0 : 1; + } + + return Error; +} + +int test_packUnorm4x8() +{ + int Error = 0; + + std::vector A; + A.push_back(glm::vec4(1.0f, 0.7f, 0.3f, 0.0f)); + A.push_back(glm::vec4(0.5f, 0.1f, 0.2f, 0.3f)); + + for(std::size_t i = 0; i < A.size(); ++i) + { + glm::vec4 B(A[i]); + glm::uint32 C = glm::packUnorm4x8(B); + glm::vec4 D = glm::unpackUnorm4x8(C); + Error += glm::all(glm::epsilonEqual(B, D, 1.0f / 255.f)) ? 0 : 1; + assert(!Error); + } + + return Error; +} + +int test_packSnorm4x8() +{ + int Error = 0; + + std::vector A; + A.push_back(glm::vec4( 1.0f, 0.0f,-0.5f,-1.0f)); + A.push_back(glm::vec4(-0.7f,-0.1f, 0.1f, 0.7f)); + + for(std::size_t i = 0; i < A.size(); ++i) + { + glm::vec4 B(A[i]); + glm::uint32 C = glm::packSnorm4x8(B); + glm::vec4 D = glm::unpackSnorm4x8(C); + Error += glm::all(glm::epsilonEqual(B, D, 1.0f / 127.f)) ? 0 : 1; + assert(!Error); + } + + return Error; +} + +int test_packUnorm() +{ + int Error = 0; + + std::vector A; + A.push_back(glm::vec2(1.0f, 0.7f)); + A.push_back(glm::vec2(0.5f, 0.1f)); + + for(std::size_t i = 0; i < A.size(); ++i) + { + glm::vec2 B(A[i]); + glm::u16vec2 C = glm::packUnorm(B); + glm::vec2 D = glm::unpackUnorm(C); + Error += glm::all(glm::epsilonEqual(B, D, 1.0f / 255.f)) ? 0 : 1; + assert(!Error); + } + + return Error; +} + +int test_packSnorm() +{ + int Error = 0; + + std::vector A; + A.push_back(glm::vec2( 1.0f, 0.0f)); + A.push_back(glm::vec2(-0.5f,-0.7f)); + A.push_back(glm::vec2(-0.1f, 0.1f)); + + for(std::size_t i = 0; i < A.size(); ++i) + { + glm::vec2 B(A[i]); + glm::i16vec2 C = glm::packSnorm(B); + glm::vec2 D = glm::unpackSnorm(C); + Error += glm::all(glm::epsilonEqual(B, D, 1.0f / 32767.0f * 2.0f)) ? 0 : 1; + assert(!Error); + } + + return Error; +} + +int test_packUnorm2x4() +{ + int Error = 0; + + std::vector A; + A.push_back(glm::vec2(1.0f, 0.7f)); + A.push_back(glm::vec2(0.5f, 0.0f)); + + for(std::size_t i = 0; i < A.size(); ++i) + { + glm::vec2 B(A[i]); + glm::uint8 C = glm::packUnorm2x4(B); + glm::vec2 D = glm::unpackUnorm2x4(C); + Error += glm::all(glm::epsilonEqual(B, D, 1.0f / 15.f)) ? 0 : 1; + assert(!Error); + } + + return Error; +} + +int test_packUnorm4x4() +{ + int Error = 0; + + std::vector A; + A.push_back(glm::vec4(1.0f, 0.7f, 0.5f, 0.0f)); + A.push_back(glm::vec4(0.5f, 0.1f, 0.0f, 1.0f)); + + for(std::size_t i = 0; i < A.size(); ++i) + { + glm::vec4 B(A[i]); + glm::uint16 C = glm::packUnorm4x4(B); + glm::vec4 D = glm::unpackUnorm4x4(C); + Error += glm::all(glm::epsilonEqual(B, D, 1.0f / 15.f)) ? 0 : 1; + assert(!Error); + } + + return Error; +} + +int test_packUnorm3x5_1x1() +{ + int Error = 0; + + std::vector A; + A.push_back(glm::vec4(1.0f, 0.7f, 0.5f, 0.0f)); + A.push_back(glm::vec4(0.5f, 0.1f, 0.0f, 1.0f)); + + for(std::size_t i = 0; i < A.size(); ++i) + { + glm::vec4 B(A[i]); + glm::uint16 C = glm::packUnorm3x5_1x1(B); + glm::vec4 D = glm::unpackUnorm3x5_1x1(C); + Error += glm::all(glm::epsilonEqual(B, D, 1.0f / 15.f)) ? 0 : 1; + assert(!Error); + } + + return Error; +} + +int test_packUnorm1x5_1x6_1x5() +{ + int Error = 0; + + std::vector A; + A.push_back(glm::vec3(1.0f, 0.7f, 0.5f)); + A.push_back(glm::vec3(0.5f, 0.1f, 0.0f)); + + for(std::size_t i = 0; i < A.size(); ++i) + { + glm::vec3 B(A[i]); + glm::uint16 C = glm::packUnorm1x5_1x6_1x5(B); + glm::vec3 D = glm::unpackUnorm1x5_1x6_1x5(C); + Error += glm::all(glm::epsilonEqual(B, D, 1.0f / 15.f)) ? 0 : 1; + assert(!Error); + } + + return Error; +} + +int test_packUnorm2x3_1x2() +{ + int Error = 0; + + std::vector A; + A.push_back(glm::vec3(1.0f, 0.7f, 0.5f)); + A.push_back(glm::vec3(0.5f, 0.1f, 0.0f)); + + for(std::size_t i = 0; i < A.size(); ++i) + { + glm::vec3 B(A[i]); + glm::uint8 C = glm::packUnorm2x3_1x2(B); + glm::vec3 D = glm::unpackUnorm2x3_1x2(C); + Error += glm::all(glm::epsilonEqual(B, D, 1.0f / 3.f)) ? 0 : 1; + assert(!Error); + } + + return Error; +} + +int test_packUint2x8() +{ + int Error = 0; + + glm::u8vec2 const Source(1, 2); + + glm::uint16 const Packed = glm::packUint2x8(Source); + Error += Packed != 0 ? 0 : 1; + + glm::u8vec2 const Unpacked = glm::unpackUint2x8(Packed); + Error += Source == Unpacked ? 0 : 1; + + return Error; +} + +int test_packUint4x8() +{ + int Error = 0; + + glm::u8vec4 const Source(1, 2, 3, 4); + + glm::uint32 const Packed = glm::packUint4x8(Source); + Error += Packed != 0 ? 0 : 1; + + glm::u8vec4 const Unpacked = glm::unpackUint4x8(Packed); + Error += Source == Unpacked ? 0 : 1; + + return Error; +} + +int test_packUint2x16() +{ + int Error = 0; + + glm::u16vec2 const Source(1, 2); + + glm::uint32 const Packed = glm::packUint2x16(Source); + Error += Packed != 0 ? 0 : 1; + + glm::u16vec2 const Unpacked = glm::unpackUint2x16(Packed); + Error += Source == Unpacked ? 0 : 1; + + return Error; +} + +int test_packUint4x16() +{ + int Error = 0; + + glm::u16vec4 const Source(1, 2, 3, 4); + + glm::uint64 const Packed = glm::packUint4x16(Source); + Error += Packed != 0 ? 0 : 1; + + glm::u16vec4 const Unpacked = glm::unpackUint4x16(Packed); + Error += Source == Unpacked ? 0 : 1; + + return Error; +} + +int test_packUint2x32() +{ + int Error = 0; + + glm::u32vec2 const Source(1, 2); + + glm::uint64 const Packed = glm::packUint2x32(Source); + Error += Packed != 0 ? 0 : 1; + + glm::u32vec2 const Unpacked = glm::unpackUint2x32(Packed); + Error += Source == Unpacked ? 0 : 1; + + return Error; +} + +int test_packInt2x8() +{ + int Error = 0; + + glm::i8vec2 const Source(1, 2); + + glm::int16 const Packed = glm::packInt2x8(Source); + Error += Packed != 0 ? 0 : 1; + + glm::i8vec2 const Unpacked = glm::unpackInt2x8(Packed); + Error += Source == Unpacked ? 0 : 1; + + return Error; +} + +int test_packInt4x8() +{ + int Error = 0; + + glm::i8vec4 const Source(1, 2, 3, 4); + + glm::int32 const Packed = glm::packInt4x8(Source); + Error += Packed != 0 ? 0 : 1; + + glm::i8vec4 const Unpacked = glm::unpackInt4x8(Packed); + Error += Source == Unpacked ? 0 : 1; + + return Error; +} + +int test_packInt2x16() +{ + int Error = 0; + + glm::i16vec2 const Source(1, 2); + + glm::int32 const Packed = glm::packInt2x16(Source); + Error += Packed != 0 ? 0 : 1; + + glm::i16vec2 const Unpacked = glm::unpackInt2x16(Packed); + Error += Source == Unpacked ? 0 : 1; + + return Error; +} + +int test_packInt4x16() +{ + int Error = 0; + + glm::i16vec4 const Source(1, 2, 3, 4); + + glm::int64 const Packed = glm::packInt4x16(Source); + Error += Packed != 0 ? 0 : 1; + + glm::i16vec4 const Unpacked = glm::unpackInt4x16(Packed); + Error += Source == Unpacked ? 0 : 1; + + return Error; +} + +int test_packInt2x32() +{ + int Error = 0; + + glm::i32vec2 const Source(1, 2); + + glm::int64 const Packed = glm::packInt2x32(Source); + Error += Packed != 0 ? 0 : 1; + + glm::i32vec2 const Unpacked = glm::unpackInt2x32(Packed); + Error += Source == Unpacked ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_packUnorm(); + Error += test_packSnorm(); + + Error += test_packSnorm1x16(); + Error += test_packSnorm2x16(); + Error += test_packSnorm4x16(); + + Error += test_packSnorm1x8(); + Error += test_packSnorm2x8(); + Error += test_packSnorm4x8(); + + Error += test_packUnorm1x16(); + Error += test_packUnorm2x16(); + Error += test_packUnorm4x16(); + + Error += test_packUnorm1x8(); + Error += test_packUnorm2x8(); + Error += test_packUnorm4x8(); + + Error += test_packUnorm2x4(); + Error += test_packUnorm4x4(); + Error += test_packUnorm3x5_1x1(); + Error += test_packUnorm1x5_1x6_1x5(); + Error += test_packUnorm2x3_1x2(); + + Error += test_packUint2x8(); + Error += test_packUint4x8(); + Error += test_packUint2x16(); + Error += test_packUint4x16(); + Error += test_packUint2x32(); + + Error += test_packInt2x8(); + Error += test_packInt4x8(); + Error += test_packInt2x16(); + Error += test_packInt4x16(); + Error += test_packInt2x32(); + + Error += test_F2x11_1x10(); + Error += test_F3x9_E1x5(); + Error += test_RGBM(); + Error += test_Unorm3x10_1x2(); + Error += test_Snorm3x10_1x2(); + + Error += test_I3x10_1x2(); + Error += test_U3x10_1x2(); + Error += test_Half1x16(); + Error += test_Half4x16(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_quaternion.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_quaternion.cpp new file mode 100644 index 0000000000000000000000000000000000000000..540ca42de593463d3b3ed1c3869a6cfa4beaf905 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_quaternion.cpp @@ -0,0 +1,345 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +int test_quat_angle() +{ + int Error = 0; + + { + glm::quat Q = glm::angleAxis(glm::pi() * 0.25f, glm::vec3(0, 0, 1)); + glm::quat N = glm::normalize(Q); + float L = glm::length(N); + Error += glm::equal(L, 1.0f, 0.01f) ? 0 : 1; + float A = glm::angle(N); + Error += glm::equal(A, glm::pi() * 0.25f, 0.01f) ? 0 : 1; + } + { + glm::quat Q = glm::angleAxis(glm::pi() * 0.25f, glm::normalize(glm::vec3(0, 1, 1))); + glm::quat N = glm::normalize(Q); + float L = glm::length(N); + Error += glm::equal(L, 1.0f, 0.01f) ? 0 : 1; + float A = glm::angle(N); + Error += glm::equal(A, glm::pi() * 0.25f, 0.01f) ? 0 : 1; + } + { + glm::quat Q = glm::angleAxis(glm::pi() * 0.25f, glm::normalize(glm::vec3(1, 2, 3))); + glm::quat N = glm::normalize(Q); + float L = glm::length(N); + Error += glm::equal(L, 1.0f, 0.01f) ? 0 : 1; + float A = glm::angle(N); + Error += glm::equal(A, glm::pi() * 0.25f, 0.01f) ? 0 : 1; + } + + return Error; +} + +int test_quat_angleAxis() +{ + int Error = 0; + + glm::quat A = glm::angleAxis(0.f, glm::vec3(0.f, 0.f, 1.f)); + glm::quat B = glm::angleAxis(glm::pi() * 0.5f, glm::vec3(0, 0, 1)); + glm::quat C = glm::mix(A, B, 0.5f); + glm::quat D = glm::angleAxis(glm::pi() * 0.25f, glm::vec3(0, 0, 1)); + + Error += glm::equal(C.x, D.x, 0.01f) ? 0 : 1; + Error += glm::equal(C.y, D.y, 0.01f) ? 0 : 1; + Error += glm::equal(C.z, D.z, 0.01f) ? 0 : 1; + Error += glm::equal(C.w, D.w, 0.01f) ? 0 : 1; + + return Error; +} + +int test_quat_mix() +{ + int Error = 0; + + glm::quat A = glm::angleAxis(0.f, glm::vec3(0.f, 0.f, 1.f)); + glm::quat B = glm::angleAxis(glm::pi() * 0.5f, glm::vec3(0, 0, 1)); + glm::quat C = glm::mix(A, B, 0.5f); + glm::quat D = glm::angleAxis(glm::pi() * 0.25f, glm::vec3(0, 0, 1)); + + Error += glm::equal(C.x, D.x, 0.01f) ? 0 : 1; + Error += glm::equal(C.y, D.y, 0.01f) ? 0 : 1; + Error += glm::equal(C.z, D.z, 0.01f) ? 0 : 1; + Error += glm::equal(C.w, D.w, 0.01f) ? 0 : 1; + + return Error; +} + +int test_quat_normalize() +{ + int Error(0); + + { + glm::quat Q = glm::angleAxis(glm::pi() * 0.25f, glm::vec3(0, 0, 1)); + glm::quat N = glm::normalize(Q); + float L = glm::length(N); + Error += glm::equal(L, 1.0f, 0.000001f) ? 0 : 1; + } + { + glm::quat Q = glm::angleAxis(glm::pi() * 0.25f, glm::vec3(0, 0, 2)); + glm::quat N = glm::normalize(Q); + float L = glm::length(N); + Error += glm::equal(L, 1.0f, 0.000001f) ? 0 : 1; + } + { + glm::quat Q = glm::angleAxis(glm::pi() * 0.25f, glm::vec3(1, 2, 3)); + glm::quat N = glm::normalize(Q); + float L = glm::length(N); + Error += glm::equal(L, 1.0f, 0.000001f) ? 0 : 1; + } + + return Error; +} + +int test_quat_euler() +{ + int Error = 0; + + { + glm::quat q(1.0f, 0.0f, 0.0f, 1.0f); + float Roll = glm::roll(q); + float Pitch = glm::pitch(q); + float Yaw = glm::yaw(q); + glm::vec3 Angles = glm::eulerAngles(q); + Error += glm::all(glm::equal(Angles, glm::vec3(Pitch, Yaw, Roll), 0.000001f)) ? 0 : 1; + } + + { + glm::dquat q(1.0, 0.0, 0.0, 1.0); + double Roll = glm::roll(q); + double Pitch = glm::pitch(q); + double Yaw = glm::yaw(q); + glm::dvec3 Angles = glm::eulerAngles(q); + Error += glm::all(glm::equal(Angles, glm::dvec3(Pitch, Yaw, Roll), 0.000001)) ? 0 : 1; + } + + return Error; +} + +int test_quat_slerp() +{ + int Error = 0; + + float const Epsilon = 0.0001f;//glm::epsilon(); + + float sqrt2 = std::sqrt(2.0f)/2.0f; + glm::quat id(static_cast(1), static_cast(0), static_cast(0), static_cast(0)); + glm::quat Y90rot(sqrt2, 0.0f, sqrt2, 0.0f); + glm::quat Y180rot(0.0f, 0.0f, 1.0f, 0.0f); + + // Testing a == 0 + // Must be id + glm::quat id2 = glm::slerp(id, Y90rot, 0.0f); + Error += glm::all(glm::equal(id, id2, Epsilon)) ? 0 : 1; + + // Testing a == 1 + // Must be 90οΏ½ rotation on Y : 0 0.7 0 0.7 + glm::quat Y90rot2 = glm::slerp(id, Y90rot, 1.0f); + Error += glm::all(glm::equal(Y90rot, Y90rot2, Epsilon)) ? 0 : 1; + + // Testing standard, easy case + // Must be 45οΏ½ rotation on Y : 0 0.38 0 0.92 + glm::quat Y45rot1 = glm::slerp(id, Y90rot, 0.5f); + + // Testing reverse case + // Must be 45οΏ½ rotation on Y : 0 0.38 0 0.92 + glm::quat Ym45rot2 = glm::slerp(Y90rot, id, 0.5f); + + // Testing against full circle around the sphere instead of shortest path + // Must be 45οΏ½ rotation on Y + // certainly not a 135οΏ½ rotation + glm::quat Y45rot3 = glm::slerp(id , -Y90rot, 0.5f); + float Y45angle3 = glm::angle(Y45rot3); + Error += glm::equal(Y45angle3, glm::pi() * 0.25f, Epsilon) ? 0 : 1; + Error += glm::all(glm::equal(Ym45rot2, Y45rot3, Epsilon)) ? 0 : 1; + + // Same, but inverted + // Must also be 45οΏ½ rotation on Y : 0 0.38 0 0.92 + // -0 -0.38 -0 -0.92 is ok too + glm::quat Y45rot4 = glm::slerp(-Y90rot, id, 0.5f); + Error += glm::all(glm::equal(Ym45rot2, -Y45rot4, Epsilon)) ? 0 : 1; + + // Testing q1 = q2 + // Must be 90οΏ½ rotation on Y : 0 0.7 0 0.7 + glm::quat Y90rot3 = glm::slerp(Y90rot, Y90rot, 0.5f); + Error += glm::all(glm::equal(Y90rot, Y90rot3, Epsilon)) ? 0 : 1; + + // Testing 180οΏ½ rotation + // Must be 90οΏ½ rotation on almost any axis that is on the XZ plane + glm::quat XZ90rot = glm::slerp(id, -Y90rot, 0.5f); + float XZ90angle = glm::angle(XZ90rot); // Must be PI/4 = 0.78; + Error += glm::equal(XZ90angle, glm::pi() * 0.25f, Epsilon) ? 0 : 1; + + // Testing almost equal quaternions (this test should pass through the linear interpolation) + // Must be 0 0.00X 0 0.99999 + glm::quat almostid = glm::slerp(id, glm::angleAxis(0.1f, glm::vec3(0.0f, 1.0f, 0.0f)), 0.5f); + + // Testing quaternions with opposite sign + { + glm::quat a(-1, 0, 0, 0); + + glm::quat result = glm::slerp(a, id, 0.5f); + + Error += glm::equal(glm::pow(glm::dot(id, result), 2.f), 1.f, 0.01f) ? 0 : 1; + } + + return Error; +} + +int test_quat_slerp_spins() +{ + int Error = 0; + + float const Epsilon = 0.0001f;//glm::epsilon(); + + float sqrt2 = std::sqrt(2.0f) / 2.0f; + glm::quat id(static_cast(1), static_cast(0), static_cast(0), static_cast(0)); + glm::quat Y90rot(sqrt2, 0.0f, sqrt2, 0.0f); + glm::quat Y180rot(0.0f, 0.0f, 1.0f, 0.0f); + + // Testing a == 0, k == 1 + // Must be id + glm::quat id2 = glm::slerp(id, id, 1.0f, 1); + Error += glm::all(glm::equal(id, id2, Epsilon)) ? 0 : 1; + + // Testing a == 1, k == 2 + // Must be id + glm::quat id3 = glm::slerp(id, id, 1.0f, 2); + Error += glm::all(glm::equal(id, id3, Epsilon)) ? 0 : 1; + + // Testing a == 1, k == 1 + // Must be 90οΏ½ rotation on Y : 0 0.7 0 0.7 + // Negative quaternion is representing same orientation + glm::quat Y90rot2 = glm::slerp(id, Y90rot, 1.0f, 1); + Error += glm::all(glm::equal(Y90rot, -Y90rot2, Epsilon)) ? 0 : 1; + + // Testing a == 1, k == 2 + // Must be id + glm::quat Y90rot3 = glm::slerp(id, Y90rot, 8.0f / 9.0f, 2); + Error += glm::all(glm::equal(id, Y90rot3, Epsilon)) ? 0 : 1; + + // Testing a == 1, k == 1 + // Must be 90οΏ½ rotation on Y : 0 0.7 0 0.7 + glm::quat Y90rot4 = glm::slerp(id, Y90rot, 0.2f, 1); + Error += glm::all(glm::equal(Y90rot, Y90rot4, Epsilon)) ? 0 : 1; + + // Testing reverse case + // Must be 45οΏ½ rotation on Y : 0 0.38 0 0.92 + // Negative quaternion is representing same orientation + glm::quat Ym45rot2 = glm::slerp(Y90rot, id, 0.9f, 1); + glm::quat Ym45rot3 = glm::slerp(Y90rot, id, 0.5f); + Error += glm::all(glm::equal(-Ym45rot2, Ym45rot3, Epsilon)) ? 0 : 1; + + // Testing against full circle around the sphere instead of shortest path + // Must be 45οΏ½ rotation on Y + // certainly not a 135οΏ½ rotation + glm::quat Y45rot3 = glm::slerp(id, -Y90rot, 0.5f, 0); + float Y45angle3 = glm::angle(Y45rot3); + Error += glm::equal(Y45angle3, glm::pi() * 0.25f, Epsilon) ? 0 : 1; + Error += glm::all(glm::equal(Ym45rot3, Y45rot3, Epsilon)) ? 0 : 1; + + // Same, but inverted + // Must also be 45οΏ½ rotation on Y : 0 0.38 0 0.92 + // -0 -0.38 -0 -0.92 is ok too + glm::quat Y45rot4 = glm::slerp(-Y90rot, id, 0.5f, 0); + Error += glm::all(glm::equal(Ym45rot2, Y45rot4, Epsilon)) ? 0 : 1; + + // Testing q1 = q2 k == 2 + // Must be 90οΏ½ rotation on Y : 0 0.7 0 0.7 + glm::quat Y90rot5 = glm::slerp(Y90rot, Y90rot, 0.5f, 2); + Error += glm::all(glm::equal(Y90rot, Y90rot5, Epsilon)) ? 0 : 1; + + // Testing 180οΏ½ rotation + // Must be 90οΏ½ rotation on almost any axis that is on the XZ plane + glm::quat XZ90rot = glm::slerp(id, -Y90rot, 0.5f, 1); + float XZ90angle = glm::angle(XZ90rot); // Must be PI/4 = 0.78; + Error += glm::equal(XZ90angle, glm::pi() * 1.25f, Epsilon) ? 0 : 1; + + // Testing rotation over long arc + // Distance from id to 90οΏ½ is 270οΏ½, so 2/3 of it should be 180οΏ½ + // Negative quaternion is representing same orientation + glm::quat Neg90rot = glm::slerp(id, Y90rot, 2.0f / 3.0f, -1); + Error += glm::all(glm::equal(Y180rot, -Neg90rot, Epsilon)) ? 0 : 1; + + return Error; +} + +static int test_quat_mul_vec() +{ + int Error(0); + + glm::quat q = glm::angleAxis(glm::pi() * 0.5f, glm::vec3(0, 0, 1)); + glm::vec3 v(1, 0, 0); + glm::vec3 u(q * v); + glm::vec3 w(u * q); + + Error += glm::all(glm::equal(v, w, 0.01f)) ? 0 : 1; + + return Error; +} + +static int test_mul() +{ + int Error = 0; + + glm::quat temp1 = glm::normalize(glm::quat(1.0f, glm::vec3(0.0, 1.0, 0.0))); + glm::quat temp2 = glm::normalize(glm::quat(0.5f, glm::vec3(1.0, 0.0, 0.0))); + + glm::vec3 transformed0 = (temp1 * glm::vec3(0.0, 1.0, 0.0) * glm::inverse(temp1)); + glm::vec3 temp4 = temp2 * transformed0 * glm::inverse(temp2); + + glm::quat temp5 = glm::normalize(temp1 * temp2); + glm::vec3 temp6 = temp5 * glm::vec3(0.0, 1.0, 0.0) * glm::inverse(temp5); + + glm::quat temp7(1.0f, glm::vec3(0.0, 1.0, 0.0)); + + temp7 *= temp5; + temp7 *= glm::inverse(temp5); + + Error += glm::any(glm::notEqual(temp7, glm::quat(1.0f, glm::vec3(0.0, 1.0, 0.0)), glm::epsilon())) ? 1 : 0; + + return Error; +} + +int test_identity() +{ + int Error = 0; + + glm::quat const Q = glm::identity(); + + Error += glm::all(glm::equal(Q, glm::quat(1, 0, 0, 0), 0.0001f)) ? 0 : 1; + Error += glm::any(glm::notEqual(Q, glm::quat(1, 0, 0, 0), 0.0001f)) ? 1 : 0; + + glm::mat4 const M = glm::identity(); + glm::mat4 const N(1.0f); + + Error += glm::all(glm::equal(M, N, 0.0001f)) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_mul(); + Error += test_quat_mul_vec(); + Error += test_quat_angle(); + Error += test_quat_angleAxis(); + Error += test_quat_mix(); + Error += test_quat_normalize(); + Error += test_quat_euler(); + Error += test_quat_slerp(); + Error += test_quat_slerp_spins(); + Error += test_identity(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_random.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_random.cpp new file mode 100644 index 0000000000000000000000000000000000000000..60fb60c4291f7ef366fa0fd1e8d5e10a5eebed30 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_random.cpp @@ -0,0 +1,381 @@ +#define GLM_FORCE_DEFAULT_ALIGNED_GENTYPES +#include +#include +#include +#if GLM_LANG & GLM_LANG_CXX0X_FLAG +# include +#endif + +std::size_t const TestSamples = 10000; + +int test_linearRand() +{ + int Error = 0; + + glm::int32 const Min = 16; + glm::int32 const Max = 32; + + { + glm::u8vec2 AMin(std::numeric_limits::max()); + glm::u8vec2 AMax(std::numeric_limits::min()); + { + for(std::size_t i = 0; i < TestSamples; ++i) + { + glm::u8vec2 A = glm::linearRand(glm::u8vec2(Min), glm::u8vec2(Max)); + AMin = glm::min(AMin, A); + AMax = glm::max(AMax, A); + + if(!glm::all(glm::lessThanEqual(A, glm::u8vec2(Max)))) + ++Error; + if(!glm::all(glm::greaterThanEqual(A, glm::u8vec2(Min)))) + ++Error; + assert(!Error); + } + + Error += glm::all(glm::equal(AMin, glm::u8vec2(Min))) ? 0 : 1; + Error += glm::all(glm::equal(AMax, glm::u8vec2(Max))) ? 0 : 1; + assert(!Error); + } + + glm::u16vec2 BMin(std::numeric_limits::max()); + glm::u16vec2 BMax(std::numeric_limits::min()); + { + for(std::size_t i = 0; i < TestSamples; ++i) + { + glm::u16vec2 B = glm::linearRand(glm::u16vec2(Min), glm::u16vec2(Max)); + BMin = glm::min(BMin, B); + BMax = glm::max(BMax, B); + + if(!glm::all(glm::lessThanEqual(B, glm::u16vec2(Max)))) + ++Error; + if(!glm::all(glm::greaterThanEqual(B, glm::u16vec2(Min)))) + ++Error; + assert(!Error); + } + + Error += glm::all(glm::equal(BMin, glm::u16vec2(Min))) ? 0 : 1; + Error += glm::all(glm::equal(BMax, glm::u16vec2(Max))) ? 0 : 1; + assert(!Error); + } + + glm::u32vec2 CMin(std::numeric_limits::max()); + glm::u32vec2 CMax(std::numeric_limits::min()); + { + for(std::size_t i = 0; i < TestSamples; ++i) + { + glm::u32vec2 C = glm::linearRand(glm::u32vec2(Min), glm::u32vec2(Max)); + CMin = glm::min(CMin, C); + CMax = glm::max(CMax, C); + + if(!glm::all(glm::lessThanEqual(C, glm::u32vec2(Max)))) + ++Error; + if(!glm::all(glm::greaterThanEqual(C, glm::u32vec2(Min)))) + ++Error; + assert(!Error); + } + + Error += glm::all(glm::equal(CMin, glm::u32vec2(Min))) ? 0 : 1; + Error += glm::all(glm::equal(CMax, glm::u32vec2(Max))) ? 0 : 1; + assert(!Error); + } + + glm::u64vec2 DMin(std::numeric_limits::max()); + glm::u64vec2 DMax(std::numeric_limits::min()); + { + for(std::size_t i = 0; i < TestSamples; ++i) + { + glm::u64vec2 D = glm::linearRand(glm::u64vec2(Min), glm::u64vec2(Max)); + DMin = glm::min(DMin, D); + DMax = glm::max(DMax, D); + + if(!glm::all(glm::lessThanEqual(D, glm::u64vec2(Max)))) + ++Error; + if(!glm::all(glm::greaterThanEqual(D, glm::u64vec2(Min)))) + ++Error; + assert(!Error); + } + + Error += glm::all(glm::equal(DMin, glm::u64vec2(Min))) ? 0 : 1; + Error += glm::all(glm::equal(DMax, glm::u64vec2(Max))) ? 0 : 1; + assert(!Error); + } + } + + { + glm::i8vec2 AMin(std::numeric_limits::max()); + glm::i8vec2 AMax(std::numeric_limits::min()); + { + for(std::size_t i = 0; i < TestSamples; ++i) + { + glm::i8vec2 A = glm::linearRand(glm::i8vec2(Min), glm::i8vec2(Max)); + AMin = glm::min(AMin, A); + AMax = glm::max(AMax, A); + + if(!glm::all(glm::lessThanEqual(A, glm::i8vec2(Max)))) + ++Error; + if(!glm::all(glm::greaterThanEqual(A, glm::i8vec2(Min)))) + ++Error; + assert(!Error); + } + + Error += glm::all(glm::equal(AMin, glm::i8vec2(Min))) ? 0 : 1; + Error += glm::all(glm::equal(AMax, glm::i8vec2(Max))) ? 0 : 1; + assert(!Error); + } + + glm::i16vec2 BMin(std::numeric_limits::max()); + glm::i16vec2 BMax(std::numeric_limits::min()); + { + for(std::size_t i = 0; i < TestSamples; ++i) + { + glm::i16vec2 B = glm::linearRand(glm::i16vec2(Min), glm::i16vec2(Max)); + BMin = glm::min(BMin, B); + BMax = glm::max(BMax, B); + + if(!glm::all(glm::lessThanEqual(B, glm::i16vec2(Max)))) + ++Error; + if(!glm::all(glm::greaterThanEqual(B, glm::i16vec2(Min)))) + ++Error; + assert(!Error); + } + + Error += glm::all(glm::equal(BMin, glm::i16vec2(Min))) ? 0 : 1; + Error += glm::all(glm::equal(BMax, glm::i16vec2(Max))) ? 0 : 1; + assert(!Error); + } + + glm::i32vec2 CMin(std::numeric_limits::max()); + glm::i32vec2 CMax(std::numeric_limits::min()); + { + for(std::size_t i = 0; i < TestSamples; ++i) + { + glm::i32vec2 C = glm::linearRand(glm::i32vec2(Min), glm::i32vec2(Max)); + CMin = glm::min(CMin, C); + CMax = glm::max(CMax, C); + + if(!glm::all(glm::lessThanEqual(C, glm::i32vec2(Max)))) + ++Error; + if(!glm::all(glm::greaterThanEqual(C, glm::i32vec2(Min)))) + ++Error; + assert(!Error); + } + + Error += glm::all(glm::equal(CMin, glm::i32vec2(Min))) ? 0 : 1; + Error += glm::all(glm::equal(CMax, glm::i32vec2(Max))) ? 0 : 1; + assert(!Error); + } + + glm::i64vec2 DMin(std::numeric_limits::max()); + glm::i64vec2 DMax(std::numeric_limits::min()); + { + for(std::size_t i = 0; i < TestSamples; ++i) + { + glm::i64vec2 D = glm::linearRand(glm::i64vec2(Min), glm::i64vec2(Max)); + DMin = glm::min(DMin, D); + DMax = glm::max(DMax, D); + + if(!glm::all(glm::lessThanEqual(D, glm::i64vec2(Max)))) + ++Error; + if(!glm::all(glm::greaterThanEqual(D, glm::i64vec2(Min)))) + ++Error; + assert(!Error); + } + + Error += glm::all(glm::equal(DMin, glm::i64vec2(Min))) ? 0 : 1; + Error += glm::all(glm::equal(DMax, glm::i64vec2(Max))) ? 0 : 1; + assert(!Error); + } + } + + for(std::size_t i = 0; i < TestSamples; ++i) + { + glm::f32vec2 const A(glm::linearRand(glm::f32vec2(static_cast(Min)), glm::f32vec2(static_cast(Max)))); + if(!glm::all(glm::lessThanEqual(A, glm::f32vec2(static_cast(Max))))) + ++Error; + if(!glm::all(glm::greaterThanEqual(A, glm::f32vec2(static_cast(Min))))) + ++Error; + + glm::f64vec2 const B(glm::linearRand(glm::f64vec2(Min), glm::f64vec2(Max))); + if(!glm::all(glm::lessThanEqual(B, glm::f64vec2(Max)))) + ++Error; + if(!glm::all(glm::greaterThanEqual(B, glm::f64vec2(Min)))) + ++Error; + assert(!Error); + } + + { + float ResultFloat = 0.0f; + double ResultDouble = 0.0; + for(std::size_t i = 0; i < TestSamples; ++i) + { + ResultFloat += glm::linearRand(-1.0f, 1.0f); + ResultDouble += glm::linearRand(-1.0, 1.0); + } + + Error += glm::epsilonEqual(ResultFloat, 0.0f, 0.0001f); + Error += glm::epsilonEqual(ResultDouble, 0.0, 0.0001); + assert(!Error); + } + + return Error; +} + +int test_circularRand() +{ + int Error = 0; + + { + std::size_t Max = TestSamples; + float ResultFloat = 0.0f; + double ResultDouble = 0.0; + double Radius = 2.0; + + for(std::size_t i = 0; i < Max; ++i) + { + ResultFloat += glm::length(glm::circularRand(1.0f)); + ResultDouble += glm::length(glm::circularRand(Radius)); + } + + Error += glm::epsilonEqual(ResultFloat, float(Max), 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(ResultDouble, double(Max) * double(Radius), 0.01) ? 0 : 1; + assert(!Error); + } + + return Error; +} + +int test_sphericalRand() +{ + int Error = 0; + + { + std::size_t Max = TestSamples; + float ResultFloatA = 0.0f; + float ResultFloatB = 0.0f; + float ResultFloatC = 0.0f; + double ResultDoubleA = 0.0; + double ResultDoubleB = 0.0; + double ResultDoubleC = 0.0; + + for(std::size_t i = 0; i < Max; ++i) + { + ResultFloatA += glm::length(glm::sphericalRand(1.0f)); + ResultDoubleA += glm::length(glm::sphericalRand(1.0)); + ResultFloatB += glm::length(glm::sphericalRand(2.0f)); + ResultDoubleB += glm::length(glm::sphericalRand(2.0)); + ResultFloatC += glm::length(glm::sphericalRand(3.0f)); + ResultDoubleC += glm::length(glm::sphericalRand(3.0)); + } + + Error += glm::epsilonEqual(ResultFloatA, float(Max), 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(ResultDoubleA, double(Max), 0.0001) ? 0 : 1; + Error += glm::epsilonEqual(ResultFloatB, float(Max * 2), 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(ResultDoubleB, double(Max * 2), 0.0001) ? 0 : 1; + Error += glm::epsilonEqual(ResultFloatC, float(Max * 3), 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(ResultDoubleC, double(Max * 3), 0.01) ? 0 : 1; + assert(!Error); + } + + return Error; +} + +int test_diskRand() +{ + int Error = 0; + + { + float ResultFloat = 0.0f; + double ResultDouble = 0.0; + + for(std::size_t i = 0; i < TestSamples; ++i) + { + ResultFloat += glm::length(glm::diskRand(2.0f)); + ResultDouble += glm::length(glm::diskRand(2.0)); + } + + Error += ResultFloat < float(TestSamples) * 2.f ? 0 : 1; + Error += ResultDouble < double(TestSamples) * 2.0 ? 0 : 1; + assert(!Error); + } + + return Error; +} + +int test_ballRand() +{ + int Error = 0; + + { + float ResultFloat = 0.0f; + double ResultDouble = 0.0; + + for(std::size_t i = 0; i < TestSamples; ++i) + { + ResultFloat += glm::length(glm::ballRand(2.0f)); + ResultDouble += glm::length(glm::ballRand(2.0)); + } + + Error += ResultFloat < float(TestSamples) * 2.f ? 0 : 1; + Error += ResultDouble < double(TestSamples) * 2.0 ? 0 : 1; + assert(!Error); + } + + return Error; +} +/* +#if(GLM_LANG & GLM_LANG_CXX0X_FLAG) +int test_grid() +{ + int Error = 0; + + typedef std::array colors; + typedef std::array grid; + + grid Grid; + colors Colors; + + grid GridBest; + colors ColorsBest; + + while(true) + { + for(std::size_t i = 0; i < Grid.size(); ++i) + Grid[i] = int(glm::linearRand(0.0, 8.0 * 8.0 * 8.0 - 1.0) / 64.0); + + for(std::size_t i = 0; i < Grid.size(); ++i) + ++Colors[Grid[i]]; + + bool Exit = true; + for(std::size_t i = 0; i < Colors.size(); ++i) + { + if(Colors[i] == 8) + continue; + + Exit = false; + break; + } + + if(Exit == true) + break; + } + + return Error; +} +#endif +*/ +int main() +{ + int Error = 0; + + Error += test_linearRand(); + Error += test_circularRand(); + Error += test_sphericalRand(); + Error += test_diskRand(); + Error += test_ballRand(); +/* +#if(GLM_LANG & GLM_LANG_CXX0X_FLAG) + Error += test_grid(); +#endif +*/ + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_reciprocal.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_reciprocal.cpp new file mode 100644 index 0000000000000000000000000000000000000000..515841325f55818bf802c719bb3c272868c961fb --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_reciprocal.cpp @@ -0,0 +1,8 @@ +#include +#include + +int main() +{ + return 0; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_round.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_round.cpp new file mode 100644 index 0000000000000000000000000000000000000000..60d9a8572c3e6acabffc99dd5f43cc7192ec3a49 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_round.cpp @@ -0,0 +1,458 @@ +#include +#include +#include +#include +#include +#include +#include + +namespace isPowerOfTwo +{ + template + struct type + { + genType Value; + bool Return; + }; + + int test_int16() + { + type const Data[] = + { + {0x0001, true}, + {0x0002, true}, + {0x0004, true}, + {0x0080, true}, + {0x0000, true}, + {0x0003, false} + }; + + int Error(0); + + for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + bool Result = glm::isPowerOfTwo(Data[i].Value); + Error += Data[i].Return == Result ? 0 : 1; + } + + return Error; + } + + int test_uint16() + { + type const Data[] = + { + {0x0001, true}, + {0x0002, true}, + {0x0004, true}, + {0x0000, true}, + {0x0000, true}, + {0x0003, false} + }; + + int Error(0); + + for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + bool Result = glm::isPowerOfTwo(Data[i].Value); + Error += Data[i].Return == Result ? 0 : 1; + } + + return Error; + } + + int test_int32() + { + type const Data[] = + { + {0x00000001, true}, + {0x00000002, true}, + {0x00000004, true}, + {0x0000000f, false}, + {0x00000000, true}, + {0x00000003, false} + }; + + int Error(0); + + for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + bool Result = glm::isPowerOfTwo(Data[i].Value); + Error += Data[i].Return == Result ? 0 : 1; + } + + for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + glm::bvec1 Result = glm::isPowerOfTwo(glm::ivec1(Data[i].Value)); + Error += glm::all(glm::equal(glm::bvec1(Data[i].Return), Result)) ? 0 : 1; + } + + for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + glm::bvec2 Result = glm::isPowerOfTwo(glm::ivec2(Data[i].Value)); + Error += glm::all(glm::equal(glm::bvec2(Data[i].Return), Result)) ? 0 : 1; + } + + for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + glm::bvec3 Result = glm::isPowerOfTwo(glm::ivec3(Data[i].Value)); + Error += glm::all(glm::equal(glm::bvec3(Data[i].Return), Result)) ? 0 : 1; + } + + for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + glm::bvec4 Result = glm::isPowerOfTwo(glm::ivec4(Data[i].Value)); + Error += glm::all(glm::equal(glm::bvec4(Data[i].Return), Result)) ? 0 : 1; + } + + return Error; + } + + int test_uint32() + { + type const Data[] = + { + {0x00000001, true}, + {0x00000002, true}, + {0x00000004, true}, + {0x80000000, true}, + {0x00000000, true}, + {0x00000003, false} + }; + + int Error(0); + + for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + bool Result = glm::isPowerOfTwo(Data[i].Value); + Error += Data[i].Return == Result ? 0 : 1; + } + + return Error; + } + + int test() + { + int Error(0); + + Error += test_int16(); + Error += test_uint16(); + Error += test_int32(); + Error += test_uint32(); + + return Error; + } +}//isPowerOfTwo + +namespace ceilPowerOfTwo_advanced +{ + template + GLM_FUNC_QUALIFIER genIUType highestBitValue(genIUType Value) + { + genIUType tmp = Value; + genIUType result = genIUType(0); + while(tmp) + { + result = (tmp & (~tmp + 1)); // grab lowest bit + tmp &= ~result; // clear lowest bit + } + return result; + } + + template + GLM_FUNC_QUALIFIER genType ceilPowerOfTwo_loop(genType value) + { + return glm::isPowerOfTwo(value) ? value : highestBitValue(value) << 1; + } + + template + struct type + { + genType Value; + genType Return; + }; + + int test_int32() + { + type const Data[] = + { + {0x0000ffff, 0x00010000}, + {-3, -4}, + {-8, -8}, + {0x00000001, 0x00000001}, + {0x00000002, 0x00000002}, + {0x00000004, 0x00000004}, + {0x00000007, 0x00000008}, + {0x0000fff0, 0x00010000}, + {0x0000f000, 0x00010000}, + {0x08000000, 0x08000000}, + {0x00000000, 0x00000000}, + {0x00000003, 0x00000004} + }; + + int Error(0); + + for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + glm::int32 Result = glm::ceilPowerOfTwo(Data[i].Value); + Error += Data[i].Return == Result ? 0 : 1; + } + + return Error; + } + + int test_uint32() + { + type const Data[] = + { + {0x00000001, 0x00000001}, + {0x00000002, 0x00000002}, + {0x00000004, 0x00000004}, + {0x00000007, 0x00000008}, + {0x0000ffff, 0x00010000}, + {0x0000fff0, 0x00010000}, + {0x0000f000, 0x00010000}, + {0x80000000, 0x80000000}, + {0x00000000, 0x00000000}, + {0x00000003, 0x00000004} + }; + + int Error(0); + + for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + glm::uint32 Result = glm::ceilPowerOfTwo(Data[i].Value); + Error += Data[i].Return == Result ? 0 : 1; + } + + return Error; + } + + int perf() + { + int Error(0); + + std::vector v; + v.resize(100000000); + + std::clock_t Timestramp0 = std::clock(); + + for(glm::uint32 i = 0, n = static_cast(v.size()); i < n; ++i) + v[i] = ceilPowerOfTwo_loop(i); + + std::clock_t Timestramp1 = std::clock(); + + for(glm::uint32 i = 0, n = static_cast(v.size()); i < n; ++i) + v[i] = glm::ceilPowerOfTwo(i); + + std::clock_t Timestramp2 = std::clock(); + + std::printf("ceilPowerOfTwo_loop: %d clocks\n", static_cast(Timestramp1 - Timestramp0)); + std::printf("glm::ceilPowerOfTwo: %d clocks\n", static_cast(Timestramp2 - Timestramp1)); + + return Error; + } + + int test() + { + int Error(0); + + Error += test_int32(); + Error += test_uint32(); + + return Error; + } +}//namespace ceilPowerOfTwo_advanced + +namespace roundPowerOfTwo +{ + int test() + { + int Error = 0; + + glm::uint32 const A = glm::roundPowerOfTwo(7u); + Error += A == 8u ? 0 : 1; + + glm::uint32 const B = glm::roundPowerOfTwo(15u); + Error += B == 16u ? 0 : 1; + + glm::uint32 const C = glm::roundPowerOfTwo(31u); + Error += C == 32u ? 0 : 1; + + glm::uint32 const D = glm::roundPowerOfTwo(9u); + Error += D == 8u ? 0 : 1; + + glm::uint32 const E = glm::roundPowerOfTwo(17u); + Error += E == 16u ? 0 : 1; + + glm::uint32 const F = glm::roundPowerOfTwo(33u); + Error += F == 32u ? 0 : 1; + + return Error; + } +}//namespace roundPowerOfTwo + +namespace floorPowerOfTwo +{ + int test() + { + int Error = 0; + + glm::uint32 const A = glm::floorPowerOfTwo(7u); + Error += A == 4u ? 0 : 1; + + glm::uint32 const B = glm::floorPowerOfTwo(15u); + Error += B == 8u ? 0 : 1; + + glm::uint32 const C = glm::floorPowerOfTwo(31u); + Error += C == 16u ? 0 : 1; + + return Error; + } +}//namespace floorPowerOfTwo + +namespace ceilPowerOfTwo +{ + int test() + { + int Error = 0; + + glm::uint32 const A = glm::ceilPowerOfTwo(7u); + Error += A == 8u ? 0 : 1; + + glm::uint32 const B = glm::ceilPowerOfTwo(15u); + Error += B == 16u ? 0 : 1; + + glm::uint32 const C = glm::ceilPowerOfTwo(31u); + Error += C == 32u ? 0 : 1; + + return Error; + } +}//namespace ceilPowerOfTwo + +namespace floorMultiple +{ + template + struct type + { + genType Source; + genType Multiple; + genType Return; + genType Epsilon; + }; + + int test_float() + { + type const Data[] = + { + {3.4, 0.3, 3.3, 0.0001}, + {-1.4, 0.3, -1.5, 0.0001}, + }; + + int Error(0); + + for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + glm::float64 Result = glm::floorMultiple(Data[i].Source, Data[i].Multiple); + Error += glm::epsilonEqual(Data[i].Return, Result, Data[i].Epsilon) ? 0 : 1; + } + + return Error; + } + + int test() + { + int Error(0); + + Error += test_float(); + + return Error; + } +}//namespace floorMultiple + +namespace ceilMultiple +{ + template + struct type + { + genType Source; + genType Multiple; + genType Return; + genType Epsilon; + }; + + int test_float() + { + type const Data[] = + { + {3.4, 0.3, 3.6, 0.0001}, + {-1.4, 0.3, -1.2, 0.0001}, + }; + + int Error(0); + + for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + glm::float64 Result = glm::ceilMultiple(Data[i].Source, Data[i].Multiple); + Error += glm::epsilonEqual(Data[i].Return, Result, Data[i].Epsilon) ? 0 : 1; + } + + return Error; + } + + int test_int() + { + type const Data[] = + { + {3, 4, 4, 0}, + {7, 4, 8, 0}, + {5, 4, 8, 0}, + {1, 4, 4, 0}, + {1, 3, 3, 0}, + {4, 3, 6, 0}, + {4, 1, 4, 0}, + {1, 1, 1, 0}, + {7, 1, 7, 0}, + }; + + int Error(0); + + for(std::size_t i = 0, n = sizeof(Data) / sizeof(type); i < n; ++i) + { + int Result = glm::ceilMultiple(Data[i].Source, Data[i].Multiple); + Error += Data[i].Return == Result ? 0 : 1; + } + + return Error; + } + + int test() + { + int Error(0); + + Error += test_int(); + Error += test_float(); + + return Error; + } +}//namespace ceilMultiple + +int main() +{ + int Error(0); + + Error += isPowerOfTwo::test(); + Error += floorPowerOfTwo::test(); + Error += roundPowerOfTwo::test(); + Error += ceilPowerOfTwo::test(); + Error += ceilPowerOfTwo_advanced::test(); + +# ifdef NDEBUG + Error += ceilPowerOfTwo_advanced::perf(); +# endif//NDEBUG + + Error += floorMultiple::test(); + Error += ceilMultiple::test(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_type_aligned.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_type_aligned.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3c071efc70a3c645293f69f3d87ad6901050d595 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_type_aligned.cpp @@ -0,0 +1,181 @@ +#include + +#if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE +#include +#include +#include +#include + +GLM_STATIC_ASSERT(glm::detail::is_aligned::value, "aligned_lowp is not aligned"); +GLM_STATIC_ASSERT(glm::detail::is_aligned::value, "aligned_mediump is not aligned"); +GLM_STATIC_ASSERT(glm::detail::is_aligned::value, "aligned_highp is not aligned"); +GLM_STATIC_ASSERT(!glm::detail::is_aligned::value, "packed_highp is aligned"); +GLM_STATIC_ASSERT(!glm::detail::is_aligned::value, "packed_mediump is aligned"); +GLM_STATIC_ASSERT(!glm::detail::is_aligned::value, "packed_lowp is aligned"); + +struct my_vec4_packed +{ + glm::uint32 a; + glm::vec4 b; +}; +GLM_STATIC_ASSERT(sizeof(my_vec4_packed) == sizeof(glm::uint32) + sizeof(glm::vec4), "glm::vec4 packed is not correct"); + +struct my_vec4_aligned +{ + glm::uint32 a; + glm::aligned_vec4 b; +}; +GLM_STATIC_ASSERT(sizeof(my_vec4_aligned) == sizeof(glm::aligned_vec4) * 2, "glm::vec4 aligned is not correct"); + +struct my_dvec4_packed +{ + glm::uint64 a; + glm::dvec4 b; +}; +GLM_STATIC_ASSERT(sizeof(my_dvec4_packed) == sizeof(glm::uint64) + sizeof(glm::dvec4), "glm::dvec4 packed is not correct"); + +struct my_dvec4_aligned +{ + glm::uint64 a; + glm::aligned_dvec4 b; +}; +//GLM_STATIC_ASSERT(sizeof(my_dvec4_aligned) == sizeof(glm::aligned_dvec4) * 2, "glm::dvec4 aligned is not correct"); + +struct my_ivec4_packed +{ + glm::uint32 a; + glm::ivec4 b; +}; +GLM_STATIC_ASSERT(sizeof(my_ivec4_packed) == sizeof(glm::uint32) + sizeof(glm::ivec4), "glm::ivec4 packed is not correct"); + +struct my_ivec4_aligned +{ + glm::uint32 a; + glm::aligned_ivec4 b; +}; +GLM_STATIC_ASSERT(sizeof(my_ivec4_aligned) == sizeof(glm::aligned_ivec4) * 2, "glm::ivec4 aligned is not correct"); + +struct my_u8vec4_packed +{ + glm::uint32 a; + glm::u8vec4 b; +}; +GLM_STATIC_ASSERT(sizeof(my_u8vec4_packed) == sizeof(glm::uint32) + sizeof(glm::u8vec4), "glm::u8vec4 packed is not correct"); + +static int test_copy() +{ + int Error = 0; + + { + glm::aligned_ivec4 const a(1, 2, 3, 4); + glm::ivec4 const u(a); + + Error += a.x == u.x ? 0 : 1; + Error += a.y == u.y ? 0 : 1; + Error += a.z == u.z ? 0 : 1; + Error += a.w == u.w ? 0 : 1; + } + + { + my_ivec4_aligned a; + a.b = glm::ivec4(1, 2, 3, 4); + + my_ivec4_packed u; + u.b = a.b; + + Error += a.b.x == u.b.x ? 0 : 1; + Error += a.b.y == u.b.y ? 0 : 1; + Error += a.b.z == u.b.z ? 0 : 1; + Error += a.b.w == u.b.w ? 0 : 1; + } + + return Error; +} + +static int test_ctor() +{ + int Error = 0; + +# if GLM_HAS_CONSTEXPR + { + constexpr glm::aligned_ivec4 v(1); + + Error += v.x == 1 ? 0 : 1; + Error += v.y == 1 ? 0 : 1; + Error += v.z == 1 ? 0 : 1; + Error += v.w == 1 ? 0 : 1; + } + + { + constexpr glm::packed_ivec4 v(1); + + Error += v.x == 1 ? 0 : 1; + Error += v.y == 1 ? 0 : 1; + Error += v.z == 1 ? 0 : 1; + Error += v.w == 1 ? 0 : 1; + } + + { + constexpr glm::ivec4 v(1); + + Error += v.x == 1 ? 0 : 1; + Error += v.y == 1 ? 0 : 1; + Error += v.z == 1 ? 0 : 1; + Error += v.w == 1 ? 0 : 1; + } +# endif//GLM_HAS_CONSTEXPR + + return Error; +} + +static int test_aligned_ivec4() +{ + int Error = 0; + + glm::aligned_ivec4 const v(1, 2, 3, 4); + Error += glm::all(glm::equal(v, glm::aligned_ivec4(1, 2, 3, 4))) ? 0 : 1; + + glm::aligned_ivec4 const u = v * 2; + Error += glm::all(glm::equal(u, glm::aligned_ivec4(2, 4, 6, 8))) ? 0 : 1; + + return Error; +} + +static int test_aligned_mat4() +{ + int Error = 0; + + glm::aligned_vec4 const u(1.f, 2.f, 3.f, 4.f); + Error += glm::all(glm::equal(u, glm::aligned_vec4(1.f, 2.f, 3.f, 4.f), 0.0001f)) ? 0 : 1; + + glm::aligned_vec4 const v(1, 2, 3, 4); + Error += glm::all(glm::equal(v, glm::aligned_vec4(1.f, 2.f, 3.f, 4.f), 0.0001f)) ? 0 : 1; + + glm::aligned_mat4 const m(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + glm::aligned_mat4 const t = glm::transpose(m); + glm::aligned_mat4 const expected = glm::mat4(0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15); + Error += glm::all(glm::equal(t, expected, 0.0001f)) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_ctor(); + Error += test_copy(); + Error += test_aligned_ivec4(); + Error += test_aligned_mat4(); + + return Error; +} + +#else + +int main() +{ + return 0; +} + +#endif diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_type_precision.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_type_precision.cpp new file mode 100644 index 0000000000000000000000000000000000000000..77f068664585a99f72b1b8c77049d01fa21729dd --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_type_precision.cpp @@ -0,0 +1,1041 @@ +#include +#include +#include +#include +#include +#if GLM_HAS_OPENMP +# include +#endif + +#if GLM_HAS_STATIC_ASSERT +static_assert(sizeof(glm::lowp_u8vec1) == 1, "uint8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::mediump_u8vec1) == 1, "uint8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::highp_u8vec1) == 1, "uint8 size isn't 1 byte on this platform"); + +static_assert(sizeof(glm::lowp_u16vec1) == 2, "uint16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::mediump_u16vec1) == 2, "uint16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::highp_u16vec1) == 2, "uint16 size isn't 2 bytes on this platform"); + +static_assert(sizeof(glm::lowp_u32vec1) == 4, "uint32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::mediump_u32vec1) == 4, "uint32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::highp_u32vec1) == 4, "uint32 size isn't 4 bytes on this platform"); + +static_assert(sizeof(glm::lowp_u64vec1) == 8, "uint64 size isn't 8 bytes on this platform"); +static_assert(sizeof(glm::mediump_u64vec1) == 8, "uint64 size isn't 8 bytes on this platform"); +static_assert(sizeof(glm::highp_u64vec1) == 8, "uint64 size isn't 8 bytes on this platform"); + + +static_assert(sizeof(glm::lowp_u8vec2) == 2, "uint8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::mediump_u8vec2) == 2, "uint8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::highp_u8vec2) == 2, "uint8 size isn't 1 byte on this platform"); + +static_assert(sizeof(glm::lowp_u16vec2) == 4, "uint16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::mediump_u16vec2) == 4, "uint16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::highp_u16vec2) == 4, "uint16 size isn't 2 bytes on this platform"); + +static_assert(sizeof(glm::lowp_u32vec2) == 8, "uint32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::mediump_u32vec2) == 8, "uint32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::highp_u32vec2) == 8, "uint32 size isn't 4 bytes on this platform"); + +static_assert(sizeof(glm::lowp_u64vec2) == 16, "uint64 size isn't 8 bytes on this platform"); +static_assert(sizeof(glm::mediump_u64vec2) == 16, "uint64 size isn't 8 bytes on this platform"); +static_assert(sizeof(glm::highp_u64vec2) == 16, "uint64 size isn't 8 bytes on this platform"); + + +static_assert(sizeof(glm::lowp_u8vec3) == 3, "uint8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::mediump_u8vec3) == 3, "uint8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::highp_u8vec3) == 3, "uint8 size isn't 1 byte on this platform"); + +static_assert(sizeof(glm::lowp_u16vec3) == 6, "uint16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::mediump_u16vec3) == 6, "uint16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::highp_u16vec3) == 6, "uint16 size isn't 2 bytes on this platform"); + +static_assert(sizeof(glm::lowp_u32vec3) == 12, "uint32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::mediump_u32vec3) == 12, "uint32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::highp_u32vec3) == 12, "uint32 size isn't 4 bytes on this platform"); + +static_assert(sizeof(glm::lowp_u64vec3) == 24, "uint64 size isn't 8 bytes on this platform"); +static_assert(sizeof(glm::mediump_u64vec3) == 24, "uint64 size isn't 8 bytes on this platform"); +static_assert(sizeof(glm::highp_u64vec3) == 24, "uint64 size isn't 8 bytes on this platform"); + + +static_assert(sizeof(glm::lowp_u8vec4) == 4, "int8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::mediump_u8vec4) == 4, "int8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::highp_u8vec4) == 4, "int8 size isn't 1 byte on this platform"); + +static_assert(sizeof(glm::lowp_u16vec4) == 8, "int16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::mediump_u16vec4) == 8, "int16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::highp_u16vec4) == 8, "int16 size isn't 2 bytes on this platform"); + +static_assert(sizeof(glm::lowp_u32vec4) == 16, "int32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::mediump_u32vec4) == 16, "int32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::highp_u32vec4) == 16, "int32 size isn't 4 bytes on this platform"); + +static_assert(sizeof(glm::lowp_u64vec4) == 32, "int64 size isn't 8 bytes on this platform"); +static_assert(sizeof(glm::mediump_u64vec4) == 32, "int64 size isn't 8 bytes on this platform"); +static_assert(sizeof(glm::highp_u64vec4) == 32, "int64 size isn't 8 bytes on this platform"); + + +static_assert(sizeof(glm::lowp_u8vec1) == 1, "uint8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::mediump_u8vec1) == 1, "uint8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::highp_u8vec1) == 1, "uint8 size isn't 1 byte on this platform"); + +static_assert(sizeof(glm::lowp_u16vec1) == 2, "uint16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::mediump_u16vec1) == 2, "uint16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::highp_u16vec1) == 2, "uint16 size isn't 2 bytes on this platform"); + +static_assert(sizeof(glm::lowp_u32vec1) == 4, "uint32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::mediump_u32vec1) == 4, "uint32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::highp_u32vec1) == 4, "uint32 size isn't 4 bytes on this platform"); + +static_assert(sizeof(glm::lowp_u64vec1) == 8, "uint64 size isn't 8 bytes on this platform"); +static_assert(sizeof(glm::mediump_u64vec1) == 8, "uint64 size isn't 8 bytes on this platform"); +static_assert(sizeof(glm::highp_u64vec1) == 8, "uint64 size isn't 8 bytes on this platform"); + + +static_assert(sizeof(glm::lowp_u8vec2) == 2, "uint8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::mediump_u8vec2) == 2, "uint8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::highp_u8vec2) == 2, "uint8 size isn't 1 byte on this platform"); + +static_assert(sizeof(glm::lowp_u16vec2) == 4, "uint16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::mediump_u16vec2) == 4, "uint16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::highp_u16vec2) == 4, "uint16 size isn't 2 bytes on this platform"); + +static_assert(sizeof(glm::lowp_u32vec2) == 8, "uint32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::mediump_u32vec2) == 8, "uint32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::highp_u32vec2) == 8, "uint32 size isn't 4 bytes on this platform"); + +static_assert(sizeof(glm::lowp_u64vec2) == 16, "uint64 size isn't 8 bytes on this platform"); +static_assert(sizeof(glm::mediump_u64vec2) == 16, "uint64 size isn't 8 bytes on this platform"); +static_assert(sizeof(glm::highp_u64vec2) == 16, "uint64 size isn't 8 bytes on this platform"); + + +static_assert(sizeof(glm::lowp_u8vec3) == 3, "uint8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::mediump_u8vec3) == 3, "uint8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::highp_u8vec3) == 3, "uint8 size isn't 1 byte on this platform"); + +static_assert(sizeof(glm::lowp_u16vec3) == 6, "uint16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::mediump_u16vec3) == 6, "uint16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::highp_u16vec3) == 6, "uint16 size isn't 2 bytes on this platform"); + +static_assert(sizeof(glm::lowp_u32vec3) == 12, "uint32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::mediump_u32vec3) == 12, "uint32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::highp_u32vec3) == 12, "uint32 size isn't 4 bytes on this platform"); + +static_assert(sizeof(glm::lowp_u64vec3) == 24, "uint64 size isn't 8 bytes on this platform"); +static_assert(sizeof(glm::mediump_u64vec3) == 24, "uint64 size isn't 8 bytes on this platform"); +static_assert(sizeof(glm::highp_u64vec3) == 24, "uint64 size isn't 8 bytes on this platform"); + + +static_assert(sizeof(glm::lowp_u8vec4) == 4, "uint8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::mediump_u8vec4) == 4, "uint8 size isn't 1 byte on this platform"); +static_assert(sizeof(glm::highp_u8vec4) == 4, "uint8 size isn't 1 byte on this platform"); + +static_assert(sizeof(glm::lowp_u16vec4) == 8, "uint16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::mediump_u16vec4) == 8, "uint16 size isn't 2 bytes on this platform"); +static_assert(sizeof(glm::highp_u16vec4) == 8, "uint16 size isn't 2 bytes on this platform"); + +static_assert(sizeof(glm::lowp_u32vec4) == 16, "uint32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::mediump_u32vec4) == 16, "uint32 size isn't 4 bytes on this platform"); +static_assert(sizeof(glm::highp_u32vec4) == 16, "uint32 size isn't 4 bytes on this platform"); + +static_assert(sizeof(glm::lowp_u64vec4) == 32, "uint64 size isn't 8 bytes on this platform"); +static_assert(sizeof(glm::mediump_u64vec4) == 32, "uint64 size isn't 8 bytes on this platform"); +static_assert(sizeof(glm::highp_u64vec4) == 32, "uint64 size isn't 8 bytes on this platform"); + +#endif + +static int test_scalar_size() +{ + int Error = 0; + + Error += sizeof(glm::int8) != 1; + Error += sizeof(glm::int16) != 2; + Error += sizeof(glm::int32) != 4; + Error += sizeof(glm::int64) != 8; + Error += sizeof(glm::uint8) != 1; + Error += sizeof(glm::uint16) != 2; + Error += sizeof(glm::uint32) != 4; + Error += sizeof(glm::uint64) != 8; + Error += sizeof(glm::float32) != 4; + Error += sizeof(glm::float64) != 8; + + Error += sizeof(glm::lowp_int8) != 1; + Error += sizeof(glm::lowp_int16) != 2; + Error += sizeof(glm::lowp_int32) != 4; + Error += sizeof(glm::lowp_int64) != 8; + Error += sizeof(glm::lowp_uint8) != 1; + Error += sizeof(glm::lowp_uint16) != 2; + Error += sizeof(glm::lowp_uint32) != 4; + Error += sizeof(glm::lowp_uint64) != 8; + Error += sizeof(glm::lowp_float32) != 4; + Error += sizeof(glm::lowp_float64) != 8; + + Error += sizeof(glm::mediump_int8) != 1; + Error += sizeof(glm::mediump_int16) != 2; + Error += sizeof(glm::mediump_int32) != 4; + Error += sizeof(glm::mediump_int64) != 8; + Error += sizeof(glm::mediump_uint8) != 1; + Error += sizeof(glm::mediump_uint16) != 2; + Error += sizeof(glm::mediump_uint32) != 4; + Error += sizeof(glm::mediump_uint64) != 8; + Error += sizeof(glm::mediump_float32) != 4; + Error += sizeof(glm::mediump_float64) != 8; + + Error += sizeof(glm::highp_int8) != 1; + Error += sizeof(glm::highp_int16) != 2; + Error += sizeof(glm::highp_int32) != 4; + Error += sizeof(glm::highp_int64) != 8; + Error += sizeof(glm::highp_uint8) != 1; + Error += sizeof(glm::highp_uint16) != 2; + Error += sizeof(glm::highp_uint32) != 4; + Error += sizeof(glm::highp_uint64) != 8; + Error += sizeof(glm::highp_float32) != 4; + Error += sizeof(glm::highp_float64) != 8; + + return Error; +} + +static int test_fvec_size() +{ + int Error = 0; + + Error += sizeof(glm::f32vec2) != 8; + Error += sizeof(glm::f32vec3) != 12; + Error += sizeof(glm::f32vec4) != 16; + Error += sizeof(glm::f64vec2) != 16; + Error += sizeof(glm::f64vec3) != 24; + Error += sizeof(glm::f64vec4) != 32; + + Error += sizeof(glm::lowp_f32vec2) != 8; + Error += sizeof(glm::lowp_f32vec3) != 12; + Error += sizeof(glm::lowp_f32vec4) != 16; + Error += sizeof(glm::lowp_f64vec2) != 16; + Error += sizeof(glm::lowp_f64vec3) != 24; + Error += sizeof(glm::lowp_f64vec4) != 32; + + Error += sizeof(glm::mediump_f32vec2) != 8; + Error += sizeof(glm::mediump_f32vec3) != 12; + Error += sizeof(glm::mediump_f32vec4) != 16; + Error += sizeof(glm::mediump_f64vec2) != 16; + Error += sizeof(glm::mediump_f64vec3) != 24; + Error += sizeof(glm::mediump_f64vec4) != 32; + + Error += sizeof(glm::highp_f32vec2) != 8; + Error += sizeof(glm::highp_f32vec3) != 12; + Error += sizeof(glm::highp_f32vec4) != 16; + Error += sizeof(glm::highp_f64vec2) != 16; + Error += sizeof(glm::highp_f64vec3) != 24; + Error += sizeof(glm::highp_f64vec4) != 32; + + return Error; +} + +static int test_fvec_precision() +{ + int Error = 0; + + { + glm::f32vec2 v1(1.f); + glm::lowp_f32vec2 v2(v1); + glm::mediump_f32vec2 v3(v1); + glm::highp_f32vec2 v4(v1); + + Error += glm::all(glm::equal(v1, glm::f32vec2(v2), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::f32vec2(v3), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::f32vec2(v4), glm::epsilon())) ? 0 : 1; + } + + { + glm::f32vec3 v1(1.f); + glm::lowp_f32vec3 v2(v1); + glm::mediump_f32vec3 v3(v1); + glm::highp_f32vec3 v4(v1); + + Error += glm::all(glm::equal(v1, glm::f32vec3(v2), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::f32vec3(v3), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::f32vec3(v4), glm::epsilon())) ? 0 : 1; + } + + { + glm::f32vec4 v1(1.f); + glm::lowp_f32vec4 v2(v1); + glm::mediump_f32vec4 v3(v1); + glm::highp_f32vec4 v4(v1); + + Error += glm::all(glm::equal(v1, glm::f32vec4(v2), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::f32vec4(v3), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::f32vec4(v4), glm::epsilon())) ? 0 : 1; + } + + return Error; +} + +static int test_dvec_precision() +{ + int Error = 0; + + { + glm::f64vec2 v1(1.0); + glm::lowp_f64vec2 v2(v1); + glm::mediump_f64vec2 v3(v1); + glm::highp_f64vec2 v4(v1); + + Error += glm::all(glm::equal(v1, glm::f64vec2(v2), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::f64vec2(v3), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::f64vec2(v4), glm::epsilon())) ? 0 : 1; + } + + { + glm::f64vec3 v1(1.0); + glm::lowp_f64vec3 v2(v1); + glm::mediump_f64vec3 v3(v1); + glm::highp_f64vec3 v4(v1); + + Error += glm::all(glm::equal(v1, glm::f64vec3(v2), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::f64vec3(v3), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::f64vec3(v4), glm::epsilon())) ? 0 : 1; + } + + { + glm::f64vec4 v1(1.0); + glm::lowp_f64vec4 v2(v1); + glm::mediump_f64vec4 v3(v1); + glm::highp_f64vec4 v4(v1); + + Error += glm::all(glm::equal(v1, glm::f64vec4(v2), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::f64vec4(v3), glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::f64vec4(v4), glm::epsilon())) ? 0 : 1; + } + + return Error; +} + +static int test_ivec_size() +{ + int Error = 0; + + Error += sizeof(glm::i8vec2) != 2; + Error += sizeof(glm::i8vec3) != 3; + Error += sizeof(glm::i8vec4) != 4; + Error += sizeof(glm::i16vec2) != 4; + Error += sizeof(glm::i16vec3) != 6; + Error += sizeof(glm::i16vec4) != 8; + Error += sizeof(glm::i32vec2) != 8; + Error += sizeof(glm::i32vec3) != 12; + Error += sizeof(glm::i32vec4) != 16; + Error += sizeof(glm::i64vec2) != 16; + Error += sizeof(glm::i64vec3) != 24; + Error += sizeof(glm::i64vec4) != 32; + + Error += sizeof(glm::lowp_i8vec2) != 2; + Error += sizeof(glm::lowp_i8vec3) != 3; + Error += sizeof(glm::lowp_i8vec4) != 4; + Error += sizeof(glm::lowp_i16vec2) != 4; + Error += sizeof(glm::lowp_i16vec3) != 6; + Error += sizeof(glm::lowp_i16vec4) != 8; + Error += sizeof(glm::lowp_i32vec2) != 8; + Error += sizeof(glm::lowp_i32vec3) != 12; + Error += sizeof(glm::lowp_i32vec4) != 16; + Error += sizeof(glm::lowp_i64vec2) != 16; + Error += sizeof(glm::lowp_i64vec3) != 24; + Error += sizeof(glm::lowp_i64vec4) != 32; + + Error += sizeof(glm::mediump_i8vec2) != 2; + Error += sizeof(glm::mediump_i8vec3) != 3; + Error += sizeof(glm::mediump_i8vec4) != 4; + Error += sizeof(glm::mediump_i16vec2) != 4; + Error += sizeof(glm::mediump_i16vec3) != 6; + Error += sizeof(glm::mediump_i16vec4) != 8; + Error += sizeof(glm::mediump_i32vec2) != 8; + Error += sizeof(glm::mediump_i32vec3) != 12; + Error += sizeof(glm::mediump_i32vec4) != 16; + Error += sizeof(glm::mediump_i64vec2) != 16; + Error += sizeof(glm::mediump_i64vec3) != 24; + Error += sizeof(glm::mediump_i64vec4) != 32; + + Error += sizeof(glm::highp_i8vec2) != 2; + Error += sizeof(glm::highp_i8vec3) != 3; + Error += sizeof(glm::highp_i8vec4) != 4; + Error += sizeof(glm::highp_i16vec2) != 4; + Error += sizeof(glm::highp_i16vec3) != 6; + Error += sizeof(glm::highp_i16vec4) != 8; + Error += sizeof(glm::highp_i32vec2) != 8; + Error += sizeof(glm::highp_i32vec3) != 12; + Error += sizeof(glm::highp_i32vec4) != 16; + Error += sizeof(glm::highp_i64vec2) != 16; + Error += sizeof(glm::highp_i64vec3) != 24; + Error += sizeof(glm::highp_i64vec4) != 32; + + return Error; +} + +static int test_ivec_precision() +{ + int Error = 0; + + { + glm::i8vec2 v1(0); + glm::lowp_i8vec2 v2(v1); + glm::mediump_i8vec2 v3(v1); + glm::highp_i8vec2 v4(v1); + + Error += glm::all(glm::equal(v1, glm::i8vec2(v2))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::i8vec2(v3))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::i8vec2(v4))) ? 0 : 1; + } + + { + glm::i8vec3 v1(0); + glm::lowp_i8vec3 v2(v1); + glm::mediump_i8vec3 v3(v1); + glm::highp_i8vec3 v4(v1); + + Error += glm::all(glm::equal(v1, glm::i8vec3(v2))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::i8vec3(v3))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::i8vec3(v4))) ? 0 : 1; + } + + { + glm::i8vec4 v1(0); + glm::lowp_i8vec4 v2(v1); + glm::mediump_i8vec4 v3(v1); + glm::highp_i8vec4 v4(v1); + + Error += glm::all(glm::equal(v1, glm::i8vec4(v2))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::i8vec4(v3))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::i8vec4(v4))) ? 0 : 1; + } + + { + glm::i16vec2 v1(0); + glm::lowp_i16vec2 v2(v1); + glm::mediump_i16vec2 v3(v1); + glm::highp_i16vec2 v4(v1); + + Error += glm::all(glm::equal(v1, glm::i16vec2(v2))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::i16vec2(v3))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::i16vec2(v4))) ? 0 : 1; + } + + { + glm::i16vec3 v1(0); + glm::lowp_i16vec3 v2(v1); + glm::mediump_i16vec3 v3(v1); + glm::highp_i16vec3 v4(v1); + + Error += glm::all(glm::equal(v1, glm::i16vec3(v2))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::i16vec3(v3))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::i16vec3(v4))) ? 0 : 1; + } + + { + glm::i16vec4 v1(0); + glm::lowp_i16vec4 v2(v1); + glm::mediump_i16vec4 v3(v1); + glm::highp_i16vec4 v4(v1); + + Error += glm::all(glm::equal(v1, glm::i16vec4(v2))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::i16vec4(v3))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::i16vec4(v4))) ? 0 : 1; + } + + { + glm::i32vec2 v1(0); + glm::lowp_i32vec2 v2(v1); + glm::mediump_i32vec2 v3(v1); + glm::highp_i32vec2 v4(v1); + + Error += glm::all(glm::equal(v1, glm::i32vec2(v2))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::i32vec2(v3))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::i32vec2(v4))) ? 0 : 1; + } + + { + glm::i32vec3 v1(0); + glm::lowp_i32vec3 v2(v1); + glm::mediump_i32vec3 v3(v1); + glm::highp_i32vec3 v4(v1); + + Error += glm::all(glm::equal(v1, glm::i32vec3(v2))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::i32vec3(v3))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::i32vec3(v4))) ? 0 : 1; + } + + { + glm::i32vec4 v1(0); + glm::lowp_i32vec4 v2(v1); + glm::mediump_i32vec4 v3(v1); + glm::highp_i32vec4 v4(v1); + + Error += glm::all(glm::equal(v1, glm::i32vec4(v2))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::i32vec4(v3))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::i32vec4(v4))) ? 0 : 1; + } + + { + glm::i64vec2 v1(0); + glm::lowp_i64vec2 v2(v1); + glm::mediump_i64vec2 v3(v1); + glm::highp_i64vec2 v4(v1); + + Error += glm::all(glm::equal(v1, glm::i64vec2(v2))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::i64vec2(v3))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::i64vec2(v4))) ? 0 : 1; + } + + { + glm::i64vec3 v1(0); + glm::lowp_i64vec3 v2(v1); + glm::mediump_i64vec3 v3(v1); + glm::highp_i64vec3 v4(v1); + + Error += glm::all(glm::equal(v1, glm::i64vec3(v2))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::i64vec3(v3))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::i64vec3(v4))) ? 0 : 1; + } + + { + glm::i64vec4 v1(0); + glm::lowp_i64vec4 v2(v1); + glm::mediump_i64vec4 v3(v1); + glm::highp_i64vec4 v4(v1); + + Error += glm::all(glm::equal(v1, glm::i64vec4(v2))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::i64vec4(v3))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::i64vec4(v4))) ? 0 : 1; + } + + return Error; +} + +static int test_uvec_size() +{ + int Error = 0; + + Error += sizeof(glm::u8vec2) != 2; + Error += sizeof(glm::u8vec3) != 3; + Error += sizeof(glm::u8vec4) != 4; + Error += sizeof(glm::u16vec2) != 4; + Error += sizeof(glm::u16vec3) != 6; + Error += sizeof(glm::u16vec4) != 8; + Error += sizeof(glm::u32vec2) != 8; + Error += sizeof(glm::u32vec3) != 12; + Error += sizeof(glm::u32vec4) != 16; + Error += sizeof(glm::u64vec2) != 16; + Error += sizeof(glm::u64vec3) != 24; + Error += sizeof(glm::u64vec4) != 32; + + Error += sizeof(glm::lowp_u8vec2) != 2; + Error += sizeof(glm::lowp_u8vec3) != 3; + Error += sizeof(glm::lowp_u8vec4) != 4; + Error += sizeof(glm::lowp_u16vec2) != 4; + Error += sizeof(glm::lowp_u16vec3) != 6; + Error += sizeof(glm::lowp_u16vec4) != 8; + Error += sizeof(glm::lowp_u32vec2) != 8; + Error += sizeof(glm::lowp_u32vec3) != 12; + Error += sizeof(glm::lowp_u32vec4) != 16; + Error += sizeof(glm::lowp_u64vec2) != 16; + Error += sizeof(glm::lowp_u64vec3) != 24; + Error += sizeof(glm::lowp_u64vec4) != 32; + + Error += sizeof(glm::mediump_u8vec2) != 2; + Error += sizeof(glm::mediump_u8vec3) != 3; + Error += sizeof(glm::mediump_u8vec4) != 4; + Error += sizeof(glm::mediump_u16vec2) != 4; + Error += sizeof(glm::mediump_u16vec3) != 6; + Error += sizeof(glm::mediump_u16vec4) != 8; + Error += sizeof(glm::mediump_u32vec2) != 8; + Error += sizeof(glm::mediump_u32vec3) != 12; + Error += sizeof(glm::mediump_u32vec4) != 16; + Error += sizeof(glm::mediump_u64vec2) != 16; + Error += sizeof(glm::mediump_u64vec3) != 24; + Error += sizeof(glm::mediump_u64vec4) != 32; + + Error += sizeof(glm::highp_u8vec2) != 2; + Error += sizeof(glm::highp_u8vec3) != 3; + Error += sizeof(glm::highp_u8vec4) != 4; + Error += sizeof(glm::highp_u16vec2) != 4; + Error += sizeof(glm::highp_u16vec3) != 6; + Error += sizeof(glm::highp_u16vec4) != 8; + Error += sizeof(glm::highp_u32vec2) != 8; + Error += sizeof(glm::highp_u32vec3) != 12; + Error += sizeof(glm::highp_u32vec4) != 16; + Error += sizeof(glm::highp_u64vec2) != 16; + Error += sizeof(glm::highp_u64vec3) != 24; + Error += sizeof(glm::highp_u64vec4) != 32; + + return Error; +} + +static int test_uvec_precision() +{ + int Error = 0; + + { + glm::u8vec2 v1(0); + glm::lowp_u8vec2 v2(v1); + glm::mediump_u8vec2 v3(v1); + glm::highp_u8vec2 v4(v1); + + Error += glm::all(glm::equal(v1, glm::u8vec2(v2))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::u8vec2(v3))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::u8vec2(v4))) ? 0 : 1; + } + + { + glm::u8vec3 v1(0); + glm::lowp_u8vec3 v2(v1); + glm::mediump_u8vec3 v3(v1); + glm::highp_u8vec3 v4(v1); + + Error += glm::all(glm::equal(v1, glm::u8vec3(v2))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::u8vec3(v3))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::u8vec3(v4))) ? 0 : 1; + } + + { + glm::u8vec4 v1(0); + glm::lowp_u8vec4 v2(v1); + glm::mediump_u8vec4 v3(v1); + glm::highp_u8vec4 v4(v1); + + Error += glm::all(glm::equal(v1, glm::u8vec4(v2))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::u8vec4(v3))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::u8vec4(v4))) ? 0 : 1; + } + + { + glm::u16vec2 v1(0); + glm::lowp_u16vec2 v2(v1); + glm::mediump_u16vec2 v3(v1); + glm::highp_u16vec2 v4(v1); + + Error += glm::all(glm::equal(v1, glm::u16vec2(v2))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::u16vec2(v3))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::u16vec2(v4))) ? 0 : 1; + } + + { + glm::u16vec3 v1(0); + glm::lowp_u16vec3 v2(v1); + glm::mediump_u16vec3 v3(v1); + glm::highp_u16vec3 v4(v1); + + Error += glm::all(glm::equal(v1, glm::u16vec3(v2))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::u16vec3(v3))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::u16vec3(v4))) ? 0 : 1; + } + + { + glm::u16vec4 v1(0); + glm::lowp_u16vec4 v2(v1); + glm::mediump_u16vec4 v3(v1); + glm::highp_u16vec4 v4(v1); + + Error += glm::all(glm::equal(v1, glm::u16vec4(v2))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::u16vec4(v3))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::u16vec4(v4))) ? 0 : 1; + } + + { + glm::u32vec2 v1(0); + glm::lowp_u32vec2 v2(v1); + glm::mediump_u32vec2 v3(v1); + glm::highp_u32vec2 v4(v1); + + Error += glm::all(glm::equal(v1, glm::u32vec2(v2))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::u32vec2(v3))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::u32vec2(v4))) ? 0 : 1; + } + + { + glm::u32vec3 v1(0); + glm::lowp_u32vec3 v2(v1); + glm::mediump_u32vec3 v3(v1); + glm::highp_u32vec3 v4(v1); + + Error += glm::all(glm::equal(v1, glm::u32vec3(v2))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::u32vec3(v3))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::u32vec3(v4))) ? 0 : 1; + } + + { + glm::u32vec4 v1(0); + glm::lowp_u32vec4 v2(v1); + glm::mediump_u32vec4 v3(v1); + glm::highp_u32vec4 v4(v1); + + Error += glm::all(glm::equal(v1, glm::u32vec4(v2))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::u32vec4(v3))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::u32vec4(v4))) ? 0 : 1; + } + + { + glm::u64vec2 v1(0); + glm::lowp_u64vec2 v2(v1); + glm::mediump_u64vec2 v3(v1); + glm::highp_u64vec2 v4(v1); + + Error += glm::all(glm::equal(v1, glm::u64vec2(v2))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::u64vec2(v3))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::u64vec2(v4))) ? 0 : 1; + } + + { + glm::u64vec3 v1(0); + glm::lowp_u64vec3 v2(v1); + glm::mediump_u64vec3 v3(v1); + glm::highp_u64vec3 v4(v1); + + Error += glm::all(glm::equal(v1, glm::u64vec3(v2))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::u64vec3(v3))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::u64vec3(v4))) ? 0 : 1; + } + + { + glm::u64vec4 v1(0); + glm::lowp_u64vec4 v2(v1); + glm::mediump_u64vec4 v3(v1); + glm::highp_u64vec4 v4(v1); + + Error += glm::all(glm::equal(v1, glm::u64vec4(v2))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::u64vec4(v3))) ? 0 : 1; + Error += glm::all(glm::equal(v1, glm::u64vec4(v4))) ? 0 : 1; + } + + return Error; +} + +static int test_fmat_size() +{ + int Error = 0; + + Error += sizeof(glm::mat2) != 16; + Error += sizeof(glm::mat3) != 36; + Error += sizeof(glm::mat4) != 64; + Error += sizeof(glm::mat2x2) != 16; + Error += sizeof(glm::mat2x3) != 24; + Error += sizeof(glm::mat2x4) != 32; + Error += sizeof(glm::mat3x2) != 24; + Error += sizeof(glm::mat3x3) != 36; + Error += sizeof(glm::mat3x4) != 48; + Error += sizeof(glm::mat4x2) != 32; + Error += sizeof(glm::mat4x3) != 48; + Error += sizeof(glm::mat4x4) != 64; + + Error += sizeof(glm::fmat2) != 16; + Error += sizeof(glm::fmat3) != 36; + Error += sizeof(glm::fmat4) != 64; + Error += sizeof(glm::fmat2x2) != 16; + Error += sizeof(glm::fmat2x3) != 24; + Error += sizeof(glm::fmat2x4) != 32; + Error += sizeof(glm::fmat3x2) != 24; + Error += sizeof(glm::fmat3x3) != 36; + Error += sizeof(glm::fmat3x4) != 48; + Error += sizeof(glm::fmat4x2) != 32; + Error += sizeof(glm::fmat4x3) != 48; + Error += sizeof(glm::fmat4x4) != 64; + + Error += sizeof(glm::f32mat2) != 16; + Error += sizeof(glm::f32mat3) != 36; + Error += sizeof(glm::f32mat4) != 64; + Error += sizeof(glm::f32mat2x2) != 16; + Error += sizeof(glm::f32mat2x3) != 24; + Error += sizeof(glm::f32mat2x4) != 32; + Error += sizeof(glm::f32mat3x2) != 24; + Error += sizeof(glm::f32mat3x3) != 36; + Error += sizeof(glm::f32mat3x4) != 48; + Error += sizeof(glm::f32mat4x2) != 32; + Error += sizeof(glm::f32mat4x3) != 48; + Error += sizeof(glm::f32mat4x4) != 64; + + + Error += sizeof(glm::lowp_mat2) != 16; + Error += sizeof(glm::lowp_mat3) != 36; + Error += sizeof(glm::lowp_mat4) != 64; + Error += sizeof(glm::lowp_mat2x2) != 16; + Error += sizeof(glm::lowp_mat2x3) != 24; + Error += sizeof(glm::lowp_mat2x4) != 32; + Error += sizeof(glm::lowp_mat3x2) != 24; + Error += sizeof(glm::lowp_mat3x3) != 36; + Error += sizeof(glm::lowp_mat3x4) != 48; + Error += sizeof(glm::lowp_mat4x2) != 32; + Error += sizeof(glm::lowp_mat4x3) != 48; + Error += sizeof(glm::lowp_mat4x4) != 64; + + Error += sizeof(glm::lowp_fmat2) != 16; + Error += sizeof(glm::lowp_fmat3) != 36; + Error += sizeof(glm::lowp_fmat4) != 64; + Error += sizeof(glm::lowp_fmat2x2) != 16; + Error += sizeof(glm::lowp_fmat2x3) != 24; + Error += sizeof(glm::lowp_fmat2x4) != 32; + Error += sizeof(glm::lowp_fmat3x2) != 24; + Error += sizeof(glm::lowp_fmat3x3) != 36; + Error += sizeof(glm::lowp_fmat3x4) != 48; + Error += sizeof(glm::lowp_fmat4x2) != 32; + Error += sizeof(glm::lowp_fmat4x3) != 48; + Error += sizeof(glm::lowp_fmat4x4) != 64; + + Error += sizeof(glm::lowp_f32mat2) != 16; + Error += sizeof(glm::lowp_f32mat3) != 36; + Error += sizeof(glm::lowp_f32mat4) != 64; + Error += sizeof(glm::lowp_f32mat2x2) != 16; + Error += sizeof(glm::lowp_f32mat2x3) != 24; + Error += sizeof(glm::lowp_f32mat2x4) != 32; + Error += sizeof(glm::lowp_f32mat3x2) != 24; + Error += sizeof(glm::lowp_f32mat3x3) != 36; + Error += sizeof(glm::lowp_f32mat3x4) != 48; + Error += sizeof(glm::lowp_f32mat4x2) != 32; + Error += sizeof(glm::lowp_f32mat4x3) != 48; + Error += sizeof(glm::lowp_f32mat4x4) != 64; + + Error += sizeof(glm::mediump_mat2) != 16; + Error += sizeof(glm::mediump_mat3) != 36; + Error += sizeof(glm::mediump_mat4) != 64; + Error += sizeof(glm::mediump_mat2x2) != 16; + Error += sizeof(glm::mediump_mat2x3) != 24; + Error += sizeof(glm::mediump_mat2x4) != 32; + Error += sizeof(glm::mediump_mat3x2) != 24; + Error += sizeof(glm::mediump_mat3x3) != 36; + Error += sizeof(glm::mediump_mat3x4) != 48; + Error += sizeof(glm::mediump_mat4x2) != 32; + Error += sizeof(glm::mediump_mat4x3) != 48; + Error += sizeof(glm::mediump_mat4x4) != 64; + + Error += sizeof(glm::mediump_fmat2) != 16; + Error += sizeof(glm::mediump_fmat3) != 36; + Error += sizeof(glm::mediump_fmat4) != 64; + Error += sizeof(glm::mediump_fmat2x2) != 16; + Error += sizeof(glm::mediump_fmat2x3) != 24; + Error += sizeof(glm::mediump_fmat2x4) != 32; + Error += sizeof(glm::mediump_fmat3x2) != 24; + Error += sizeof(glm::mediump_fmat3x3) != 36; + Error += sizeof(glm::mediump_fmat3x4) != 48; + Error += sizeof(glm::mediump_fmat4x2) != 32; + Error += sizeof(glm::mediump_fmat4x3) != 48; + Error += sizeof(glm::mediump_fmat4x4) != 64; + + Error += sizeof(glm::mediump_f32mat2) != 16; + Error += sizeof(glm::mediump_f32mat3) != 36; + Error += sizeof(glm::mediump_f32mat4) != 64; + Error += sizeof(glm::mediump_f32mat2x2) != 16; + Error += sizeof(glm::mediump_f32mat2x3) != 24; + Error += sizeof(glm::mediump_f32mat2x4) != 32; + Error += sizeof(glm::mediump_f32mat3x2) != 24; + Error += sizeof(glm::mediump_f32mat3x3) != 36; + Error += sizeof(glm::mediump_f32mat3x4) != 48; + Error += sizeof(glm::mediump_f32mat4x2) != 32; + Error += sizeof(glm::mediump_f32mat4x3) != 48; + Error += sizeof(glm::mediump_f32mat4x4) != 64; + + Error += sizeof(glm::highp_mat2) != 16; + Error += sizeof(glm::highp_mat3) != 36; + Error += sizeof(glm::highp_mat4) != 64; + Error += sizeof(glm::highp_mat2x2) != 16; + Error += sizeof(glm::highp_mat2x3) != 24; + Error += sizeof(glm::highp_mat2x4) != 32; + Error += sizeof(glm::highp_mat3x2) != 24; + Error += sizeof(glm::highp_mat3x3) != 36; + Error += sizeof(glm::highp_mat3x4) != 48; + Error += sizeof(glm::highp_mat4x2) != 32; + Error += sizeof(glm::highp_mat4x3) != 48; + Error += sizeof(glm::highp_mat4x4) != 64; + + Error += sizeof(glm::highp_fmat2) != 16; + Error += sizeof(glm::highp_fmat3) != 36; + Error += sizeof(glm::highp_fmat4) != 64; + Error += sizeof(glm::highp_fmat2x2) != 16; + Error += sizeof(glm::highp_fmat2x3) != 24; + Error += sizeof(glm::highp_fmat2x4) != 32; + Error += sizeof(glm::highp_fmat3x2) != 24; + Error += sizeof(glm::highp_fmat3x3) != 36; + Error += sizeof(glm::highp_fmat3x4) != 48; + Error += sizeof(glm::highp_fmat4x2) != 32; + Error += sizeof(glm::highp_fmat4x3) != 48; + Error += sizeof(glm::highp_fmat4x4) != 64; + + Error += sizeof(glm::highp_f32mat2) != 16; + Error += sizeof(glm::highp_f32mat3) != 36; + Error += sizeof(glm::highp_f32mat4) != 64; + Error += sizeof(glm::highp_f32mat2x2) != 16; + Error += sizeof(glm::highp_f32mat2x3) != 24; + Error += sizeof(glm::highp_f32mat2x4) != 32; + Error += sizeof(glm::highp_f32mat3x2) != 24; + Error += sizeof(glm::highp_f32mat3x3) != 36; + Error += sizeof(glm::highp_f32mat3x4) != 48; + Error += sizeof(glm::highp_f32mat4x2) != 32; + Error += sizeof(glm::highp_f32mat4x3) != 48; + Error += sizeof(glm::highp_f32mat4x4) != 64; + + return Error; +} + +static int test_dmat_size() +{ + int Error = 0; + + Error += sizeof(glm::f64mat2) != 32; + Error += sizeof(glm::f64mat3) != 72; + Error += sizeof(glm::f64mat4) != 128; + Error += sizeof(glm::f64mat2x2) != 32; + Error += sizeof(glm::f64mat2x3) != 48; + Error += sizeof(glm::f64mat2x4) != 64; + Error += sizeof(glm::f64mat3x2) != 48; + Error += sizeof(glm::f64mat3x3) != 72; + Error += sizeof(glm::f64mat3x4) != 96; + Error += sizeof(glm::f64mat4x2) != 64; + Error += sizeof(glm::f64mat4x3) != 96; + Error += sizeof(glm::f64mat4x4) != 128; + + Error += sizeof(glm::lowp_f64mat2) != 32; + Error += sizeof(glm::lowp_f64mat3) != 72; + Error += sizeof(glm::lowp_f64mat4) != 128; + Error += sizeof(glm::lowp_f64mat2x2) != 32; + Error += sizeof(glm::lowp_f64mat2x3) != 48; + Error += sizeof(glm::lowp_f64mat2x4) != 64; + Error += sizeof(glm::lowp_f64mat3x2) != 48; + Error += sizeof(glm::lowp_f64mat3x3) != 72; + Error += sizeof(glm::lowp_f64mat3x4) != 96; + Error += sizeof(glm::lowp_f64mat4x2) != 64; + Error += sizeof(glm::lowp_f64mat4x3) != 96; + Error += sizeof(glm::lowp_f64mat4x4) != 128; + + Error += sizeof(glm::mediump_f64mat2) != 32; + Error += sizeof(glm::mediump_f64mat3) != 72; + Error += sizeof(glm::mediump_f64mat4) != 128; + Error += sizeof(glm::mediump_f64mat2x2) != 32; + Error += sizeof(glm::mediump_f64mat2x3) != 48; + Error += sizeof(glm::mediump_f64mat2x4) != 64; + Error += sizeof(glm::mediump_f64mat3x2) != 48; + Error += sizeof(glm::mediump_f64mat3x3) != 72; + Error += sizeof(glm::mediump_f64mat3x4) != 96; + Error += sizeof(glm::mediump_f64mat4x2) != 64; + Error += sizeof(glm::mediump_f64mat4x3) != 96; + Error += sizeof(glm::mediump_f64mat4x4) != 128; + + Error += sizeof(glm::highp_f64mat2) != 32; + Error += sizeof(glm::highp_f64mat3) != 72; + Error += sizeof(glm::highp_f64mat4) != 128; + Error += sizeof(glm::highp_f64mat2x2) != 32; + Error += sizeof(glm::highp_f64mat2x3) != 48; + Error += sizeof(glm::highp_f64mat2x4) != 64; + Error += sizeof(glm::highp_f64mat3x2) != 48; + Error += sizeof(glm::highp_f64mat3x3) != 72; + Error += sizeof(glm::highp_f64mat3x4) != 96; + Error += sizeof(glm::highp_f64mat4x2) != 64; + Error += sizeof(glm::highp_f64mat4x3) != 96; + Error += sizeof(glm::highp_f64mat4x4) != 128; + + return Error; +} + +static int test_quat_size() +{ + int Error = 0; + + Error += sizeof(glm::f32quat) != 16; + Error += sizeof(glm::f64quat) != 32; + + Error += sizeof(glm::lowp_f32quat) != 16; + Error += sizeof(glm::lowp_f64quat) != 32; + + Error += sizeof(glm::mediump_f32quat) != 16; + Error += sizeof(glm::mediump_f64quat) != 32; + + Error += sizeof(glm::highp_f32quat) != 16; + Error += sizeof(glm::highp_f64quat) != 32; + + return Error; +} + +static int test_quat_precision() +{ + int Error = 0; + + { + glm::f32quat q1(0.f, glm::vec3(0.f, 0.f, 1.f)); + glm::lowp_f32quat qA(q1); + glm::mediump_f32quat qB(q1); + glm::highp_f32quat qC(q1); + glm::f32quat q2(qA); + glm::f32quat q3(qB); + glm::f32quat q4(qC); + + Error += glm::all(glm::equal(q1, q2, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(q1, q3, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(q1, q4, glm::epsilon())) ? 0 : 1; + } + + return Error; +} + +static int test_fvec_conversion() +{ + int Error(0); + + { + glm::highp_vec4 a = glm::vec4(1, 2, 3, 4); + glm::mediump_vec4 b = glm::vec4(1, 2, 3, 4); + glm::lowp_vec4 c = b; + glm::mediump_vec4 d = c; + glm::lowp_ivec4 e = glm::ivec4(d); + glm::lowp_ivec3 f = glm::ivec3(e); + + Error += glm::all(glm::equal(b, d, glm::epsilon())) ? 0 : 1; + } + + return Error; +} + +#if GLM_HAS_OPENMP +static int test_openmp() +{ + std::vector VectorA(1000); + std::vector VectorB(1000); + std::vector VectorC(1000); + + for (std::size_t i = 0; i < VectorA.size(); ++i) + { + VectorA[i] = glm::u8vec3(1, 1, 1); + VectorB[i] = glm::u8vec3(1, 1, 1); + } + + #pragma omp parallel for default(none) shared(VectorA, VectorB, VectorC) + for (int i = 0; i < static_cast(VectorC.size()); ++i) + { + VectorC[i] = VectorA[i] + VectorB[i]; + } + + return 0; +} +#endif//GLM_HAS_OPENMP + +int main() +{ + int Error = 0; + + Error += test_scalar_size(); + Error += test_fvec_size(); + + Error += test_fvec_precision(); + Error += test_fvec_conversion(); + + Error += test_dvec_precision(); + + Error += test_uvec_size(); + Error += test_uvec_precision(); + Error += test_ivec_size(); + Error += test_ivec_precision(); + + Error += test_fmat_size(); + Error += test_dmat_size(); + Error += test_quat_size(); + Error += test_quat_precision(); + +# if GLM_HAS_OPENMP + Error += test_openmp(); +# endif// + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_type_ptr.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_type_ptr.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6fcd305415f16cc1930528e1ed3f8430e26dd627 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_type_ptr.cpp @@ -0,0 +1,335 @@ +#include +#include +#include +#include + +int test_value_ptr_vec() +{ + int Error = 0; + + { + glm::vec2 v(1.0); + float * p = glm::value_ptr(v); + Error += p == &v[0] ? 0 : 1; + } + { + glm::vec3 v(1.0); + float * p = glm::value_ptr(v); + Error += p == &v[0] ? 0 : 1; + } + { + glm::vec4 v(1.0); + float * p = glm::value_ptr(v); + Error += p == &v[0] ? 0 : 1; + } + + { + glm::dvec2 v(1.0); + double * p = glm::value_ptr(v); + Error += p == &v[0] ? 0 : 1; + } + { + glm::dvec3 v(1.0); + double * p = glm::value_ptr(v); + Error += p == &v[0] ? 0 : 1; + } + { + glm::dvec4 v(1.0); + double * p = glm::value_ptr(v); + Error += p == &v[0] ? 0 : 1; + } + + return Error; +} + +int test_value_ptr_vec_const() +{ + int Error = 0; + + { + glm::vec2 const v(1.0); + float const * p = glm::value_ptr(v); + Error += p == &v[0] ? 0 : 1; + } + { + glm::vec3 const v(1.0); + float const * p = glm::value_ptr(v); + Error += p == &v[0] ? 0 : 1; + } + { + glm::vec4 const v(1.0); + float const * p = glm::value_ptr(v); + Error += p == &v[0] ? 0 : 1; + } + + { + glm::dvec2 const v(1.0); + double const * p = glm::value_ptr(v); + Error += p == &v[0] ? 0 : 1; + } + { + glm::dvec3 const v(1.0); + double const * p = glm::value_ptr(v); + Error += p == &v[0] ? 0 : 1; + } + { + glm::dvec4 const v(1.0); + double const * p = glm::value_ptr(v); + Error += p == &v[0] ? 0 : 1; + } + + return Error; +} + +int test_value_ptr_mat() +{ + int Error = 0; + + { + glm::mat2x2 m(1.0); + float * p = glm::value_ptr(m); + Error += p == &m[0][0] ? 0 : 1; + } + { + glm::mat2x3 m(1.0); + float * p = glm::value_ptr(m); + Error += p == &m[0][0] ? 0 : 1; + } + { + glm::mat2x4 m(1.0); + float * p = glm::value_ptr(m); + Error += p == &m[0][0] ? 0 : 1; + } + { + glm::mat3x2 m(1.0); + float * p = glm::value_ptr(m); + Error += p == &m[0][0] ? 0 : 1; + } + { + glm::mat3x3 m(1.0); + float * p = glm::value_ptr(m); + Error += p == &m[0][0] ? 0 : 1; + } + { + glm::mat3x4 m(1.0); + float * p = glm::value_ptr(m); + Error += p == &m[0][0] ? 0 : 1; + } + { + glm::mat4x2 m(1.0); + float * p = glm::value_ptr(m); + Error += p == &m[0][0] ? 0 : 1; + } + { + glm::mat4x3 m(1.0); + float * p = glm::value_ptr(m); + Error += p == &m[0][0] ? 0 : 1; + } + { + glm::mat4x4 m(1.0); + float * p = glm::value_ptr(m); + Error += p == &m[0][0] ? 0 : 1; + } + + return Error; +} + +int test_value_ptr_mat_const() +{ + int Error = 0; + + { + glm::mat2x2 const m(1.0); + float const * p = glm::value_ptr(m); + Error += p == &m[0][0] ? 0 : 1; + } + { + glm::mat2x3 const m(1.0); + float const * p = glm::value_ptr(m); + Error += p == &m[0][0] ? 0 : 1; + } + { + glm::mat2x4 const m(1.0); + float const * p = glm::value_ptr(m); + Error += p == &m[0][0] ? 0 : 1; + } + { + glm::mat3x2 const m(1.0); + float const * p = glm::value_ptr(m); + Error += p == &m[0][0] ? 0 : 1; + } + { + glm::mat3x3 const m(1.0); + float const * p = glm::value_ptr(m); + Error += p == &m[0][0] ? 0 : 1; + } + { + glm::mat3x4 const m(1.0); + float const * p = glm::value_ptr(m); + Error += p == &m[0][0] ? 0 : 1; + } + { + glm::mat4x2 const m(1.0); + float const * p = glm::value_ptr(m); + Error += p == &m[0][0] ? 0 : 1; + } + { + glm::mat4x3 const m(1.0); + float const * p = glm::value_ptr(m); + Error += p == &m[0][0] ? 0 : 1; + } + { + glm::mat4x4 const m(1.0); + float const * p = glm::value_ptr(m); + Error += p == &m[0][0] ? 0 : 1; + } + + return Error; +} + +int test_make_pointer_mat() +{ + int Error = 0; + + float ArrayA[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; + double ArrayB[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; + + glm::mat2x2 Mat2x2A = glm::make_mat2x2(ArrayA); + glm::mat2x3 Mat2x3A = glm::make_mat2x3(ArrayA); + glm::mat2x4 Mat2x4A = glm::make_mat2x4(ArrayA); + glm::mat3x2 Mat3x2A = glm::make_mat3x2(ArrayA); + glm::mat3x3 Mat3x3A = glm::make_mat3x3(ArrayA); + glm::mat3x4 Mat3x4A = glm::make_mat3x4(ArrayA); + glm::mat4x2 Mat4x2A = glm::make_mat4x2(ArrayA); + glm::mat4x3 Mat4x3A = glm::make_mat4x3(ArrayA); + glm::mat4x4 Mat4x4A = glm::make_mat4x4(ArrayA); + + glm::dmat2x2 Mat2x2B = glm::make_mat2x2(ArrayB); + glm::dmat2x3 Mat2x3B = glm::make_mat2x3(ArrayB); + glm::dmat2x4 Mat2x4B = glm::make_mat2x4(ArrayB); + glm::dmat3x2 Mat3x2B = glm::make_mat3x2(ArrayB); + glm::dmat3x3 Mat3x3B = glm::make_mat3x3(ArrayB); + glm::dmat3x4 Mat3x4B = glm::make_mat3x4(ArrayB); + glm::dmat4x2 Mat4x2B = glm::make_mat4x2(ArrayB); + glm::dmat4x3 Mat4x3B = glm::make_mat4x3(ArrayB); + glm::dmat4x4 Mat4x4B = glm::make_mat4x4(ArrayB); + + return Error; +} + +int test_make_pointer_vec() +{ + int Error = 0; + + float ArrayA[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; + int ArrayB[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; + bool ArrayC[] = {true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false}; + + glm::vec2 Vec2A = glm::make_vec2(ArrayA); + glm::vec3 Vec3A = glm::make_vec3(ArrayA); + glm::vec4 Vec4A = glm::make_vec4(ArrayA); + + glm::ivec2 Vec2B = glm::make_vec2(ArrayB); + glm::ivec3 Vec3B = glm::make_vec3(ArrayB); + glm::ivec4 Vec4B = glm::make_vec4(ArrayB); + + glm::bvec2 Vec2C = glm::make_vec2(ArrayC); + glm::bvec3 Vec3C = glm::make_vec3(ArrayC); + glm::bvec4 Vec4C = glm::make_vec4(ArrayC); + + return Error; +} + +int test_make_vec1() +{ + int Error = 0; + + glm::ivec1 const v1 = glm::make_vec1(glm::ivec1(2)); + Error += v1 == glm::ivec1(2) ? 0 : 1; + + glm::ivec1 const v2 = glm::make_vec1(glm::ivec2(2)); + Error += v2 == glm::ivec1(2) ? 0 : 1; + + glm::ivec1 const v3 = glm::make_vec1(glm::ivec3(2)); + Error += v3 == glm::ivec1(2) ? 0 : 1; + + glm::ivec1 const v4 = glm::make_vec1(glm::ivec4(2)); + Error += v3 == glm::ivec1(2) ? 0 : 1; + + return Error; +} + +int test_make_vec2() +{ + int Error = 0; + + glm::ivec2 const v1 = glm::make_vec2(glm::ivec1(2)); + Error += v1 == glm::ivec2(2, 0) ? 0 : 1; + + glm::ivec2 const v2 = glm::make_vec2(glm::ivec2(2)); + Error += v2 == glm::ivec2(2, 2) ? 0 : 1; + + glm::ivec2 const v3 = glm::make_vec2(glm::ivec3(2)); + Error += v3 == glm::ivec2(2, 2) ? 0 : 1; + + glm::ivec2 const v4 = glm::make_vec2(glm::ivec4(2)); + Error += v3 == glm::ivec2(2, 2) ? 0 : 1; + + return Error; +} + +int test_make_vec3() +{ + int Error = 0; + + glm::ivec3 const v1 = glm::make_vec3(glm::ivec1(2)); + Error += v1 == glm::ivec3(2, 0, 0) ? 0 : 1; + + glm::ivec3 const v2 = glm::make_vec3(glm::ivec2(2)); + Error += v2 == glm::ivec3(2, 2, 0) ? 0 : 1; + + glm::ivec3 const v3 = glm::make_vec3(glm::ivec3(2)); + Error += v3 == glm::ivec3(2, 2, 2) ? 0 : 1; + + glm::ivec3 const v4 = glm::make_vec3(glm::ivec4(2)); + Error += v3 == glm::ivec3(2, 2, 2) ? 0 : 1; + + return Error; +} + +int test_make_vec4() +{ + int Error = 0; + + glm::ivec4 const v1 = glm::make_vec4(glm::ivec1(2)); + Error += v1 == glm::ivec4(2, 0, 0, 1) ? 0 : 1; + + glm::ivec4 const v2 = glm::make_vec4(glm::ivec2(2)); + Error += v2 == glm::ivec4(2, 2, 0, 1) ? 0 : 1; + + glm::ivec4 const v3 = glm::make_vec4(glm::ivec3(2)); + Error += v3 == glm::ivec4(2, 2, 2, 1) ? 0 : 1; + + glm::ivec4 const v4 = glm::make_vec4(glm::ivec4(2)); + Error += v4 == glm::ivec4(2, 2, 2, 2) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_make_vec1(); + Error += test_make_vec2(); + Error += test_make_vec3(); + Error += test_make_vec4(); + Error += test_make_pointer_vec(); + Error += test_make_pointer_mat(); + Error += test_value_ptr_vec(); + Error += test_value_ptr_vec_const(); + Error += test_value_ptr_mat(); + Error += test_value_ptr_mat_const(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_ulp.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_ulp.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d5074a3d20533e853e17bfa2f13784a1a85a56d9 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_ulp.cpp @@ -0,0 +1,99 @@ +#include +#include +#include + +int test_ulp_float_dist() +{ + int Error = 0; + + float A = 1.0f; + + float B = glm::next_float(A); + Error += glm::notEqual(A, B, 0) ? 0 : 1; + float C = glm::prev_float(B); + Error += glm::equal(A, C, 0) ? 0 : 1; + + int D = glm::float_distance(A, B); + Error += D == 1 ? 0 : 1; + int E = glm::float_distance(A, C); + Error += E == 0 ? 0 : 1; + + return Error; +} + +int test_ulp_float_step() +{ + int Error = 0; + + float A = 1.0f; + + for(int i = 10; i < 1000; i *= 10) + { + float B = glm::next_float(A, i); + Error += glm::notEqual(A, B, 0) ? 0 : 1; + float C = glm::prev_float(B, i); + Error += glm::equal(A, C, 0) ? 0 : 1; + + int D = glm::float_distance(A, B); + Error += D == i ? 0 : 1; + int E = glm::float_distance(A, C); + Error += E == 0 ? 0 : 1; + } + + return Error; +} + +int test_ulp_double_dist() +{ + int Error = 0; + + double A = 1.0; + + double B = glm::next_float(A); + Error += glm::notEqual(A, B, 0) ? 0 : 1; + double C = glm::prev_float(B); + Error += glm::equal(A, C, 0) ? 0 : 1; + + glm::int64 const D = glm::float_distance(A, B); + Error += D == 1 ? 0 : 1; + glm::int64 const E = glm::float_distance(A, C); + Error += E == 0 ? 0 : 1; + + return Error; +} + +int test_ulp_double_step() +{ + int Error = 0; + + double A = 1.0; + + for(int i = 10; i < 1000; i *= 10) + { + double B = glm::next_float(A, i); + Error += glm::notEqual(A, B, 0) ? 0 : 1; + double C = glm::prev_float(B, i); + Error += glm::equal(A, C, 0) ? 0 : 1; + + glm::int64 const D = glm::float_distance(A, B); + Error += D == i ? 0 : 1; + glm::int64 const E = glm::float_distance(A, C); + Error += E == 0 ? 0 : 1; + } + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_ulp_float_dist(); + Error += test_ulp_float_step(); + Error += test_ulp_double_dist(); + Error += test_ulp_double_step(); + + return Error; +} + + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_user_defined_types.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_user_defined_types.cpp new file mode 100644 index 0000000000000000000000000000000000000000..af39620db01e0127fa632fa350abd4c673a39b18 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_user_defined_types.cpp @@ -0,0 +1,30 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +// OpenGL Mathematics Copyright (c) 2005 - 2014 G-Truc Creation (www.g-truc.net) +/////////////////////////////////////////////////////////////////////////////////////////////////// +// Created : 2010-09-16 +// Updated : 2011-05-27 +// Licence : This source is under MIT licence +// File : test/gtc/type_ptr.cpp +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#define GLM_FORCE_RADIANS +#include + +int test_make_pointer_vec() +{ + int Error = 0; + + glm::func(); + //func(); + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_make_pointer_vec(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_vec1.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_vec1.cpp new file mode 100644 index 0000000000000000000000000000000000000000..268d95e656f2ff80222006963c766b385d3a226b --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtc/gtc_vec1.cpp @@ -0,0 +1,8 @@ +#include + +int main() +{ + int Error = 0; + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/CMakeLists.txt b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..6fdb1398bc272dbc3052d5d52d216d86e0582b1c --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/CMakeLists.txt @@ -0,0 +1,60 @@ +glmCreateTestGTC(gtx) +glmCreateTestGTC(gtx_associated_min_max) +glmCreateTestGTC(gtx_closest_point) +glmCreateTestGTC(gtx_color_encoding) +glmCreateTestGTC(gtx_color_space_YCoCg) +glmCreateTestGTC(gtx_color_space) +glmCreateTestGTC(gtx_common) +glmCreateTestGTC(gtx_compatibility) +glmCreateTestGTC(gtx_component_wise) +glmCreateTestGTC(gtx_easing) +glmCreateTestGTC(gtx_euler_angle) +glmCreateTestGTC(gtx_extend) +glmCreateTestGTC(gtx_extended_min_max) +glmCreateTestGTC(gtx_exterior_product) +glmCreateTestGTC(gtx_fast_exponential) +glmCreateTestGTC(gtx_fast_square_root) +glmCreateTestGTC(gtx_fast_trigonometry) +glmCreateTestGTC(gtx_functions) +glmCreateTestGTC(gtx_gradient_paint) +glmCreateTestGTC(gtx_handed_coordinate_space) +glmCreateTestGTC(gtx_hash) +glmCreateTestGTC(gtx_integer) +glmCreateTestGTC(gtx_intersect) +glmCreateTestGTC(gtx_io) +glmCreateTestGTC(gtx_load) +glmCreateTestGTC(gtx_log_base) +glmCreateTestGTC(gtx_matrix_cross_product) +glmCreateTestGTC(gtx_matrix_decompose) +glmCreateTestGTC(gtx_matrix_factorisation) +glmCreateTestGTC(gtx_matrix_interpolation) +glmCreateTestGTC(gtx_matrix_major_storage) +glmCreateTestGTC(gtx_matrix_operation) +glmCreateTestGTC(gtx_matrix_query) +glmCreateTestGTC(gtx_matrix_transform_2d) +glmCreateTestGTC(gtx_norm) +glmCreateTestGTC(gtx_normal) +glmCreateTestGTC(gtx_normalize_dot) +glmCreateTestGTC(gtx_number_precision) +glmCreateTestGTC(gtx_orthonormalize) +glmCreateTestGTC(gtx_optimum_pow) +glmCreateTestGTC(gtx_pca) +glmCreateTestGTC(gtx_perpendicular) +glmCreateTestGTC(gtx_polar_coordinates) +glmCreateTestGTC(gtx_projection) +glmCreateTestGTC(gtx_quaternion) +glmCreateTestGTC(gtx_dual_quaternion) +glmCreateTestGTC(gtx_range) +glmCreateTestGTC(gtx_rotate_normalized_axis) +glmCreateTestGTC(gtx_rotate_vector) +glmCreateTestGTC(gtx_scalar_multiplication) +glmCreateTestGTC(gtx_scalar_relational) +glmCreateTestGTC(gtx_spline) +glmCreateTestGTC(gtx_string_cast) +glmCreateTestGTC(gtx_texture) +glmCreateTestGTC(gtx_type_aligned) +glmCreateTestGTC(gtx_type_trait) +glmCreateTestGTC(gtx_vec_swizzle) +glmCreateTestGTC(gtx_vector_angle) +glmCreateTestGTC(gtx_vector_query) +glmCreateTestGTC(gtx_wrap) diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1b143b61ee3bb5ad24a1f6fa857d30e73272eb5b --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx.cpp @@ -0,0 +1,8 @@ +#include + +int main() +{ + int Error = 0; + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_associated_min_max.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_associated_min_max.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9007f8aac2f12a05fb3c88417b669dc555f94cd7 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_associated_min_max.cpp @@ -0,0 +1,10 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include +#include + +int main() +{ + int Error(0); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_closest_point.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_closest_point.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0f6303a5d19571eec1ebe9da7af98bc529af08a2 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_closest_point.cpp @@ -0,0 +1,9 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include + +int main() +{ + int Error(0); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_color_encoding.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_color_encoding.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8b499be3a86effb5be952500257bf52acb0ed637 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_color_encoding.cpp @@ -0,0 +1,51 @@ +#include +#include +#include +#include + +namespace srgb +{ + int test() + { + int Error(0); + + glm::vec3 const ColorSourceRGB(1.0, 0.5, 0.0); +/* + { + glm::vec3 const ColorSRGB = glm::convertLinearSRGBToD65XYZ(ColorSourceRGB); + glm::vec3 const ColorRGB = glm::convertD65XYZToLinearSRGB(ColorSRGB); + Error += glm::all(glm::epsilonEqual(ColorSourceRGB, ColorRGB, 0.00001f)) ? 0 : 1; + } +*/ + { + glm::vec3 const ColorSRGB = glm::convertLinearToSRGB(ColorSourceRGB, 2.8f); + glm::vec3 const ColorRGB = glm::convertSRGBToLinear(ColorSRGB, 2.8f); + Error += glm::all(glm::epsilonEqual(ColorSourceRGB, ColorRGB, 0.00001f)) ? 0 : 1; + } + + glm::vec4 const ColorSourceRGBA(1.0, 0.5, 0.0, 1.0); + + { + glm::vec4 const ColorSRGB = glm::convertLinearToSRGB(ColorSourceRGBA); + glm::vec4 const ColorRGB = glm::convertSRGBToLinear(ColorSRGB); + Error += glm::all(glm::epsilonEqual(ColorSourceRGBA, ColorRGB, 0.00001f)) ? 0 : 1; + } + + { + glm::vec4 const ColorSRGB = glm::convertLinearToSRGB(ColorSourceRGBA, 2.8f); + glm::vec4 const ColorRGB = glm::convertSRGBToLinear(ColorSRGB, 2.8f); + Error += glm::all(glm::epsilonEqual(ColorSourceRGBA, ColorRGB, 0.00001f)) ? 0 : 1; + } + + return Error; + } +}//namespace srgb + +int main() +{ + int Error(0); + + Error += srgb::test(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_color_space.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_color_space.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a23d2c86b1b7f02ad3a57495e723f0478cc0a5fe --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_color_space.cpp @@ -0,0 +1,20 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include + +int test_saturation() +{ + int Error(0); + + glm::vec4 Color = glm::saturation(1.0f, glm::vec4(1.0, 0.5, 0.0, 1.0)); + + return Error; +} + +int main() +{ + int Error(0); + + Error += test_saturation(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_color_space_YCoCg.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_color_space_YCoCg.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2ca131dc1d685028334426fa3cd0f68cd2f475f8 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_color_space_YCoCg.cpp @@ -0,0 +1,9 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include + +int main() +{ + int Error(0); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_common.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_common.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fd4fa99bddf13a59a927c16d9249d5b946e83508 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_common.cpp @@ -0,0 +1,161 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include +#include +#include +#include +#include + +namespace fmod_ +{ + template + GLM_FUNC_QUALIFIER genType modTrunc(genType a, genType b) + { + return a - b * glm::trunc(a / b); + } + + int test() + { + int Error(0); + + { + float A0(3.0); + float B0(2.0f); + float C0 = glm::fmod(A0, B0); + + Error += glm::abs(C0 - 1.0f) < 0.00001f ? 0 : 1; + + glm::vec4 A1(3.0); + float B1(2.0f); + glm::vec4 C1 = glm::fmod(A1, B1); + + Error += glm::all(glm::epsilonEqual(C1, glm::vec4(1.0f), 0.00001f)) ? 0 : 1; + + glm::vec4 A2(3.0); + glm::vec4 B2(2.0f); + glm::vec4 C2 = glm::fmod(A2, B2); + + Error += glm::all(glm::epsilonEqual(C2, glm::vec4(1.0f), 0.00001f)) ? 0 : 1; + + glm::ivec4 A3(3); + int B3(2); + glm::ivec4 C3 = glm::fmod(A3, B3); + + Error += glm::all(glm::equal(C3, glm::ivec4(1))) ? 0 : 1; + + glm::ivec4 A4(3); + glm::ivec4 B4(2); + glm::ivec4 C4 = glm::fmod(A4, B4); + + Error += glm::all(glm::equal(C4, glm::ivec4(1))) ? 0 : 1; + } + + { + float A0(22.0); + float B0(-10.0f); + float C0 = glm::fmod(A0, B0); + + Error += glm::abs(C0 - 2.0f) < 0.00001f ? 0 : 1; + + glm::vec4 A1(22.0); + float B1(-10.0f); + glm::vec4 C1 = glm::fmod(A1, B1); + + Error += glm::all(glm::epsilonEqual(C1, glm::vec4(2.0f), 0.00001f)) ? 0 : 1; + + glm::vec4 A2(22.0); + glm::vec4 B2(-10.0f); + glm::vec4 C2 = glm::fmod(A2, B2); + + Error += glm::all(glm::epsilonEqual(C2, glm::vec4(2.0f), 0.00001f)) ? 0 : 1; + + glm::ivec4 A3(22); + int B3(-10); + glm::ivec4 C3 = glm::fmod(A3, B3); + + Error += glm::all(glm::equal(C3, glm::ivec4(2))) ? 0 : 1; + + glm::ivec4 A4(22); + glm::ivec4 B4(-10); + glm::ivec4 C4 = glm::fmod(A4, B4); + + Error += glm::all(glm::equal(C4, glm::ivec4(2))) ? 0 : 1; + } + + // http://stackoverflow.com/questions/7610631/glsl-mod-vs-hlsl-fmod + { + for (float y = -10.0f; y < 10.0f; y += 0.1f) + for (float x = -10.0f; x < 10.0f; x += 0.1f) + { + float const A(std::fmod(x, y)); + //float const B(std::remainder(x, y)); + float const C(glm::fmod(x, y)); + float const D(modTrunc(x, y)); + + //Error += glm::epsilonEqual(A, B, 0.0001f) ? 0 : 1; + //assert(!Error); + Error += glm::epsilonEqual(A, C, 0.0001f) ? 0 : 1; + assert(!Error); + Error += glm::epsilonEqual(A, D, 0.00001f) ? 0 : 1; + assert(!Error); + } + } + + return Error; + } +}//namespace fmod_ + +int test_isdenormal() +{ + int Error = 0; + + bool A = glm::isdenormal(1.0f); + Error += !A ? 0 : 1; + + glm::bvec1 B = glm::isdenormal(glm::vec1(1.0f)); + Error += !glm::any(B) ? 0 : 1; + + glm::bvec2 C = glm::isdenormal(glm::vec2(1.0f)); + Error += !glm::any(C) ? 0 : 1; + + glm::bvec3 D = glm::isdenormal(glm::vec3(1.0f)); + Error += !glm::any(D) ? 0 : 1; + + glm::bvec4 E = glm::isdenormal(glm::vec4(1.0f)); + Error += !glm::any(E) ? 0 : 1; + + return Error; +} + +int test_openBounded() +{ + int Error = 0; + + Error += glm::all(glm::openBounded(glm::ivec2(2), glm::ivec2(1), glm::ivec2(3))) ? 0 : 1; + Error += !glm::all(glm::openBounded(glm::ivec2(1), glm::ivec2(1), glm::ivec2(3))) ? 0 : 1; + Error += !glm::all(glm::openBounded(glm::ivec2(3), glm::ivec2(1), glm::ivec2(3))) ? 0 : 1; + + return Error; +} + +int test_closeBounded() +{ + int Error = 0; + + Error += glm::all(glm::closeBounded(glm::ivec2(2), glm::ivec2(1), glm::ivec2(3))) ? 0 : 1; + Error += glm::all(glm::closeBounded(glm::ivec2(1), glm::ivec2(1), glm::ivec2(3))) ? 0 : 1; + Error += glm::all(glm::closeBounded(glm::ivec2(3), glm::ivec2(1), glm::ivec2(3))) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_isdenormal(); + Error += ::fmod_::test(); + Error += test_openBounded(); + Error += test_closeBounded(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_compatibility.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_compatibility.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e5351ce684d5c00939b4ad54ff7b9fb4abc11154 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_compatibility.cpp @@ -0,0 +1,19 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include + +int main() +{ + int Error(0); + + Error += glm::isfinite(1.0f) ? 0 : 1; + Error += glm::isfinite(1.0) ? 0 : 1; + Error += glm::isfinite(-1.0f) ? 0 : 1; + Error += glm::isfinite(-1.0) ? 0 : 1; + + Error += glm::all(glm::isfinite(glm::vec4(1.0f))) ? 0 : 1; + Error += glm::all(glm::isfinite(glm::dvec4(1.0))) ? 0 : 1; + Error += glm::all(glm::isfinite(glm::vec4(-1.0f))) ? 0 : 1; + Error += glm::all(glm::isfinite(glm::dvec4(-1.0))) ? 0 : 1; + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_component_wise.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_component_wise.cpp new file mode 100644 index 0000000000000000000000000000000000000000..29c81af4c78d139bcb5cff5939fb6130bba376fa --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_component_wise.cpp @@ -0,0 +1,116 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include +#include +#include +#include +#include + +namespace compNormalize +{ + int run() + { + int Error(0); + + { + glm::vec4 const A = glm::compNormalize(glm::u8vec4(0, 127, 128, 255)); + + Error += glm::epsilonEqual(A.x, 0.0f, glm::epsilon()) ? 0 : 1; + Error += A.y < 0.5f ? 0 : 1; + Error += A.z > 0.5f ? 0 : 1; + Error += glm::epsilonEqual(A.w, 1.0f, glm::epsilon()) ? 0 : 1; + } + + { + glm::vec4 const A = glm::compNormalize(glm::i8vec4(-128, -1, 0, 127)); + + Error += glm::epsilonEqual(A.x,-1.0f, glm::epsilon()) ? 0 : 1; + Error += A.y < 0.0f ? 0 : 1; + Error += A.z > 0.0f ? 0 : 1; + Error += glm::epsilonEqual(A.w, 1.0f, glm::epsilon()) ? 0 : 1; + } + + { + glm::vec4 const A = glm::compNormalize(glm::u16vec4( + std::numeric_limits::min(), + (std::numeric_limits::max() >> 1) + 0, + (std::numeric_limits::max() >> 1) + 1, + std::numeric_limits::max())); + + Error += glm::epsilonEqual(A.x, 0.0f, glm::epsilon()) ? 0 : 1; + Error += A.y < 0.5f ? 0 : 1; + Error += A.z > 0.5f ? 0 : 1; + Error += glm::epsilonEqual(A.w, 1.0f, glm::epsilon()) ? 0 : 1; + } + + { + glm::vec4 const A = glm::compNormalize(glm::i16vec4( + std::numeric_limits::min(), + static_cast(-1), + static_cast(0), + std::numeric_limits::max())); + + Error += glm::epsilonEqual(A.x,-1.0f, glm::epsilon()) ? 0 : 1; + Error += A.y < 0.0f ? 0 : 1; + Error += A.z > 0.0f ? 0 : 1; + Error += glm::epsilonEqual(A.w, 1.0f, glm::epsilon()) ? 0 : 1; + } + + return Error; + } +}//namespace compNormalize + +namespace compScale +{ + int run() + { + int Error(0); + + { + glm::u8vec4 const A = glm::compScale(glm::vec4(0.0f, 0.2f, 0.5f, 1.0f)); + + Error += A.x == std::numeric_limits::min() ? 0 : 1; + Error += A.y < (std::numeric_limits::max() >> 2) ? 0 : 1; + Error += A.z == 127 ? 0 : 1; + Error += A.w == 255 ? 0 : 1; + } + + { + glm::i8vec4 const A = glm::compScale(glm::vec4(0.0f,-1.0f, 0.5f, 1.0f)); + + Error += A.x == 0 ? 0 : 1; + Error += A.y == -128 ? 0 : 1; + Error += A.z == 63 ? 0 : 1; + Error += A.w == 127 ? 0 : 1; + } + + { + glm::u16vec4 const A = glm::compScale(glm::vec4(0.0f, 0.2f, 0.5f, 1.0f)); + + Error += A.x == std::numeric_limits::min() ? 0 : 1; + Error += A.y < (std::numeric_limits::max() >> 2) ? 0 : 1; + Error += A.z == 32767 ? 0 : 1; + Error += A.w == 65535 ? 0 : 1; + } + + { + glm::i16vec4 const A = glm::compScale(glm::vec4(0.0f,-1.0f, 0.5f, 1.0f)); + + Error += A.x == 0 ? 0 : 1; + Error += A.y == -32768 ? 0 : 1; + Error += A.z == 16383 ? 0 : 1; + Error += A.w == 32767 ? 0 : 1; + } + + return Error; + } +}// compScale + +int main() +{ + int Error(0); + + Error += compNormalize::run(); + Error += compScale::run(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_dual_quaternion.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_dual_quaternion.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ceedc2c2e324362d8775b9cef2729933dd9920dc --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_dual_quaternion.cpp @@ -0,0 +1,205 @@ +#define GLM_ENABLE_EXPERIMENTAL +#define GLM_FORCE_CTOR_INIT +#include +#include +#include +#include +#include +#if GLM_HAS_TRIVIAL_QUERIES +# include +#endif + +int myrand() +{ + static int holdrand = 1; + return (((holdrand = holdrand * 214013L + 2531011L) >> 16) & 0x7fff); +} + +float myfrand() // returns values from -1 to 1 inclusive +{ + return float(double(myrand()) / double( 0x7ffff )) * 2.0f - 1.0f; +} + +int test_dquat_type() +{ + glm::dvec3 vA; + glm::dquat dqA, dqB; + glm::ddualquat C(dqA, dqB); + glm::ddualquat B(dqA); + glm::ddualquat D(dqA, vA); + return 0; +} + +int test_scalars() +{ + float const Epsilon = 0.0001f; + + int Error(0); + + glm::quat src_q1 = glm::quat(1.0f,2.0f,3.0f,4.0f); + glm::quat src_q2 = glm::quat(5.0f,6.0f,7.0f,8.0f); + glm::dualquat src1(src_q1,src_q2); + + { + glm::dualquat dst1 = src1 * 2.0f; + glm::dualquat dst2 = 2.0f * src1; + glm::dualquat dst3 = src1; + dst3 *= 2.0f; + glm::dualquat dstCmp(src_q1 * 2.0f,src_q2 * 2.0f); + Error += glm::all(glm::epsilonEqual(dst1.real,dstCmp.real, Epsilon)) && glm::all(glm::epsilonEqual(dst1.dual,dstCmp.dual, Epsilon)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(dst2.real,dstCmp.real, Epsilon)) && glm::all(glm::epsilonEqual(dst2.dual,dstCmp.dual, Epsilon)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(dst3.real,dstCmp.real, Epsilon)) && glm::all(glm::epsilonEqual(dst3.dual,dstCmp.dual, Epsilon)) ? 0 : 1; + } + + { + glm::dualquat dst1 = src1 / 2.0f; + glm::dualquat dst2 = src1; + dst2 /= 2.0f; + glm::dualquat dstCmp(src_q1 / 2.0f,src_q2 / 2.0f); + Error += glm::all(glm::epsilonEqual(dst1.real,dstCmp.real, Epsilon)) && glm::all(glm::epsilonEqual(dst1.dual,dstCmp.dual, Epsilon)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(dst2.real,dstCmp.real, Epsilon)) && glm::all(glm::epsilonEqual(dst2.dual,dstCmp.dual, Epsilon)) ? 0 : 1; + } + return Error; +} + +int test_inverse() +{ + int Error(0); + + float const Epsilon = 0.0001f; + + glm::dualquat dqid = glm::dual_quat_identity(); + glm::mat4x4 mid(1.0f); + + for (int j = 0; j < 100; ++j) + { + glm::mat4x4 rot = glm::yawPitchRoll(myfrand() * 360.0f, myfrand() * 360.0f, myfrand() * 360.0f); + glm::vec3 vt = glm::vec3(myfrand() * 10.0f, myfrand() * 10.0f, myfrand() * 10.0f); + + glm::mat4x4 m = glm::translate(mid, vt) * rot; + + glm::quat qr = glm::quat_cast(m); + + glm::dualquat dq(qr); + + glm::dualquat invdq = glm::inverse(dq); + + glm::dualquat r1 = invdq * dq; + glm::dualquat r2 = dq * invdq; + + Error += glm::all(glm::epsilonEqual(r1.real, dqid.real, Epsilon)) && glm::all(glm::epsilonEqual(r1.dual, dqid.dual, Epsilon)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(r2.real, dqid.real, Epsilon)) && glm::all(glm::epsilonEqual(r2.dual, dqid.dual, Epsilon)) ? 0 : 1; + + // testing commutative property + glm::dualquat r ( glm::quat( myfrand() * glm::pi() * 2.0f, myfrand(), myfrand(), myfrand() ), + glm::vec3(myfrand() * 10.0f, myfrand() * 10.0f, myfrand() * 10.0f) ); + glm::dualquat riq = (r * invdq) * dq; + glm::dualquat rqi = (r * dq) * invdq; + + Error += glm::all(glm::epsilonEqual(riq.real, rqi.real, Epsilon)) && glm::all(glm::epsilonEqual(riq.dual, rqi.dual, Epsilon)) ? 0 : 1; + } + + return Error; +} + +int test_mul() +{ + int Error(0); + + float const Epsilon = 0.0001f; + + glm::mat4x4 mid(1.0f); + + for (int j = 0; j < 100; ++j) + { + // generate random rotations and translations and compare transformed by matrix and dualquats random points + glm::vec3 vt1 = glm::vec3(myfrand() * 10.0f, myfrand() * 10.0f, myfrand() * 10.0f); + glm::vec3 vt2 = glm::vec3(myfrand() * 10.0f, myfrand() * 10.0f, myfrand() * 10.0f); + + glm::mat4x4 rot1 = glm::yawPitchRoll(myfrand() * 360.0f, myfrand() * 360.0f, myfrand() * 360.0f); + glm::mat4x4 rot2 = glm::yawPitchRoll(myfrand() * 360.0f, myfrand() * 360.0f, myfrand() * 360.0f); + glm::mat4x4 m1 = glm::translate(mid, vt1) * rot1; + glm::mat4x4 m2 = glm::translate(mid, vt2) * rot2; + glm::mat4x4 m3 = m2 * m1; + glm::mat4x4 m4 = m1 * m2; + + glm::quat qrot1 = glm::quat_cast(rot1); + glm::quat qrot2 = glm::quat_cast(rot2); + + glm::dualquat dq1 = glm::dualquat(qrot1,vt1); + glm::dualquat dq2 = glm::dualquat(qrot2,vt2); + glm::dualquat dq3 = dq2 * dq1; + glm::dualquat dq4 = dq1 * dq2; + + for (int i = 0; i < 100; ++i) + { + glm::vec4 src_pt = glm::vec4(myfrand() * 4.0f, myfrand() * 5.0f, myfrand() * 3.0f,1.0f); + // test both multiplication orders + glm::vec4 dst_pt_m3 = m3 * src_pt; + glm::vec4 dst_pt_dq3 = dq3 * src_pt; + + glm::vec4 dst_pt_m3_i = glm::inverse(m3) * src_pt; + glm::vec4 dst_pt_dq3_i = src_pt * dq3; + + glm::vec4 dst_pt_m4 = m4 * src_pt; + glm::vec4 dst_pt_dq4 = dq4 * src_pt; + + glm::vec4 dst_pt_m4_i = glm::inverse(m4) * src_pt; + glm::vec4 dst_pt_dq4_i = src_pt * dq4; + + Error += glm::all(glm::epsilonEqual(dst_pt_m3, dst_pt_dq3, Epsilon)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(dst_pt_m4, dst_pt_dq4, Epsilon)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(dst_pt_m3_i, dst_pt_dq3_i, Epsilon)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(dst_pt_m4_i, dst_pt_dq4_i, Epsilon)) ? 0 : 1; + } + } + + return Error; +} + +int test_dual_quat_ctr() +{ + int Error(0); + +# if GLM_HAS_TRIVIAL_QUERIES + // Error += std::is_trivially_default_constructible::value ? 0 : 1; + // Error += std::is_trivially_default_constructible::value ? 0 : 1; + // Error += std::is_trivially_copy_assignable::value ? 0 : 1; + // Error += std::is_trivially_copy_assignable::value ? 0 : 1; + Error += std::is_trivially_copyable::value ? 0 : 1; + Error += std::is_trivially_copyable::value ? 0 : 1; + + Error += std::is_copy_constructible::value ? 0 : 1; + Error += std::is_copy_constructible::value ? 0 : 1; +# endif + + return Error; +} + +int test_size() +{ + int Error = 0; + + Error += 32 == sizeof(glm::dualquat) ? 0 : 1; + Error += 64 == sizeof(glm::ddualquat) ? 0 : 1; + Error += glm::dualquat().length() == 2 ? 0 : 1; + Error += glm::ddualquat().length() == 2 ? 0 : 1; + Error += glm::dualquat::length() == 2 ? 0 : 1; + Error += glm::ddualquat::length() == 2 ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_dual_quat_ctr(); + Error += test_dquat_type(); + Error += test_scalars(); + Error += test_inverse(); + Error += test_mul(); + Error += test_size(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_easing.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_easing.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0e98cd53dc25d10fec48eec6f59425b86ddc12e4 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_easing.cpp @@ -0,0 +1,65 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include +#include +#include + +namespace +{ + + template + void _test_easing() + { + T a = static_cast(0.5); + T r; + + r = glm::linearInterpolation(a); + + r = glm::quadraticEaseIn(a); + r = glm::quadraticEaseOut(a); + r = glm::quadraticEaseInOut(a); + + r = glm::cubicEaseIn(a); + r = glm::cubicEaseOut(a); + r = glm::cubicEaseInOut(a); + + r = glm::quarticEaseIn(a); + r = glm::quarticEaseOut(a); + r = glm::quinticEaseInOut(a); + + r = glm::sineEaseIn(a); + r = glm::sineEaseOut(a); + r = glm::sineEaseInOut(a); + + r = glm::circularEaseIn(a); + r = glm::circularEaseOut(a); + r = glm::circularEaseInOut(a); + + r = glm::exponentialEaseIn(a); + r = glm::exponentialEaseOut(a); + r = glm::exponentialEaseInOut(a); + + r = glm::elasticEaseIn(a); + r = glm::elasticEaseOut(a); + r = glm::elasticEaseInOut(a); + + r = glm::backEaseIn(a); + r = glm::backEaseOut(a); + r = glm::backEaseInOut(a); + + r = glm::bounceEaseIn(a); + r = glm::bounceEaseOut(a); + r = glm::bounceEaseInOut(a); + } + +} + +int main() +{ + int Error = 0; + + _test_easing(); + _test_easing(); + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_euler_angle.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_euler_angle.cpp new file mode 100644 index 0000000000000000000000000000000000000000..348f581874363075de300ba53e06ad95c1669a9e --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_euler_angle.cpp @@ -0,0 +1,539 @@ +// Code sample from Filippo Ramaciotti + +#define GLM_ENABLE_EXPERIMENTAL +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace test_eulerAngleX +{ + int test() + { + int Error = 0; + + float const Angle(glm::pi() * 0.5f); + glm::vec3 const X(1.0f, 0.0f, 0.0f); + + glm::vec4 const Y(0.0f, 1.0f, 0.0f, 1.0f); + glm::vec4 const Y1 = glm::rotate(glm::mat4(1.0f), Angle, X) * Y; + glm::vec4 const Y2 = glm::eulerAngleX(Angle) * Y; + glm::vec4 const Y3 = glm::eulerAngleXY(Angle, 0.0f) * Y; + glm::vec4 const Y4 = glm::eulerAngleYX(0.0f, Angle) * Y; + glm::vec4 const Y5 = glm::eulerAngleXZ(Angle, 0.0f) * Y; + glm::vec4 const Y6 = glm::eulerAngleZX(0.0f, Angle) * Y; + glm::vec4 const Y7 = glm::eulerAngleYXZ(0.0f, Angle, 0.0f) * Y; + Error += glm::all(glm::epsilonEqual(Y1, Y2, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(Y1, Y3, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(Y1, Y4, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(Y1, Y5, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(Y1, Y6, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(Y1, Y7, 0.00001f)) ? 0 : 1; + + glm::vec4 const Z(0.0f, 0.0f, 1.0f, 1.0f); + glm::vec4 const Z1 = glm::rotate(glm::mat4(1.0f), Angle, X) * Z; + glm::vec4 const Z2 = glm::eulerAngleX(Angle) * Z; + glm::vec4 const Z3 = glm::eulerAngleXY(Angle, 0.0f) * Z; + glm::vec4 const Z4 = glm::eulerAngleYX(0.0f, Angle) * Z; + glm::vec4 const Z5 = glm::eulerAngleXZ(Angle, 0.0f) * Z; + glm::vec4 const Z6 = glm::eulerAngleZX(0.0f, Angle) * Z; + glm::vec4 const Z7 = glm::eulerAngleYXZ(0.0f, Angle, 0.0f) * Z; + Error += glm::all(glm::epsilonEqual(Z1, Z2, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(Z1, Z3, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(Z1, Z4, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(Z1, Z5, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(Z1, Z6, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(Z1, Z7, 0.00001f)) ? 0 : 1; + + return Error; + } +}//namespace test_eulerAngleX + +namespace test_eulerAngleY +{ + int test() + { + int Error = 0; + + float const Angle(glm::pi() * 0.5f); + glm::vec3 const Y(0.0f, 1.0f, 0.0f); + + glm::vec4 const X(1.0f, 0.0f, 0.0f, 1.0f); + glm::vec4 const X1 = glm::rotate(glm::mat4(1.0f), Angle, Y) * X; + glm::vec4 const X2 = glm::eulerAngleY(Angle) * X; + glm::vec4 const X3 = glm::eulerAngleYX(Angle, 0.0f) * X; + glm::vec4 const X4 = glm::eulerAngleXY(0.0f, Angle) * X; + glm::vec4 const X5 = glm::eulerAngleYZ(Angle, 0.0f) * X; + glm::vec4 const X6 = glm::eulerAngleZY(0.0f, Angle) * X; + glm::vec4 const X7 = glm::eulerAngleYXZ(Angle, 0.0f, 0.0f) * X; + Error += glm::all(glm::epsilonEqual(X1, X2, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(X1, X3, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(X1, X4, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(X1, X5, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(X1, X6, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(X1, X7, 0.00001f)) ? 0 : 1; + + glm::vec4 const Z(0.0f, 0.0f, 1.0f, 1.0f); + glm::vec4 const Z1 = glm::eulerAngleY(Angle) * Z; + glm::vec4 const Z2 = glm::rotate(glm::mat4(1.0f), Angle, Y) * Z; + glm::vec4 const Z3 = glm::eulerAngleYX(Angle, 0.0f) * Z; + glm::vec4 const Z4 = glm::eulerAngleXY(0.0f, Angle) * Z; + glm::vec4 const Z5 = glm::eulerAngleYZ(Angle, 0.0f) * Z; + glm::vec4 const Z6 = glm::eulerAngleZY(0.0f, Angle) * Z; + glm::vec4 const Z7 = glm::eulerAngleYXZ(Angle, 0.0f, 0.0f) * Z; + Error += glm::all(glm::epsilonEqual(Z1, Z2, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(Z1, Z3, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(Z1, Z4, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(Z1, Z5, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(Z1, Z6, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(Z1, Z7, 0.00001f)) ? 0 : 1; + + return Error; + } +}//namespace test_eulerAngleY + +namespace test_eulerAngleZ +{ + int test() + { + int Error = 0; + + float const Angle(glm::pi() * 0.5f); + glm::vec3 const Z(0.0f, 0.0f, 1.0f); + + glm::vec4 const X(1.0f, 0.0f, 0.0f, 1.0f); + glm::vec4 const X1 = glm::rotate(glm::mat4(1.0f), Angle, Z) * X; + glm::vec4 const X2 = glm::eulerAngleZ(Angle) * X; + glm::vec4 const X3 = glm::eulerAngleZX(Angle, 0.0f) * X; + glm::vec4 const X4 = glm::eulerAngleXZ(0.0f, Angle) * X; + glm::vec4 const X5 = glm::eulerAngleZY(Angle, 0.0f) * X; + glm::vec4 const X6 = glm::eulerAngleYZ(0.0f, Angle) * X; + glm::vec4 const X7 = glm::eulerAngleYXZ(0.0f, 0.0f, Angle) * X; + Error += glm::all(glm::epsilonEqual(X1, X2, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(X1, X3, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(X1, X4, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(X1, X5, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(X1, X6, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(X1, X7, 0.00001f)) ? 0 : 1; + + glm::vec4 const Y(1.0f, 0.0f, 0.0f, 1.0f); + glm::vec4 const Z1 = glm::rotate(glm::mat4(1.0f), Angle, Z) * Y; + glm::vec4 const Z2 = glm::eulerAngleZ(Angle) * Y; + glm::vec4 const Z3 = glm::eulerAngleZX(Angle, 0.0f) * Y; + glm::vec4 const Z4 = glm::eulerAngleXZ(0.0f, Angle) * Y; + glm::vec4 const Z5 = glm::eulerAngleZY(Angle, 0.0f) * Y; + glm::vec4 const Z6 = glm::eulerAngleYZ(0.0f, Angle) * Y; + glm::vec4 const Z7 = glm::eulerAngleYXZ(0.0f, 0.0f, Angle) * Y; + Error += glm::all(glm::epsilonEqual(Z1, Z2, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(Z1, Z3, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(Z1, Z4, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(Z1, Z5, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(Z1, Z6, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(Z1, Z7, 0.00001f)) ? 0 : 1; + + return Error; + } +}//namespace test_eulerAngleZ + +namespace test_derivedEulerAngles +{ + bool epsilonEqual(glm::mat4 const& mat1, glm::mat4 const& mat2, glm::mat4::value_type const& epsilon) + { + return glm::all(glm::epsilonEqual(mat1[0], mat2[0], epsilon)) ? + ( + glm::all(glm::epsilonEqual(mat1[1], mat2[1], epsilon)) ? + ( + glm::all(glm::epsilonEqual(mat1[2], mat2[2], epsilon)) ? + ( + glm::all(glm::epsilonEqual(mat1[3], mat2[3], epsilon)) ? true : false + ) : false + ) : false + ) : false; + } + + template + int test(RotationFunc rotationFunc, TestDerivedFunc testDerivedFunc, const glm::vec3& basis) + { + int Error = 0; + + typedef glm::vec3::value_type value; + value const zeroAngle(0.0f); + value const Angle(glm::pi() * 0.75f); + value const negativeAngle(-Angle); + value const zeroAngleVelocity(0.0f); + value const AngleVelocity(glm::pi() * 0.27f); + value const negativeAngleVelocity(-AngleVelocity); + + typedef std::pair AngleAndAngleVelocity; + std::vector testPairs; + testPairs.push_back(AngleAndAngleVelocity(zeroAngle, zeroAngleVelocity)); + testPairs.push_back(AngleAndAngleVelocity(zeroAngle, AngleVelocity)); + testPairs.push_back(AngleAndAngleVelocity(zeroAngle, negativeAngleVelocity)); + testPairs.push_back(AngleAndAngleVelocity(Angle, zeroAngleVelocity)); + testPairs.push_back(AngleAndAngleVelocity(Angle, AngleVelocity)); + testPairs.push_back(AngleAndAngleVelocity(Angle, negativeAngleVelocity)); + testPairs.push_back(AngleAndAngleVelocity(negativeAngle, zeroAngleVelocity)); + testPairs.push_back(AngleAndAngleVelocity(negativeAngle, AngleVelocity)); + testPairs.push_back(AngleAndAngleVelocity(negativeAngle, negativeAngleVelocity)); + + for (size_t i = 0, size = testPairs.size(); i < size; ++i) + { + AngleAndAngleVelocity const& pair = testPairs.at(i); + + glm::mat4 const W = glm::matrixCross4(basis * pair.second); + glm::mat4 const rotMt = glm::transpose(rotationFunc(pair.first)); + glm::mat4 const derivedRotM = testDerivedFunc(pair.first, pair.second); + + Error += epsilonEqual(W, derivedRotM * rotMt, 0.00001f) ? 0 : 1; + } + + return Error; + } +}//namespace test_derivedEulerAngles + +namespace test_eulerAngleXY +{ + int test() + { + int Error = 0; + + glm::vec4 const V(1.0f); + + float const AngleX(glm::pi() * 0.5f); + float const AngleY(glm::pi() * 0.25f); + + glm::vec3 const axisX(1.0f, 0.0f, 0.0f); + glm::vec3 const axisY(0.0f, 1.0f, 0.0f); + + glm::vec4 const V1 = (glm::rotate(glm::mat4(1.0f), AngleX, axisX) * glm::rotate(glm::mat4(1.0f), AngleY, axisY)) * V; + glm::vec4 const V2 = glm::eulerAngleXY(AngleX, AngleY) * V; + glm::vec4 const V3 = glm::eulerAngleX(AngleX) * glm::eulerAngleY(AngleY) * V; + Error += glm::all(glm::epsilonEqual(V1, V2, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(V1, V3, 0.00001f)) ? 0 : 1; + + return Error; + } +}//namespace test_eulerAngleXY + +namespace test_eulerAngleYX +{ + int test() + { + int Error = 0; + + glm::vec4 const V(1.0f); + + float const AngleX(glm::pi() * 0.5f); + float const AngleY(glm::pi() * 0.25f); + + glm::vec3 const axisX(1.0f, 0.0f, 0.0f); + glm::vec3 const axisY(0.0f, 1.0f, 0.0f); + + glm::vec4 const V1 = (glm::rotate(glm::mat4(1.0f), AngleY, axisY) * glm::rotate(glm::mat4(1.0f), AngleX, axisX)) * V; + glm::vec4 const V2 = glm::eulerAngleYX(AngleY, AngleX) * V; + glm::vec4 const V3 = glm::eulerAngleY(AngleY) * glm::eulerAngleX(AngleX) * V; + Error += glm::all(glm::epsilonEqual(V1, V2, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(V1, V3, 0.00001f)) ? 0 : 1; + + return Error; + } +}//namespace test_eulerAngleYX + +namespace test_eulerAngleXZ +{ + int test() + { + int Error = 0; + + glm::vec4 const V(1.0f); + + float const AngleX(glm::pi() * 0.5f); + float const AngleZ(glm::pi() * 0.25f); + + glm::vec3 const axisX(1.0f, 0.0f, 0.0f); + glm::vec3 const axisZ(0.0f, 0.0f, 1.0f); + + glm::vec4 const V1 = (glm::rotate(glm::mat4(1.0f), AngleX, axisX) * glm::rotate(glm::mat4(1.0f), AngleZ, axisZ)) * V; + glm::vec4 const V2 = glm::eulerAngleXZ(AngleX, AngleZ) * V; + glm::vec4 const V3 = glm::eulerAngleX(AngleX) * glm::eulerAngleZ(AngleZ) * V; + Error += glm::all(glm::epsilonEqual(V1, V2, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(V1, V3, 0.00001f)) ? 0 : 1; + + return Error; + } +}//namespace test_eulerAngleXZ + +namespace test_eulerAngleZX +{ + int test() + { + int Error = 0; + + glm::vec4 const V(1.0f); + + float const AngleX(glm::pi() * 0.5f); + float const AngleZ(glm::pi() * 0.25f); + + glm::vec3 const axisX(1.0f, 0.0f, 0.0f); + glm::vec3 const axisZ(0.0f, 0.0f, 1.0f); + + glm::vec4 const V1 = (glm::rotate(glm::mat4(1.0f), AngleZ, axisZ) * glm::rotate(glm::mat4(1.0f), AngleX, axisX)) * V; + glm::vec4 const V2 = glm::eulerAngleZX(AngleZ, AngleX) * V; + glm::vec4 const V3 = glm::eulerAngleZ(AngleZ) * glm::eulerAngleX(AngleX) * V; + Error += glm::all(glm::epsilonEqual(V1, V2, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(V1, V3, 0.00001f)) ? 0 : 1; + + return Error; + } +}//namespace test_eulerAngleZX + +namespace test_eulerAngleYZ +{ + int test() + { + int Error = 0; + + glm::vec4 const V(1.0f); + + float const AngleY(glm::pi() * 0.5f); + float const AngleZ(glm::pi() * 0.25f); + + glm::vec3 const axisX(1.0f, 0.0f, 0.0f); + glm::vec3 const axisY(0.0f, 1.0f, 0.0f); + glm::vec3 const axisZ(0.0f, 0.0f, 1.0f); + + glm::vec4 const V1 = (glm::rotate(glm::mat4(1.0f), AngleY, axisY) * glm::rotate(glm::mat4(1.0f), AngleZ, axisZ)) * V; + glm::vec4 const V2 = glm::eulerAngleYZ(AngleY, AngleZ) * V; + glm::vec4 const V3 = glm::eulerAngleY(AngleY) * glm::eulerAngleZ(AngleZ) * V; + Error += glm::all(glm::epsilonEqual(V1, V2, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(V1, V3, 0.00001f)) ? 0 : 1; + + return Error; + } +}//namespace test_eulerAngleYZ + +namespace test_eulerAngleZY +{ + int test() + { + int Error = 0; + + glm::vec4 const V(1.0f); + + float const AngleY(glm::pi() * 0.5f); + float const AngleZ(glm::pi() * 0.25f); + + glm::vec3 const axisX(1.0f, 0.0f, 0.0f); + glm::vec3 const axisY(0.0f, 1.0f, 0.0f); + glm::vec3 const axisZ(0.0f, 0.0f, 1.0f); + + glm::vec4 const V1 = (glm::rotate(glm::mat4(1.0f), AngleZ, axisZ) * glm::rotate(glm::mat4(1.0f), AngleY, axisY)) * V; + glm::vec4 const V2 = glm::eulerAngleZY(AngleZ, AngleY) * V; + glm::vec4 const V3 = glm::eulerAngleZ(AngleZ) * glm::eulerAngleY(AngleY) * V; + Error += glm::all(glm::epsilonEqual(V1, V2, 0.00001f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(V1, V3, 0.00001f)) ? 0 : 1; + + return Error; + } +}//namespace test_eulerAngleZY + +namespace test_eulerAngleYXZ +{ + int test() + { + glm::f32 first = 1.046f; + glm::f32 second = 0.52f; + glm::f32 third = -0.785f; + + glm::fmat4 rotationEuler = glm::eulerAngleYXZ(first, second, third); + + glm::fmat4 rotationInvertedY = glm::eulerAngleY(-1.f*first) * glm::eulerAngleX(second) * glm::eulerAngleZ(third); + glm::fmat4 rotationDumb = glm::fmat4(); + rotationDumb = glm::rotate(rotationDumb, first, glm::fvec3(0,1,0)); + rotationDumb = glm::rotate(rotationDumb, second, glm::fvec3(1,0,0)); + rotationDumb = glm::rotate(rotationDumb, third, glm::fvec3(0,0,1)); + + std::printf("%s\n", glm::to_string(glm::fmat3(rotationEuler)).c_str()); + std::printf("%s\n", glm::to_string(glm::fmat3(rotationDumb)).c_str()); + std::printf("%s\n", glm::to_string(glm::fmat3(rotationInvertedY)).c_str()); + + std::printf("\nRESIDUAL\n"); + std::printf("%s\n", glm::to_string(glm::fmat3(rotationEuler-(rotationDumb))).c_str()); + std::printf("%s\n", glm::to_string(glm::fmat3(rotationEuler-(rotationInvertedY))).c_str()); + + return 0; + } +}//namespace eulerAngleYXZ + +namespace test_eulerAngles +{ + template + int test(TestRotationFunc testRotationFunc, glm::vec3 const& I, glm::vec3 const& J, glm::vec3 const& K) + { + int Error = 0; + + typedef glm::mat4::value_type value; + value const minAngle(-glm::pi()); + value const maxAngle(glm::pi()); + value const maxAngleWithDelta(maxAngle - 0.0000001f); + value const minMidAngle(-glm::pi() * 0.5f); + value const maxMidAngle(glm::pi() * 0.5f); + + std::vector testEulerAngles; + testEulerAngles.push_back(glm::vec3(1.046f, 0.52f, -0.785f)); + testEulerAngles.push_back(glm::vec3(minAngle, minMidAngle, minAngle)); + testEulerAngles.push_back(glm::vec3(minAngle, minMidAngle, maxAngle)); + testEulerAngles.push_back(glm::vec3(minAngle, minMidAngle, maxAngleWithDelta)); + testEulerAngles.push_back(glm::vec3(minAngle, maxMidAngle, minAngle)); + testEulerAngles.push_back(glm::vec3(minAngle, maxMidAngle, maxAngle)); + testEulerAngles.push_back(glm::vec3(minAngle, maxMidAngle, maxAngleWithDelta)); + testEulerAngles.push_back(glm::vec3(maxAngle, minMidAngle, minAngle)); + testEulerAngles.push_back(glm::vec3(maxAngle, minMidAngle, maxAngle)); + testEulerAngles.push_back(glm::vec3(maxAngle, minMidAngle, maxAngleWithDelta)); + testEulerAngles.push_back(glm::vec3(maxAngleWithDelta, minMidAngle, maxAngle)); + testEulerAngles.push_back(glm::vec3(maxAngleWithDelta, minMidAngle, maxAngleWithDelta)); + testEulerAngles.push_back(glm::vec3(maxAngle, maxMidAngle, minAngle)); + testEulerAngles.push_back(glm::vec3(maxAngleWithDelta, maxMidAngle, minAngle)); + testEulerAngles.push_back(glm::vec3(maxAngle, maxMidAngle, maxAngle)); + testEulerAngles.push_back(glm::vec3(maxAngle, maxMidAngle, maxAngleWithDelta)); + testEulerAngles.push_back(glm::vec3(maxAngleWithDelta, maxMidAngle, maxAngle)); + testEulerAngles.push_back(glm::vec3(maxAngleWithDelta, maxMidAngle, maxAngleWithDelta)); + testEulerAngles.push_back(glm::vec3(minAngle, 0.0f, minAngle)); + testEulerAngles.push_back(glm::vec3(minAngle, 0.0f, maxAngle)); + testEulerAngles.push_back(glm::vec3(maxAngle, maxAngle, minAngle)); + testEulerAngles.push_back(glm::vec3(maxAngle, maxAngle, maxAngle)); + + for (size_t i = 0, size = testEulerAngles.size(); i < size; ++i) + { + glm::vec3 const& angles = testEulerAngles.at(i); + glm::mat4 const rotationEuler = testRotationFunc(angles.x, angles.y, angles.z); + + glm::mat4 rotationDumb = glm::diagonal4x4(glm::mat4::col_type(1.0f)); + rotationDumb = glm::rotate(rotationDumb, angles.x, I); + rotationDumb = glm::rotate(rotationDumb, angles.y, J); + rotationDumb = glm::rotate(rotationDumb, angles.z, K); + + glm::vec4 const V(1.0f,1.0f,1.0f,1.0f); + glm::vec4 const V1 = rotationEuler * V; + glm::vec4 const V2 = rotationDumb * V; + + Error += glm::all(glm::epsilonEqual(V1, V2, 0.00001f)) ? 0 : 1; + } + + return Error; + } +}//namespace test_extractsEulerAngles + +namespace test_extractsEulerAngles +{ + template + int test(RotationFunc rotationFunc, TestExtractionFunc testExtractionFunc) + { + int Error = 0; + + typedef glm::mat4::value_type value; + value const minAngle(-glm::pi()); + value const maxAngle(glm::pi()); + value const maxAngleWithDelta(maxAngle - 0.0000001f); + value const minMidAngle(-glm::pi() * 0.5f); + value const maxMidAngle(glm::pi() * 0.5f); + + std::vector testEulerAngles; + testEulerAngles.push_back(glm::vec3(1.046f, 0.52f, -0.785f)); + testEulerAngles.push_back(glm::vec3(minAngle, minMidAngle, minAngle)); + testEulerAngles.push_back(glm::vec3(minAngle, minMidAngle, maxAngle)); + testEulerAngles.push_back(glm::vec3(minAngle, minMidAngle, maxAngleWithDelta)); + testEulerAngles.push_back(glm::vec3(minAngle, maxMidAngle, minAngle)); + testEulerAngles.push_back(glm::vec3(minAngle, maxMidAngle, maxAngle)); + testEulerAngles.push_back(glm::vec3(minAngle, maxMidAngle, maxAngleWithDelta)); + testEulerAngles.push_back(glm::vec3(maxAngle, minMidAngle, minAngle)); + testEulerAngles.push_back(glm::vec3(maxAngle, minMidAngle, maxAngle)); + testEulerAngles.push_back(glm::vec3(maxAngle, minMidAngle, maxAngleWithDelta)); + testEulerAngles.push_back(glm::vec3(maxAngleWithDelta, minMidAngle, maxAngle)); + testEulerAngles.push_back(glm::vec3(maxAngleWithDelta, minMidAngle, maxAngleWithDelta)); + testEulerAngles.push_back(glm::vec3(maxAngle, maxMidAngle, minAngle)); + testEulerAngles.push_back(glm::vec3(maxAngleWithDelta, maxMidAngle, minAngle)); + testEulerAngles.push_back(glm::vec3(maxAngle, maxMidAngle, maxAngle)); + testEulerAngles.push_back(glm::vec3(maxAngle, maxMidAngle, maxAngleWithDelta)); + testEulerAngles.push_back(glm::vec3(maxAngleWithDelta, maxMidAngle, maxAngle)); + testEulerAngles.push_back(glm::vec3(maxAngleWithDelta, maxMidAngle, maxAngleWithDelta)); + testEulerAngles.push_back(glm::vec3(minAngle, 0.0f, minAngle)); + testEulerAngles.push_back(glm::vec3(minAngle, 0.0f, maxAngle)); + testEulerAngles.push_back(glm::vec3(maxAngle, maxAngle, minAngle)); + testEulerAngles.push_back(glm::vec3(maxAngle, maxAngle, maxAngle)); + + for (size_t i = 0, size = testEulerAngles.size(); i < size; ++i) + { + glm::vec3 const& angles = testEulerAngles.at(i); + glm::mat4 const rotation = rotationFunc(angles.x, angles.y, angles.z); + + glm::vec3 extractedEulerAngles(0.0f); + testExtractionFunc(rotation, extractedEulerAngles.x, extractedEulerAngles.y, extractedEulerAngles.z); + glm::mat4 const extractedRotation = rotationFunc(extractedEulerAngles.x, extractedEulerAngles.y, extractedEulerAngles.z); + + glm::vec4 const V(1.0f,1.0f,1.0f,1.0f); + glm::vec4 const V1 = rotation * V; + glm::vec4 const V2 = extractedRotation * V; + + Error += glm::all(glm::epsilonEqual(V1, V2, 0.00001f)) ? 0 : 1; + } + + return Error; + } +}//namespace test_extractsEulerAngles + +int main() +{ + int Error = 0; + + typedef glm::mat4::value_type value; + glm::vec3 const X(1.0f, 0.0f, 0.0f); + glm::vec3 const Y(0.0f, 1.0f, 0.0f); + glm::vec3 const Z(0.0f, 0.0f, 1.0f); + + Error += test_eulerAngleX::test(); + Error += test_eulerAngleY::test(); + Error += test_eulerAngleZ::test(); + + Error += test_derivedEulerAngles::test(glm::eulerAngleX, glm::derivedEulerAngleX, X); + Error += test_derivedEulerAngles::test(glm::eulerAngleY, glm::derivedEulerAngleY, Y); + Error += test_derivedEulerAngles::test(glm::eulerAngleZ, glm::derivedEulerAngleZ, Z); + + Error += test_eulerAngleXY::test(); + Error += test_eulerAngleYX::test(); + Error += test_eulerAngleXZ::test(); + Error += test_eulerAngleZX::test(); + Error += test_eulerAngleYZ::test(); + Error += test_eulerAngleZY::test(); + Error += test_eulerAngleYXZ::test(); + + Error += test_eulerAngles::test(glm::eulerAngleXZX, X, Z, X); + Error += test_eulerAngles::test(glm::eulerAngleXYX, X, Y, X); + Error += test_eulerAngles::test(glm::eulerAngleYXY, Y, X, Y); + Error += test_eulerAngles::test(glm::eulerAngleYZY, Y, Z, Y); + Error += test_eulerAngles::test(glm::eulerAngleZYZ, Z, Y, Z); + Error += test_eulerAngles::test(glm::eulerAngleZXZ, Z, X, Z); + Error += test_eulerAngles::test(glm::eulerAngleXZY, X, Z, Y); + Error += test_eulerAngles::test(glm::eulerAngleYZX, Y, Z, X); + Error += test_eulerAngles::test(glm::eulerAngleZYX, Z, Y, X); + Error += test_eulerAngles::test(glm::eulerAngleZXY, Z, X, Y); + + Error += test_extractsEulerAngles::test(glm::eulerAngleYXZ, glm::extractEulerAngleYXZ); + Error += test_extractsEulerAngles::test(glm::eulerAngleXZX, glm::extractEulerAngleXZX); + Error += test_extractsEulerAngles::test(glm::eulerAngleXYX, glm::extractEulerAngleXYX); + Error += test_extractsEulerAngles::test(glm::eulerAngleYXY, glm::extractEulerAngleYXY); + Error += test_extractsEulerAngles::test(glm::eulerAngleYZY, glm::extractEulerAngleYZY); + Error += test_extractsEulerAngles::test(glm::eulerAngleZYZ, glm::extractEulerAngleZYZ); + Error += test_extractsEulerAngles::test(glm::eulerAngleZXZ, glm::extractEulerAngleZXZ); + Error += test_extractsEulerAngles::test(glm::eulerAngleXZY, glm::extractEulerAngleXZY); + Error += test_extractsEulerAngles::test(glm::eulerAngleYZX, glm::extractEulerAngleYZX); + Error += test_extractsEulerAngles::test(glm::eulerAngleZYX, glm::extractEulerAngleZYX); + Error += test_extractsEulerAngles::test(glm::eulerAngleZXY, glm::extractEulerAngleZXY); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_extend.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_extend.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0c37df567d59ba85dc8d88e293eaa32ebb4aa45c --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_extend.cpp @@ -0,0 +1,9 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include + +int main() +{ + int Error(0); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_extended_min_max.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_extended_min_max.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3d20f10e266c0a3fb66daec821536d5187890248 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_extended_min_max.cpp @@ -0,0 +1,101 @@ +#define GLM_ENABLE_EXPERIMENTAL + +#include +#include +#include +#include +#include + +// This file has divisions by zero to test isnan +#if GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(disable : 4723) +#endif + +namespace fmin_ +{ + static int test() + { + int Error = 0; + + float Zero_f = 0.0f; + glm::vec1 A0 = glm::fmin(glm::vec1(1), glm::vec1(Zero_f / 0.0f)); + Error += glm::equal(A0.x, 1.0f, glm::epsilon()) ? 0 : 1; + + glm::vec1 A1 = glm::fmin(glm::vec1(Zero_f / 0.0f), glm::vec1(1)); + Error += glm::equal(A1.x, 1.0f, glm::epsilon()) ? 0 : 1; + + glm::vec2 B0 = glm::fmin(glm::vec2(1), glm::vec2(1)); + glm::vec2 B1 = glm::fmin(glm::vec2(1), 1.0f); + bool B2 = glm::all(glm::equal(B0, B1, glm::epsilon())); + Error += B2 ? 0 : 1; + + glm::vec3 C0 = glm::fmin(glm::vec3(1), glm::vec3(1)); + glm::vec3 C1 = glm::fmin(glm::vec3(1), 1.0f); + bool C2 = glm::all(glm::equal(C0, C1, glm::epsilon())); + Error += C2 ? 0 : 1; + + glm::vec4 D0 = glm::fmin(glm::vec4(1), glm::vec4(1)); + glm::vec4 D1 = glm::fmin(glm::vec4(1), 1.0f); + bool D2 = glm::all(glm::equal(D0, D1, glm::epsilon())); + Error += D2 ? 0 : 1; + + return Error; + } +}//namespace fmin_ + +namespace fmax_ +{ + static int test() + { + int Error = 0; + + float Zero_f = 0.0f; + glm::vec1 A0 = glm::fmax(glm::vec1(1), glm::vec1(Zero_f / 0.0f)); + Error += glm::equal(A0.x, 1.0f, glm::epsilon()) ? 0 : 1; + + glm::vec1 A1 = glm::fmax(glm::vec1(Zero_f / 0.0f), glm::vec1(1)); + Error += glm::equal(A0.x, 1.0f, glm::epsilon()) ? 0 : 1; + + glm::vec2 B0 = glm::fmax(glm::vec2(1), glm::vec2(1)); + glm::vec2 B1 = glm::fmax(glm::vec2(1), 1.0f); + bool B2 = glm::all(glm::equal(B0, B1, glm::epsilon())); + Error += B2 ? 0 : 1; + + glm::vec3 C0 = glm::fmax(glm::vec3(1), glm::vec3(1)); + glm::vec3 C1 = glm::fmax(glm::vec3(1), 1.0f); + bool C2 = glm::all(glm::equal(C0, C1, glm::epsilon())); + Error += C2 ? 0 : 1; + + glm::vec4 D0 = glm::fmax(glm::vec4(1), glm::vec4(1)); + glm::vec4 D1 = glm::fmax(glm::vec4(1), 1.0f); + bool D2 = glm::all(glm::equal(D0, D1, glm::epsilon())); + Error += D2 ? 0 : 1; + + return Error; + } +}//namespace fmax_ + +namespace fclamp_ +{ + static int test() + { + int Error = 0; + + float Zero_f = 0.0f; + glm::vec1 A0 = glm::fclamp(glm::vec1(1), glm::vec1(Zero_f / 0.0f), glm::vec1(2.0f)); + Error += glm::equal(A0.x, 1.0f, glm::epsilon()) ? 0 : 1; + + return Error; + } +}//namespace fclamp_ + +int main() +{ + int Error = 0; + + Error += fmin_::test(); + Error += fmax_::test(); + Error += fclamp_::test(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_extented_min_max.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_extented_min_max.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c8c78479c27fb5194ed37968dcceb6c97c4970e4 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_extented_min_max.cpp @@ -0,0 +1,39 @@ +/////////////////////////////////////////////////////////////////////////////////// +/// OpenGL Mathematics (glm.g-truc.net) +/// +/// Copyright (c) 2005 - 2015 G-Truc Creation (www.g-truc.net) +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// of this software and associated documentation files (the "Software"), to deal +/// in the Software without restriction, including without limitation the rights +/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +/// copies of the Software, and to permit persons to whom the Software is +/// furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// Restrictions: +/// By making use of the Software for military purposes, you choose to make +/// a Bunny unhappy. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +/// THE SOFTWARE. +/// +/// @file test/gtx/gtx_extented_min_max.cpp +/// @date 2013-10-25 / 2014-11-25 +/// @author Christophe Riccio +/////////////////////////////////////////////////////////////////////////////////// + +#include + +int main() +{ + int Error(0); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_exterior_product.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_exterior_product.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a02c98303dd0e5e84f2cc08a2f0412d5bec60e35 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_exterior_product.cpp @@ -0,0 +1,14 @@ +#include +#include +#include + +int main() +{ + int Error = 0; + + float const f = glm::cross(glm::vec2(1.0f, 1.0f), glm::vec2(1.0f, 1.0f)); + Error += glm::epsilonEqual(f, 0.0f, 0.001f) ? 0 : 1; + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_fast_exponential.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_fast_exponential.cpp new file mode 100644 index 0000000000000000000000000000000000000000..341e26ef9e3621ca5939fff4dc2348f1a862a5d0 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_fast_exponential.cpp @@ -0,0 +1,9 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include + +int main() +{ + int Error(0); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_fast_square_root.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_fast_square_root.cpp new file mode 100644 index 0000000000000000000000000000000000000000..80d7fe4b7960a9b429c02a0739c99140bead183f --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_fast_square_root.cpp @@ -0,0 +1,45 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include +#include +#include +#include + +int test_fastInverseSqrt() +{ + int Error = 0; + + Error += glm::epsilonEqual(glm::fastInverseSqrt(1.0f), 1.0f, 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(glm::fastInverseSqrt(1.0), 1.0, 0.01) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(glm::fastInverseSqrt(glm::vec2(1.0f)), glm::vec2(1.0f), 0.01f)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(glm::fastInverseSqrt(glm::dvec3(1.0)), glm::dvec3(1.0), 0.01)) ? 0 : 1; + Error += glm::all(glm::epsilonEqual(glm::fastInverseSqrt(glm::dvec4(1.0)), glm::dvec4(1.0), 0.01)) ? 0 : 1; + + return Error; +} + +int test_fastDistance() +{ + int Error = 0; + + float const A = glm::fastDistance(0.0f, 1.0f); + float const B = glm::fastDistance(glm::vec2(0.0f), glm::vec2(1.0f, 0.0f)); + float const C = glm::fastDistance(glm::vec3(0.0f), glm::vec3(1.0f, 0.0f, 0.0f)); + float const D = glm::fastDistance(glm::vec4(0.0f), glm::vec4(1.0f, 0.0f, 0.0f, 0.0f)); + + Error += glm::epsilonEqual(A, 1.0f, 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(B, 1.0f, 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(C, 1.0f, 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(D, 1.0f, 0.01f) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_fastInverseSqrt(); + Error += test_fastDistance(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_fast_trigonometry.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_fast_trigonometry.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8bf86ba02fc3481326987a8c32ab45c48a8d1267 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_fast_trigonometry.cpp @@ -0,0 +1,564 @@ +#include + +#define GLM_ENABLE_EXPERIMENTAL +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace fastCos +{ + int perf(bool NextFloat) + { + const float begin = -glm::pi(); + const float end = glm::pi(); + float result = 0.f; + + const std::clock_t timestamp1 = std::clock(); + for(float i = begin; i < end; i = NextFloat ? glm::nextFloat(i) : i += 0.1f) + result = glm::fastCos(i); + + const std::clock_t timestamp2 = std::clock(); + for(float i = begin; i < end; i = NextFloat ? glm::nextFloat(i) : i += 0.1f) + result = glm::cos(i); + + const std::clock_t timestamp3 = std::clock(); + const std::clock_t time_fast = timestamp2 - timestamp1; + const std::clock_t time_default = timestamp3 - timestamp2; + std::printf("fastCos Time %d clocks\n", static_cast(time_fast)); + std::printf("cos Time %d clocks\n", static_cast(time_default)); + + return time_fast <= time_default ? 0 : 1; + } +}//namespace fastCos + +namespace fastSin +{ + /* + float sin(float x) { + float temp; + temp = (x + M_PI) / ((2 * M_PI) - M_PI); + return limited_sin((x + M_PI) - ((2 * M_PI) - M_PI) * temp)); + } + */ + + int perf(bool NextFloat) + { + const float begin = -glm::pi(); + const float end = glm::pi(); + float result = 0.f; + + const std::clock_t timestamp1 = std::clock(); + for(float i = begin; i < end; i = NextFloat ? glm::nextFloat(i) : i += 0.1f) + result = glm::fastSin(i); + + const std::clock_t timestamp2 = std::clock(); + for(float i = begin; i < end; i = NextFloat ? glm::nextFloat(i) : i += 0.1f) + result = glm::sin(i); + + const std::clock_t timestamp3 = std::clock(); + const std::clock_t time_fast = timestamp2 - timestamp1; + const std::clock_t time_default = timestamp3 - timestamp2; + std::printf("fastSin Time %d clocks\n", static_cast(time_fast)); + std::printf("sin Time %d clocks\n", static_cast(time_default)); + + return time_fast <= time_default ? 0 : 1; + } +}//namespace fastSin + +namespace fastTan +{ + int perf(bool NextFloat) + { + const float begin = -glm::pi(); + const float end = glm::pi(); + float result = 0.f; + + const std::clock_t timestamp1 = std::clock(); + for(float i = begin; i < end; i = NextFloat ? glm::nextFloat(i) : i += 0.1f) + result = glm::fastTan(i); + + const std::clock_t timestamp2 = std::clock(); + for (float i = begin; i < end; i = NextFloat ? glm::nextFloat(i) : i += 0.1f) + result = glm::tan(i); + + const std::clock_t timestamp3 = std::clock(); + const std::clock_t time_fast = timestamp2 - timestamp1; + const std::clock_t time_default = timestamp3 - timestamp2; + std::printf("fastTan Time %d clocks\n", static_cast(time_fast)); + std::printf("tan Time %d clocks\n", static_cast(time_default)); + + return time_fast <= time_default ? 0 : 1; + } +}//namespace fastTan + +namespace fastAcos +{ + int perf(bool NextFloat) + { + const float begin = -glm::pi(); + const float end = glm::pi(); + float result = 0.f; + + const std::clock_t timestamp1 = std::clock(); + for(float i = begin; i < end; i = NextFloat ? glm::nextFloat(i) : i += 0.1f) + result = glm::fastAcos(i); + + const std::clock_t timestamp2 = std::clock(); + for(float i = begin; i < end; i = NextFloat ? glm::nextFloat(i) : i += 0.1f) + result = glm::acos(i); + + const std::clock_t timestamp3 = std::clock(); + const std::clock_t time_fast = timestamp2 - timestamp1; + const std::clock_t time_default = timestamp3 - timestamp2; + + std::printf("fastAcos Time %d clocks\n", static_cast(time_fast)); + std::printf("acos Time %d clocks\n", static_cast(time_default)); + + return time_fast <= time_default ? 0 : 1; + } +}//namespace fastAcos + +namespace fastAsin +{ + int perf(bool NextFloat) + { + const float begin = -glm::pi(); + const float end = glm::pi(); + float result = 0.f; + const std::clock_t timestamp1 = std::clock(); + for(float i = begin; i < end; i = NextFloat ? glm::nextFloat(i) : i += 0.1f) + result = glm::fastAsin(i); + const std::clock_t timestamp2 = std::clock(); + for(float i = begin; i < end; i = NextFloat ? glm::nextFloat(i) : i += 0.1f) + result = glm::asin(i); + const std::clock_t timestamp3 = std::clock(); + const std::clock_t time_fast = timestamp2 - timestamp1; + const std::clock_t time_default = timestamp3 - timestamp2; + std::printf("fastAsin Time %d clocks\n", static_cast(time_fast)); + std::printf("asin Time %d clocks\n", static_cast(time_default)); + + return time_fast <= time_default ? 0 : 1; + } +}//namespace fastAsin + +namespace fastAtan +{ + int perf(bool NextFloat) + { + const float begin = -glm::pi(); + const float end = glm::pi(); + float result = 0.f; + const std::clock_t timestamp1 = std::clock(); + for(float i = begin; i < end; i = NextFloat ? glm::nextFloat(i) : i += 0.1f) + result = glm::fastAtan(i); + const std::clock_t timestamp2 = std::clock(); + for(float i = begin; i < end; i = NextFloat ? glm::nextFloat(i) : i += 0.1f) + result = glm::atan(i); + const std::clock_t timestamp3 = std::clock(); + const std::clock_t time_fast = timestamp2 - timestamp1; + const std::clock_t time_default = timestamp3 - timestamp2; + std::printf("fastAtan Time %d clocks\n", static_cast(time_fast)); + std::printf("atan Time %d clocks\n", static_cast(time_default)); + + return time_fast <= time_default ? 0 : 1; + } +}//namespace fastAtan + +namespace taylorCos +{ + using glm::qualifier; + using glm::length_t; + + glm::vec4 const AngleShift(0.0f, glm::half_pi(), glm::pi(), glm::three_over_two_pi()); + + template + GLM_FUNC_QUALIFIER glm::vec taylorSeriesNewCos(glm::vec const& x) + { + glm::vec const Powed2(x * x); + glm::vec const Powed4(Powed2 * Powed2); + glm::vec const Powed6(Powed4 * Powed2); + glm::vec const Powed8(Powed4 * Powed4); + + return static_cast(1) + - Powed2 * static_cast(0.5) + + Powed4 * static_cast(0.04166666666666666666666666666667) + - Powed6 * static_cast(0.00138888888888888888888888888889) + + Powed8 * static_cast(2.4801587301587301587301587301587e-5); + } + + template + GLM_FUNC_QUALIFIER glm::vec taylorSeriesNewCos6(glm::vec const& x) + { + glm::vec const Powed2(x * x); + glm::vec const Powed4(Powed2 * Powed2); + glm::vec const Powed6(Powed4 * Powed2); + + return static_cast(1) + - Powed2 * static_cast(0.5) + + Powed4 * static_cast(0.04166666666666666666666666666667) + - Powed6 * static_cast(0.00138888888888888888888888888889); + } + + template + GLM_FUNC_QUALIFIER glm::vec fastAbs(glm::vec x) + { + int* Pointer = reinterpret_cast(&x[0]); + Pointer[0] &= 0x7fffffff; + Pointer[1] &= 0x7fffffff; + Pointer[2] &= 0x7fffffff; + Pointer[3] &= 0x7fffffff; + return x; + } + + template + GLM_FUNC_QUALIFIER glm::vec fastCosNew(glm::vec const& x) + { + glm::vec const Angle0_PI(fastAbs(fmod(x + glm::pi(), glm::two_pi()) - glm::pi())); + return taylorSeriesNewCos6(x); +/* + vec const FirstQuarterPi(lessThanEqual(Angle0_PI, vec(glm::half_pi()))); + + vec const RevertAngle(mix(vec(glm::pi()), vec(0), FirstQuarterPi)); + vec const ReturnSign(mix(vec(-1), vec(1), FirstQuarterPi)); + vec const SectionAngle(RevertAngle - Angle0_PI); + + return ReturnSign * taylorSeriesNewCos(SectionAngle); +*/ + } + + int perf_fastCosNew(float Begin, float End, std::size_t Samples) + { + std::vector Results; + Results.resize(Samples); + + float const Steps = (End - Begin) / static_cast(Samples); + + std::clock_t const TimeStampBegin = std::clock(); + + for(std::size_t i = 0; i < Samples; ++i) + Results[i] = fastCosNew(AngleShift + glm::vec4(Begin + Steps * static_cast(i))); + + std::clock_t const TimeStampEnd = std::clock(); + + std::printf("fastCosNew %d clocks\n", static_cast(TimeStampEnd - TimeStampBegin)); + + int Error = 0; + for(std::size_t i = 0; i < Samples; ++i) + Error += Results[i].x >= -1.0f && Results[i].x <= 1.0f ? 0 : 1; + return Error; + } + + template + GLM_FUNC_QUALIFIER glm::vec deterministic_fmod(glm::vec const& x, T y) + { + return x - y * trunc(x / y); + } + + template + GLM_FUNC_QUALIFIER glm::vec fastCosDeterminisctic(glm::vec const& x) + { + glm::vec const Angle0_PI(abs(deterministic_fmod(x + glm::pi(), glm::two_pi()) - glm::pi())); + glm::vec const FirstQuarterPi(lessThanEqual(Angle0_PI, glm::vec(glm::half_pi()))); + + glm::vec const RevertAngle(mix(glm::vec(glm::pi()), glm::vec(0), FirstQuarterPi)); + glm::vec const ReturnSign(mix(glm::vec(-1), glm::vec(1), FirstQuarterPi)); + glm::vec const SectionAngle(RevertAngle - Angle0_PI); + + return ReturnSign * taylorSeriesNewCos(SectionAngle); + } + + int perf_fastCosDeterminisctic(float Begin, float End, std::size_t Samples) + { + std::vector Results; + Results.resize(Samples); + + float const Steps = (End - Begin) / static_cast(Samples); + + std::clock_t const TimeStampBegin = std::clock(); + + for(std::size_t i = 0; i < Samples; ++i) + Results[i] = taylorCos::fastCosDeterminisctic(AngleShift + glm::vec4(Begin + Steps * static_cast(i))); + + std::clock_t const TimeStampEnd = std::clock(); + + std::printf("fastCosDeterminisctic %d clocks\n", static_cast(TimeStampEnd - TimeStampBegin)); + + int Error = 0; + for(std::size_t i = 0; i < Samples; ++i) + Error += Results[i].x >= -1.0f && Results[i].x <= 1.0f ? 0 : 1; + return Error; + } + + template + GLM_FUNC_QUALIFIER glm::vec taylorSeriesRefCos(glm::vec const& x) + { + return static_cast(1) + - (x * x) / glm::factorial(static_cast(2)) + + (x * x * x * x) / glm::factorial(static_cast(4)) + - (x * x * x * x * x * x) / glm::factorial(static_cast(6)) + + (x * x * x * x * x * x * x * x) / glm::factorial(static_cast(8)); + } + + template + GLM_FUNC_QUALIFIER glm::vec fastRefCos(glm::vec const& x) + { + glm::vec const Angle0_PI(glm::abs(fmod(x + glm::pi(), glm::two_pi()) - glm::pi())); +// return taylorSeriesRefCos(Angle0_PI); + + glm::vec const FirstQuarterPi(lessThanEqual(Angle0_PI, glm::vec(glm::half_pi()))); + + glm::vec const RevertAngle(mix(glm::vec(glm::pi()), glm::vec(0), FirstQuarterPi)); + glm::vec const ReturnSign(mix(glm::vec(-1), glm::vec(1), FirstQuarterPi)); + glm::vec const SectionAngle(RevertAngle - Angle0_PI); + + return ReturnSign * taylorSeriesRefCos(SectionAngle); + } + + int perf_fastCosRef(float Begin, float End, std::size_t Samples) + { + std::vector Results; + Results.resize(Samples); + + float const Steps = (End - Begin) / static_cast(Samples); + + std::clock_t const TimeStampBegin = std::clock(); + + for(std::size_t i = 0; i < Samples; ++i) + Results[i] = taylorCos::fastRefCos(AngleShift + glm::vec4(Begin + Steps * static_cast(i))); + + std::clock_t const TimeStampEnd = std::clock(); + + std::printf("fastCosRef %d clocks\n", static_cast(TimeStampEnd - TimeStampBegin)); + + int Error = 0; + for(std::size_t i = 0; i < Samples; ++i) + Error += Results[i].x >= -1.0f && Results[i].x <= 1.0f ? 0 : 1; + return Error; + } + + int perf_fastCosOld(float Begin, float End, std::size_t Samples) + { + std::vector Results; + Results.resize(Samples); + + float const Steps = (End - Begin) / static_cast(Samples); + + std::clock_t const TimeStampBegin = std::clock(); + + for(std::size_t i = 0; i < Samples; ++i) + Results[i] = glm::fastCos(AngleShift + glm::vec4(Begin + Steps * static_cast(i))); + + std::clock_t const TimeStampEnd = std::clock(); + + std::printf("fastCosOld %d clocks\n", static_cast(TimeStampEnd - TimeStampBegin)); + + int Error = 0; + for(std::size_t i = 0; i < Samples; ++i) + Error += Results[i].x >= -1.0f && Results[i].x <= 1.0f ? 0 : 1; + return Error; + } + + int perf_cos(float Begin, float End, std::size_t Samples) + { + std::vector Results; + Results.resize(Samples); + + float const Steps = (End - Begin) / static_cast(Samples); + + std::clock_t const TimeStampBegin = std::clock(); + + for(std::size_t i = 0; i < Samples; ++i) + Results[i] = glm::cos(AngleShift + glm::vec4(Begin + Steps * static_cast(i))); + + std::clock_t const TimeStampEnd = std::clock(); + + std::printf("cos %d clocks\n", static_cast(TimeStampEnd - TimeStampBegin)); + + int Error = 0; + for(std::size_t i = 0; i < Samples; ++i) + Error += Results[i].x >= -1.0f && Results[i].x <= 1.0f ? 0 : 1; + return Error; + } + + int perf(std::size_t const Samples) + { + int Error = 0; + + float const Begin = -glm::pi(); + float const End = glm::pi(); + + Error += perf_cos(Begin, End, Samples); + Error += perf_fastCosOld(Begin, End, Samples); + Error += perf_fastCosRef(Begin, End, Samples); + //Error += perf_fastCosNew(Begin, End, Samples); + Error += perf_fastCosDeterminisctic(Begin, End, Samples); + + return Error; + } + + int test() + { + int Error = 0; + + //for(float Angle = -4.0f * glm::pi(); Angle < 4.0f * glm::pi(); Angle += 0.1f) + //for(float Angle = -720.0f; Angle < 720.0f; Angle += 0.1f) + for(float Angle = 0.0f; Angle < 180.0f; Angle += 0.1f) + { + float const modAngle = std::fmod(glm::abs(Angle), 360.f); + assert(modAngle >= 0.0f && modAngle <= 360.f); + float const radAngle = glm::radians(modAngle); + float const Cos0 = std::cos(radAngle); + + float const Cos1 = taylorCos::fastRefCos(glm::fvec1(radAngle)).x; + Error += glm::abs(Cos1 - Cos0) < 0.1f ? 0 : 1; + + //float const Cos2 = taylorCos::fastCosNew(glm::fvec1(radAngle)).x; + //Error += glm::abs(Cos2 - Cos0) < 0.1f ? 0 : 1; + + assert(!Error); + } + + return Error; + } +}//namespace taylorCos + +namespace taylor2 +{ + glm::vec4 const AngleShift(0.0f, glm::pi() * 0.5f, glm::pi() * 1.0f, glm::pi() * 1.5f); + + float taylorCosA(float x) + { + return 1.f + - (x * x) * (1.f / 2.f) + + (x * x * x * x) * (1.f / 24.f) + - (x * x * x * x * x * x) * (1.f / 720.f) + + (x * x * x * x * x * x * x * x) * (1.f / 40320.f); + } + + float taylorCosB(float x) + { + return 1.f + - (x * x) * (1.f / 2.f) + + (x * x * x * x) * (1.f / 24.f) + - (x * x * x * x * x * x) * (1.f / 720.f) + + (x * x * x * x * x * x * x * x) * (1.f / 40320.f); + } + + float taylorCosC(float x) + { + return 1.f + - (x * x) * (1.f / 2.f) + + ((x * x) * (x * x)) * (1.f / 24.f) + - (((x * x) * (x * x)) * (x * x)) * (1.f / 720.f) + + (((x * x) * (x * x)) * ((x * x) * (x * x))) * (1.f / 40320.f); + } + + int perf_taylorCosA(float Begin, float End, std::size_t Samples) + { + std::vector Results; + Results.resize(Samples); + + float const Steps = (End - Begin) / static_cast(Samples); + + std::clock_t const TimeStampBegin = std::clock(); + + for(std::size_t i = 0; i < Samples; ++i) + Results[i] = taylorCosA(AngleShift.x + Begin + Steps * static_cast(i)); + + std::clock_t const TimeStampEnd = std::clock(); + + std::printf("taylorCosA %d clocks\n", static_cast(TimeStampEnd - TimeStampBegin)); + + int Error = 0; + for(std::size_t i = 0; i < Samples; ++i) + Error += Results[i] >= -1.0f && Results[i] <= 1.0f ? 0 : 1; + return Error; + } + + int perf_taylorCosB(float Begin, float End, std::size_t Samples) + { + std::vector Results; + Results.resize(Samples); + + float const Steps = (End - Begin) / static_cast(Samples); + + std::clock_t const TimeStampBegin = std::clock(); + + for(std::size_t i = 0; i < Samples; ++i) + Results[i] = taylorCosB(AngleShift.x + Begin + Steps * static_cast(i)); + + std::clock_t const TimeStampEnd = std::clock(); + + std::printf("taylorCosB %d clocks\n", static_cast(TimeStampEnd - TimeStampBegin)); + + int Error = 0; + for(std::size_t i = 0; i < Samples; ++i) + Error += Results[i] >= -1.0f && Results[i] <= 1.0f ? 0 : 1; + return Error; + } + + int perf_taylorCosC(float Begin, float End, std::size_t Samples) + { + std::vector Results; + Results.resize(Samples); + + float const Steps = (End - Begin) / static_cast(Samples); + + std::clock_t const TimeStampBegin = std::clock(); + + for(std::size_t i = 0; i < Samples; ++i) + Results[i] = taylorCosC(AngleShift.x + Begin + Steps * static_cast(i)); + + std::clock_t const TimeStampEnd = std::clock(); + + std::printf("taylorCosC %d clocks\n", static_cast(TimeStampEnd - TimeStampBegin)); + + int Error = 0; + for(std::size_t i = 0; i < Samples; ++i) + Error += Results[i] >= -1.0f && Results[i] <= 1.0f ? 0 : 1; + return Error; + } + + int perf(std::size_t Samples) + { + int Error = 0; + + float const Begin = -glm::pi(); + float const End = glm::pi(); + + Error += perf_taylorCosA(Begin, End, Samples); + Error += perf_taylorCosB(Begin, End, Samples); + Error += perf_taylorCosC(Begin, End, Samples); + + return Error; + } + +}//namespace taylor2 + +int main() +{ + int Error(0); + + Error += ::taylor2::perf(1000); + Error += ::taylorCos::test(); + Error += ::taylorCos::perf(1000); + +# ifdef NDEBUG + ::fastCos::perf(false); + ::fastSin::perf(false); + ::fastTan::perf(false); + ::fastAcos::perf(false); + ::fastAsin::perf(false); + ::fastAtan::perf(false); +# endif//NDEBUG + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_functions.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_functions.cpp new file mode 100644 index 0000000000000000000000000000000000000000..48a6af0e9bbf4e9e79562cc2c317dded500e0e5c --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_functions.cpp @@ -0,0 +1,36 @@ +#include +#include +#include + +int test_gauss_1d() +{ + int Error = 0; + + std::vector Result(20); + for(std::size_t i = 0, n = Result.size(); i < n; ++i) + Result[i] = glm::gauss(static_cast(i) * 0.1f, 0.0f, 1.0f); + + return Error; +} + +int test_gauss_2d() +{ + int Error = 0; + + std::vector Result(20); + for(std::size_t i = 0, n = Result.size(); i < n; ++i) + Result[i] = glm::gauss(glm::vec2(static_cast(i)) * 0.1f, glm::vec2(0.0f), glm::vec2(1.0f)); + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_gauss_1d(); + Error += test_gauss_2d(); + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_gradient_paint.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_gradient_paint.cpp new file mode 100644 index 0000000000000000000000000000000000000000..01f521bf24a42099973aff7c0f21bfbab49ab253 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_gradient_paint.cpp @@ -0,0 +1,34 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include + +int test_radialGradient() +{ + int Error = 0; + + float Gradient = glm::radialGradient(glm::vec2(0), 1.0f, glm::vec2(1), glm::vec2(0.5)); + Error += Gradient != 0.0f ? 0 : 1; + + return Error; +} + +int test_linearGradient() +{ + int Error = 0; + + float Gradient = glm::linearGradient(glm::vec2(0), glm::vec2(1), glm::vec2(0.5)); + Error += Gradient != 0.0f ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_radialGradient(); + Error += test_linearGradient(); + + return Error; +} + + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_handed_coordinate_space.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_handed_coordinate_space.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e417688b4497b8434d5141b545fa575bbb4203af --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_handed_coordinate_space.cpp @@ -0,0 +1,9 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include + +int main() +{ + int Error(0); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_hash.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_hash.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a3d43144019a301dde2f13c1340e2b12a9cb155f --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_hash.cpp @@ -0,0 +1,55 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include +#include + +int test_compile() +{ + int Error = 0; + + // Vector types + std::unordered_map map_vec1; + Error += ++map_vec1[glm::vec1(0.0f)]; + std::unordered_map map_vec2; + Error += ++map_vec2[glm::vec2(0.0f)]; + std::unordered_map map_vec3; + Error += ++map_vec3[glm::vec3(0.0f)]; + std::unordered_map map_vec4; + Error += ++map_vec4[glm::vec4(0.0f)]; + + // Quaternion types + std::unordered_map map_quat; + Error += ++map_quat[glm::quat(0.0f, glm::vec3(0.0f))]; + std::unordered_map map_dualquat; + Error += ++map_dualquat[glm::dualquat(glm::vec3(0.0f))]; + + // Matrix types + std::unordered_map map_mat2x2; + Error += ++map_mat2x2[glm::mat2x2(0.0f)]; + std::unordered_map map_mat2x3; + Error += ++map_mat2x3[glm::mat2x3(0.0f)]; + std::unordered_map map_mat2x4; + Error += ++map_mat2x4[glm::mat2x4(0.0f)]; + std::unordered_map map_mat3x2; + Error += ++map_mat3x2[glm::mat3x2(0.0f)]; + std::unordered_map map_mat3x3; + Error += ++map_mat3x3[glm::mat3x3(0.0f)]; + std::unordered_map map_mat3x4; + Error += ++map_mat3x4[glm::mat3x4(0.0f)]; + std::unordered_map map_mat4x2; + Error += ++map_mat4x2[glm::mat4x2(0.0f)]; + std::unordered_map map_mat4x3; + Error += ++map_mat4x3[glm::mat4x3(0.0f)]; + std::unordered_map map_mat4x4; + Error += ++map_mat4x4[glm::mat4x4(0.0f)]; + + return Error > 0 ? 0 : 1; +} + +int main() +{ + int Error = 0; + + Error += test_compile(); + + return Error; +} \ No newline at end of file diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_int_10_10_10_2.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_int_10_10_10_2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ab59bb2f40d11276201804be576b0610bf59322b --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_int_10_10_10_2.cpp @@ -0,0 +1,18 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +// OpenGL Mathematics Copyright (c) 2005 - 2013 G-Truc Creation (www.g-truc.net) +/////////////////////////////////////////////////////////////////////////////////////////////////// +// Created : 2013-10-25 +// Updated : 2013-10-25 +// Licence : This source is under MIT licence +// File : test/gtx/associated_min_max.cpp +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#include +#include + +int main() +{ + int Error(0); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_integer.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_integer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4c4225d95e1779b3fd4f3d54ae57df0b4fa0e666 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_integer.cpp @@ -0,0 +1,108 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include +#include +#include +#include +/* +int test_floor_log2() +{ + int Error = 0; + + for(std::size_t i = 1; i < 1000000; ++i) + { + glm::uint A = glm::floor_log2(glm::uint(i)); + glm::uint B = glm::uint(glm::floor(glm::log2(double(i)))); // Will fail with float, lack of accuracy + + Error += A == B ? 0 : 1; + assert(!Error); + } + + return Error; +} +*/ +int test_log2() +{ + int Error = 0; + + for(std::size_t i = 1; i < 24; ++i) + { + glm::uint A = glm::log2(glm::uint(1 << i)); + glm::uint B = glm::uint(glm::log2(double(1 << i))); + + //Error += glm::equalEpsilon(double(A), B, 1.0) ? 0 : 1; + Error += glm::abs(double(A) - B) <= 24 ? 0 : 1; + assert(!Error); + + std::printf("Log2(%d) error A=%d, B=%d\n", 1 << i, A, B); + } + + std::printf("log2 error=%d\n", Error); + + return Error; +} + +int test_nlz() +{ + int Error = 0; + + for(glm::uint i = 1; i < glm::uint(33); ++i) + Error += glm::nlz(i) == glm::uint(31u) - glm::findMSB(i) ? 0 : 1; + //printf("%d, %d\n", glm::nlz(i), 31u - glm::findMSB(i)); + + return Error; +} + +int test_pow_uint() +{ + int Error = 0; + + glm::uint const p0 = glm::pow(2u, 0u); + Error += p0 == 1u ? 0 : 1; + + glm::uint const p1 = glm::pow(2u, 1u); + Error += p1 == 2u ? 0 : 1; + + glm::uint const p2 = glm::pow(2u, 2u); + Error += p2 == 4u ? 0 : 1; + + return Error; +} + +int test_pow_int() +{ + int Error = 0; + + int const p0 = glm::pow(2, 0u); + Error += p0 == 1 ? 0 : 1; + + int const p1 = glm::pow(2, 1u); + Error += p1 == 2 ? 0 : 1; + + int const p2 = glm::pow(2, 2u); + Error += p2 == 4 ? 0 : 1; + + int const p0n = glm::pow(-2, 0u); + Error += p0n == -1 ? 0 : 1; + + int const p1n = glm::pow(-2, 1u); + Error += p1n == -2 ? 0 : 1; + + int const p2n = glm::pow(-2, 2u); + Error += p2n == 4 ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_nlz(); +// Error += test_floor_log2(); + Error += test_log2(); + Error += test_pow_uint(); + Error += test_pow_int(); + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_intersect.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_intersect.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c4a1b2a50c1cab36d38960c114f560fbc55c8fdd --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_intersect.cpp @@ -0,0 +1,88 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include +#include +#include + +int test_intersectRayPlane() +{ + int Error = 0; + glm::vec3 const PlaneOrigin(0, 0, 1); + glm::vec3 const PlaneNormal(0, 0, -1); + glm::vec3 const RayOrigin(0, 0, 0); + glm::vec3 const RayDir(0, 0, 1); + + // check that inversion of the plane normal has no effect + { + float Distance = 0; + bool const Result = glm::intersectRayPlane(RayOrigin, RayDir, PlaneOrigin, PlaneNormal, Distance); + Error += glm::abs(Distance - 1.f) <= std::numeric_limits::epsilon() ? 0 : 1; + Error += Result ? 0 : 1; + } + { + float Distance = 0; + bool const Result = glm::intersectRayPlane(RayOrigin, RayDir, PlaneOrigin, -1.f * PlaneNormal, Distance); + Error += glm::abs(Distance - 1.f) <= std::numeric_limits::epsilon() ? 0 : 1; + Error += Result ? 0 : 1; + } + + // check if plane is before of behind the ray origin + { + float Distance = 9.9999f; // value should not be changed + bool const Result = glm::intersectRayPlane(RayOrigin, RayDir, -1.f * PlaneOrigin, PlaneNormal, Distance); + Error += glm::abs(Distance - 9.9999f) <= std::numeric_limits::epsilon() ? 0 : 1; + Error += Result ? 1 : 0; // there is no intersection in front of the ray origin, only behind + } + + return Error; +} + +int test_intersectRayTriangle() +{ + int Error = 0; + + glm::vec3 const Orig(0, 0, 2); + glm::vec3 const Dir(0, 0, -1); + glm::vec3 const Vert0(0, 0, 0); + glm::vec3 const Vert1(-1, -1, 0); + glm::vec3 const Vert2(1, -1, 0); + glm::vec2 BaryPosition(0); + float Distance = 0; + + bool const Result = glm::intersectRayTriangle(Orig, Dir, Vert0, Vert1, Vert2, BaryPosition, Distance); + + Error += glm::all(glm::epsilonEqual(BaryPosition, glm::vec2(0), std::numeric_limits::epsilon())) ? 0 : 1; + Error += glm::abs(Distance - 2.f) <= std::numeric_limits::epsilon() ? 0 : 1; + Error += Result ? 0 : 1; + + return Error; +} + +int test_intersectLineTriangle() +{ + int Error = 0; + + glm::vec3 const Orig(0, 0, 2); + glm::vec3 const Dir(0, 0, -1); + glm::vec3 const Vert0(0, 0, 0); + glm::vec3 const Vert1(-1, -1, 0); + glm::vec3 const Vert2(1, -1, 0); + glm::vec3 Position(2.0f, 0.0f, 0.0f); + + bool const Result = glm::intersectLineTriangle(Orig, Dir, Vert0, Vert1, Vert2, Position); + + Error += glm::all(glm::epsilonEqual(Position, glm::vec3(2.0f, 0.0f, 0.0f), std::numeric_limits::epsilon())) ? 0 : 1; + Error += Result ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_intersectRayPlane(); + Error += test_intersectRayTriangle(); + Error += test_intersectLineTriangle(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_io.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_io.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7d90fd78055c845fb4d78468567fa230ff3770c9 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_io.cpp @@ -0,0 +1,186 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include +#if GLM_LANG & GLM_LANG_CXXMS_FLAG +#include +#include +#include +#include +#include + +namespace +{ + template + std::basic_ostream& operator<<(std::basic_ostream& os, glm::qualifier const& a) + { + typename std::basic_ostream::sentry const cerberus(os); + + if (cerberus) + { + switch (a) { + case glm::highp: os << "uhi"; break; + case glm::mediump: os << "umd"; break; + case glm::lowp: os << "ulo"; break; +# if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE + case glm::aligned_highp: os << "ahi"; break; + case glm::aligned_mediump: os << "amd"; break; + case glm::aligned_lowp: os << "alo"; break; +# endif + } + } + + return os; + } + + template + std::basic_string type_name(std::basic_ostream&, T const&) + { + std::basic_ostringstream ostr; + + if (typeid(T) == typeid(glm::qua)) { ostr << "quat"; } + else if (typeid(T) == typeid(glm::vec<2, U,P>)) { ostr << "vec2"; } + else if (typeid(T) == typeid(glm::vec<3, U,P>)) { ostr << "vec3"; } + else if (typeid(T) == typeid(glm::vec<4, U,P>)) { ostr << "vec4"; } + else if (typeid(T) == typeid(glm::mat<2, 2, U,P>)) { ostr << "mat2x2"; } + else if (typeid(T) == typeid(glm::mat<2, 3, U,P>)) { ostr << "mat2x3"; } + else if (typeid(T) == typeid(glm::mat<2, 4, U,P>)) { ostr << "mat2x4"; } + else if (typeid(T) == typeid(glm::mat<3, 2, U,P>)) { ostr << "mat3x2"; } + else if (typeid(T) == typeid(glm::mat<3, 3, U,P>)) { ostr << "mat3x3"; } + else if (typeid(T) == typeid(glm::mat<3, 4, U,P>)) { ostr << "mat3x4"; } + else if (typeid(T) == typeid(glm::mat<4, 2, U,P>)) { ostr << "mat4x2"; } + else if (typeid(T) == typeid(glm::mat<4, 3, U,P>)) { ostr << "mat4x3"; } + else if (typeid(T) == typeid(glm::mat<4, 4, U,P>)) { ostr << "mat4x4"; } + else { ostr << "unknown"; } + + ostr << '<' << typeid(U).name() << ',' << P << '>'; + + return ostr.str(); + } +} // namespace { + +template +int test_io_quat(OS& os) +{ + os << '\n' << typeid(OS).name() << '\n'; + + glm::qua const q(1, 0, 0, 0); + + { + glm::io::basic_format_saver const iofs(os); + + os << glm::io::precision(2) << glm::io::width(1 + 2 + 1 + 2) + << type_name(os, q) << ": " << q << '\n'; + } + + { + glm::io::basic_format_saver const iofs(os); + + os << glm::io::unformatted + << type_name(os, q) << ": " << q << '\n'; + } + + return 0; +} + +template +int test_io_vec(OS& os) +{ + os << '\n' << typeid(OS).name() << '\n'; + + glm::vec<2, T,P> const v2(0, 1); + glm::vec<3, T,P> const v3(2, 3, 4); + glm::vec<4, T,P> const v4(5, 6, 7, 8); + + os << type_name(os, v2) << ": " << v2 << '\n' + << type_name(os, v3) << ": " << v3 << '\n' + << type_name(os, v4) << ": " << v4 << '\n'; + + glm::io::basic_format_saver const iofs(os); + + os << glm::io::precision(2) << glm::io::width(1 + 2 + 1 + 2) + << type_name(os, v2) << ": " << v2 << '\n' + << type_name(os, v3) << ": " << v3 << '\n' + << type_name(os, v4) << ": " << v4 << '\n'; + + return 0; +} + +template +int test_io_mat(OS& os, glm::io::order_type otype) +{ + os << '\n' << typeid(OS).name() << '\n'; + + glm::vec<2, T,P> const v2_1( 0, 1); + glm::vec<2, T,P> const v2_2( 2, 3); + glm::vec<2, T,P> const v2_3( 4, 5); + glm::vec<2, T,P> const v2_4( 6, 7); + glm::vec<3, T,P> const v3_1( 8, 9, 10); + glm::vec<3, T,P> const v3_2(11, 12, 13); + glm::vec<3, T,P> const v3_3(14, 15, 16); + glm::vec<3, T,P> const v3_4(17, 18, 19); + glm::vec<4, T,P> const v4_1(20, 21, 22, 23); + glm::vec<4, T,P> const v4_2(24, 25, 26, 27); + glm::vec<4, T,P> const v4_3(28, 29, 30, 31); + glm::vec<4, T,P> const v4_4(32, 33, 34, 35); + + glm::io::basic_format_saver const iofs(os); + + os << glm::io::precision(2) << glm::io::width(1 + 2 + 1 + 2) + << glm::io::order(otype) + << "mat2x2<" << typeid(T).name() << ',' << P << ">: " << glm::mat<2, 2, T,P>(v2_1, v2_2) << '\n' + << "mat2x3<" << typeid(T).name() << ',' << P << ">: " << glm::mat<2, 3, T,P>(v3_1, v3_2) << '\n' + << "mat2x4<" << typeid(T).name() << ',' << P << ">: " << glm::mat<2, 4, T,P>(v4_1, v4_2) << '\n' + << "mat3x2<" << typeid(T).name() << ',' << P << ">: " << glm::mat<3, 2, T,P>(v2_1, v2_2, v2_3) << '\n' + << "mat3x3<" << typeid(T).name() << ',' << P << ">: " << glm::mat<3, 3, T,P>(v3_1, v3_2, v3_3) << '\n' + << "mat3x4<" << typeid(T).name() << ',' << P << ">: " << glm::mat<3, 4, T,P>(v4_1, v4_2, v4_3) << '\n' + << "mat4x2<" << typeid(T).name() << ',' << P << ">: " << glm::mat<4, 2, T,P>(v2_1, v2_2, v2_3, v2_4) << '\n' + << "mat4x3<" << typeid(T).name() << ',' << P << ">: " << glm::mat<4, 3, T,P>(v3_1, v3_2, v3_3, v3_4) << '\n' + << "mat4x4<" << typeid(T).name() << ',' << P << ">: " << glm::mat<4, 4, T,P>(v4_1, v4_2, v4_3, v4_4) << '\n'; + + os << glm::io::unformatted + << glm::io::order(otype) + << "mat2x2<" << typeid(T).name() << ',' << P << ">: " << glm::mat<2, 2, T,P>(v2_1, v2_2) << '\n' + << "mat2x3<" << typeid(T).name() << ',' << P << ">: " << glm::mat<2, 3, T,P>(v3_1, v3_2) << '\n' + << "mat2x4<" << typeid(T).name() << ',' << P << ">: " << glm::mat<2, 4, T,P>(v4_1, v4_2) << '\n' + << "mat3x2<" << typeid(T).name() << ',' << P << ">: " << glm::mat<3, 2, T,P>(v2_1, v2_2, v2_3) << '\n' + << "mat3x3<" << typeid(T).name() << ',' << P << ">: " << glm::mat<3, 3, T,P>(v3_1, v3_2, v3_3) << '\n' + << "mat3x4<" << typeid(T).name() << ',' << P << ">: " << glm::mat<3, 4, T,P>(v4_1, v4_2, v4_3) << '\n' + << "mat4x2<" << typeid(T).name() << ',' << P << ">: " << glm::mat<4, 2, T,P>(v2_1, v2_2, v2_3, v2_4) << '\n' + << "mat4x3<" << typeid(T).name() << ',' << P << ">: " << glm::mat<4, 3, T,P>(v3_1, v3_2, v3_3, v3_4) << '\n' + << "mat4x4<" << typeid(T).name() << ',' << P << ">: " << glm::mat<4, 4, T,P>(v4_1, v4_2, v4_3, v4_4) << '\n'; + + return 0; +} + +int main() +{ + int Error(0); + + Error += test_io_quat(std::cout); + Error += test_io_quat(std::wcout); + Error += test_io_quat(std::cout); + Error += test_io_quat(std::wcout); + Error += test_io_quat(std::cout); + Error += test_io_quat(std::wcout); + + Error += test_io_vec(std::cout); + Error += test_io_vec(std::wcout); + Error += test_io_vec(std::cout); + Error += test_io_vec(std::wcout); + Error += test_io_vec(std::cout); + Error += test_io_vec(std::wcout); + + Error += test_io_mat(std::cout, glm::io::column_major); + Error += test_io_mat(std::wcout, glm::io::column_major); + Error += test_io_mat(std::cout, glm::io::row_major); + Error += test_io_mat(std::wcout, glm::io::row_major); + + return Error; +} +#else + +int main() +{ + return 0; +} + +#endif// GLM_LANG & GLM_LANG_CXXMS_FLAG diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_load.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_load.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1467b9b1376c1a38b722ca72ddb8ec4dd8307079 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_load.cpp @@ -0,0 +1,124 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include +/* +#if GLM_CONFIG_SIMD == GLM_ENABLE + +#include +#include +#include +#include +#include + +namespace glm +{ + enum genTypeEnum + { + QUALIFIER_HIGHP, + QUALIFIER_MEDIUMP, + QUALIFIER_LOWP + }; + + template + struct genTypeTrait + {}; + + template + struct genTypeTrait > + { + static const genTypeEnum GENTYPE = QUALIFIER_HIGHP; + }; + + template + struct genTypeTrait > + { + static const genTypeEnum GENTYPE = QUALIFIER_MEDIUMP; + }; + + template + struct genTypeTrait > + { + static const genTypeEnum GENTYPE = QUALIFIER_LOWP; + }; + + template + struct load_gentype + { + + }; + +# if GLM_ARCH & GLM_ARCH_SSE_BIT + template + struct load_gentype<4, float, Q, true> + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, float, Q> load(float const* Mem) + { + vec<4, float, Q> Result; + Result.data = _mm_loadu_ps(Mem); + return Result; + } + }; +# endif//GLM_ARCH & GLM_ARCH_SSE_BIT + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType example_identity() + { + return detail::init_gentype::GENTYPE>::identity(); + } + + template + genType load(valType const* Mem) + { + + } + + aligned_vec4 loadu(float const* Mem) + { + aligned_vec4 Result; +# if GLM_ARCH & GLM_ARCH_SSE_BIT + Result.data = _mm_loadu_ps(Mem); +# else + Result[0] = *(Mem + 0); + Result[1] = *(Mem + 1); + Result[2] = *(Mem + 2); + Result[3] = *(Mem + 3); +# endif//GLM_ARCH & GLM_ARCH_SSE_BIT + return Result; + } + + aligned_vec4 loada(float const* Mem) + { + aligned_vec4 Result; +# if GLM_ARCH & GLM_ARCH_SSE_BIT + Result.data = _mm_load_ps(Mem); +# else + Result[0] = *(Mem + 0); + Result[1] = *(Mem + 1); + Result[2] = *(Mem + 2); + Result[3] = *(Mem + 3); +# endif//GLM_ARCH & GLM_ARCH_SSE_BIT + return Result; + } +}//namespace glm + +int test_vec4_load() +{ + int Error = 0; + + float Data[] = {1.f, 2.f, 3.f, 4.f}; + glm::aligned_vec4 const V = glm::loadu(Data); + Error += glm::all(glm::equal(V, glm::aligned_vec4(1.f, 2.f, 3.f, 4.f), glm::epsilon())) ? 0 : 1; + + return Error; +} +#endif +*/ +int main() +{ + int Error = 0; +/* +# if GLM_CONFIG_SIMD == GLM_ENABLE + Error += test_vec4_load(); +# endif +*/ + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_log_base.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_log_base.cpp new file mode 100644 index 0000000000000000000000000000000000000000..37c746439d2ea4a4310281411a4dc21432be5c21 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_log_base.cpp @@ -0,0 +1,54 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include +#include +#include +#include + +namespace test_log +{ + int run() + { + int Error = 0; + + { + float A = glm::log(10.f, 2.0f); + float B = glm::log2(10.f); + Error += glm::epsilonEqual(A, B, 0.00001f) ? 0 : 1; + } + + { + glm::vec1 A = glm::log(glm::vec1(10.f), glm::vec1(2.0f)); + glm::vec1 B = glm::log2(glm::vec1(10.f)); + Error += glm::all(glm::epsilonEqual(A, B, glm::vec1(0.00001f))) ? 0 : 1; + } + + { + glm::vec2 A = glm::log(glm::vec2(10.f), glm::vec2(2.0f)); + glm::vec2 B = glm::log2(glm::vec2(10.f)); + Error += glm::all(glm::epsilonEqual(A, B, glm::vec2(0.00001f))) ? 0 : 1; + } + + { + glm::vec3 A = glm::log(glm::vec3(10.f), glm::vec3(2.0f)); + glm::vec3 B = glm::log2(glm::vec3(10.f)); + Error += glm::all(glm::epsilonEqual(A, B, glm::vec3(0.00001f))) ? 0 : 1; + } + + { + glm::vec4 A = glm::log(glm::vec4(10.f), glm::vec4(2.0f)); + glm::vec4 B = glm::log2(glm::vec4(10.f)); + Error += glm::all(glm::epsilonEqual(A, B, glm::vec4(0.00001f))) ? 0 : 1; + } + + return Error; + } +}//namespace test_log + +int main() +{ + int Error(0); + + Error += test_log::run(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_matrix_cross_product.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_matrix_cross_product.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c1d0fa958a12b2e46ddb3f29e0c5a6e845119066 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_matrix_cross_product.cpp @@ -0,0 +1,9 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include + +int main() +{ + int Error(0); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_matrix_decompose.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_matrix_decompose.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5a1884e5c05a1c684492f43c76589fe18c45c1aa --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_matrix_decompose.cpp @@ -0,0 +1,19 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include + +int main() +{ + int Error(0); + + glm::mat4 Matrix(1); + + glm::vec3 Scale; + glm::quat Orientation; + glm::vec3 Translation; + glm::vec3 Skew(1); + glm::vec4 Perspective(1); + + glm::decompose(Matrix, Scale, Orientation, Translation, Skew, Perspective); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_matrix_factorisation.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_matrix_factorisation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6771dbac08fc776ab0915821db59060b7063f7a2 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_matrix_factorisation.cpp @@ -0,0 +1,105 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include +#include +#include + +template +int test_qr(glm::mat m) +{ + int Error = 0; + + T const epsilon = static_cast(1e-10); + + glm::mat<(C < R ? C : R), R, T, Q> q(-999); + glm::mat r(-999); + + glm::qr_decompose(m, q, r); + + //Test if q*r really equals the input matrix + glm::mat tm = q*r; + glm::mat err = tm - m; + + for (glm::length_t i = 0; i < C; i++) + for (glm::length_t j = 0; j < R; j++) + Error += glm::abs(err[i][j]) > epsilon ? 1 : 0; + + //Test if the columns of q are orthonormal + for (glm::length_t i = 0; i < (C < R ? C : R); i++) + { + Error += (length(q[i]) - 1) > epsilon ? 1 : 0; + + for (glm::length_t j = 0; j epsilon ? 1 : 0; + } + + //Test if the matrix r is upper triangular + for (glm::length_t i = 0; i < C; i++) + for (glm::length_t j = i + 1; j < (C < R ? C : R); j++) + Error += glm::epsilonEqual(r[i][j], static_cast(0), glm::epsilon()) ? 0 : 1; + + return Error; +} + +template +int test_rq(glm::mat m) +{ + int Error = 0; + + T const epsilon = static_cast(1e-10); + + glm::mat q(-999); + glm::mat<(C < R ? C : R), R, T, Q> r(-999); + + glm::rq_decompose(m, r, q); + + //Test if q*r really equals the input matrix + glm::mat tm = r*q; + glm::mat err = tm - m; + + for (glm::length_t i = 0; i < C; i++) + for (glm::length_t j = 0; j < R; j++) + Error += glm::abs(err[i][j]) > epsilon ? 1 : 0; + + //Test if the rows of q are orthonormal + glm::mat<(C < R ? C : R), C, T, Q> tq = transpose(q); + + for (glm::length_t i = 0; i < (C < R ? C : R); i++) + { + Error += (length(tq[i]) - 1) > epsilon ? 1 : 0; + + for (glm::length_t j = 0; j epsilon ? 1 : 0; + } + + //Test if the matrix r is upper triangular + for (glm::length_t i = 0; i < (C < R ? C : R); i++) + for (glm::length_t j = R - (C < R ? C : R) + i + 1; j < R; j++) + Error += glm::epsilonEqual(r[i][j], static_cast(0), glm::epsilon()) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + //Test QR square + Error += test_qr(glm::dmat3(12.0, 6.0, -4.0, -51.0, 167.0, 24.0, 4.0, -68.0, -41.0)) ? 1 : 0; + + //Test RQ square + Error += test_rq(glm::dmat3(12.0, 6.0, -4.0, -51.0, 167.0, 24.0, 4.0, -68.0, -41.0)) ? 1 : 0; + + //Test QR triangular 1 + Error += test_qr(glm::dmat3x4(12.0, 6.0, -4.0, -51.0, 167.0, 24.0, 4.0, -68.0, -41.0, 7.0, 2.0, 15.0)) ? 1 : 0; + + //Test QR triangular 2 + Error += test_qr(glm::dmat4x3(12.0, 6.0, -4.0, -51.0, 167.0, 24.0, 4.0, -68.0, -41.0, 7.0, 2.0, 15.0)) ? 1 : 0; + + //Test RQ triangular 1 : Fails at the triangular test + Error += test_rq(glm::dmat3x4(12.0, 6.0, -4.0, -51.0, 167.0, 24.0, 4.0, -68.0, -41.0, 7.0, 2.0, 15.0)) ? 1 : 0; + + //Test QR triangular 2 + Error += test_rq(glm::dmat4x3(12.0, 6.0, -4.0, -51.0, 167.0, 24.0, 4.0, -68.0, -41.0, 7.0, 2.0, 15.0)) ? 1 : 0; + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_matrix_interpolation.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_matrix_interpolation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..108f02e975223d970cd556f6a5298a50230039cf --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_matrix_interpolation.cpp @@ -0,0 +1,122 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include +#include +#include + +#include +#include +#include + + +static int test_axisAngle() +{ + int Error = 0; + + glm::mat4 m1(-0.9946f, 0.0f, -0.104531f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.104531f, 0.0f, -0.9946f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f); + glm::mat4 m2(-0.992624f, 0.0f, -0.121874f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.121874f, 0.0f, -0.992624f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f); + + glm::mat4 const m1rot = glm::extractMatrixRotation(m1); + glm::mat4 const dltRotation = m2 * glm::transpose(m1rot); + + glm::vec3 dltAxis(0.0f); + float dltAngle = 0.0f; + glm::axisAngle(dltRotation, dltAxis, dltAngle); + + std::cout << "dltAxis: (" << dltAxis.x << ", " << dltAxis.y << ", " << dltAxis.z << "), dltAngle: " << dltAngle << std::endl; + + glm::quat q = glm::quat_cast(dltRotation); + std::cout << "q: (" << q.x << ", " << q.y << ", " << q.z << ", " << q.w << ")" << std::endl; + float yaw = glm::yaw(q); + std::cout << "Yaw: " << yaw << std::endl; + + return Error; +} + +template +int testForAxisAngle(glm::vec<3, T, glm::defaultp> const axisTrue, T const angleTrue) +{ + T const eps = std::sqrt(std::numeric_limits::epsilon()); + + glm::mat<4, 4, T, glm::defaultp> const matTrue = glm::axisAngleMatrix(axisTrue, angleTrue); + + glm::vec<3, T, glm::defaultp> axis; + T angle; + glm::axisAngle(matTrue, axis, angle); + glm::mat<4, 4, T, glm::defaultp> const matRebuilt = glm::axisAngleMatrix(axis, angle); + + glm::mat<4, 4, T, glm::defaultp> const errMat = matTrue - matRebuilt; + T const maxErr = glm::compMax(glm::vec<4, T, glm::defaultp>( + glm::compMax(glm::abs(errMat[0])), + glm::compMax(glm::abs(errMat[1])), + glm::compMax(glm::abs(errMat[2])), + glm::compMax(glm::abs(errMat[3])) + )); + + return maxErr < eps ? 0 : 1; +} + +static int test_axisAngle2() +{ + int Error = 0; + + Error += testForAxisAngle(glm::vec3(0.0f, 1.0f, 0.0f), 0.0f); + Error += testForAxisAngle(glm::vec3(0.358f, 0.0716f, 0.9309f), 0.00001f); + Error += testForAxisAngle(glm::vec3(1.0f, 0.0f, 0.0f), 0.0001f); + Error += testForAxisAngle(glm::vec3(0.0f, 0.0f, 1.0f), 0.001f); + Error += testForAxisAngle(glm::vec3(0.0f, 0.0f, 1.0f), 0.001f); + Error += testForAxisAngle(glm::vec3(0.0f, 1.0f, 0.0f), 0.005f); + Error += testForAxisAngle(glm::vec3(0.0f, 0.0f, 1.0f), 0.005f); + Error += testForAxisAngle(glm::vec3(0.358f, 0.0716f, 0.9309f), 0.03f); + Error += testForAxisAngle(glm::vec3(0.358f, 0.0716f, 0.9309f), 0.0003f); + Error += testForAxisAngle(glm::vec3(0.0f, 0.0f, 1.0f), 0.01f); + Error += testForAxisAngle(glm::dvec3(0.0f, 1.0f, 0.0f), 0.00005); + Error += testForAxisAngle(glm::dvec3(-1.0f, 0.0f, 0.0f), 0.000001); + Error += testForAxisAngle(glm::dvec3(0.7071f, 0.7071f, 0.0f), 0.5); + Error += testForAxisAngle(glm::dvec3(0.7071f, 0.0f, 0.7071f), 0.0002); + Error += testForAxisAngle(glm::dvec3(0.7071f, 0.0f, 0.7071f), 0.00002); + Error += testForAxisAngle(glm::dvec3(0.7071f, 0.0f, 0.7071f), 0.000002); + Error += testForAxisAngle(glm::dvec3(0.7071f, 0.0f, 0.7071f), 0.0000002); + Error += testForAxisAngle(glm::vec3(0.0f, 0.7071f, 0.7071f), 1.3f); + Error += testForAxisAngle(glm::vec3(0.0f, 0.7071f, 0.7071f), 6.3f); + Error += testForAxisAngle(glm::vec3(1.0f, 0.0f, 0.0f), -0.23456f); + Error += testForAxisAngle(glm::vec3(1.0f, 0.0f, 0.0f), glm::pi()); + Error += testForAxisAngle(glm::vec3(0.0f, 1.0f, 0.0f), -glm::pi()); + Error += testForAxisAngle(glm::vec3(0.358f, 0.0716f, 0.9309f), -glm::pi()); + Error += testForAxisAngle(glm::vec3(1.0f, 0.0f, 0.0f), glm::pi() + 2e-6f); + Error += testForAxisAngle(glm::vec3(1.0f, 0.0f, 0.0f), glm::pi() + 1e-4f); + Error += testForAxisAngle(glm::vec3(0.0f, 1.0f, 0.0f), -glm::pi() + 1e-3f); + Error += testForAxisAngle(glm::vec3(0.358f, 0.0716f, 0.9309f), -glm::pi() + 5e-3f); + + return Error; +} + +static int test_rotate() +{ + glm::mat4 m2(1.0); + float myAngle = 1.0f; + m2 = glm::rotate(m2, myAngle, glm::vec3(1.0f, 0.0f, 0.0f)); + glm::vec3 m2Axis; + float m2Angle; + glm::axisAngle(m2, m2Axis, m2Angle); + + return 0; +} + +int main() +{ + int Error = 0; + + Error += test_axisAngle(); + Error += test_axisAngle2(); + Error += test_rotate(); + + return Error; +} + + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_matrix_major_storage.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_matrix_major_storage.cpp new file mode 100644 index 0000000000000000000000000000000000000000..21de7f71dc5168034668b70050703249835d8a8c --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_matrix_major_storage.cpp @@ -0,0 +1,9 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include + +int main() +{ + int Error(0); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_matrix_operation.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_matrix_operation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..79c95c528533d9272b850caf04d611b1aeea3fce --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_matrix_operation.cpp @@ -0,0 +1,86 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include +#include +#include +#include + +int test_adjugate() +{ + int Error = 0; + + const float epsilon = std::numeric_limits::epsilon(); + + // mat2 + const glm::mat2 m2( + 2, 3, + 1, 5 + ); + + const glm::mat2 eam2( + 5, -3, + -1, 2 + ); + + const glm::mat2 am2 = glm::adjugate(m2); + + Error += glm::all(glm::bvec2( + glm::all(glm::epsilonEqual(am2[0], eam2[0], epsilon)), + glm::all(glm::epsilonEqual(am2[1], eam2[1], epsilon)) + )) ? 0 : 1; + + // mat3 + const glm::mat3 m3( + 2, 3, 3, + 1, 5, 4, + 4, 6, 8 + ); + + const glm::mat3 eam3( + 16, -6, -3, + 8, 4, -5, + -14, 0, 7 + ); + + const glm::mat3 am3 = glm::adjugate(m3); + + Error += glm::all(glm::bvec3( + glm::all(glm::epsilonEqual(am3[0], eam3[0], epsilon)), + glm::all(glm::epsilonEqual(am3[1], eam3[1], epsilon)), + glm::all(glm::epsilonEqual(am3[2], eam3[2], epsilon)) + )) ? 0 : 1; + + // mat4 + const glm::mat4 m4( + 2, 3, 3, 1, + 1, 5, 4, 3, + 4, 6, 8, 5, + -2, -3, -3, 4 + ); + + const glm::mat4 eam4( + 97, -30, -15, 17, + 45, 20, -25, 5, + -91, 0, 35, -21, + 14, 0, 0, 14 + ); + + const glm::mat4 am4 = glm::adjugate(m4); + + Error += glm::all(glm::bvec4( + glm::all(glm::epsilonEqual(am4[0], eam4[0], epsilon)), + glm::all(glm::epsilonEqual(am4[1], eam4[1], epsilon)), + glm::all(glm::epsilonEqual(am4[2], eam4[2], epsilon)), + glm::all(glm::epsilonEqual(am4[3], eam4[3], epsilon)) + )) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_adjugate(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_matrix_query.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_matrix_query.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0dda1f0938344d6ec66e833b08830c581b30c7a0 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_matrix_query.cpp @@ -0,0 +1,66 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include + +int test_isNull() +{ + int Error(0); + + bool TestA = glm::isNull(glm::mat4(0), 0.00001f); + Error += TestA ? 0 : 1; + + return Error; +} + +int test_isIdentity() +{ + int Error(0); + + { + bool TestA = glm::isIdentity(glm::mat2(1), 0.00001f); + Error += TestA ? 0 : 1; + } + { + bool TestA = glm::isIdentity(glm::mat3(1), 0.00001f); + Error += TestA ? 0 : 1; + } + { + bool TestA = glm::isIdentity(glm::mat4(1), 0.00001f); + Error += TestA ? 0 : 1; + } + + return Error; +} + +int test_isNormalized() +{ + int Error(0); + + bool TestA = glm::isNormalized(glm::mat4(1), 0.00001f); + Error += TestA ? 0 : 1; + + return Error; +} + +int test_isOrthogonal() +{ + int Error(0); + + bool TestA = glm::isOrthogonal(glm::mat4(1), 0.00001f); + Error += TestA ? 0 : 1; + + return Error; +} + +int main() +{ + int Error(0); + + Error += test_isNull(); + Error += test_isIdentity(); + Error += test_isNormalized(); + Error += test_isOrthogonal(); + + return Error; +} + + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_matrix_transform_2d.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_matrix_transform_2d.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f80d2633ff0ad92330db34751b99b9cc4274f7fa --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_matrix_transform_2d.cpp @@ -0,0 +1,9 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include + +int main() +{ + int Error(0); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_mixed_product.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_mixed_product.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ab59bb2f40d11276201804be576b0610bf59322b --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_mixed_product.cpp @@ -0,0 +1,18 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +// OpenGL Mathematics Copyright (c) 2005 - 2013 G-Truc Creation (www.g-truc.net) +/////////////////////////////////////////////////////////////////////////////////////////////////// +// Created : 2013-10-25 +// Updated : 2013-10-25 +// Licence : This source is under MIT licence +// File : test/gtx/associated_min_max.cpp +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#include +#include + +int main() +{ + int Error(0); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_norm.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_norm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e82102ac571218bb7afb9bb4869ce14bd2dd1569 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_norm.cpp @@ -0,0 +1,81 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include + + +int test_lMaxNorm() +{ + int Error(0); + + { + float norm = glm::lMaxNorm(glm::vec3(-1, -2, -3)); + Error += glm::epsilonEqual(norm, 3.f, 0.00001f) ? 0 : 1; + } + + { + float norm = glm::lMaxNorm(glm::vec3(2, 3, 1)); + Error += glm::epsilonEqual(norm, 3.f, 0.00001f) ? 0 : 1; + } + + return Error; +} + +int test_lxNorm() +{ + int Error(0); + + { + unsigned int depth_1 = 1; + float normA = glm::lxNorm(glm::vec3(2, 3, 1), depth_1); + float normB = glm::l1Norm(glm::vec3(2, 3, 1)); + Error += glm::epsilonEqual(normA, normB, 0.00001f) ? 0 : 1; + Error += glm::epsilonEqual(normA, 6.f, 0.00001f) ? 0 : 1; + } + + { + unsigned int depth_1 = 1; + float normA = glm::lxNorm(glm::vec3(-1, -2, -3), depth_1); + float normB = glm::l1Norm(glm::vec3(-1, -2, -3)); + Error += glm::epsilonEqual(normA, normB, 0.00001f) ? 0 : 1; + Error += glm::epsilonEqual(normA, 6.f, 0.00001f) ? 0 : 1; + } + + { + unsigned int depth_2 = 2; + float normA = glm::lxNorm(glm::vec3(2, 3, 1), depth_2); + float normB = glm::l2Norm(glm::vec3(2, 3, 1)); + Error += glm::epsilonEqual(normA, normB, 0.00001f) ? 0 : 1; + Error += glm::epsilonEqual(normA, 3.741657387f, 0.00001f) ? 0 : 1; + } + + { + unsigned int depth_2 = 2; + float normA = glm::lxNorm(glm::vec3(-1, -2, -3), depth_2); + float normB = glm::l2Norm(glm::vec3(-1, -2, -3)); + Error += glm::epsilonEqual(normA, normB, 0.00001f) ? 0 : 1; + Error += glm::epsilonEqual(normA, 3.741657387f, 0.00001f) ? 0 : 1; + } + + { + unsigned int oddDepth = 3; + float norm = glm::lxNorm(glm::vec3(2, 3, 1), oddDepth); + Error += glm::epsilonEqual(norm, 3.301927249f, 0.00001f) ? 0 : 1; + } + + { + unsigned int oddDepth = 3; + float norm = glm::lxNorm(glm::vec3(-1, -2, -3), oddDepth); + Error += glm::epsilonEqual(norm, 3.301927249f, 0.00001f) ? 0 : 1; + } + + return Error; +} + +int main() +{ + int Error(0); + + Error += test_lMaxNorm(); + Error += test_lxNorm(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_normal.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_normal.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7a01ec0b233a6ada5c499217a9cbd1557557fcce --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_normal.cpp @@ -0,0 +1,9 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include + +int main() +{ + int Error(0); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_normalize_dot.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_normalize_dot.cpp new file mode 100644 index 0000000000000000000000000000000000000000..960586300f308b7e7383ed994d1f62dc52dbdd47 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_normalize_dot.cpp @@ -0,0 +1,9 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include + +int main() +{ + int Error(0); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_number_precision.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_number_precision.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a5a3ef23759c1621f8005fe45d1426bfecb0d9e7 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_number_precision.cpp @@ -0,0 +1,9 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include + +int main() +{ + int Error(0); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_optimum_pow.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_optimum_pow.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c0a3fd411977c3710d2a3e46c5785a4aa52756f0 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_optimum_pow.cpp @@ -0,0 +1,9 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include + +int main() +{ + int Error(0); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_orthonormalize.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_orthonormalize.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0e7a8c8b4ebb86b1cd011de534c371aa23a5b578 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_orthonormalize.cpp @@ -0,0 +1,9 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include + +int main() +{ + int Error(0); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_pca.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_pca.cpp new file mode 100644 index 0000000000000000000000000000000000000000..120e277e78e999f6cfa189f9d4f48c7d7b0e2d93 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_pca.cpp @@ -0,0 +1,724 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include +#include +#include +#include + +#include +#include +#if GLM_HAS_CXX11_STL == 1 +#include +#endif + +template +T myEpsilon(); +template<> +GLM_INLINE GLM_CONSTEXPR float myEpsilon() { return 0.00001f; } +template<> +GLM_INLINE GLM_CONSTEXPR double myEpsilon() { return 0.000001; } + +template +bool vectorEpsilonEqual(glm::vec const& a, glm::vec const& b, T epsilon) +{ + for (int c = 0; c < D; ++c) + if (!glm::epsilonEqual(a[c], b[c], epsilon)) + { + fprintf(stderr, "failing vectorEpsilonEqual: [%d] %lf != %lf (~%lf)\n", + c, + static_cast(a[c]), + static_cast(b[c]), + static_cast(epsilon) + ); + return false; + } + return true; +} + +template +bool matrixEpsilonEqual(glm::mat const& a, glm::mat const& b, T epsilon) +{ + for (int c = 0; c < D; ++c) + for (int r = 0; r < D; ++r) + if (!glm::epsilonEqual(a[c][r], b[c][r], epsilon)) + { + fprintf(stderr, "failing vectorEpsilonEqual: [%d][%d] %lf != %lf (~%lf)\n", + c, r, + static_cast(a[c][r]), + static_cast(b[c][r]), + static_cast(epsilon) + ); + return false; + } + return true; +} + +template +GLM_INLINE bool sameSign(T const& a, T const& b) +{ + return ((a >= 0) && (b >= 0)) || ((a < 0) && (b < 0)); +} + +template +T failReport(T line) +{ + fprintf(stderr, "Failed in line %d\n", static_cast(line)); + return line; +} + +// Test data: 1AGA 'agarose double helix' +// https://www.rcsb.org/structure/1aga +// The fourth coordinate is randomized +namespace _1aga +{ + + // Fills `outTestData` with hard-coded atom positions from 1AGA + // The fourth coordinate is randomized + template + void fillTestData(std::vector& outTestData) + { + // x,y,z coordinates copied from RCSB PDB file of 1AGA + // w coordinate randomized with standard normal distribution + static const double _1aga[] = { + 3.219, -0.637, 19.462, 2.286, + 4.519, 0.024, 18.980, -0.828, + 4.163, 1.425, 18.481, -0.810, + 3.190, 1.341, 17.330, -0.170, + 1.962, 0.991, 18.165, 0.816, + 2.093, 1.952, 19.331, 0.276, + 5.119, -0.701, 17.908, -0.490, + 3.517, 2.147, 19.514, -0.207, + 2.970, 2.609, 16.719, 0.552, + 2.107, -0.398, 18.564, 0.403, + 2.847, 2.618, 15.335, 0.315, + 1.457, 3.124, 14.979, 0.683, + 1.316, 3.291, 13.473, 0.446, + 2.447, 4.155, 12.931, 1.324, + 3.795, 3.614, 13.394, 0.112, + 4.956, 4.494, 12.982, 0.253, + 0.483, 2.217, 15.479, 1.316, + 0.021, 3.962, 13.166, 1.522, + 2.311, 5.497, 13.395, 0.248, + 3.830, 3.522, 14.827, 0.591, + 5.150, 4.461, 11.576, 0.635, + -1.057, 3.106, 13.132, 0.191, + -2.280, 3.902, 12.650, 1.135, + -3.316, 2.893, 12.151, 0.794, + -2.756, 2.092, 11.000, 0.720, + -1.839, 1.204, 11.835, -1.172, + -2.737, 0.837, 13.001, -0.313, + -1.952, 4.784, 11.578, 2.082, + -3.617, 1.972, 13.184, 0.653, + -3.744, 1.267, 10.389, -0.413, + -0.709, 2.024, 12.234, -1.747, + -3.690, 1.156, 9.005, -1.275, + -3.434, -0.300, 8.649, 0.441, + -3.508, -0.506, 7.143, 0.237, + -4.822, 0.042, 6.601, -2.856, + -5.027, 1.480, 7.064, 0.985, + -6.370, 2.045, 6.652, 0.915, + -2.162, -0.690, 9.149, 1.100, + -3.442, -1.963, 6.836, -0.081, + -5.916, -0.747, 7.065, -2.345, + -4.965, 1.556, 8.497, 0.504, + -6.439, 2.230, 5.246, 1.451, + -2.161, -2.469, 6.802, -1.171, + -2.239, -3.925, 6.320, -1.434, + -0.847, -4.318, 5.821, 0.098, + -0.434, -3.433, 4.670, -1.446, + -0.123, -2.195, 5.505, 0.182, + 0.644, -2.789, 6.671, 0.865, + -3.167, -4.083, 5.248, -0.098, + 0.101, -4.119, 6.854, -0.001, + 0.775, -3.876, 4.059, 1.061, + -1.398, -1.625, 5.904, 0.230, + 0.844, -3.774, 2.675, 1.313, + 1.977, -2.824, 2.319, -0.112, + 2.192, -2.785, 0.813, -0.981, + 2.375, -4.197, 0.271, -0.355, + 1.232, -5.093, 0.734, 0.632, + 1.414, -6.539, 0.322, 0.576, + 1.678, -1.527, 2.819, -1.187, + 3.421, -1.999, 0.496, -1.770, + 3.605, -4.750, 0.735, 1.099, + 1.135, -5.078, 2.167, 0.854, + 1.289, -6.691, -1.084, -0.487, + -1.057, 3.106, 22.602, -1.297, + -2.280, 3.902, 22.120, 0.376, + -3.316, 2.893, 21.621, 0.932, + -2.756, 2.092, 20.470, 1.680, + -1.839, 1.204, 21.305, 0.615, + -2.737, 0.837, 22.471, 0.899, + -1.952, 4.784, 21.048, -0.521, + -3.617, 1.972, 22.654, 0.133, + -3.744, 1.267, 19.859, 0.081, + -0.709, 2.024, 21.704, 1.420, + -3.690, 1.156, 18.475, -0.850, + -3.434, -0.300, 18.119, -0.249, + -3.508, -0.506, 16.613, 1.434, + -4.822, 0.042, 16.071, -2.466, + -5.027, 1.480, 16.534, -1.045, + -6.370, 2.045, 16.122, 1.707, + -2.162, -0.690, 18.619, -2.023, + -3.442, -1.963, 16.336, -0.304, + -5.916, -0.747, 16.535, 0.979, + -4.965, 1.556, 17.967, -1.165, + -6.439, 2.230, 14.716, 0.929, + -2.161, -2.469, 16.302, -0.234, + -2.239, -3.925, 15.820, -0.228, + -0.847, -4.318, 15.321, 1.844, + -0.434, -3.433, 14.170, 1.132, + -0.123, -2.195, 15.005, 0.211, + 0.644, -2.789, 16.171, -0.632, + -3.167, -4.083, 14.748, -0.519, + 0.101, -4.119, 16.354, 0.173, + 0.775, -3.876, 13.559, 1.243, + -1.398, -1.625, 15.404, -0.187, + 0.844, -3.774, 12.175, -1.332, + 1.977, -2.824, 11.819, -1.616, + 2.192, -2.785, 10.313, 1.320, + 2.375, -4.197, 9.771, 0.237, + 1.232, -5.093, 10.234, 0.851, + 1.414, -6.539, 9.822, 1.816, + 1.678, -1.527, 12.319, -1.657, + 3.421, -1.999, 10.036, 1.559, + 3.605, -4.750, 10.235, 0.831, + 1.135, -5.078, 11.667, 0.060, + 1.289, -6.691, 8.416, 1.066, + 3.219, -0.637, 10.002, 2.111, + 4.519, 0.024, 9.520, -0.874, + 4.163, 1.425, 9.021, -1.012, + 3.190, 1.341, 7.870, -0.250, + 1.962, 0.991, 8.705, -1.359, + 2.093, 1.952, 9.871, -0.126, + 5.119, -0.701, 8.448, 0.995, + 3.517, 2.147, 10.054, 0.941, + 2.970, 2.609, 7.259, -0.562, + 2.107, -0.398, 9.104, -0.038, + 2.847, 2.618, 5.875, 0.398, + 1.457, 3.124, 5.519, 0.481, + 1.316, 3.291, 4.013, -0.187, + 2.447, 4.155, 3.471, -0.429, + 3.795, 3.614, 3.934, -0.432, + 4.956, 4.494, 3.522, -0.788, + 0.483, 2.217, 6.019, -0.923, + 0.021, 3.962, 3.636, -0.316, + 2.311, 5.497, 3.935, -1.917, + 3.830, 3.522, 5.367, -0.302, + 5.150, 4.461, 2.116, -1.615 + }; + static const glm::length_t _1agaSize = sizeof(_1aga) / (4 * sizeof(double)); + + outTestData.resize(_1agaSize); + for(glm::length_t i = 0; i < _1agaSize; ++i) + for(glm::length_t d = 0; d < static_cast(vec::length()); ++d) + outTestData[i][d] = static_cast(_1aga[i * 4 + d]); + } + + // All reference values computed separately using symbolic precision + // https://github.com/sgrottel/exp-pca-precision + // This applies to all functions named: `_1aga::expected*()` + + GLM_INLINE glm::dmat4 const& expectedCovarData() + { + static const glm::dmat4 covar4x4d( + 9.62434068027210898322, -0.00006657369614512471, -4.29321376568405099761, 0.01879374187452758846, + -0.00006657369614512471, 9.62443937868480681175, 5.35113872637944076871, -0.11569259145880574080, + -4.29321376568405099761, 5.35113872637944076871, 35.62848549634668415820, 0.90874239254220201545, + 0.01879374187452758846, -0.11569259145880574080, 0.90874239254220201545, 1.09705971856890904803 + ); + return covar4x4d; + } + + template + GLM_INLINE glm::vec const& expectedEigenvalues(); + template<> + GLM_INLINE glm::dvec2 const& expectedEigenvalues<2>() + { + static const glm::dvec2 evals2( + 9.62447289926297399961763301774251330057894539467032275382255, + 9.62430715969394210015560961264297422776572580714373620309355 + ); + return evals2; + } + template<> + GLM_INLINE glm::dvec3 const& expectedEigenvalues<3>() + { + static const glm::dvec3 evals3( + 37.3274494274683425233695502581182052836449738530676689472257, + 9.62431434161498823505729817436585077939509766554969096873168, + 7.92550178622027216422369326567668971675332732240052872097887 + ); + return evals3; + } + template<> + GLM_INLINE glm::dvec4 const& expectedEigenvalues<4>() + { + static const glm::dvec4 evals4( + 37.3477389918792213596879452204499702406947817221901007885630, + 9.62470688921105696017807313860277172063600080413412567999700, + 7.94017075281634999342344275928070533134615133171969063657713, + 1.06170863996588365446060186982477896078741484440002343404155 + ); + return evals4; + } + + template + GLM_INLINE glm::mat const& expectedEigenvectors(); + template<> + GLM_INLINE glm::dmat2 const& expectedEigenvectors<2>() + { + static const glm::dmat2 evecs2( + glm::dvec2( + -0.503510847492551904906870957742619139443409162857537237123308, + 1 + ), + glm::dvec2( + 1.98605453086051402895741763848787613048533838388005162794043, + 1 + ) + ); + return evecs2; + } + template<> + GLM_INLINE glm::dmat3 const& expectedEigenvectors<3>() + { + static const glm::dmat3 evecs3( + glm::dvec3( + -0.154972738414395866005286433008304444294405085038689821864654, + 0.193161285869815165989799191097521722568079378840201629578695, + 1 + ), + glm::dvec3( + -158565.112775416943154745839952575022429933119522746586149868, + -127221.506282351944358932458687410410814983610301927832439675, + 1 + ), + glm::dvec3( + 2.52702248596556806145700361724323960543858113426446460406536, + -3.14959802931313870497377546974185300816008580801457419079412, + 1 + ) + ); + return evecs3; + } + template<> + GLM_INLINE glm::dmat4 const& expectedEigenvectors<4>() + { + static const glm::dmat4 evecs4( + glm::dvec4( + -6.35322390281037045217295803597357821705371650876122113027264, + 7.91546394153385394517767054617789939529794642646629201212056, + 41.0301543819240679808549819457450130787045236815736490549663, + 1 + ), + glm::dvec4( + -114.622418941087829756565311692197154422302604224781253861297, + -92.2070185807065289900871215218752013659402949497379896153118, + 0.0155846091025912430932734548933329458404665760587569100867246, + 1 + ), + glm::dvec4( + 13.1771887761559019483954743159026938257325190511642952175789, + -16.3688257459634877666638419310116970616615816436949741766895, + 5.17386502341472097227408249233288958059579189051394773143190, + 1 + ), + glm::dvec4( + -0.0192777078948229800494895064532553117703859768210647632969276, + 0.0348034950916108873629241563077465542944938906271231198634442, + -0.0340715609308469289267379681032545422644143611273049912226126, + 1 + ) + ); + return evecs4; + } + +} // namespace _1aga + +// Compute center of gravity +template +vec computeCenter(const std::vector& testData) +{ + double c[4]; + std::fill(c, c + vec::length(), 0.0); + + typename std::vector::const_iterator e = testData.end(); + for(typename std::vector::const_iterator i = testData.begin(); i != e; ++i) + for(glm::length_t d = 0; d < static_cast(vec::length()); ++d) + c[d] += static_cast((*i)[d]); + + vec cVec(0); + for(glm::length_t d = 0; d < static_cast(vec::length()); ++d) + cVec[d] = static_cast(c[d] / static_cast(testData.size())); + return cVec; +} + +// Test sorting of Eigenvalue&Eigenvector lists. Use exhaustive search. +template +int testEigenvalueSort() +{ + // Test input data: four arbitrary values + static const glm::vec refVal( + glm::vec<4, T, Q>( + 10, 8, 6, 4 + ) + ); + // Test input data: four arbitrary vectors, which can be matched to the above values + static const glm::mat refVec( + glm::mat<4, 4, T, Q>( + 10, 20, 5, 40, + 8, 16, 4, 32, + 6, 12, 3, 24, + 4, 8, 2, 16 + ) + ); + // Permutations of test input data for exhaustive check, based on `D` (1 <= D <= 4) + static const int permutationCount[] = { + 0, + 1, + 2, + 6, + 24 + }; + // The permutations t perform, based on `D` (1 <= D <= 4) + static const glm::ivec4 permutation[] = { + glm::ivec4(0, 1, 2, 3), + glm::ivec4(1, 0, 2, 3), // last for D = 2 + glm::ivec4(0, 2, 1, 3), + glm::ivec4(1, 2, 0, 3), + glm::ivec4(2, 0, 1, 3), + glm::ivec4(2, 1, 0, 3), // last for D = 3 + glm::ivec4(0, 1, 3, 2), + glm::ivec4(1, 0, 3, 2), + glm::ivec4(0, 2, 3, 1), + glm::ivec4(1, 2, 3, 0), + glm::ivec4(2, 0, 3, 1), + glm::ivec4(2, 1, 3, 0), + glm::ivec4(0, 3, 1, 2), + glm::ivec4(1, 3, 0, 2), + glm::ivec4(0, 3, 2, 1), + glm::ivec4(1, 3, 2, 0), + glm::ivec4(2, 3, 0, 1), + glm::ivec4(2, 3, 1, 0), + glm::ivec4(3, 0, 1, 2), + glm::ivec4(3, 1, 0, 2), + glm::ivec4(3, 0, 2, 1), + glm::ivec4(3, 1, 2, 0), + glm::ivec4(3, 2, 0, 1), + glm::ivec4(3, 2, 1, 0) // last for D = 4 + }; + + // initial sanity check + if(!vectorEpsilonEqual(refVal, refVal, myEpsilon())) + return failReport(__LINE__); + if(!matrixEpsilonEqual(refVec, refVec, myEpsilon())) + return failReport(__LINE__); + + // Exhaustive search through all permutations + for(int p = 0; p < permutationCount[D]; ++p) + { + glm::vec testVal; + glm::mat testVec; + for(int i = 0; i < D; ++i) + { + testVal[i] = refVal[permutation[p][i]]; + testVec[i] = refVec[permutation[p][i]]; + } + + glm::sortEigenvalues(testVal, testVec); + + if (!vectorEpsilonEqual(testVal, refVal, myEpsilon())) + return failReport(__LINE__); + if (!matrixEpsilonEqual(testVec, refVec, myEpsilon())) + return failReport(__LINE__); + } + + return 0; +} + +// Test covariance matrix creation functions +template +int testCovar( +#if GLM_HAS_CXX11_STL == 1 + glm::length_t dataSize, unsigned int randomEngineSeed +#else // GLM_HAS_CXX11_STL == 1 + glm::length_t, unsigned int +#endif // GLM_HAS_CXX11_STL == 1 +) +{ + typedef glm::vec vec; + typedef glm::mat mat; + + // #1: test expected result with fixed data set + std::vector testData; + _1aga::fillTestData(testData); + + // compute center of gravity + vec center = computeCenter(testData); + + mat covarMat = glm::computeCovarianceMatrix(testData.data(), testData.size(), center); + if(!matrixEpsilonEqual(covarMat, mat(_1aga::expectedCovarData()), myEpsilon())) + { + fprintf(stderr, "Reconstructed covarMat:\n%s\n", glm::to_string(covarMat).c_str()); + return failReport(__LINE__); + } + + // #2: test function variant consitency with random data +#if GLM_HAS_CXX11_STL == 1 + std::default_random_engine rndEng(randomEngineSeed); + std::normal_distribution normalDist; + testData.resize(dataSize); + // some common offset of all data + T offset[D]; + for(glm::length_t d = 0; d < D; ++d) + offset[d] = normalDist(rndEng); + // init data + for(glm::length_t i = 0; i < dataSize; ++i) + for(glm::length_t d = 0; d < D; ++d) + testData[i][d] = offset[d] + normalDist(rndEng); + center = computeCenter(testData); + + std::vector centeredTestData; + centeredTestData.reserve(testData.size()); + typename std::vector::const_iterator e = testData.end(); + for(typename std::vector::const_iterator i = testData.begin(); i != e; ++i) + centeredTestData.push_back((*i) - center); + + mat c1 = glm::computeCovarianceMatrix(centeredTestData.data(), centeredTestData.size()); + mat c2 = glm::computeCovarianceMatrix(centeredTestData.begin(), centeredTestData.end()); + mat c3 = glm::computeCovarianceMatrix(testData.data(), testData.size(), center); + mat c4 = glm::computeCovarianceMatrix(testData.rbegin(), testData.rend(), center); + + if(!matrixEpsilonEqual(c1, c2, myEpsilon())) + return failReport(__LINE__); + if(!matrixEpsilonEqual(c1, c3, myEpsilon())) + return failReport(__LINE__); + if(!matrixEpsilonEqual(c1, c4, myEpsilon())) + return failReport(__LINE__); +#endif // GLM_HAS_CXX11_STL == 1 + return 0; +} + +// Computes eigenvalues and eigenvectors from well-known covariance matrix +template +int testEigenvectors(T epsilon) +{ + typedef glm::vec vec; + typedef glm::mat mat; + + // test expected result with fixed data set + std::vector testData; + mat covarMat(_1aga::expectedCovarData()); + + vec eigenvalues; + mat eigenvectors; + unsigned int c = glm::findEigenvaluesSymReal(covarMat, eigenvalues, eigenvectors); + if(c != D) + return failReport(__LINE__); + glm::sortEigenvalues(eigenvalues, eigenvectors); + + if (!vectorEpsilonEqual(eigenvalues, vec(_1aga::expectedEigenvalues()), epsilon)) + return failReport(__LINE__); + + for (int i = 0; i < D; ++i) + { + vec act = glm::normalize(eigenvectors[i]); + vec exp = glm::normalize(_1aga::expectedEigenvectors()[i]); + if (!sameSign(act[0], exp[0])) exp = -exp; + if (!vectorEpsilonEqual(act, exp, epsilon)) + return failReport(__LINE__); + } + + return 0; +} + +// A simple small smoke test: +// - a uniformly sampled block +// - reconstruct main axes +// - check order of eigenvalues equals order of extends of block in direction of main axes +int smokeTest() +{ + using glm::vec3; + using glm::mat3; + std::vector pts; + pts.reserve(11 * 15 * 7); + + for(int x = -5; x <= 5; ++x) + for(int y = -7; y <= 7; ++y) + for(int z = -3; z <= 3; ++z) + pts.push_back(vec3(x, y, z)); + + mat3 covar = glm::computeCovarianceMatrix(pts.data(), pts.size()); + mat3 eVec; + vec3 eVal; + int eCnt = glm::findEigenvaluesSymReal(covar, eVal, eVec); + if(eCnt != 3) + return failReport(__LINE__); + + // sort eVec by decending eVal + if(eVal[0] < eVal[1]) + { + std::swap(eVal[0], eVal[1]); + std::swap(eVec[0], eVec[1]); + } + if(eVal[0] < eVal[2]) + { + std::swap(eVal[0], eVal[2]); + std::swap(eVec[0], eVec[2]); + } + if(eVal[1] < eVal[2]) + { + std::swap(eVal[1], eVal[2]); + std::swap(eVec[1], eVec[2]); + } + + if(!vectorEpsilonEqual(glm::abs(eVec[0]), vec3(0, 1, 0), myEpsilon())) + return failReport(__LINE__); + if(!vectorEpsilonEqual(glm::abs(eVec[1]), vec3(1, 0, 0), myEpsilon())) + return failReport(__LINE__); + if(!vectorEpsilonEqual(glm::abs(eVec[2]), vec3(0, 0, 1), myEpsilon())) + return failReport(__LINE__); + + return 0; +} + +#if GLM_HAS_CXX11_STL == 1 +int rndTest(unsigned int randomEngineSeed) +{ + std::default_random_engine rndEng(randomEngineSeed); + std::normal_distribution normalDist; + + // construct orthonormal system + glm::dvec3 x(normalDist(rndEng), normalDist(rndEng), normalDist(rndEng)); + double l = glm::length(x); + while(l < myEpsilon()) + x = glm::dvec3(normalDist(rndEng), normalDist(rndEng), normalDist(rndEng)); + x = glm::normalize(x); + glm::dvec3 y(normalDist(rndEng), normalDist(rndEng), normalDist(rndEng)); + l = glm::length(y); + while(l < myEpsilon()) + y = glm::dvec3(normalDist(rndEng), normalDist(rndEng), normalDist(rndEng)); + while(glm::abs(glm::dot(x, y)) < myEpsilon()) + { + y = glm::dvec3(normalDist(rndEng), normalDist(rndEng), normalDist(rndEng)); + while(l < myEpsilon()) + y = glm::dvec3(normalDist(rndEng), normalDist(rndEng), normalDist(rndEng)); + } + y = glm::normalize(y); + glm::dvec3 z = glm::normalize(glm::cross(x, y)); + y = glm::normalize(glm::cross(z, x)); + + // generate input point data + std::vector ptData; + static const int pattern[] = { + 8, 0, 0, + 4, 1, 2, + 0, 2, 0, + 0, 0, 4 + }; + glm::dvec3 offset(normalDist(rndEng), normalDist(rndEng), normalDist(rndEng)); + for(int p = 0; p < 4; ++p) + for(int xs = 1; xs >= -1; xs -= 2) + for(int ys = 1; ys >= -1; ys -= 2) + for(int zs = 1; zs >= -1; zs -= 2) + ptData.push_back( + offset + + x * static_cast(pattern[p * 3 + 0] * xs) + + y * static_cast(pattern[p * 3 + 1] * ys) + + z * static_cast(pattern[p * 3 + 2] * zs)); + + // perform PCA: + glm::dvec3 center = computeCenter(ptData); + glm::dmat3 covarMat = glm::computeCovarianceMatrix(ptData.data(), ptData.size(), center); + glm::dvec3 evals; + glm::dmat3 evecs; + int evcnt = glm::findEigenvaluesSymReal(covarMat, evals, evecs); + if(evcnt != 3) + return failReport(__LINE__); + glm::sortEigenvalues(evals, evecs); + + if (!sameSign(evecs[0][0], x[0])) evecs[0] = -evecs[0]; + if(!vectorEpsilonEqual(x, evecs[0], myEpsilon())) + return failReport(__LINE__); + if (!sameSign(evecs[2][0], y[0])) evecs[2] = -evecs[2]; + if (!vectorEpsilonEqual(y, evecs[2], myEpsilon())) + return failReport(__LINE__); + if (!sameSign(evecs[1][0], z[0])) evecs[1] = -evecs[1]; + if (!vectorEpsilonEqual(z, evecs[1], myEpsilon())) + return failReport(__LINE__); + + return 0; +} +#endif // GLM_HAS_CXX11_STL == 1 + +int main() +{ + int error(0); + + // A small smoke test to fail early with most problems + if(smokeTest()) + return failReport(__LINE__); + + // test sorting utility. + if(testEigenvalueSort<2, float, glm::defaultp>() != 0) + error = failReport(__LINE__); + if(testEigenvalueSort<2, double, glm::defaultp>() != 0) + error = failReport(__LINE__); + if(testEigenvalueSort<3, float, glm::defaultp>() != 0) + error = failReport(__LINE__); + if(testEigenvalueSort<3, double, glm::defaultp>() != 0) + error = failReport(__LINE__); + if(testEigenvalueSort<4, float, glm::defaultp>() != 0) + error = failReport(__LINE__); + if(testEigenvalueSort<4, double, glm::defaultp>() != 0) + error = failReport(__LINE__); + if (error != 0) + return error; + + // Note: the random engine uses a fixed seed to create consistent and reproducible test data + // test covariance matrix computation from different data sources + if(testCovar<2, float, glm::defaultp>(100, 12345) != 0) + error = failReport(__LINE__); + if(testCovar<2, double, glm::defaultp>(100, 42) != 0) + error = failReport(__LINE__); + if(testCovar<3, float, glm::defaultp>(100, 2021) != 0) + error = failReport(__LINE__); + if(testCovar<3, double, glm::defaultp>(100, 815) != 0) + error = failReport(__LINE__); + if(testCovar<4, float, glm::defaultp>(100, 3141) != 0) + error = failReport(__LINE__); + if(testCovar<4, double, glm::defaultp>(100, 174) != 0) + error = failReport(__LINE__); + if (error != 0) + return error; + + // test PCA eigen vector reconstruction + // Expected epsilon precision evaluated separately: + // https://github.com/sgrottel/exp-pca-precision + if(testEigenvectors<2, float, glm::defaultp>(0.002f) != 0) + error = failReport(__LINE__); + if(testEigenvectors<2, double, glm::defaultp>(0.00000000001) != 0) + error = failReport(__LINE__); + if(testEigenvectors<3, float, glm::defaultp>(0.00001f) != 0) + error = failReport(__LINE__); + if(testEigenvectors<3, double, glm::defaultp>(0.0000000001) != 0) + error = failReport(__LINE__); + if(testEigenvectors<4, float, glm::defaultp>(0.0001f) != 0) + error = failReport(__LINE__); + if(testEigenvectors<4, double, glm::defaultp>(0.0000001) != 0) + error = failReport(__LINE__); + if(error != 0) + return error; + + // Final tests with randomized data +#if GLM_HAS_CXX11_STL == 1 + if(rndTest(12345) != 0) + error = failReport(__LINE__); + if(rndTest(42) != 0) + error = failReport(__LINE__); + if (error != 0) + return error; +#endif // GLM_HAS_CXX11_STL == 1 + + return error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_perpendicular.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_perpendicular.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d14cfee30b33f3b8372c45a45f85f015975c6ff3 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_perpendicular.cpp @@ -0,0 +1,9 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include + +int main() +{ + int Error(0); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_polar_coordinates.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_polar_coordinates.cpp new file mode 100644 index 0000000000000000000000000000000000000000..da2fe536e950054941aa21a1f9fa93970e68b96d --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_polar_coordinates.cpp @@ -0,0 +1,9 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include + +int main() +{ + int Error(0); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_projection.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_projection.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8f9f77223c28c09a79b8235db52ae80a5d731cae --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_projection.cpp @@ -0,0 +1,9 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include + +int main() +{ + int Error(0); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_quaternion.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_quaternion.cpp new file mode 100644 index 0000000000000000000000000000000000000000..80cbbacd03d395925b505a4efca13dfb849cb793 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_quaternion.cpp @@ -0,0 +1,107 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include +#include +#include +#include +#include +#include +#include + +int test_quat_fastMix() +{ + int Error = 0; + + glm::quat A = glm::angleAxis(0.0f, glm::vec3(0, 0, 1)); + glm::quat B = glm::angleAxis(glm::pi() * 0.5f, glm::vec3(0, 0, 1)); + glm::quat C = glm::fastMix(A, B, 0.5f); + glm::quat D = glm::angleAxis(glm::pi() * 0.25f, glm::vec3(0, 0, 1)); + + Error += glm::epsilonEqual(C.x, D.x, 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(C.y, D.y, 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(C.z, D.z, 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(C.w, D.w, 0.01f) ? 0 : 1; + + return Error; +} + +int test_quat_shortMix() +{ + int Error(0); + + glm::quat A = glm::angleAxis(0.0f, glm::vec3(0, 0, 1)); + glm::quat B = glm::angleAxis(glm::pi() * 0.5f, glm::vec3(0, 0, 1)); + glm::quat C = glm::shortMix(A, B, 0.5f); + glm::quat D = glm::angleAxis(glm::pi() * 0.25f, glm::vec3(0, 0, 1)); + + Error += glm::epsilonEqual(C.x, D.x, 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(C.y, D.y, 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(C.z, D.z, 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(C.w, D.w, 0.01f) ? 0 : 1; + + return Error; +} + +int test_orientation() +{ + int Error = 0; + + { + glm::quat q(1.0f, 0.0f, 0.0f, 1.0f); + float p = glm::roll(q); + Error += glm::epsilonEqual(p, glm::pi() * 0.5f, 0.0001f) ? 0 : 1; + } + + { + glm::quat q(1.0f, 0.0f, 0.0f, 1.0f); + float p = glm::pitch(q); + Error += glm::epsilonEqual(p, 0.f, 0.0001f) ? 0 : 1; + } + + { + glm::quat q(1.0f, 0.0f, 0.0f, 1.0f); + float p = glm::yaw(q); + Error += glm::epsilonEqual(p, 0.f, 0.0001f) ? 0 : 1; + } + + return Error; +} + +int test_rotation() +{ + int Error(0); + + glm::vec3 v(1, 0, 0); + glm::vec3 u(0, 1, 0); + + glm::quat Rotation = glm::rotation(v, u); + + float Angle = glm::angle(Rotation); + + Error += glm::abs(Angle - glm::pi() * 0.5f) < glm::epsilon() ? 0 : 1; + + return Error; +} + +int test_log() +{ + int Error(0); + + glm::quat q; + glm::quat p = glm::log(q); + glm::quat r = glm::exp(p); + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_log(); + Error += test_rotation(); + Error += test_orientation(); + Error += test_quat_fastMix(); + Error += test_quat_shortMix(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_random.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_random.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e562c3145ebc527c86eecf73a22e4350bbb611e7 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_random.cpp @@ -0,0 +1,99 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +// OpenGL Mathematics Copyright (c) 2005 - 2012 G-Truc Creation (www.g-truc.net) +/////////////////////////////////////////////////////////////////////////////////////////////////// +// Created : 2011-05-31 +// Updated : 2011-05-31 +// Licence : This source is under MIT licence +// File : test/gtx/random.cpp +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include + +int test_signedRand1() +{ + int Error = 0; + + { + float ResultFloat = 0.0f; + double ResultDouble = 0.0f; + for(std::size_t i = 0; i < 100000; ++i) + { + ResultFloat += glm::signedRand1(); + ResultDouble += glm::signedRand1(); + } + + Error += glm::equalEpsilon(ResultFloat, 0.0f, 0.0001f); + Error += glm::equalEpsilon(ResultDouble, 0.0, 0.0001); + } + + return Error; +} + +int test_normalizedRand2() +{ + int Error = 0; + + { + std::size_t Max = 100000; + float ResultFloat = 0.0f; + double ResultDouble = 0.0f; + for(std::size_t i = 0; i < Max; ++i) + { + ResultFloat += glm::length(glm::normalizedRand2()); + ResultDouble += glm::length(glm::normalizedRand2()); + } + + Error += glm::equalEpsilon(ResultFloat, float(Max), 0.000001f) ? 0 : 1; + Error += glm::equalEpsilon(ResultDouble, double(Max), 0.000001) ? 0 : 1; + assert(!Error); + } + + return Error; +} + +int test_normalizedRand3() +{ + int Error = 0; + + { + std::size_t Max = 100000; + float ResultFloatA = 0.0f; + float ResultFloatB = 0.0f; + float ResultFloatC = 0.0f; + double ResultDoubleA = 0.0f; + double ResultDoubleB = 0.0f; + double ResultDoubleC = 0.0f; + for(std::size_t i = 0; i < Max; ++i) + { + ResultFloatA += glm::length(glm::normalizedRand3()); + ResultDoubleA += glm::length(glm::normalizedRand3()); + ResultFloatB += glm::length(glm::normalizedRand3(2.0f, 2.0f)); + ResultDoubleB += glm::length(glm::normalizedRand3(2.0, 2.0)); + ResultFloatC += glm::length(glm::normalizedRand3(1.0f, 3.0f)); + ResultDoubleC += glm::length(glm::normalizedRand3(1.0, 3.0)); + } + + Error += glm::equalEpsilon(ResultFloatA, float(Max), 0.0001f) ? 0 : 1; + Error += glm::equalEpsilon(ResultDoubleA, double(Max), 0.0001) ? 0 : 1; + Error += glm::equalEpsilon(ResultFloatB, float(Max * 2), 0.0001f) ? 0 : 1; + Error += glm::equalEpsilon(ResultDoubleB, double(Max * 2), 0.0001) ? 0 : 1; + Error += (ResultFloatC >= float(Max) && ResultFloatC <= float(Max * 3)) ? 0 : 1; + Error += (ResultDoubleC >= double(Max) && ResultDoubleC <= double(Max * 3)) ? 0 : 1; + } + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_signedRand1(); + Error += test_normalizedRand2(); + Error += test_normalizedRand3(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_range.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_range.cpp new file mode 100644 index 0000000000000000000000000000000000000000..434731b9ac8595d1100bab1e07bd94a329c69681 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_range.cpp @@ -0,0 +1,83 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include +#include +#include +#include + +#if GLM_HAS_RANGE_FOR + +#include + +int test_vec() +{ + int Error = 0; + + { + glm::ivec3 const v(1, 2, 3); + + int count = 0; + glm::ivec3 Result(0); + for(int x : v) + { + Result[count] = x; + count++; + } + Error += count == 3 ? 0 : 1; + Error += v == Result ? 0 : 1; + } + + { + glm::ivec3 v(1, 2, 3); + for(int& x : v) + x = 0; + Error += glm::all(glm::equal(v, glm::ivec3(0))) ? 0 : 1; + } + + return Error; +} + +int test_mat() +{ + int Error = 0; + + { + glm::mat4x3 m(1.0f); + + int count = 0; + float Sum = 0.0f; + for(float x : m) + { + count++; + Sum += x; + } + Error += count == 12 ? 0 : 1; + Error += glm::equal(Sum, 3.0f, 0.001f) ? 0 : 1; + } + + { + glm::mat4x3 m(1.0f); + + for (float& x : m) { x = 0; } + glm::vec4 v(1, 1, 1, 1); + Error += glm::all(glm::equal(m*v, glm::vec3(0, 0, 0), glm::epsilon())) ? 0 : 1; + } + + return Error; +} + +int main() +{ + int Error = 0; + Error += test_vec(); + Error += test_mat(); + return Error; +} + +#else + +int main() +{ + return 0; +} + +#endif//GLM_HAS_RANGE_FOR diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_rotate_normalized_axis.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_rotate_normalized_axis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d4eecdfce346404b189a11b4a9dd373b997f533e --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_rotate_normalized_axis.cpp @@ -0,0 +1,9 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include + +int main() +{ + int Error(0); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_rotate_vector.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_rotate_vector.cpp new file mode 100644 index 0000000000000000000000000000000000000000..becd63f4e366ac19c07a37922f45bf8d2d77f05c --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_rotate_vector.cpp @@ -0,0 +1,77 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include +#include +#include + +int test_rotate() +{ + int Error = 0; + + glm::vec2 A = glm::rotate(glm::vec2(1, 0), glm::pi() * 0.5f); + glm::vec3 B = glm::rotate(glm::vec3(1, 0, 0), glm::pi() * 0.5f, glm::vec3(0, 0, 1)); + glm::vec4 C = glm::rotate(glm::vec4(1, 0, 0, 1), glm::pi() * 0.5f, glm::vec3(0, 0, 1)); + glm::vec3 D = glm::rotateX(glm::vec3(1, 0, 0), glm::pi() * 0.5f); + glm::vec4 E = glm::rotateX(glm::vec4(1, 0, 0, 1), glm::pi() * 0.5f); + glm::vec3 F = glm::rotateY(glm::vec3(1, 0, 0), glm::pi() * 0.5f); + glm::vec4 G = glm::rotateY(glm::vec4(1, 0, 0, 1), glm::pi() * 0.5f); + glm::vec3 H = glm::rotateZ(glm::vec3(1, 0, 0), glm::pi() * 0.5f); + glm::vec4 I = glm::rotateZ(glm::vec4(1, 0, 0,1 ), glm::pi() * 0.5f); + glm::mat4 O = glm::orientation(glm::normalize(glm::vec3(1)), glm::vec3(0, 0, 1)); + + return Error; +} + +int test_rotateX() +{ + int Error = 0; + + glm::vec3 D = glm::rotateX(glm::vec3(1, 0, 0), glm::pi() * 0.5f); + glm::vec4 E = glm::rotateX(glm::vec4(1, 0, 0, 1), glm::pi() * 0.5f); + + return Error; +} + +int test_rotateY() +{ + int Error = 0; + + glm::vec3 F = glm::rotateY(glm::vec3(1, 0, 0), glm::pi() * 0.5f); + glm::vec4 G = glm::rotateY(glm::vec4(1, 0, 0, 1), glm::pi() * 0.5f); + + return Error; +} + + +int test_rotateZ() +{ + int Error = 0; + + glm::vec3 H = glm::rotateZ(glm::vec3(1, 0, 0), glm::pi() * 0.5f); + glm::vec4 I = glm::rotateZ(glm::vec4(1, 0, 0,1 ), glm::pi() * 0.5f); + + return Error; +} + +int test_orientation() +{ + int Error = 0; + + glm::mat4 O = glm::orientation(glm::normalize(glm::vec3(1)), glm::vec3(0, 0, 1)); + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_rotate(); + Error += test_rotateX(); + Error += test_rotateY(); + Error += test_rotateZ(); + Error += test_orientation(); + + return Error; +} + + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_scalar_multiplication.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_scalar_multiplication.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4aa96d67e8ad06978a28399daa059b168ef75051 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_scalar_multiplication.cpp @@ -0,0 +1,37 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include +#include +#include + +#if GLM_HAS_TEMPLATE_ALIASES && !(GLM_COMPILER & GLM_COMPILER_GCC) +#include + +int main() +{ + int Error(0); + glm::vec3 v(0.5, 3.1, -9.1); + + Error += glm::all(glm::equal(v, 1.0 * v, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(v, 1 * v, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(v, 1u * v, glm::epsilon())) ? 0 : 1; + + glm::mat3 m(1, 2, 3, 4, 5, 6, 7, 8, 9); + glm::vec3 w = 0.5f * m * v; + + Error += glm::all(glm::equal((m*v)/2, w, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(m*(v/2), w, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal((m/2)*v, w, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal((0.5*m)*v, w, glm::epsilon())) ? 0 : 1; + Error += glm::all(glm::equal(0.5*(m*v), w, glm::epsilon())) ? 0 : 1; + + return Error; +} + +#else + +int main() +{ + return 0; +} + +#endif diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_scalar_relational.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_scalar_relational.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fc6a09ac74eff91292791dfb5b309a2a35e43256 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_scalar_relational.cpp @@ -0,0 +1,174 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include +#include +#include +#include +#include +#include + +static int test_lessThan() +{ + int Error = 0; + + Error += glm::lessThan(0, 1) ? 0 : 1; + Error += glm::lessThan(1, 0) ? 1 : 0; + Error += glm::lessThan(0, 0) ? 1 : 0; + Error += glm::lessThan(1, 1) ? 1 : 0; + Error += glm::lessThan(0.0f, 1.0f) ? 0 : 1; + Error += glm::lessThan(1.0f, 0.0f) ? 1 : 0; + Error += glm::lessThan(0.0f, 0.0f) ? 1 : 0; + Error += glm::lessThan(1.0f, 1.0f) ? 1 : 0; + Error += glm::lessThan(0.0, 1.0) ? 0 : 1; + Error += glm::lessThan(1.0, 0.0) ? 1 : 0; + Error += glm::lessThan(0.0, 0.0) ? 1 : 0; + Error += glm::lessThan(1.0, 1.0) ? 1 : 0; + + return Error; +} + +static int test_lessThanEqual() +{ + int Error = 0; + + Error += glm::lessThanEqual(0, 1) ? 0 : 1; + Error += glm::lessThanEqual(1, 0) ? 1 : 0; + Error += glm::lessThanEqual(0, 0) ? 0 : 1; + Error += glm::lessThanEqual(1, 1) ? 0 : 1; + Error += glm::lessThanEqual(0.0f, 1.0f) ? 0 : 1; + Error += glm::lessThanEqual(1.0f, 0.0f) ? 1 : 0; + Error += glm::lessThanEqual(0.0f, 0.0f) ? 0 : 1; + Error += glm::lessThanEqual(1.0f, 1.0f) ? 0 : 1; + Error += glm::lessThanEqual(0.0, 1.0) ? 0 : 1; + Error += glm::lessThanEqual(1.0, 0.0) ? 1 : 0; + Error += glm::lessThanEqual(0.0, 0.0) ? 0 : 1; + Error += glm::lessThanEqual(1.0, 1.0) ? 0 : 1; + + return Error; +} + +static int test_greaterThan() +{ + int Error = 0; + + Error += glm::greaterThan(0, 1) ? 1 : 0; + Error += glm::greaterThan(1, 0) ? 0 : 1; + Error += glm::greaterThan(0, 0) ? 1 : 0; + Error += glm::greaterThan(1, 1) ? 1 : 0; + Error += glm::greaterThan(0.0f, 1.0f) ? 1 : 0; + Error += glm::greaterThan(1.0f, 0.0f) ? 0 : 1; + Error += glm::greaterThan(0.0f, 0.0f) ? 1 : 0; + Error += glm::greaterThan(1.0f, 1.0f) ? 1 : 0; + Error += glm::greaterThan(0.0, 1.0) ? 1 : 0; + Error += glm::greaterThan(1.0, 0.0) ? 0 : 1; + Error += glm::greaterThan(0.0, 0.0) ? 1 : 0; + Error += glm::greaterThan(1.0, 1.0) ? 1 : 0; + + return Error; +} + +static int test_greaterThanEqual() +{ + int Error = 0; + + Error += glm::greaterThanEqual(0, 1) ? 1 : 0; + Error += glm::greaterThanEqual(1, 0) ? 0 : 1; + Error += glm::greaterThanEqual(0, 0) ? 0 : 1; + Error += glm::greaterThanEqual(1, 1) ? 0 : 1; + Error += glm::greaterThanEqual(0.0f, 1.0f) ? 1 : 0; + Error += glm::greaterThanEqual(1.0f, 0.0f) ? 0 : 1; + Error += glm::greaterThanEqual(0.0f, 0.0f) ? 0 : 1; + Error += glm::greaterThanEqual(1.0f, 1.0f) ? 0 : 1; + Error += glm::greaterThanEqual(0.0, 1.0) ? 1 : 0; + Error += glm::greaterThanEqual(1.0, 0.0) ? 0 : 1; + Error += glm::greaterThanEqual(0.0, 0.0) ? 0 : 1; + Error += glm::greaterThanEqual(1.0, 1.0) ? 0 : 1; + + return Error; +} + +static int test_equal() +{ + int Error = 0; + + Error += glm::equal(0, 1) ? 1 : 0; + Error += glm::equal(1, 0) ? 1 : 0; + Error += glm::equal(0, 0) ? 0 : 1; + Error += glm::equal(1, 1) ? 0 : 1; + Error += glm::equal(0.0f, 1.0f, glm::epsilon()) ? 1 : 0; + Error += glm::equal(1.0f, 0.0f, glm::epsilon()) ? 1 : 0; + Error += glm::equal(0.0f, 0.0f, glm::epsilon()) ? 0 : 1; + Error += glm::equal(1.0f, 1.0f, glm::epsilon()) ? 0 : 1; + Error += glm::equal(0.0, 1.0, glm::epsilon()) ? 1 : 0; + Error += glm::equal(1.0, 0.0, glm::epsilon()) ? 1 : 0; + Error += glm::equal(0.0, 0.0, glm::epsilon()) ? 0 : 1; + Error += glm::equal(1.0, 1.0, glm::epsilon()) ? 0 : 1; + + return Error; +} + +static int test_notEqual() +{ + int Error = 0; + + Error += glm::notEqual(0, 1) ? 0 : 1; + Error += glm::notEqual(1, 0) ? 0 : 1; + Error += glm::notEqual(0, 0) ? 1 : 0; + Error += glm::notEqual(1, 1) ? 1 : 0; + Error += glm::notEqual(0.0f, 1.0f, glm::epsilon()) ? 0 : 1; + Error += glm::notEqual(1.0f, 0.0f, glm::epsilon()) ? 0 : 1; + Error += glm::notEqual(0.0f, 0.0f, glm::epsilon()) ? 1 : 0; + Error += glm::notEqual(1.0f, 1.0f, glm::epsilon()) ? 1 : 0; + Error += glm::notEqual(0.0, 1.0, glm::epsilon()) ? 0 : 1; + Error += glm::notEqual(1.0, 0.0, glm::epsilon()) ? 0 : 1; + Error += glm::notEqual(0.0, 0.0, glm::epsilon()) ? 1 : 0; + Error += glm::notEqual(1.0, 1.0, glm::epsilon()) ? 1 : 0; + + return Error; +} + +static int test_any() +{ + int Error = 0; + + Error += glm::any(true) ? 0 : 1; + Error += glm::any(false) ? 1 : 0; + + return Error; +} + +static int test_all() +{ + int Error = 0; + + Error += glm::all(true) ? 0 : 1; + Error += glm::all(false) ? 1 : 0; + + return Error; +} + +static int test_not() +{ + int Error = 0; + + Error += glm::not_(true) ? 1 : 0; + Error += glm::not_(false) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_lessThan(); + Error += test_lessThanEqual(); + Error += test_greaterThan(); + Error += test_greaterThanEqual(); + Error += test_equal(); + Error += test_notEqual(); + Error += test_any(); + Error += test_all(); + Error += test_not(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_simd_mat4.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_simd_mat4.cpp new file mode 100644 index 0000000000000000000000000000000000000000..28d7ec5639246d3c108170e06580f07a27203e3b --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_simd_mat4.cpp @@ -0,0 +1,324 @@ +/////////////////////////////////////////////////////////////////////////////////// +/// OpenGL Mathematics (glm.g-truc.net) +/// +/// Copyright (c) 2005 - 2012 G-Truc Creation (www.g-truc.net) +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// of this software and associated documentation files (the "Software"), to deal +/// in the Software without restriction, including without limitation the rights +/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +/// copies of the Software, and to permit persons to whom the Software is +/// furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// Restrictions: +/// By making use of the Software for military purposes, you choose to make +/// a Bunny unhappy. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +/// THE SOFTWARE. +/// +/// @file test/gtx/gtx_simd_mat4.cpp +/// @date 2010-09-16 / 2014-11-25 +/// @author Christophe Riccio +/////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if(GLM_ARCH != GLM_ARCH_PURE) + +std::vector test_detA(std::vector const & Data) +{ + std::vector Test(Data.size()); + + std::clock_t TimeStart = clock(); + + for(std::size_t i = 0; i < Test.size() - 1; ++i) + Test[i] = glm::determinant(Data[i]); + + std::clock_t TimeEnd = clock(); + printf("Det A: %ld\n", TimeEnd - TimeStart); + + return Test; +} + +std::vector test_detB(std::vector const & Data) +{ + std::vector Test(Data.size()); + + std::clock_t TimeStart = clock(); + + for(std::size_t i = 0; i < Test.size() - 1; ++i) + { + _mm_prefetch((char*)&Data[i + 1], _MM_HINT_T0); + glm::simdMat4 m(Data[i]); + glm::simdVec4 d(glm::detail::sse_slow_det_ps((__m128 const * const)&m)); + glm::vec4 v;//(d); + Test[i] = v.x; + } + + std::clock_t TimeEnd = clock(); + printf("Det B: %ld\n", TimeEnd - TimeStart); + + return Test; +} + +std::vector test_detC(std::vector const & Data) +{ + std::vector Test(Data.size()); + + std::clock_t TimeStart = clock(); + + for(std::size_t i = 0; i < Test.size() - 1; ++i) + { + _mm_prefetch((char*)&Data[i + 1], _MM_HINT_T0); + glm::simdMat4 m(Data[i]); + glm::simdVec4 d(glm::detail::sse_det_ps((__m128 const * const)&m)); + glm::vec4 v;//(d); + Test[i] = v.x; + } + + std::clock_t TimeEnd = clock(); + printf("Det C: %ld\n", TimeEnd - TimeStart); + + return Test; +} + +std::vector test_detD(std::vector const & Data) +{ + std::vector Test(Data.size()); + + std::clock_t TimeStart = clock(); + + for(std::size_t i = 0; i < Test.size() - 1; ++i) + { + _mm_prefetch((char*)&Data[i + 1], _MM_HINT_T0); + glm::simdMat4 m(Data[i]); + glm::simdVec4 d(glm::detail::sse_detd_ps((__m128 const * const)&m)); + glm::vec4 v;//(d); + Test[i] = v.x; + } + + std::clock_t TimeEnd = clock(); + printf("Det D: %ld\n", TimeEnd - TimeStart); + + return Test; +} + +void test_invA(std::vector const & Data, std::vector & Out) +{ + //std::vector Test(Data.size()); + Out.resize(Data.size()); + + std::clock_t TimeStart = clock(); + + for(std::size_t i = 0; i < Out.size() - 1; ++i) + { + Out[i] = glm::inverse(Data[i]); + } + + std::clock_t TimeEnd = clock(); + printf("Inv A: %ld\n", TimeEnd - TimeStart); +} + +void test_invC(std::vector const & Data, std::vector & Out) +{ + //std::vector Test(Data.size()); + Out.resize(Data.size()); + + std::clock_t TimeStart = clock(); + + for(std::size_t i = 0; i < Out.size() - 1; ++i) + { + _mm_prefetch((char*)&Data[i + 1], _MM_HINT_T0); + glm::simdMat4 m(Data[i]); + glm::simdMat4 o; + glm::detail::sse_inverse_fast_ps((__m128 const * const)&m, (__m128 *)&o); + Out[i] = *(glm::mat4*)&o; + } + + std::clock_t TimeEnd = clock(); + printf("Inv C: %ld\n", TimeEnd - TimeStart); +} + +void test_invD(std::vector const & Data, std::vector & Out) +{ + //std::vector Test(Data.size()); + Out.resize(Data.size()); + + std::clock_t TimeStart = clock(); + + for(std::size_t i = 0; i < Out.size() - 1; ++i) + { + _mm_prefetch((char*)&Data[i + 1], _MM_HINT_T0); + glm::simdMat4 m(Data[i]); + glm::simdMat4 o; + glm::detail::sse_inverse_ps((__m128 const * const)&m, (__m128 *)&o); + Out[i] = *(glm::mat4*)&o; + } + + std::clock_t TimeEnd = clock(); + printf("Inv D: %ld\n", TimeEnd - TimeStart); +} + +void test_mulA(std::vector const & Data, std::vector & Out) +{ + //std::vector Test(Data.size()); + Out.resize(Data.size()); + + std::clock_t TimeStart = clock(); + + for(std::size_t i = 0; i < Out.size() - 1; ++i) + { + Out[i] = Data[i] * Data[i]; + } + + std::clock_t TimeEnd = clock(); + printf("Mul A: %ld\n", TimeEnd - TimeStart); +} + +void test_mulD(std::vector const & Data, std::vector & Out) +{ + //std::vector Test(Data.size()); + Out.resize(Data.size()); + + std::clock_t TimeStart = clock(); + + for(std::size_t i = 0; i < Out.size() - 1; ++i) + { + _mm_prefetch((char*)&Data[i + 1], _MM_HINT_T0); + glm::simdMat4 m(Data[i]); + glm::simdMat4 o; + glm::detail::sse_mul_ps((__m128 const * const)&m, (__m128 const * const)&m, (__m128*)&o); + Out[i] = *(glm::mat4*)&o; + } + + std::clock_t TimeEnd = clock(); + printf("Mul D: %ld\n", TimeEnd - TimeStart); +} + +int test_compute_glm() +{ + return 0; +} + +int test_compute_gtx() +{ + std::vector Output(1000000); + + std::clock_t TimeStart = clock(); + + for(std::size_t k = 0; k < Output.size(); ++k) + { + float i = float(k) / 1000.f + 0.001f; + glm::vec3 A = glm::normalize(glm::vec3(i)); + glm::vec3 B = glm::cross(A, glm::normalize(glm::vec3(1, 1, 2))); + glm::mat4 C = glm::rotate(glm::mat4(1.0f), i, B); + glm::mat4 D = glm::scale(C, glm::vec3(0.8f, 1.0f, 1.2f)); + glm::mat4 E = glm::translate(D, glm::vec3(1.4f, 1.2f, 1.1f)); + glm::mat4 F = glm::perspective(i, 1.5f, 0.1f, 1000.f); + glm::mat4 G = glm::inverse(F * E); + glm::vec3 H = glm::unProject(glm::vec3(i), G, F, E[3]); + glm::vec3 I = glm::any(glm::isnan(glm::project(H, G, F, E[3]))) ? glm::vec3(2) : glm::vec3(1); + glm::mat4 J = glm::lookAt(glm::normalize(glm::max(B, glm::vec3(0.001f))), H, I); + glm::mat4 K = glm::transpose(J); + glm::quat L = glm::normalize(glm::quat_cast(K)); + glm::vec4 M = L * glm::smoothstep(K[3], J[3], glm::vec4(i)); + glm::mat4 N = glm::mat4(glm::normalize(glm::max(M, glm::vec4(0.001f))), K[3], J[3], glm::vec4(i)); + glm::mat4 O = N * glm::inverse(N); + glm::vec4 P = O * glm::reflect(N[3], glm::vec4(A, 1.0f)); + glm::vec4 Q = glm::vec4(glm::dot(M, P)); + glm::vec4 R = glm::quat(Q.w, glm::vec3(Q)) * P; + Output[k] = R; + } + + std::clock_t TimeEnd = clock(); + printf("test_compute_gtx: %ld\n", TimeEnd - TimeStart); + + return 0; +} + +int main() +{ + int Error = 0; + + std::vector Data(64 * 64 * 1); + for(std::size_t i = 0; i < Data.size(); ++i) + Data[i] = glm::mat4( + glm::vec4(glm::linearRand(glm::vec4(-2.0f), glm::vec4(2.0f))), + glm::vec4(glm::linearRand(glm::vec4(-2.0f), glm::vec4(2.0f))), + glm::vec4(glm::linearRand(glm::vec4(-2.0f), glm::vec4(2.0f))), + glm::vec4(glm::linearRand(glm::vec4(-2.0f), glm::vec4(2.0f)))); + + { + std::vector TestInvA; + test_invA(Data, TestInvA); + } + { + std::vector TestInvC; + test_invC(Data, TestInvC); + } + { + std::vector TestInvD; + test_invD(Data, TestInvD); + } + + { + std::vector TestA; + test_mulA(Data, TestA); + } + { + std::vector TestD; + test_mulD(Data, TestD); + } + + { + std::vector TestDetA = test_detA(Data); + std::vector TestDetB = test_detB(Data); + std::vector TestDetD = test_detD(Data); + std::vector TestDetC = test_detC(Data); + + for(std::size_t i = 0; i < TestDetA.size(); ++i) + if(TestDetA[i] != TestDetB[i] && TestDetC[i] != TestDetB[i] && TestDetC[i] != TestDetD[i]) + return 1; + } + + // shuffle test + glm::simdVec4 A(1.0f, 2.0f, 3.0f, 4.0f); + glm::simdVec4 B(5.0f, 6.0f, 7.0f, 8.0f); + //__m128 C = _mm_shuffle_ps(A.Data, B.Data, _MM_SHUFFLE(1, 0, 1, 0)); + + Error += test_compute_glm(); + Error += test_compute_gtx(); + float Det = glm::determinant(glm::simdMat4(1.0)); + Error += Det == 1.0f ? 0 : 1; + + glm::simdMat4 D = glm::matrixCompMult(glm::simdMat4(1.0), glm::simdMat4(1.0)); + + return Error; +} + +#else + +int main() +{ + int Error = 0; + + return Error; +} + +#endif//(GLM_ARCH != GLM_ARCH_PURE) diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_simd_vec4.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_simd_vec4.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e71a60b9c22bac3282cab53c5f10cad34cf42352 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_simd_vec4.cpp @@ -0,0 +1,71 @@ +/////////////////////////////////////////////////////////////////////////////////// +/// OpenGL Mathematics (glm.g-truc.net) +/// +/// Copyright (c) 2005 - 2012 G-Truc Creation (www.g-truc.net) +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// of this software and associated documentation files (the "Software"), to deal +/// in the Software without restriction, including without limitation the rights +/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +/// copies of the Software, and to permit persons to whom the Software is +/// furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// Restrictions: +/// By making use of the Software for military purposes, you choose to make +/// a Bunny unhappy. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +/// THE SOFTWARE. +/// +/// @file test/gtx/gtx_simd_vec4.cpp +/// @date 2010-09-16 / 2014-11-25 +/// @author Christophe Riccio +/////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +#if(GLM_ARCH != GLM_ARCH_PURE) + +int main() +{ + glm::simdVec4 A1(0.0f, 0.1f, 0.2f, 0.3f); + glm::simdVec4 B1(0.4f, 0.5f, 0.6f, 0.7f); + glm::simdVec4 C1 = A1 + B1; + glm::simdVec4 D1 = A1.swizzle(); + glm::simdVec4 E1(glm::vec4(1.0f)); + glm::vec4 F1 = glm::vec4_cast(E1); + //glm::vec4 G1(E1); + + //printf("A1(%2.3f, %2.3f, %2.3f, %2.3f)\n", A1.x, A1.y, A1.z, A1.w); + //printf("B1(%2.3f, %2.3f, %2.3f, %2.3f)\n", B1.x, B1.y, B1.z, B1.w); + //printf("C1(%2.3f, %2.3f, %2.3f, %2.3f)\n", C1.x, C1.y, C1.z, C1.w); + //printf("D1(%2.3f, %2.3f, %2.3f, %2.3f)\n", D1.x, D1.y, D1.z, D1.w); + + __m128 value = _mm_set1_ps(0.0f); + __m128 data = _mm_cmpeq_ps(value, value); + __m128 add0 = _mm_add_ps(data, data); + + glm::simdVec4 GNI(add0); + + return 0; +} + +#else + +int main() +{ + int Error = 0; + + return Error; +} + +#endif//(GLM_ARCH != GLM_ARCH_PURE) diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_spline.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_spline.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c93ee17aed6ae1eefaf7ceab64deb009f724a7a5 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_spline.cpp @@ -0,0 +1,100 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include +#include +#include +#include + +namespace catmullRom +{ + int test() + { + int Error(0); + + glm::vec2 Result2 = glm::catmullRom( + glm::vec2(0.0f, 0.0f), + glm::vec2(1.0f, 0.0f), + glm::vec2(1.0f, 1.0f), + glm::vec2(0.0f, 1.0f), 0.5f); + + glm::vec3 Result3 = glm::catmullRom( + glm::vec3(0.0f, 0.0f, 0.0f), + glm::vec3(1.0f, 0.0f, 0.0f), + glm::vec3(1.0f, 1.0f, 0.0f), + glm::vec3(0.0f, 1.0f, 0.0f), 0.5f); + + glm::vec4 Result4 = glm::catmullRom( + glm::vec4(0.0f, 0.0f, 0.0f, 1.0f), + glm::vec4(1.0f, 0.0f, 0.0f, 1.0f), + glm::vec4(1.0f, 1.0f, 0.0f, 1.0f), + glm::vec4(0.0f, 1.0f, 0.0f, 1.0f), 0.5f); + + return Error; + } +}//catmullRom + +namespace hermite +{ + int test() + { + int Error(0); + + glm::vec2 Result2 = glm::hermite( + glm::vec2(0.0f, 0.0f), + glm::vec2(1.0f, 0.0f), + glm::vec2(1.0f, 1.0f), + glm::vec2(0.0f, 1.0f), 0.5f); + + glm::vec3 Result3 = glm::hermite( + glm::vec3(0.0f, 0.0f, 0.0f), + glm::vec3(1.0f, 0.0f, 0.0f), + glm::vec3(1.0f, 1.0f, 0.0f), + glm::vec3(0.0f, 1.0f, 0.0f), 0.5f); + + glm::vec4 Result4 = glm::hermite( + glm::vec4(0.0f, 0.0f, 0.0f, 1.0f), + glm::vec4(1.0f, 0.0f, 0.0f, 1.0f), + glm::vec4(1.0f, 1.0f, 0.0f, 1.0f), + glm::vec4(0.0f, 1.0f, 0.0f, 1.0f), 0.5f); + + return Error; + } +}//catmullRom + +namespace cubic +{ + int test() + { + int Error(0); + + glm::vec2 Result2 = glm::cubic( + glm::vec2(0.0f, 0.0f), + glm::vec2(1.0f, 0.0f), + glm::vec2(1.0f, 1.0f), + glm::vec2(0.0f, 1.0f), 0.5f); + + glm::vec3 Result3 = glm::cubic( + glm::vec3(0.0f, 0.0f, 0.0f), + glm::vec3(1.0f, 0.0f, 0.0f), + glm::vec3(1.0f, 1.0f, 0.0f), + glm::vec3(0.0f, 1.0f, 0.0f), 0.5f); + + glm::vec4 Result = glm::cubic( + glm::vec4(0.0f, 0.0f, 0.0f, 1.0f), + glm::vec4(1.0f, 0.0f, 0.0f, 1.0f), + glm::vec4(1.0f, 1.0f, 0.0f, 1.0f), + glm::vec4(0.0f, 1.0f, 0.0f, 1.0f), 0.5f); + + return Error; + } +}//catmullRom + +int main() +{ + int Error(0); + + Error += catmullRom::test(); + Error += hermite::test(); + Error += cubic::test(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_string_cast.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_string_cast.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b04c8700fbcae4511c8029141f9c818a438a06ea --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_string_cast.cpp @@ -0,0 +1,155 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include +#include +#include + +int test_string_cast_vector() +{ + int Error = 0; + + { + glm::vec2 A1(1, 2); + std::string A2 = glm::to_string(A1); + Error += A2 != std::string("vec2(1.000000, 2.000000)") ? 1 : 0; + + glm::vec3 B1(1, 2, 3); + std::string B2 = glm::to_string(B1); + Error += B2 != std::string("vec3(1.000000, 2.000000, 3.000000)") ? 1 : 0; + + glm::vec4 C1(1, 2, 3, 4); + std::string C2 = glm::to_string(C1); + Error += C2 != std::string("vec4(1.000000, 2.000000, 3.000000, 4.000000)") ? 1 : 0; + + glm::dvec2 J1(1, 2); + std::string J2 = glm::to_string(J1); + Error += J2 != std::string("dvec2(1.000000, 2.000000)") ? 1 : 0; + + glm::dvec3 K1(1, 2, 3); + std::string K2 = glm::to_string(K1); + Error += K2 != std::string("dvec3(1.000000, 2.000000, 3.000000)") ? 1 : 0; + + glm::dvec4 L1(1, 2, 3, 4); + std::string L2 = glm::to_string(L1); + Error += L2 != std::string("dvec4(1.000000, 2.000000, 3.000000, 4.000000)") ? 1 : 0; + } + + { + glm::bvec2 M1(false, true); + std::string M2 = glm::to_string(M1); + Error += M2 != std::string("bvec2(false, true)") ? 1 : 0; + + glm::bvec3 O1(false, true, false); + std::string O2 = glm::to_string(O1); + Error += O2 != std::string("bvec3(false, true, false)") ? 1 : 0; + + glm::bvec4 P1(false, true, false, true); + std::string P2 = glm::to_string(P1); + Error += P2 != std::string("bvec4(false, true, false, true)") ? 1 : 0; + } + + { + glm::ivec2 D1(1, 2); + std::string D2 = glm::to_string(D1); + Error += D2 != std::string("ivec2(1, 2)") ? 1 : 0; + + glm::ivec3 E1(1, 2, 3); + std::string E2 = glm::to_string(E1); + Error += E2 != std::string("ivec3(1, 2, 3)") ? 1 : 0; + + glm::ivec4 F1(1, 2, 3, 4); + std::string F2 = glm::to_string(F1); + Error += F2 != std::string("ivec4(1, 2, 3, 4)") ? 1 : 0; + } + + { + glm::i8vec2 D1(1, 2); + std::string D2 = glm::to_string(D1); + Error += D2 != std::string("i8vec2(1, 2)") ? 1 : 0; + + glm::i8vec3 E1(1, 2, 3); + std::string E2 = glm::to_string(E1); + Error += E2 != std::string("i8vec3(1, 2, 3)") ? 1 : 0; + + glm::i8vec4 F1(1, 2, 3, 4); + std::string F2 = glm::to_string(F1); + Error += F2 != std::string("i8vec4(1, 2, 3, 4)") ? 1 : 0; + } + + { + glm::i16vec2 D1(1, 2); + std::string D2 = glm::to_string(D1); + Error += D2 != std::string("i16vec2(1, 2)") ? 1 : 0; + + glm::i16vec3 E1(1, 2, 3); + std::string E2 = glm::to_string(E1); + Error += E2 != std::string("i16vec3(1, 2, 3)") ? 1 : 0; + + glm::i16vec4 F1(1, 2, 3, 4); + std::string F2 = glm::to_string(F1); + Error += F2 != std::string("i16vec4(1, 2, 3, 4)") ? 1 : 0; + } + + { + glm::i64vec2 D1(1, 2); + std::string D2 = glm::to_string(D1); + Error += D2 != std::string("i64vec2(1, 2)") ? 1 : 0; + + glm::i64vec3 E1(1, 2, 3); + std::string E2 = glm::to_string(E1); + Error += E2 != std::string("i64vec3(1, 2, 3)") ? 1 : 0; + + glm::i64vec4 F1(1, 2, 3, 4); + std::string F2 = glm::to_string(F1); + Error += F2 != std::string("i64vec4(1, 2, 3, 4)") ? 1 : 0; + } + + return Error; +} + +int test_string_cast_matrix() +{ + int Error = 0; + + glm::mat2x2 A1(1.000000, 2.000000, 3.000000, 4.000000); + std::string A2 = glm::to_string(A1); + Error += A2 != std::string("mat2x2((1.000000, 2.000000), (3.000000, 4.000000))") ? 1 : 0; + + return Error; +} + +int test_string_cast_quaternion() +{ + int Error = 0; + + glm::quat Q0 = glm::quat(1.0f, 2.0f, 3.0f, 4.0f); + std::string S0 = glm::to_string(Q0); + Error += S0 != std::string("quat(1.000000, {2.000000, 3.000000, 4.000000})") ? 1 : 0; + + return Error; + +} + +int test_string_cast_dual_quaternion() +{ + int Error = 0; + + glm::dualquat Q0 = glm::dualquat(glm::quat(1.0f, 2.0f, 3.0f, 4.0f), glm::quat(5.0f, 6.0f, 7.0f, 8.0f)); + std::string S0 = glm::to_string(Q0); + Error += S0 != std::string("dualquat((1.000000, {2.000000, 3.000000, 4.000000}), (5.000000, {6.000000, 7.000000, 8.000000}))") ? 1 : 0; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_string_cast_vector(); + Error += test_string_cast_matrix(); + Error += test_string_cast_quaternion(); + Error += test_string_cast_dual_quaternion(); + + return Error; +} + + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_texture.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_texture.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0b98ed75366bb093a97463b5677df06ae7000c3e --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_texture.cpp @@ -0,0 +1,22 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include +#include + +int test_levels() +{ + int Error = 0; + + int const Levels = glm::levels(glm::ivec2(3, 2)); + Error += Levels == 2 ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_levels(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_type_aligned.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_type_aligned.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8d045c0dc008126300afb971cfd21c1a8593c06c --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_type_aligned.cpp @@ -0,0 +1,114 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include +#include + +int test_decl() +{ + int Error(0); + + { + struct S1 + { + glm::aligned_vec4 B; + }; + + struct S2 + { + glm::vec4 B; + }; + + std::printf("vec4 - Aligned: %d, unaligned: %d\n", static_cast(sizeof(S1)), static_cast(sizeof(S2))); + + Error += sizeof(S1) >= sizeof(S2) ? 0 : 1; + } + + { + struct S1 + { + bool A; + glm::vec3 B; + }; + + struct S2 + { + bool A; + glm::aligned_vec3 B; + }; + + std::printf("vec3 - Aligned: %d, unaligned: %d\n", static_cast(sizeof(S1)), static_cast(sizeof(S2))); + + Error += sizeof(S1) <= sizeof(S2) ? 0 : 1; + } + + { + struct S1 + { + bool A; + glm::aligned_vec4 B; + }; + + struct S2 + { + bool A; + glm::vec4 B; + }; + + std::printf("vec4 - Aligned: %d, unaligned: %d\n", static_cast(sizeof(S1)), static_cast(sizeof(S2))); + + Error += sizeof(S1) >= sizeof(S2) ? 0 : 1; + } + + { + struct S1 + { + bool A; + glm::aligned_dvec4 B; + }; + + struct S2 + { + bool A; + glm::dvec4 B; + }; + + std::printf("dvec4 - Aligned: %d, unaligned: %d\n", static_cast(sizeof(S1)), static_cast(sizeof(S2))); + + Error += sizeof(S1) >= sizeof(S2) ? 0 : 1; + } + + return Error; +} + +template +void print(genType const& Mat0) +{ + std::printf("mat4(\n"); + std::printf("\tvec4(%2.9f, %2.9f, %2.9f, %2.9f)\n", static_cast(Mat0[0][0]), static_cast(Mat0[0][1]), static_cast(Mat0[0][2]), static_cast(Mat0[0][3])); + std::printf("\tvec4(%2.9f, %2.9f, %2.9f, %2.9f)\n", static_cast(Mat0[1][0]), static_cast(Mat0[1][1]), static_cast(Mat0[1][2]), static_cast(Mat0[1][3])); + std::printf("\tvec4(%2.9f, %2.9f, %2.9f, %2.9f)\n", static_cast(Mat0[2][0]), static_cast(Mat0[2][1]), static_cast(Mat0[2][2]), static_cast(Mat0[2][3])); + std::printf("\tvec4(%2.9f, %2.9f, %2.9f, %2.9f))\n\n", static_cast(Mat0[3][0]), static_cast(Mat0[3][1]), static_cast(Mat0[3][2]), static_cast(Mat0[3][3])); +} + +int perf_mul() +{ + int Error = 0; + + glm::mat4 A(1.0f); + glm::mat4 B(1.0f); + + glm::mat4 C = A * B; + + print(C); + + return Error; +} + +int main() +{ + int Error(0); + + Error += test_decl(); + Error += perf_mul(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_type_trait.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_type_trait.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9b96a3631ce39e4fddaa19a8ae98ee9682e3c5f8 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_type_trait.cpp @@ -0,0 +1,13 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include +#include + +int main() +{ + int Error = 0; + + + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_vec_swizzle.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_vec_swizzle.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0b0c8b89cf02922e822ba1bc6dac51a0fe6c7f90 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_vec_swizzle.cpp @@ -0,0 +1,11 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include + +int main() +{ + int Error = 0; + + + return Error; +} + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_vector_angle.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_vector_angle.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4e8172b076d04a8e35e730a41af282bbfeb21022 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_vector_angle.cpp @@ -0,0 +1,59 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include +#include +#include + +int test_angle() +{ + int Error = 0; + + float AngleA = glm::angle(glm::vec2(1, 0), glm::normalize(glm::vec2(1, 1))); + Error += glm::epsilonEqual(AngleA, glm::pi() * 0.25f, 0.01f) ? 0 : 1; + float AngleB = glm::angle(glm::vec3(1, 0, 0), glm::normalize(glm::vec3(1, 1, 0))); + Error += glm::epsilonEqual(AngleB, glm::pi() * 0.25f, 0.01f) ? 0 : 1; + float AngleC = glm::angle(glm::vec4(1, 0, 0, 0), glm::normalize(glm::vec4(1, 1, 0, 0))); + Error += glm::epsilonEqual(AngleC, glm::pi() * 0.25f, 0.01f) ? 0 : 1; + + return Error; +} + +int test_orientedAngle_vec2() +{ + int Error = 0; + + float AngleA = glm::orientedAngle(glm::vec2(1, 0), glm::normalize(glm::vec2(1, 1))); + Error += glm::epsilonEqual(AngleA, glm::pi() * 0.25f, 0.01f) ? 0 : 1; + float AngleB = glm::orientedAngle(glm::vec2(0, 1), glm::normalize(glm::vec2(1, 1))); + Error += glm::epsilonEqual(AngleB, -glm::pi() * 0.25f, 0.01f) ? 0 : 1; + float AngleC = glm::orientedAngle(glm::normalize(glm::vec2(1, 1)), glm::vec2(0, 1)); + Error += glm::epsilonEqual(AngleC, glm::pi() * 0.25f, 0.01f) ? 0 : 1; + + return Error; +} + +int test_orientedAngle_vec3() +{ + int Error = 0; + + float AngleA = glm::orientedAngle(glm::vec3(1, 0, 0), glm::normalize(glm::vec3(1, 1, 0)), glm::vec3(0, 0, 1)); + Error += glm::epsilonEqual(AngleA, glm::pi() * 0.25f, 0.01f) ? 0 : 1; + float AngleB = glm::orientedAngle(glm::vec3(0, 1, 0), glm::normalize(glm::vec3(1, 1, 0)), glm::vec3(0, 0, 1)); + Error += glm::epsilonEqual(AngleB, -glm::pi() * 0.25f, 0.01f) ? 0 : 1; + float AngleC = glm::orientedAngle(glm::normalize(glm::vec3(1, 1, 0)), glm::vec3(0, 1, 0), glm::vec3(0, 0, 1)); + Error += glm::epsilonEqual(AngleC, glm::pi() * 0.25f, 0.01f) ? 0 : 1; + + return Error; +} + +int main() +{ + int Error(0); + + Error += test_angle(); + Error += test_orientedAngle_vec2(); + Error += test_orientedAngle_vec3(); + + return Error; +} + + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_vector_query.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_vector_query.cpp new file mode 100644 index 0000000000000000000000000000000000000000..729f9e18a375532dc64a8bc48fd0c7904b0ac4af --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_vector_query.cpp @@ -0,0 +1,82 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include +#include +#include +#include + +int test_areCollinear() +{ + int Error(0); + + { + bool TestA = glm::areCollinear(glm::vec2(-1), glm::vec2(1), 0.00001f); + Error += TestA ? 0 : 1; + } + + { + bool TestA = glm::areCollinear(glm::vec3(-1), glm::vec3(1), 0.00001f); + Error += TestA ? 0 : 1; + } + + { + bool TestA = glm::areCollinear(glm::vec4(-1), glm::vec4(1), 0.00001f); + Error += TestA ? 0 : 1; + } + + return Error; +} + +int test_areOrthogonal() +{ + int Error(0); + + bool TestA = glm::areOrthogonal(glm::vec2(1, 0), glm::vec2(0, 1), 0.00001f); + Error += TestA ? 0 : 1; + + return Error; +} + +int test_isNormalized() +{ + int Error(0); + + bool TestA = glm::isNormalized(glm::vec4(1, 0, 0, 0), 0.00001f); + Error += TestA ? 0 : 1; + + return Error; +} + +int test_isNull() +{ + int Error(0); + + bool TestA = glm::isNull(glm::vec4(0), 0.00001f); + Error += TestA ? 0 : 1; + + return Error; +} + +int test_areOrthonormal() +{ + int Error(0); + + bool TestA = glm::areOrthonormal(glm::vec2(1, 0), glm::vec2(0, 1), 0.00001f); + Error += TestA ? 0 : 1; + + return Error; +} + +int main() +{ + int Error(0); + + Error += test_areCollinear(); + Error += test_areOrthogonal(); + Error += test_isNormalized(); + Error += test_isNull(); + Error += test_areOrthonormal(); + + return Error; +} + + diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_wrap.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_wrap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2354cc8bc4b5e0449ea420048a6c1c66e5ecbf01 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/gtx/gtx_wrap.cpp @@ -0,0 +1,191 @@ +#define GLM_ENABLE_EXPERIMENTAL +#include +#include +#include + +namespace clamp +{ + int test() + { + int Error(0); + + float A = glm::clamp(0.5f); + Error += glm::equal(A, 0.5f, 0.00001f) ? 0 : 1; + + float B = glm::clamp(0.0f); + Error += glm::equal(B, 0.0f, 0.00001f) ? 0 : 1; + + float C = glm::clamp(1.0f); + Error += glm::equal(C, 1.0f, 0.00001f) ? 0 : 1; + + float D = glm::clamp(-0.5f); + Error += glm::equal(D, 0.0f, 0.00001f) ? 0 : 1; + + float E = glm::clamp(1.5f); + Error += glm::equal(E, 1.0f, 0.00001f) ? 0 : 1; + + glm::vec2 K = glm::clamp(glm::vec2(0.5f)); + Error += glm::all(glm::equal(K, glm::vec2(0.5f), glm::vec2(0.00001f))) ? 0 : 1; + + glm::vec3 L = glm::clamp(glm::vec3(0.5f)); + Error += glm::all(glm::equal(L, glm::vec3(0.5f), glm::vec3(0.00001f))) ? 0 : 1; + + glm::vec4 M = glm::clamp(glm::vec4(0.5f)); + Error += glm::all(glm::equal(M, glm::vec4(0.5f), glm::vec4(0.00001f))) ? 0 : 1; + + glm::vec1 N = glm::clamp(glm::vec1(0.5f)); + Error += glm::all(glm::equal(N, glm::vec1(0.5f), glm::vec1(0.00001f))) ? 0 : 1; + + return Error; + } +}//namespace clamp + +namespace repeat +{ + int test() + { + int Error(0); + + float A = glm::repeat(0.5f); + Error += glm::equal(A, 0.5f, 0.00001f) ? 0 : 1; + + float B = glm::repeat(0.0f); + Error += glm::equal(B, 0.0f, 0.00001f) ? 0 : 1; + + float C = glm::repeat(1.0f); + Error += glm::equal(C, 0.0f, 0.00001f) ? 0 : 1; + + float D = glm::repeat(-0.5f); + Error += glm::equal(D, 0.5f, 0.00001f) ? 0 : 1; + + float E = glm::repeat(1.5f); + Error += glm::equal(E, 0.5f, 0.00001f) ? 0 : 1; + + float F = glm::repeat(0.9f); + Error += glm::equal(F, 0.9f, 0.00001f) ? 0 : 1; + + glm::vec2 K = glm::repeat(glm::vec2(0.5f)); + Error += glm::all(glm::equal(K, glm::vec2(0.5f), glm::vec2(0.00001f))) ? 0 : 1; + + glm::vec3 L = glm::repeat(glm::vec3(0.5f)); + Error += glm::all(glm::equal(L, glm::vec3(0.5f), glm::vec3(0.00001f))) ? 0 : 1; + + glm::vec4 M = glm::repeat(glm::vec4(0.5f)); + Error += glm::all(glm::equal(M, glm::vec4(0.5f), glm::vec4(0.00001f))) ? 0 : 1; + + glm::vec1 N = glm::repeat(glm::vec1(0.5f)); + Error += glm::all(glm::equal(N, glm::vec1(0.5f), glm::vec1(0.00001f))) ? 0 : 1; + + return Error; + } +}//namespace repeat + +namespace mirrorClamp +{ + int test() + { + int Error(0); + + float A = glm::mirrorClamp(0.5f); + Error += glm::equal(A, 0.5f, 0.00001f) ? 0 : 1; + + float B = glm::mirrorClamp(0.0f); + Error += glm::equal(B, 0.0f, 0.00001f) ? 0 : 1; + + float C = glm::mirrorClamp(1.1f); + Error += glm::equal(C, 0.1f, 0.00001f) ? 0 : 1; + + float D = glm::mirrorClamp(-0.5f); + Error += glm::equal(D, 0.5f, 0.00001f) ? 0 : 1; + + float E = glm::mirrorClamp(1.5f); + Error += glm::equal(E, 0.5f, 0.00001f) ? 0 : 1; + + float F = glm::mirrorClamp(0.9f); + Error += glm::equal(F, 0.9f, 0.00001f) ? 0 : 1; + + float G = glm::mirrorClamp(3.1f); + Error += glm::equal(G, 0.1f, 0.00001f) ? 0 : 1; + + float H = glm::mirrorClamp(-3.1f); + Error += glm::equal(H, 0.1f, 0.00001f) ? 0 : 1; + + float I = glm::mirrorClamp(-0.9f); + Error += glm::equal(I, 0.9f, 0.00001f) ? 0 : 1; + + glm::vec2 K = glm::mirrorClamp(glm::vec2(0.5f)); + Error += glm::all(glm::equal(K, glm::vec2(0.5f), glm::vec2(0.00001f))) ? 0 : 1; + + glm::vec3 L = glm::mirrorClamp(glm::vec3(0.5f)); + Error += glm::all(glm::equal(L, glm::vec3(0.5f), glm::vec3(0.00001f))) ? 0 : 1; + + glm::vec4 M = glm::mirrorClamp(glm::vec4(0.5f)); + Error += glm::all(glm::equal(M, glm::vec4(0.5f), glm::vec4(0.00001f))) ? 0 : 1; + + glm::vec1 N = glm::mirrorClamp(glm::vec1(0.5f)); + Error += glm::all(glm::equal(N, glm::vec1(0.5f), glm::vec1(0.00001f))) ? 0 : 1; + + return Error; + } +}//namespace mirrorClamp + +namespace mirrorRepeat +{ + int test() + { + int Error(0); + + float A = glm::mirrorRepeat(0.5f); + Error += glm::equal(A, 0.5f, 0.00001f) ? 0 : 1; + + float B = glm::mirrorRepeat(0.0f); + Error += glm::equal(B, 0.0f, 0.00001f) ? 0 : 1; + + float C = glm::mirrorRepeat(1.0f); + Error += glm::equal(C, 1.0f, 0.00001f) ? 0 : 1; + + float D = glm::mirrorRepeat(-0.5f); + Error += glm::equal(D, 0.5f, 0.00001f) ? 0 : 1; + + float E = glm::mirrorRepeat(1.5f); + Error += glm::equal(E, 0.5f, 0.00001f) ? 0 : 1; + + float F = glm::mirrorRepeat(0.9f); + Error += glm::equal(F, 0.9f, 0.00001f) ? 0 : 1; + + float G = glm::mirrorRepeat(3.0f); + Error += glm::equal(G, 1.0f, 0.00001f) ? 0 : 1; + + float H = glm::mirrorRepeat(-3.0f); + Error += glm::equal(H, 1.0f, 0.00001f) ? 0 : 1; + + float I = glm::mirrorRepeat(-1.0f); + Error += glm::equal(I, 1.0f, 0.00001f) ? 0 : 1; + + glm::vec2 K = glm::mirrorRepeat(glm::vec2(0.5f)); + Error += glm::all(glm::equal(K, glm::vec2(0.5f), glm::vec2(0.00001f))) ? 0 : 1; + + glm::vec3 L = glm::mirrorRepeat(glm::vec3(0.5f)); + Error += glm::all(glm::equal(L, glm::vec3(0.5f), glm::vec3(0.00001f))) ? 0 : 1; + + glm::vec4 M = glm::mirrorRepeat(glm::vec4(0.5f)); + Error += glm::all(glm::equal(M, glm::vec4(0.5f), glm::vec4(0.00001f))) ? 0 : 1; + + glm::vec1 N = glm::mirrorRepeat(glm::vec1(0.5f)); + Error += glm::all(glm::equal(N, glm::vec1(0.5f), glm::vec1(0.00001f))) ? 0 : 1; + + return Error; + } +}//namespace mirrorRepeat + +int main() +{ + int Error(0); + + Error += clamp::test(); + Error += repeat::test(); + Error += mirrorClamp::test(); + Error += mirrorRepeat::test(); + + return Error; +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/perf/CMakeLists.txt b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/perf/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..19c70508ce9fa497a2fcc4a45ceaaf886da40ab8 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/perf/CMakeLists.txt @@ -0,0 +1,6 @@ +glmCreateTestGTC(perf_matrix_div) +glmCreateTestGTC(perf_matrix_inverse) +glmCreateTestGTC(perf_matrix_mul) +glmCreateTestGTC(perf_matrix_mul_vector) +glmCreateTestGTC(perf_matrix_transpose) +glmCreateTestGTC(perf_vector_mul_matrix) diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/perf/perf_matrix_div.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/perf/perf_matrix_div.cpp new file mode 100644 index 0000000000000000000000000000000000000000..630188d5906034bb178a7235bd9a80450a6181c3 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/perf/perf_matrix_div.cpp @@ -0,0 +1,153 @@ +#define GLM_FORCE_INLINE +#include +#include +#include +#include +#include +#if GLM_CONFIG_SIMD == GLM_ENABLE +#include +#include +#include +#include + +template +static void test_mat_div_mat(matType const& M, std::vector const& I, std::vector& O) +{ + for (std::size_t i = 0, n = I.size(); i < n; ++i) + O[i] = M / I[i]; +} + +template +static int launch_mat_div_mat(std::vector& O, matType const& Transform, matType const& Scale, std::size_t Samples) +{ + typedef typename matType::value_type T; + + std::vector I(Samples); + O.resize(Samples); + + for(std::size_t i = 0; i < Samples; ++i) + I[i] = Scale * static_cast(i) + Scale; + + std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now(); + test_mat_div_mat(Transform, I, O); + std::chrono::high_resolution_clock::time_point t2 = std::chrono::high_resolution_clock::now(); + + return static_cast(std::chrono::duration_cast(t2 - t1).count()); +} + +template +static int comp_mat2_div_mat2(std::size_t Samples) +{ + typedef typename packedMatType::value_type T; + + int Error = 0; + + packedMatType const Transform(1, 2, 3, 4); + packedMatType const Scale(0.01, 0.02, 0.03, 0.05); + + std::vector SISD; + std::printf("- SISD: %d us\n", launch_mat_div_mat(SISD, Transform, Scale, Samples)); + + std::vector SIMD; + std::printf("- SIMD: %d us\n", launch_mat_div_mat(SIMD, Transform, Scale, Samples)); + + for(std::size_t i = 0; i < Samples; ++i) + { + packedMatType const A = SISD[i]; + packedMatType const B = SIMD[i]; + Error += glm::all(glm::equal(A, B, static_cast(0.001))) ? 0 : 1; + assert(!Error); + } + + return Error; +} + +template +static int comp_mat3_div_mat3(std::size_t Samples) +{ + typedef typename packedMatType::value_type T; + + int Error = 0; + + packedMatType const Transform(1, 2, 3, 4, 5, 6, 7, 8, 9); + packedMatType const Scale(0.01, 0.02, 0.03, 0.05, 0.01, 0.02, 0.03, 0.05, 0.01); + + std::vector SISD; + std::printf("- SISD: %d us\n", launch_mat_div_mat(SISD, Transform, Scale, Samples)); + + std::vector SIMD; + std::printf("- SIMD: %d us\n", launch_mat_div_mat(SIMD, Transform, Scale, Samples)); + + for(std::size_t i = 0; i < Samples; ++i) + { + packedMatType const A = SISD[i]; + packedMatType const B = SIMD[i]; + Error += glm::all(glm::equal(A, B, static_cast(0.001))) ? 0 : 1; + assert(!Error); + } + + return Error; +} + +template +static int comp_mat4_div_mat4(std::size_t Samples) +{ + typedef typename packedMatType::value_type T; + + int Error = 0; + + packedMatType const Transform(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + packedMatType const Scale(0.01, 0.02, 0.05, 0.04, 0.02, 0.08, 0.05, 0.01, 0.08, 0.03, 0.05, 0.06, 0.02, 0.03, 0.07, 0.05); + + std::vector SISD; + std::printf("- SISD: %d us\n", launch_mat_div_mat(SISD, Transform, Scale, Samples)); + + std::vector SIMD; + std::printf("- SIMD: %d us\n", launch_mat_div_mat(SIMD, Transform, Scale, Samples)); + + for(std::size_t i = 0; i < Samples; ++i) + { + packedMatType const A = SISD[i]; + packedMatType const B = SIMD[i]; + Error += glm::all(glm::equal(A, B, static_cast(0.001))) ? 0 : 1; + assert(!Error); + } + + return Error; +} + +int main() +{ + std::size_t const Samples = 100000; + + int Error = 0; + + std::printf("mat2 / mat2:\n"); + Error += comp_mat2_div_mat2(Samples); + + std::printf("dmat2 / dmat2:\n"); + Error += comp_mat2_div_mat2(Samples); + + std::printf("mat3 / mat3:\n"); + Error += comp_mat3_div_mat3(Samples); + + std::printf("dmat3 / dmat3:\n"); + Error += comp_mat3_div_mat3(Samples); + + std::printf("mat4 / mat4:\n"); + Error += comp_mat4_div_mat4(Samples); + + std::printf("dmat4 / dmat4:\n"); + Error += comp_mat4_div_mat4(Samples); + + return Error; +} + +#else + +int main() +{ + return 0; +} + +#endif diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/perf/perf_matrix_inverse.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/perf/perf_matrix_inverse.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1a989ae98d35e36709e2c1e3bc48aea40b6907cc --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/perf/perf_matrix_inverse.cpp @@ -0,0 +1,150 @@ +#define GLM_FORCE_INLINE +#include +#include +#include +#include +#include +#if GLM_CONFIG_SIMD == GLM_ENABLE +#include +#include +#include +#include + +template +static void test_mat_inverse(std::vector const& I, std::vector& O) +{ + for (std::size_t i = 0, n = I.size(); i < n; ++i) + O[i] = glm::inverse(I[i]); +} + +template +static int launch_mat_inverse(std::vector& O, matType const& Scale, std::size_t Samples) +{ + typedef typename matType::value_type T; + + std::vector I(Samples); + O.resize(Samples); + + for(std::size_t i = 0; i < Samples; ++i) + I[i] = Scale * static_cast(i) + Scale; + + std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now(); + test_mat_inverse(I, O); + std::chrono::high_resolution_clock::time_point t2 = std::chrono::high_resolution_clock::now(); + + return static_cast(std::chrono::duration_cast(t2 - t1).count()); +} + +template +static int comp_mat2_inverse(std::size_t Samples) +{ + typedef typename packedMatType::value_type T; + + int Error = 0; + + packedMatType const Scale(0.01, 0.02, 0.03, 0.05); + + std::vector SISD; + std::printf("- SISD: %d us\n", launch_mat_inverse(SISD, Scale, Samples)); + + std::vector SIMD; + std::printf("- SIMD: %d us\n", launch_mat_inverse(SIMD, Scale, Samples)); + + for(std::size_t i = 0; i < Samples; ++i) + { + packedMatType const A = SISD[i]; + packedMatType const B = SIMD[i]; + Error += glm::all(glm::equal(A, B, static_cast(0.001))) ? 0 : 1; + assert(!Error); + } + + return Error; +} + +template +static int comp_mat3_inverse(std::size_t Samples) +{ + typedef typename packedMatType::value_type T; + + int Error = 0; + + packedMatType const Scale(0.01, 0.02, 0.03, 0.05, 0.01, 0.02, 0.03, 0.05, 0.01); + + std::vector SISD; + std::printf("- SISD: %d us\n", launch_mat_inverse(SISD, Scale, Samples)); + + std::vector SIMD; + std::printf("- SIMD: %d us\n", launch_mat_inverse(SIMD, Scale, Samples)); + + for(std::size_t i = 0; i < Samples; ++i) + { + packedMatType const A = SISD[i]; + packedMatType const B = SIMD[i]; + Error += glm::all(glm::equal(A, B, static_cast(0.001))) ? 0 : 1; + assert(!Error); + } + + return Error; +} + +template +static int comp_mat4_inverse(std::size_t Samples) +{ + typedef typename packedMatType::value_type T; + + int Error = 0; + + packedMatType const Scale(0.01, 0.02, 0.05, 0.04, 0.02, 0.08, 0.05, 0.01, 0.08, 0.03, 0.05, 0.06, 0.02, 0.03, 0.07, 0.05); + + std::vector SISD; + std::printf("- SISD: %d us\n", launch_mat_inverse(SISD, Scale, Samples)); + + std::vector SIMD; + std::printf("- SIMD: %d us\n", launch_mat_inverse(SIMD, Scale, Samples)); + + for(std::size_t i = 0; i < Samples; ++i) + { + packedMatType const A = SISD[i]; + packedMatType const B = SIMD[i]; + Error += glm::all(glm::equal(A, B, static_cast(0.001))) ? 0 : 1; + assert(!Error); + } + + return Error; +} + +int main() +{ + std::size_t const Samples = 100000; + + int Error = 0; + + std::printf("glm::inverse(mat2):\n"); + Error += comp_mat2_inverse(Samples); + + std::printf("glm::inverse(dmat2):\n"); + Error += comp_mat2_inverse(Samples); + + std::printf("glm::inverse(mat3):\n"); + Error += comp_mat3_inverse(Samples); + + std::printf("glm::inverse(dmat3):\n"); + Error += comp_mat3_inverse(Samples); + + std::printf("glm::inverse(mat4):\n"); + Error += comp_mat4_inverse(Samples); + + std::printf("glm::inverse(dmat4):\n"); + Error += comp_mat4_inverse(Samples); + + return Error; +} + +#else + +int main() +{ + return 0; +} + +#endif diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/perf/perf_matrix_mul.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/perf/perf_matrix_mul.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d6b1f104bbe988f7073579e6ceca24a5cc21d071 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/perf/perf_matrix_mul.cpp @@ -0,0 +1,154 @@ +#define GLM_FORCE_INLINE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if GLM_CONFIG_SIMD == GLM_ENABLE +#include +#include +#include +#include + +template +static void test_mat_mul_mat(matType const& M, std::vector const& I, std::vector& O) +{ + for (std::size_t i = 0, n = I.size(); i < n; ++i) + O[i] = M * I[i]; +} + +template +static int launch_mat_mul_mat(std::vector& O, matType const& Transform, matType const& Scale, std::size_t Samples) +{ + typedef typename matType::value_type T; + + std::vector I(Samples); + O.resize(Samples); + + for(std::size_t i = 0; i < Samples; ++i) + I[i] = Scale * static_cast(i); + + std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now(); + test_mat_mul_mat(Transform, I, O); + std::chrono::high_resolution_clock::time_point t2 = std::chrono::high_resolution_clock::now(); + + return static_cast(std::chrono::duration_cast(t2 - t1).count()); +} + +template +static int comp_mat2_mul_mat2(std::size_t Samples) +{ + typedef typename packedMatType::value_type T; + + int Error = 0; + + packedMatType const Transform(1, 2, 3, 4); + packedMatType const Scale(0.01, 0.02, 0.03, 0.05); + + std::vector SISD; + std::printf("- SISD: %d us\n", launch_mat_mul_mat(SISD, Transform, Scale, Samples)); + + std::vector SIMD; + std::printf("- SIMD: %d us\n", launch_mat_mul_mat(SIMD, Transform, Scale, Samples)); + + for(std::size_t i = 0; i < Samples; ++i) + { + packedMatType const A = SISD[i]; + packedMatType const B = SIMD[i]; + Error += glm::all(glm::equal(A, B, static_cast(0.001))) ? 0 : 1; + } + + return Error; +} + +template +static int comp_mat3_mul_mat3(std::size_t Samples) +{ + typedef typename packedMatType::value_type T; + + int Error = 0; + + packedMatType const Transform(1, 2, 3, 4, 5, 6, 7, 8, 9); + packedMatType const Scale(0.01, 0.02, 0.03, 0.05, 0.01, 0.02, 0.03, 0.05, 0.01); + + std::vector SISD; + std::printf("- SISD: %d us\n", launch_mat_mul_mat(SISD, Transform, Scale, Samples)); + + std::vector SIMD; + std::printf("- SIMD: %d us\n", launch_mat_mul_mat(SIMD, Transform, Scale, Samples)); + + for(std::size_t i = 0; i < Samples; ++i) + { + packedMatType const A = SISD[i]; + packedMatType const B = SIMD[i]; + Error += glm::all(glm::equal(A, B, static_cast(0.001))) ? 0 : 1; + } + + return Error; +} + +template +static int comp_mat4_mul_mat4(std::size_t Samples) +{ + typedef typename packedMatType::value_type T; + + int Error = 0; + + packedMatType const Transform(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + packedMatType const Scale(0.01, 0.02, 0.03, 0.05, 0.01, 0.02, 0.03, 0.05, 0.01, 0.02, 0.03, 0.05, 0.01, 0.02, 0.03, 0.05); + + std::vector SISD; + std::printf("- SISD: %d us\n", launch_mat_mul_mat(SISD, Transform, Scale, Samples)); + + std::vector SIMD; + std::printf("- SIMD: %d us\n", launch_mat_mul_mat(SIMD, Transform, Scale, Samples)); + + for(std::size_t i = 0; i < Samples; ++i) + { + packedMatType const A = SISD[i]; + packedMatType const B = SIMD[i]; + Error += glm::all(glm::equal(A, B, static_cast(0.001))) ? 0 : 1; + } + + return Error; +} + +int main() +{ + std::size_t const Samples = 100000; + + int Error = 0; + + std::printf("mat2 * mat2:\n"); + Error += comp_mat2_mul_mat2(Samples); + + std::printf("dmat2 * dmat2:\n"); + Error += comp_mat2_mul_mat2(Samples); + + std::printf("mat3 * mat3:\n"); + Error += comp_mat3_mul_mat3(Samples); + + std::printf("dmat3 * dmat3:\n"); + Error += comp_mat3_mul_mat3(Samples); + + std::printf("mat4 * mat4:\n"); + Error += comp_mat4_mul_mat4(Samples); + + std::printf("dmat4 * dmat4:\n"); + Error += comp_mat4_mul_mat4(Samples); + + return Error; +} + +#else + +int main() +{ + return 0; +} + +#endif diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/perf/perf_matrix_mul_vector.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/perf/perf_matrix_mul_vector.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8e555f81beb8afe9f411343be96b9598746abc6e --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/perf/perf_matrix_mul_vector.cpp @@ -0,0 +1,154 @@ +#define GLM_FORCE_INLINE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if GLM_CONFIG_SIMD == GLM_ENABLE +#include +#include +#include +#include + +template +static void test_mat_mul_vec(matType const& M, std::vector const& I, std::vector& O) +{ + for (std::size_t i = 0, n = I.size(); i < n; ++i) + O[i] = M * I[i]; +} + +template +static int launch_mat_mul_vec(std::vector& O, matType const& Transform, vecType const& Scale, std::size_t Samples) +{ + typedef typename matType::value_type T; + + std::vector I(Samples); + O.resize(Samples); + + for(std::size_t i = 0; i < Samples; ++i) + I[i] = Scale * static_cast(i); + + std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now(); + test_mat_mul_vec(Transform, I, O); + std::chrono::high_resolution_clock::time_point t2 = std::chrono::high_resolution_clock::now(); + + return static_cast(std::chrono::duration_cast(t2 - t1).count()); +} + +template +static int comp_mat2_mul_vec2(std::size_t Samples) +{ + typedef typename packedMatType::value_type T; + + int Error = 0; + + packedMatType const Transform(1, 2, 3, 4); + packedVecType const Scale(0.01, 0.02); + + std::vector SISD; + std::printf("- SISD: %d us\n", launch_mat_mul_vec(SISD, Transform, Scale, Samples)); + + std::vector SIMD; + std::printf("- SIMD: %d us\n", launch_mat_mul_vec(SIMD, Transform, Scale, Samples)); + + for(std::size_t i = 0; i < Samples; ++i) + { + packedVecType const A = SISD[i]; + packedVecType const B = packedVecType(SIMD[i]); + Error += glm::all(glm::equal(A, B, static_cast(0.001))) ? 0 : 1; + } + + return Error; +} + +template +static int comp_mat3_mul_vec3(std::size_t Samples) +{ + typedef typename packedMatType::value_type T; + + int Error = 0; + + packedMatType const Transform(1, 2, 3, 4, 5, 6, 7, 8, 9); + packedVecType const Scale(0.01, 0.02, 0.05); + + std::vector SISD; + std::printf("- SISD: %d us\n", launch_mat_mul_vec(SISD, Transform, Scale, Samples)); + + std::vector SIMD; + std::printf("- SIMD: %d us\n", launch_mat_mul_vec(SIMD, Transform, Scale, Samples)); + + for(std::size_t i = 0; i < Samples; ++i) + { + packedVecType const A = SISD[i]; + packedVecType const B = SIMD[i]; + Error += glm::all(glm::equal(A, B, static_cast(0.001))) ? 0 : 1; + } + + return Error; +} + +template +static int comp_mat4_mul_vec4(std::size_t Samples) +{ + typedef typename packedMatType::value_type T; + + int Error = 0; + + packedMatType const Transform(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + packedVecType const Scale(0.01, 0.02, 0.03, 0.05); + + std::vector SISD; + std::printf("- SISD: %d us\n", launch_mat_mul_vec(SISD, Transform, Scale, Samples)); + + std::vector SIMD; + std::printf("- SIMD: %d us\n", launch_mat_mul_vec(SIMD, Transform, Scale, Samples)); + + for(std::size_t i = 0; i < Samples; ++i) + { + packedVecType const A = SISD[i]; + packedVecType const B = SIMD[i]; + Error += glm::all(glm::equal(A, B, static_cast(0.001))) ? 0 : 1; + } + + return Error; +} + +int main() +{ + std::size_t const Samples = 100000; + + int Error = 0; + + std::printf("mat2 * vec2:\n"); + Error += comp_mat2_mul_vec2(Samples); + + std::printf("dmat2 * dvec2:\n"); + Error += comp_mat2_mul_vec2(Samples); + + std::printf("mat3 * vec3:\n"); + Error += comp_mat3_mul_vec3(Samples); + + std::printf("dmat3 * dvec3:\n"); + Error += comp_mat3_mul_vec3(Samples); + + std::printf("mat4 * vec4:\n"); + Error += comp_mat4_mul_vec4(Samples); + + std::printf("dmat4 * dvec4:\n"); + Error += comp_mat4_mul_vec4(Samples); + + return Error; +} + +#else + +int main() +{ + return 0; +} + +#endif diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/perf/perf_matrix_transpose.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/perf/perf_matrix_transpose.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2fdc782ad9fcecdd7a450ef20e5bc3209278573e --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/perf/perf_matrix_transpose.cpp @@ -0,0 +1,150 @@ +#define GLM_FORCE_INLINE +#include +#include +#include +#include +#include +#if GLM_CONFIG_SIMD == GLM_ENABLE +#include +#include +#include +#include + +template +static void test_mat_transpose(std::vector const& I, std::vector& O) +{ + for (std::size_t i = 0, n = I.size(); i < n; ++i) + O[i] = glm::transpose(I[i]); +} + +template +static int launch_mat_transpose(std::vector& O, matType const& Scale, std::size_t Samples) +{ + typedef typename matType::value_type T; + + std::vector I(Samples); + O.resize(Samples); + + for(std::size_t i = 0; i < Samples; ++i) + I[i] = Scale * static_cast(i) + Scale; + + std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now(); + test_mat_transpose(I, O); + std::chrono::high_resolution_clock::time_point t2 = std::chrono::high_resolution_clock::now(); + + return static_cast(std::chrono::duration_cast(t2 - t1).count()); +} + +template +static int comp_mat2_transpose(std::size_t Samples) +{ + typedef typename packedMatType::value_type T; + + int Error = 0; + + packedMatType const Scale(0.01, 0.02, 0.03, 0.05); + + std::vector SISD; + std::printf("- SISD: %d us\n", launch_mat_transpose(SISD, Scale, Samples)); + + std::vector SIMD; + std::printf("- SIMD: %d us\n", launch_mat_transpose(SIMD, Scale, Samples)); + + for(std::size_t i = 0; i < Samples; ++i) + { + packedMatType const A = SISD[i]; + packedMatType const B = SIMD[i]; + Error += glm::all(glm::equal(A, B, static_cast(0.001))) ? 0 : 1; + assert(!Error); + } + + return Error; +} + +template +static int comp_mat3_transpose(std::size_t Samples) +{ + typedef typename packedMatType::value_type T; + + int Error = 0; + + packedMatType const Scale(0.01, 0.02, 0.03, 0.05, 0.01, 0.02, 0.03, 0.05, 0.01); + + std::vector SISD; + std::printf("- SISD: %d us\n", launch_mat_transpose(SISD, Scale, Samples)); + + std::vector SIMD; + std::printf("- SIMD: %d us\n", launch_mat_transpose(SIMD, Scale, Samples)); + + for(std::size_t i = 0; i < Samples; ++i) + { + packedMatType const A = SISD[i]; + packedMatType const B = SIMD[i]; + Error += glm::all(glm::equal(A, B, static_cast(0.001))) ? 0 : 1; + assert(!Error); + } + + return Error; +} + +template +static int comp_mat4_transpose(std::size_t Samples) +{ + typedef typename packedMatType::value_type T; + + int Error = 0; + + packedMatType const Scale(0.01, 0.02, 0.05, 0.04, 0.02, 0.08, 0.05, 0.01, 0.08, 0.03, 0.05, 0.06, 0.02, 0.03, 0.07, 0.05); + + std::vector SISD; + std::printf("- SISD: %d us\n", launch_mat_transpose(SISD, Scale, Samples)); + + std::vector SIMD; + std::printf("- SIMD: %d us\n", launch_mat_transpose(SIMD, Scale, Samples)); + + for(std::size_t i = 0; i < Samples; ++i) + { + packedMatType const A = SISD[i]; + packedMatType const B = SIMD[i]; + Error += glm::all(glm::equal(A, B, static_cast(0.001))) ? 0 : 1; + assert(!Error); + } + + return Error; +} + +int main() +{ + std::size_t const Samples = 100000; + + int Error = 0; + + std::printf("glm::transpose(mat2):\n"); + Error += comp_mat2_transpose(Samples); + + std::printf("glm::transpose(dmat2):\n"); + Error += comp_mat2_transpose(Samples); + + std::printf("glm::transpose(mat3):\n"); + Error += comp_mat3_transpose(Samples); + + std::printf("glm::transpose(dmat3):\n"); + Error += comp_mat3_transpose(Samples); + + std::printf("glm::transpose(mat4):\n"); + Error += comp_mat4_transpose(Samples); + + std::printf("glm::transpose(dmat4):\n"); + Error += comp_mat4_transpose(Samples); + + return Error; +} + +#else + +int main() +{ + return 0; +} + +#endif diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/perf/perf_vector_mul_matrix.cpp b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/perf/perf_vector_mul_matrix.cpp new file mode 100644 index 0000000000000000000000000000000000000000..20991df89dcfd9c20d84b901af41e4eb5bfd4707 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/test/perf/perf_vector_mul_matrix.cpp @@ -0,0 +1,154 @@ +#define GLM_FORCE_INLINE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if GLM_CONFIG_SIMD == GLM_ENABLE +#include +#include +#include +#include + +template +static void test_vec_mul_mat(matType const& M, std::vector const& I, std::vector& O) +{ + for (std::size_t i = 0, n = I.size(); i < n; ++i) + O[i] = I[i] * M; +} + +template +static int launch_vec_mul_mat(std::vector& O, matType const& Transform, vecType const& Scale, std::size_t Samples) +{ + typedef typename matType::value_type T; + + std::vector I(Samples); + O.resize(Samples); + + for(std::size_t i = 0; i < Samples; ++i) + I[i] = Scale * static_cast(i); + + std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now(); + test_vec_mul_mat(Transform, I, O); + std::chrono::high_resolution_clock::time_point t2 = std::chrono::high_resolution_clock::now(); + + return static_cast(std::chrono::duration_cast(t2 - t1).count()); +} + +template +static int comp_vec2_mul_mat2(std::size_t Samples) +{ + typedef typename packedMatType::value_type T; + + int Error = 0; + + packedMatType const Transform(1, 2, 3, 4); + packedVecType const Scale(0.01, 0.02); + + std::vector SISD; + std::printf("- SISD: %d us\n", launch_vec_mul_mat(SISD, Transform, Scale, Samples)); + + std::vector SIMD; + std::printf("- SIMD: %d us\n", launch_vec_mul_mat(SIMD, Transform, Scale, Samples)); + + for(std::size_t i = 0; i < Samples; ++i) + { + packedVecType const A = SISD[i]; + packedVecType const B = packedVecType(SIMD[i]); + Error += glm::all(glm::equal(A, B, static_cast(0.001))) ? 0 : 1; + } + + return Error; +} + +template +static int comp_vec3_mul_mat3(std::size_t Samples) +{ + typedef typename packedMatType::value_type T; + + int Error = 0; + + packedMatType const Transform(1, 2, 3, 4, 5, 6, 7, 8, 9); + packedVecType const Scale(0.01, 0.02, 0.05); + + std::vector SISD; + std::printf("- SISD: %d us\n", launch_vec_mul_mat(SISD, Transform, Scale, Samples)); + + std::vector SIMD; + std::printf("- SIMD: %d us\n", launch_vec_mul_mat(SIMD, Transform, Scale, Samples)); + + for(std::size_t i = 0; i < Samples; ++i) + { + packedVecType const A = SISD[i]; + packedVecType const B = SIMD[i]; + Error += glm::all(glm::equal(A, B, static_cast(0.001))) ? 0 : 1; + } + + return Error; +} + +template +static int comp_vec4_mul_mat4(std::size_t Samples) +{ + typedef typename packedMatType::value_type T; + + int Error = 0; + + packedMatType const Transform(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + packedVecType const Scale(0.01, 0.02, 0.03, 0.05); + + std::vector SISD; + std::printf("- SISD: %d us\n", launch_vec_mul_mat(SISD, Transform, Scale, Samples)); + + std::vector SIMD; + std::printf("- SIMD: %d us\n", launch_vec_mul_mat(SIMD, Transform, Scale, Samples)); + + for(std::size_t i = 0; i < Samples; ++i) + { + packedVecType const A = SISD[i]; + packedVecType const B = SIMD[i]; + Error += glm::all(glm::equal(A, B, static_cast(0.001))) ? 0 : 1; + } + + return Error; +} + +int main() +{ + std::size_t const Samples = 100000; + + int Error = 0; + + std::printf("vec2 * mat2:\n"); + Error += comp_vec2_mul_mat2(Samples); + + std::printf("dvec2 * dmat2:\n"); + Error += comp_vec2_mul_mat2(Samples); + + std::printf("vec3 * mat3:\n"); + Error += comp_vec3_mul_mat3(Samples); + + std::printf("dvec3 * dmat3:\n"); + Error += comp_vec3_mul_mat3(Samples); + + std::printf("vec4 * mat4:\n"); + Error += comp_vec4_mul_mat4(Samples); + + std::printf("dvec4 * dmat4:\n"); + Error += comp_vec4_mul_mat4(Samples); + + return Error; +} + +#else + +int main() +{ + return 0; +} + +#endif diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/util/autoexp.txt b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/util/autoexp.txt new file mode 100644 index 0000000000000000000000000000000000000000..5a07bed552e182aa10f78674ff702d314ed02ba5 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/util/autoexp.txt @@ -0,0 +1,28 @@ +[Visualizer] + +glm::detail::tvec2<*>{ + preview ( + #(#($c.x,$c.y)) + ) + children ( + #([x]: $c.x,[y]: $c.y) + ) +} + +glm::detail::tvec3<*>{ + preview ( + #($e.x,$e.y,$e.z) + ) + children ( + #([x]: $e.x,[y]: $e.y,[z]: $e.z) + ) +} + +glm::detail::tvec4<*>{ + preview ( + #($c.x,$c.y,$c.z,$c.w) + ) + children ( + #([x]: $e.x,[y]: $e.y,[z]: $e.z, #([w]: $e.w)) + ) +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/util/autoexp.vc2010.dat b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/util/autoexp.vc2010.dat new file mode 100644 index 0000000000000000000000000000000000000000..e28d31df7fac4ec2f8ac0b6ea66166541a6a4fb0 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/util/autoexp.vc2010.dat @@ -0,0 +1,3896 @@ +; AutoExp.Dat - templates for automatically expanding data +; Copyright(c) Microsoft Corporation. All Rights Reserved. +;--------------------------------------------------------------- +; +; While debugging, Data Tips and items in the Watch and Variable +; windows are automatically expanded to show their most important +; elements. The expansion follows the format given by the rules +; in this file. You can add rules for your types or change the +; predefined rules. +; +; For good examples, read the rules in this file. +; +; To find what the debugger considers the type of a variable to +; be, add it to the Watch window and look at the Type column. +; +; An AutoExpand rule is a line with the name of a type, an equals +; sign, and text with replaceable parts in angle brackets. The +; part in angle brackets names a member of the type and an +; optional Watch format specifier. +; +; AutoExpand rules use the following syntax. The equals sign (=), +; angle brackets (<>), and comma are taken literally. Square +; brackets ([]) indicate optional items. +; +; type=[text]... +; +; type Name of the type (may be followed by <*> for template +; types such as the ATL types listed below). +; +; text Any text.Usually the name of the member to display, +; or a shorthand name for the member. +; +; member Name of a member to display. +; +; format Watch format specifier. One of the following: +; +; Letter Description Sample Display +; ------ -------------------------- ------------ ------------- +; d,i Signed decimal integer 0xF000F065,d -268373915 +; u Unsigned decimal integer 0x0065,u 101 +; o Unsigned octal integer 0xF065,o 0170145 +; x,X Hexadecimal integer 61541,X 0X0000F065 +; l,h long or short prefix for 00406042,hx 0x0c22 +; d, i, u, o, x, X +; f Signed floating-point 3./2.,f 1.500000 +; e Signed scientific-notation 3./2.,e 1.500000e+000 +; g Shorter of e and f 3./2.,g 1.5 +; c Single character 0x0065,c 'e' +; s Zero-terminated string pVar,s "Hello world" +; su Unicode string pVar,su "Hello world" +; +; For details of other format specifiers see Help under: +; "format specifiers/watch variable" +; +; The special format <,t> specifies the name of the most-derived +; type of the object. This is especially useful with pointers or +; references to a base class. +; +; If there is no rule for a class, the base classes are checked for +; a matching rule. +; +; There are some special entries allowed in the AutoExpand section: +; $BUILTIN is used to display more complex types that need to do more +; than just show a member variable or two. +; $ADDIN allows external DLLs to be added to display even more complex +; types via the EE Add-in API. The first argument is the DLL name, the +; second argument is the name of the export from the DLL to use. For +; further information on this API see the sample called EEAddIn. +; +; WARNING: if hexadecimal mode is on in the watch window, all numbers here are +; evaluated in hex, e.g. 42 becomes 0x42 + +[AutoExpand] + +; from windef.h +tagPOINT =x= y= +tagRECT =top= bottom= left= right= + +; from winuser.h +tagMSG =msg= wp= lp= + +; intrinsics +__m64 = +__m128=$BUILTIN(M128) +__m128i=$BUILTIN(M128I) +__m128d=$BUILTIN(M128D) + +; from afxwin.h +CDC =hDC= attrib= +CPaintDC =<,t> hWnd= +CPoint =x= y= +CRect =top= bottom= left= right= +CSize =cx= cy= +CWnd =<,t> hWnd= +CWinApp =<,t> +CWinThread =<,t> h= proc= + +; from afxcoll.h +CPtrList =cnt= + +; from afxstat_.h +CProcessLocalObject =<,t> +CThreadLocalObject =<,t> + +; from afx.h +CArchiveException =cause= +CFile =hFile= name= +CFileException =cause= OS Error=m_lOsError +CMemFile =pos= size= +CObject =<,t> +CRuntimeClass = +CStdioFile =FILE*= name= +CTimeSpan =time= +CTime =time= + +; from afxcoll.h +CByteArray =count= +CStringList =count= +; same for all CXXXArray classes +; same for CXXXList +; same for CMapXXToXX + +; various string classes from MFC & ATL + +_com_error= +_bstr_t=m_wstr,su> (m_RefCount,u>) +_com_ptr_t<*>= +_LARGE_INTEGER= +_ULARGE_INTEGER= +ATL::CComPtr<*>=

+ +ATL::CComQIPtr<*>=

+ +tagVARIANT=$BUILTIN(VARIANT) +VARIANT=$BUILTIN(VARIANT) +_GUID=$BUILTIN(GUID) + +; see EEAddIn sample for how to use these +;_SYSTEMTIME=$ADDIN(EEAddIn.dll,AddIn_SystemTime) +;_FILETIME=$ADDIN(EEAddIn.dll,AddIn_FileTime) + +[Visualizer] +; This section contains visualizers for STL and ATL containers +; DO NOT MODIFY +ATL::CStringT|CSimpleStringT|ATL::CSimpleStringT{ + preview ([$e.m_pszData,s]) + stringview ([$e.m_pszData,sb]) +} +ATL::CStringT|CSimpleStringT|ATL::CSimpleStringT|ATL::CStringT|CSimpleStringT|ATL::CSimpleStringT{ + preview ([$e.m_pszData,su]) + stringview ([$e.m_pszData,sub]) +} +ATL::CComBSTR{ + preview ([$e.m_str,su]) + stringview ([$e.m_str,sub]) +} + + +; Many visualizers use nested #()s. +; Why not use #(foo, bar) instead of #(#(foo), #(bar))? +; The former alphabetically sorts its fields, while the latter does not. + +;------------------------------------------------------------------------------ +; std::pair from +;------------------------------------------------------------------------------ +std::pair<*>{ + ; pair is previewed with "(, )". + preview ( + #( + "(", + $e.first, + ", ", + $e.second, + ")" + ) + ) + + ; We gloss over the fact that first and second are actually stored in _Pair_base. + children ( + #( + #(first : $e.first), + #(second : $e.second) + ) + ) +} + +;------------------------------------------------------------------------------ +; std::plus, etc. from +;------------------------------------------------------------------------------ +; STL functors are previewed with their names. +; They have no state, so they have no children. +std::plus<*>{ + preview ( "plus" ) + children ( #array(expr: 0, size: 0) ) +} +std::minus<*>{ + preview ( "minus" ) + children ( #array(expr: 0, size: 0) ) +} +std::multiplies<*>{ + preview ( "multiplies" ) + children ( #array(expr: 0, size: 0) ) +} +std::divides<*>{ + preview ( "divides" ) + children ( #array(expr: 0, size: 0) ) +} +std::modulus<*>{ + preview ( "modulus" ) + children ( #array(expr: 0, size: 0) ) +} +std::negate<*>{ + preview ( "negate" ) + children ( #array(expr: 0, size: 0) ) +} +std::equal_to<*>{ + preview ( "equal_to" ) + children ( #array(expr: 0, size: 0) ) +} +std::not_equal_to<*>{ + preview ( "not_equal_to" ) + children ( #array(expr: 0, size: 0) ) +} +std::greater<*>{ + preview ( "greater" ) + children ( #array(expr: 0, size: 0) ) +} +std::less<*>{ + preview ( "less" ) + children ( #array(expr: 0, size: 0) ) +} +std::greater_equal<*>{ + preview ( "greater_equal" ) + children ( #array(expr: 0, size: 0) ) +} +std::less_equal<*>{ + preview ( "less_equal" ) + children ( #array(expr: 0, size: 0) ) +} +std::logical_and<*>{ + preview ( "logical_and" ) + children ( #array(expr: 0, size: 0) ) +} +std::logical_or<*>{ + preview ( "logical_or" ) + children ( #array(expr: 0, size: 0) ) +} +std::logical_not<*>{ + preview ( "logical_not" ) + children ( #array(expr: 0, size: 0) ) +} + +;------------------------------------------------------------------------------ +; std::not1() from +; std::not2() from +;------------------------------------------------------------------------------ +; STL negators are previewed with "not[12]()". +; They have a child with the fake name of [pred], so that the +; stored functor can be inspected. +std::unary_negate<*>{ + preview ( + #( + "not1(", + $e._Functor, + ")" + ) + ) + + children ( + #([pred] : $e._Functor) + ) +} +std::binary_negate<*>{ + preview ( + #( + "not2(", + $e._Functor, + ")" + ) + ) + + children ( + #([pred] : $e._Functor) + ) +} + +;------------------------------------------------------------------------------ +; std::bind1st() from +; std::bind2nd() from +;------------------------------------------------------------------------------ +; STL binders are previewed with "bind1st(, )" or "bind2nd(, )". +; We gloss over the fact that they derive from unary_function. +std::binder1st<*>{ + preview ( + #( + "bind1st(", + $e.op, + ", ", + $e.value, + ")" + ) + ) + + children ( + #( + #(op : $e.op), + #(value : $e.value) + ) + ) +} +std::binder2nd<*>{ + preview ( + #( + "bind2nd(", + $e.op, + ", ", + $e.value, + ")" + ) + ) + + children ( + #( + #(op : $e.op), + #(value : $e.value) + ) + ) +} + +;------------------------------------------------------------------------------ +; std::ptr_fun() from +;------------------------------------------------------------------------------ +; STL function pointer adaptors are previewed with "ptr_fun()". +; Function pointers have no children, so the adaptors have no children. +std::pointer_to_unary_function<*>|std::pointer_to_binary_function<*>{ + preview ( + #( + "ptr_fun(", + $e._Pfun, + ")" + ) + ) + + children ( #array(expr: 0, size: 0) ) +} + +;------------------------------------------------------------------------------ +; std::mem_fun() from +; std::mem_fun_ref() from +;------------------------------------------------------------------------------ +; See ptr_fun(). +std::mem_fun_t<*>|std::mem_fun1_t<*>|std::const_mem_fun_t<*>|std::const_mem_fun1_t<*>{ + preview ( + #( + "mem_fun(", + $e._Pmemfun, + ")" + ) + ) + + children ( #array(expr: 0, size: 0) ) +} +std::mem_fun_ref_t<*>|std::mem_fun1_ref_t<*>|std::const_mem_fun_ref_t<*>|std::const_mem_fun1_ref_t<*>{ + preview ( + #( + "mem_fun_ref(", + $e._Pmemfun, + ")" + ) + ) + + children ( #array(expr: 0, size: 0) ) +} + +;------------------------------------------------------------------------------ +; std::auto_ptr from +;------------------------------------------------------------------------------ +std::auto_ptr<*>{ + ; An empty auto_ptr is previewed with "empty". + ; Otherwise, it is previewed with "auto_ptr ". + preview ( + #if ($e._Myptr == 0) ( + "empty" + ) #else ( + #( + "auto_ptr ", + *$e._Myptr + ) + ) + ) + + ; An empty auto_ptr has no children. + ; Otherwise, it has a single child, its stored pointer, with a fake name of [ptr]. + children ( + #if ($e._Myptr == 0) ( + #array(expr: 0, size: 0) + ) #else ( + #([ptr] : $e._Myptr) + ) + ) +} + +;------------------------------------------------------------------------------ +; std::basic_string from +;------------------------------------------------------------------------------ +; basic_string is previewed with its stored string. +; It has [size] and [capacity] children, followed by [0], [1], [2], etc. children +; displaying its stored characters. +; The ($e._Myres) < ($e._BUF_SIZE) test determines whether the Small String Optimization +; is in effect. +; NOTE: The parentheses in ($e._Myres) < ($e._BUF_SIZE) are necessary. +std::basic_string{ + preview ( #if (($e._Myres) < ($e._BUF_SIZE)) ( [$e._Bx._Buf,s] ) #else ( [$e._Bx._Ptr,s] )) + stringview ( #if (($e._Myres) < ($e._BUF_SIZE)) ( [$e._Bx._Buf,sb] ) #else ( [$e._Bx._Ptr,sb] )) + + children ( + #( + #([size] : $e._Mysize), + #([capacity] : $e._Myres), + #if (($e._Myres) < ($e._BUF_SIZE)) ( + #array(expr: $e._Bx._Buf[$i], size: $e._Mysize) + ) #else ( + #array(expr: $e._Bx._Ptr[$i], size: $e._Mysize) + ) + ) + ) +} +std::basic_string|std::basic_string{ + preview ( #if (($e._Myres) < ($e._BUF_SIZE)) ( [$e._Bx._Buf,su] ) #else ( [$e._Bx._Ptr,su] )) + stringview ( #if (($e._Myres) < ($e._BUF_SIZE)) ( [$e._Bx._Buf,sub] ) #else ( [$e._Bx._Ptr,sub] )) + + children ( + #( + #([size] : $e._Mysize), + #([capacity] : $e._Myres), + #if (($e._Myres) < ($e._BUF_SIZE)) ( + #array(expr: $e._Bx._Buf[$i], size: $e._Mysize) + ) #else ( + #array(expr: $e._Bx._Ptr[$i], size: $e._Mysize) + ) + ) + ) +} +std::_String_iterator|std::_String_const_iterator{ + preview ( [$e._Ptr,s] ) + stringview ( [$e._Ptr,sb] ) + children ( #([ptr] : $e._Ptr) ) +} +std::_String_iterator|std::_String_const_iterator|std::_String_iterator|std::_String_const_iterator{ + preview ( [$e._Ptr,su] ) + stringview ( [$e._Ptr,sub] ) + children ( #([ptr] : $e._Ptr) ) +} + +;------------------------------------------------------------------------------ +; std::vector from +;------------------------------------------------------------------------------ +; Despite its packed representation, vector is visualized like vector. +std::vector{ + preview ( + #( + "[", + $e._Mysize, + "](", + #array( + expr: (bool)(($e._Myvec._Myfirst[$i / _VBITS] >> ($i % _VBITS)) & 1), + size: $e._Mysize + ), + ")" + ) + ) + + children ( + #( + #([size] : $e._Mysize), + #([capacity] : ($e._Myvec._Myend - $e._Myvec._Myfirst) * _VBITS), + #array( + expr: (bool)(($e._Myvec._Myfirst[$i / _VBITS] >> ($i % _VBITS)) & 1), + size: $e._Mysize + ) + ) + ) +} +std::_Vb_reference<*>|std::_Vb_iterator<*>|std::_Vb_const_iterator<*>{ + preview ( + (bool)((*$e._Myptr >> $e._Myoff) & 1) + ) + + children ( + #( + #([ptr] : $e._Myptr), + #([offset] : $e._Myoff) + ) + ) +} + +;------------------------------------------------------------------------------ +; std::vector from +;------------------------------------------------------------------------------ +; vector is previewed with "[]()". +; It has [size] and [capacity] children, followed by its elements. +; The other containers follow its example. +std::vector<*>{ + preview ( + #( + "[", + $e._Mylast - $e._Myfirst, + "](", + #array( + expr: $e._Myfirst[$i], + size: $e._Mylast - $e._Myfirst + ), + ")" + ) + ) + + children ( + #( + #([size] : $e._Mylast - $e._Myfirst), + #([capacity] : $e._Myend - $e._Myfirst), + #array( + expr: $e._Myfirst[$i], + size: $e._Mylast - $e._Myfirst + ) + ) + ) +} +std::_Vector_iterator<*>|std::_Vector_const_iterator<*>{ + preview ( + *$e._Ptr + ) + + children ( + #([ptr] : $e._Ptr) + ) +} + +;------------------------------------------------------------------------------ +; std::deque from +;------------------------------------------------------------------------------ +std::deque<*>{ + preview ( + #( + "[", + $e._Mysize, + "](", + #array( + expr: $e._Map[(($i + $e._Myoff) / $e._EEN_DS) % $e._Mapsize][($i + $e._Myoff) % $e._EEN_DS], + size: $e._Mysize + ), + ")" + ) + ) + + children ( + #( + #array( + expr: $e._Map[(($i + $e._Myoff) / $e._EEN_DS) % $e._Mapsize][($i + $e._Myoff) % $e._EEN_DS], + size: $e._Mysize + ) + ) + ) +} +std::_Deque_iterator<*,*>|std::_Deque_const_iterator<*,*>{ + preview ( + #if ($e._Myoff >= ((std::deque<$T1,$T2> *)$e._Myproxy->_Mycont)->_Myoff + ((std::deque<$T1,$T2> *)$e._Myproxy->_Mycont)->_Mysize) ( + "end" + ) #else ( + ((std::deque<$T1,$T2> *)$e._Myproxy->_Mycont)->_Map[($e._Myoff / ((std::deque<$T1,$T2> *)$e._Myproxy->_Mycont)->_EEN_DS) % ((std::deque<$T1,$T2> *)$e._Myproxy->_Mycont)->_Mapsize][$e._Myoff % ((std::deque<$T1,$T2> *)$e._Myproxy->_Mycont)->_EEN_DS] + ) + ) + + children ( + #if ($e._Myoff >= ((std::deque<$T1,$T2> *)$e._Myproxy->_Mycont)->_Myoff + ((std::deque<$T1,$T2> *)$e._Myproxy->_Mycont)->_Mysize) ( + #array(expr: 0, size: 0) + ) #else ( + #( + #([index] : $e._Myoff - ((std::deque<$T1,$T2> *)$e._Myproxy->_Mycont)->_Myoff), + #([ptr] : &((std::deque<$T1,$T2> *)$e._Myproxy->_Mycont)->_Map[($e._Myoff / ((std::deque<$T1,$T2> *)$e._Myproxy->_Mycont)->_EEN_DS) % ((std::deque<$T1,$T2> *)$e._Myproxy->_Mycont)->_Mapsize][$e._Myoff % ((std::deque<$T1,$T2> *)$e._Myproxy->_Mycont)->_EEN_DS] ) + ) + ) + ) +} + +;------------------------------------------------------------------------------ +; std::list from +;------------------------------------------------------------------------------ +std::list<*>{ + preview ( + #( + "[", + $e._Mysize, + "](", + #list( + head: $e._Myhead->_Next, + size: $e._Mysize, + next: _Next + ) : $e._Myval, + ")" + ) + ) + + children ( + #list( + head: $e._Myhead->_Next, + size: $e._Mysize, + next: _Next + ) : $e._Myval + ) +} +std::_List_iterator<*>|std::_List_const_iterator<*>{ + preview ( $e._Ptr->_Myval ) + children ( #([ptr] : &$e._Ptr->_Myval) ) +} + +;------------------------------------------------------------------------------ +; std::queue from +; std::stack from +;------------------------------------------------------------------------------ +std::queue<*>|std::stack<*>{ + preview ( $e.c ) + children ( #(c : $e.c) ) +} + +;------------------------------------------------------------------------------ +; std::priority_queue from +;------------------------------------------------------------------------------ +std::priority_queue<*>{ + preview ( $e.c ) + + children ( + #( + #(c [heap]: $e.c), + #(comp : $e.comp) + ) + ) +} + +;------------------------------------------------------------------------------ +; std::map from +; std::multimap from +; std::set from +; std::multiset from +;------------------------------------------------------------------------------ +std::map<*>|std::multimap<*>|std::set<*>|std::multiset<*>{ + preview ( + #( + "[", + $e._Mysize, + "](", + #tree( + head: $e._Myhead->_Parent, + skip: $e._Myhead, + left: _Left, + right: _Right, + size: $e._Mysize + ) : $e._Myval, + ")" + ) + ) + + children ( + #( + #([comp] : $e.comp), + #tree( + head: $e._Myhead->_Parent, + skip: $e._Myhead, + left: _Left, + right: _Right, + size: $e._Mysize + ) : $e._Myval + ) + ) +} +std::_Tree_iterator<*>|std::_Tree_const_iterator<*>{ + preview ( $e._Ptr->_Myval ) + children ( #([ptr] : &$e._Ptr->_Myval) ) +} + +;------------------------------------------------------------------------------ +; std::bitset from +;------------------------------------------------------------------------------ +std::bitset<*>{ + preview ( + #( + "[", + $e._EEN_BITS, + "](", + #array( + expr: [($e._Array[$i / $e._Bitsperword] >> ($i % $e._Bitsperword)) & 1,d], + size: $e._EEN_BITS + ), + ")" + ) + ) + + children ( + #array( + expr: [($e._Array[$i / $e._Bitsperword] >> ($i % $e._Bitsperword)) & 1,d], + size: $e._EEN_BITS + ) + ) +} +std::bitset<*>::reference{ + preview ( + [($e._Pbitset->_Array[$i / $e._Pbitset->_Bitsperword] >> ($e._Mypos % $e._Pbitset->_Bitsperword)) & 1,d] + ) + + children ( + #( + #([bitset] : $e._Pbitset), + #([pos] : $e._Mypos) + ) + ) +} + +;------------------------------------------------------------------------------ +; std::reverse_iterator from +;------------------------------------------------------------------------------ +std::reverse_iterator >|std::reverse_iterator >{ + preview ( + #( + "reverse_iterator to ", + $e.current._Ptr[-1] + ) + ) + + children ( + #( + #([to] : $e.current._Ptr - 1), + #(current : $e.current) + ) + ) +} +std::reverse_iterator >|std::reverse_iterator >{ + preview ( + #( + "reverse_iterator to ", + #if ($e.current._Myoff != 0) ( + (bool)((*$e.current._Myptr >> ($e.current._Myoff - 1)) & 1) + ) #else ( + (bool)(($e.current._Myptr[-1] >> (_VBITS - 1)) & 1) + ) + ) + ) + + children ( + #if ($e.current._Myoff != 0) ( + #( + #([to ptr] : $e.current._Myptr), + #([to offset] : $e.current._Myoff - 1), + #(current : $e.current) + ) + ) #else ( + #( + #([to ptr] : $e.current._Myptr - 1), + #([to offset] : _VBITS - 1), + #(current : $e.current) + ) + ) + ) +} +std::reverse_iterator >|std::reverse_iterator >{ + preview ( + #( + "reverse_iterator to ", + $e.current._Ptr[-1] + ) + ) + + children ( + #( + #([to] : $e.current._Ptr - 1), + #(current : $e.current) + ) + ) +} +std::reverse_iterator >|std::reverse_iterator >{ + preview ( + #( + "reverse_iterator to ", + #if ($e.current._Myoff == ((std::deque<$T1,$T2> *)$e.current._Myproxy->_Mycont)->_Myoff) ( + "end" + ) #else ( + ((std::deque<$T1,$T2> *)$e.current._Myproxy->_Mycont)->_Map[(($e.current._Myoff - 1) / ((std::deque<$T1,$T2> *)$e.current._Myproxy->_Mycont)->_EEN_DS) % ((std::deque<$T1,$T2> *)$e.current._Myproxy->_Mycont)->_Mapsize][($e.current._Myoff - 1) % ((std::deque<$T1,$T2> *)$e.current._Myproxy->_Mycont)->_EEN_DS] + ) + ) + ) + + children ( + #if ($e.current._Myoff == ((std::deque<$T1,$T2> *)$e.current._Myproxy->_Mycont)->_Myoff) ( + #(current : $e.current) + ) #else ( + #( + #([to index] : ($e.current._Myoff - 1) - ((std::deque<$T1,$T2> *)$e.current._Myproxy->_Mycont)->_Myoff), + #([to ptr] : &((std::deque<$T1,$T2> *)$e.current._Myproxy->_Mycont)->_Map[(($e.current._Myoff - 1) / ((std::deque<$T1,$T2> *)$e.current._Myproxy->_Mycont)->_EEN_DS) % ((std::deque<$T1,$T2> *)$e.current._Myproxy->_Mycont)->_Mapsize][($e.current._Myoff - 1) % ((std::deque<$T1,$T2> *)$e.current._Myproxy->_Mycont)->_EEN_DS] ), + #(current : $e.current) + ) + ) + ) +} +std::reverse_iterator >|std::reverse_iterator >{ + preview ( + #( + "reverse_iterator to ", + $e.current._Ptr->_Prev->_Myval + ) + ) + + children ( + #( + #([to] : &$e.current._Ptr->_Prev->_Myval), + #(current : $e.current) + ) + ) +} +std::reverse_iterator >|std::reverse_iterator >{ + preview ( + #( + "reverse_iterator to ", + #if ($e.current._EEN_IDL == 0) ( + $e.current._Ptr[-1] + ) #else ( + #if ($e.current._Idx == 0) ( + "end" + ) #else ( + $e.current._Ptr[$e.current._Idx - 1] + ) + ) + ) + ) + + children ( + #if ($e.current._EEN_IDL == 0) ( + #( + #([to] : $e.current._Ptr - 1), + #(current : $e.current) + ) + ) #else ( + #if ($e.current._Idx == 0) ( + #(current : $e.current) + ) #else ( + #( + #([to] : $e.current._Ptr + $e.current._Idx - 1), + #(current : $e.current) + ) + ) + ) + ) +} +std::reverse_iterator<*>{ + preview ( + #( + "reverse_iterator current ", + $e.current + ) + ) + + children ( + #(current : $e.current) + ) +} + +;------------------------------------------------------------------------------ +; std::complex from +;------------------------------------------------------------------------------ +std::complex<*>{ + preview ( + #if ($e._Val[1] == 0) ( + ; Purely real. + $e._Val[0] + ) #else ( + #if ($e._Val[0] == 0) ( + ; Purely imaginary. + #if ($e._Val[1] < 0) ( + #("-i*", -$e._Val[1]) + ) #else ( + #("i*", $e._Val[1]) + ) + ) #else ( + ; Mixed. + #if ($e._Val[1] < 0) ( + #($e._Val[0], "-i*", -$e._Val[1]) + ) #else ( + #($e._Val[0], "+i*", $e._Val[1]) + ) + ) + ) + ) + + children ( + #( + #(real : $e._Val[0]), + #(imag : $e._Val[1]) + ) + ) +} + +;------------------------------------------------------------------------------ +; std::valarray from +;------------------------------------------------------------------------------ +std::valarray<*>{ + preview ( + #( + "[", + $e._Mysize, + "](", + #array( + expr: $e._Myptr[$i], + size: $e._Mysize + ), + ")" + ) + ) + + children ( + #array( + expr: $e._Myptr[$i], + size: $e._Mysize + ) + ) +} + +;------------------------------------------------------------------------------ +; std::tr1::reference_wrapper from +;------------------------------------------------------------------------------ +std::tr1::reference_wrapper<*>{ + preview ( + #if ($e._Callee._EEN_INDIRECT == 1) ( + ; For ordinary T, reference_wrapper stores a T * _Callee._Ptr + ; which is non-null. Actual references are previewed with what they + ; refer to, so reference_wrapper is previewed with dereferencing its + ; stored pointer. + *$e._Callee._Ptr + ) #else ( + ; When T is a pointer to data member type, reference_wrapper + ; stores a T _Callee._Object directly. + $e._Callee._Object + ) + ) + + children ( + #if ($e._Callee._EEN_INDIRECT == 1) ( + ; Actual references have the same children as what they refer to. + ; Unfortunately, there appears to be no way to imitate this exactly. + ; Therefore, we make reference_wrapper appear to have a single + ; child, its stored pointer, with a fake name of [ptr]. + #([ptr] : $e._Callee._Ptr) + ) #else ( + ; When T is a pointer to data member type, T has no children, + ; so we make reference_wrapper appear to have no children. + #array(expr: 0, size: 0) + ) + ) +} + +;------------------------------------------------------------------------------ +; std::tr1::shared_ptr from +;------------------------------------------------------------------------------ +std::tr1::_Ref_count<*>{ + preview ( "default" ) + children ( #array(expr: 0, size: 0) ) +} +std::tr1::_Ref_count_del<*>{ + preview ( "custom deleter" ) + children ( #([deleter] : $e._Dtor) ) +} +std::tr1::_Ref_count_del_alloc<*>{ + preview ( "custom deleter, custom allocator" ) + children ( + #( + #([deleter] : $e._Dtor), + #([allocator] : $e._Myal) + ) + ) +} +std::tr1::_Ref_count_obj<*>{ + preview ( "make_shared" ) + children ( #array(expr: 0, size: 0) ) +} +std::tr1::_Ref_count_obj_alloc<*>{ + preview ( "allocate_shared" ) + children ( #([allocator] : $e._Myal) ) +} +std::tr1::shared_ptr<*>{ + preview ( + ; shared_ptr stores a T * _Ptr . + #if ($e._Ptr == 0) ( + ; A default-constructed shared_ptr has a null _Ptr and a null _Rep, + ; and is formally said to be empty. + ; A shared_ptr constructed from a null pointer has a null _Ptr + ; and a NON-null _Rep . It is formally said to own the null pointer. + ; We preview both with "empty". + "empty" + ) #else ( + ; Raw pointers are previewed with " ". + ; auto_ptr is previewed with "auto_ptr ". + ; Following these examples, shared_ptr is previewed with + ; "shared_ptr [N strong refs, M weak refs]". + #( + "shared_ptr ", + *$e._Ptr, + " [", + $e._Rep->_Uses, + #if ($e._Rep->_Uses == 1) (" strong ref") #else (" strong refs"), + #if ($e._Rep->_Weaks - 1 > 0) ( + #( + ", ", + $e._Rep->_Weaks - 1, + #if ($e._Rep->_Weaks - 1 == 1) (" weak ref") #else (" weak refs") + ) + ), + "] [", + *$e._Rep, + "]" + ) + ; Note: _Rep->_Uses counts how many shared_ptrs share ownership of the object, + ; so we directly display it as the strong reference count. + ; _Rep->_Weaks counts how many shared_ptrs and weak_ptrs share ownership of + ; the "representation object" (or "control block"). All of the shared_ptrs are + ; counted as a single owner. That is, _Weaks is initialized to 1, and when + ; _Uses falls to 0, _Weaks is decremented. This avoids incrementing and decrementing + ; _Weaks every time that a shared_ptr gains or loses ownership. Therefore, + ; _Weaks - 1 is the weak reference count, the number of weak_ptrs that are observing + ; the shared object. + ) + ) + + children ( + #if ($e._Ptr == 0) ( + ; We make empty shared_ptrs (and shared_ptrs that own + ; the null pointer) appear to have no children. + #array(expr: 0, size: 0) + ) #else ( + #( + ; We make shared_ptr appear to have two children: + + ; Its stored pointer, with a fake name of [ptr]. + #([ptr] : $e._Ptr), + + ; Its deleter and allocator, which may be default or custom. + #([deleter and allocator] : *$e._Rep) + ) + ) + ) +} + +;------------------------------------------------------------------------------ +; std::tr1::weak_ptr from +;------------------------------------------------------------------------------ +std::tr1::weak_ptr<*>{ + preview ( + #if ($e._Ptr == 0) ( + "empty" + ) #elif ($e._Rep->_Uses == 0) ( + ; weak_ptr is just like shared_ptr, except that a weak_ptr can be expired. + #( + "expired [", + *$e._Rep, + "]" + ) + ) #else ( + #( + "weak_ptr ", + *$e._Ptr, + " [", + $e._Rep->_Uses, + #if ($e._Rep->_Uses == 1) (" strong ref") #else (" strong refs"), + #if ($e._Rep->_Weaks - 1 > 0) ( + #( + ", ", + $e._Rep->_Weaks - 1, + #if ($e._Rep->_Weaks - 1 == 1) (" weak ref") #else (" weak refs") + ) + ), + "] [", + *$e._Rep, + "]" + ) + ) + ) + + children ( + #if ($e._Ptr == 0) ( + #array(expr: 0, size: 0) + ) #elif ($e._Rep->_Uses == 0) ( + ; When a weak_ptr is expired, we show its deleter and allocator. + ; The deleter has already been used, but the control block has not yet been deallocated. + #([deleter and allocator] : *$e._Rep) + ) #else ( + #( + #([ptr] : $e._Ptr), + #([deleter and allocator] : *$e._Rep) + ) + ) + ) +} + +;------------------------------------------------------------------------------ +; std::tr1::mem_fn() from +;------------------------------------------------------------------------------ +; Note that when mem_fn() is given a data member pointer, it returns a _Call_wrapper<_Callable_pmd<*> > . +; Data member pointers themselves don't have useful previews, so we don't attempt to visualize this. +; When mem_fn() is given a member function pointer, it returns a _Mem_fn[N], which we can visualize. +std::tr1::_Mem_fn1<*>|std::tr1::_Mem_fn2<*>|std::tr1::_Mem_fn3<*>|std::tr1::_Mem_fn4<*>|std::tr1::_Mem_fn5<*>|std::tr1::_Mem_fn6<*>|std::tr1::_Mem_fn7<*>|std::tr1::_Mem_fn8<*>|std::tr1::_Mem_fn9<*>|std::tr1::_Mem_fn10<*>{ + preview ( + ; We preview the functor returned by mem_fn() with "mem_fn()". + #( + "mem_fn(", + $e._Callee._Object, + ")" + ) + ) + + children ( + ; Member function pointers have no children. + #array(expr: 0, size: 0) + ) +} + +;------------------------------------------------------------------------------ +; std::tr1::bind() from +;------------------------------------------------------------------------------ +; bind() placeholders are previewed with their names. +; They have no state, so they have no children. +std::tr1::_Ph<1>{ + preview ( "_1" ) + children ( #array(expr: 0, size: 0) ) +} +std::tr1::_Ph<2>{ + preview ( "_2" ) + children ( #array(expr: 0, size: 0) ) +} +std::tr1::_Ph<3>{ + preview ( "_3" ) + children ( #array(expr: 0, size: 0) ) +} +std::tr1::_Ph<4>{ + preview ( "_4" ) + children ( #array(expr: 0, size: 0) ) +} +std::tr1::_Ph<5>{ + preview ( "_5" ) + children ( #array(expr: 0, size: 0) ) +} +std::tr1::_Ph<6>{ + preview ( "_6" ) + children ( #array(expr: 0, size: 0) ) +} +std::tr1::_Ph<7>{ + preview ( "_7" ) + children ( #array(expr: 0, size: 0) ) +} +std::tr1::_Ph<8>{ + preview ( "_8" ) + children ( #array(expr: 0, size: 0) ) +} +std::tr1::_Ph<9>{ + preview ( "_9" ) + children ( #array(expr: 0, size: 0) ) +} +std::tr1::_Ph<10>{ + preview ( "_10" ) + children ( #array(expr: 0, size: 0) ) +} + +; The functor returned by bind(f, t1, t2) is previewed with "bind(f, t1, t2)". +; It has children with the fake names of [f], [t1], [t2], etc. +std::tr1::_Bind<*,*,std::tr1::_Bind0<*> >|std::tr1::_Bind_fty<*,*,std::tr1::_Bind0<*> >{ + preview ( + #( + "bind(", $e._Bx._Callee._Object, + ")" + ) + ) + + children ( + #( + #([f] : $e._Bx._Callee._Object) + ) + ) +} +std::tr1::_Bind<*,*,std::tr1::_Bind1<*> >|std::tr1::_Bind_fty<*,*,std::tr1::_Bind1<*> >{ + preview ( + #( + "bind(", $e._Bx._Callee._Object, + ", ", $e._Bx._Vx0, + ")" + ) + ) + + children ( + #( + #([f] : $e._Bx._Callee._Object), + #([t1] : $e._Bx._Vx0) + ) + ) +} +std::tr1::_Bind<*,*,std::tr1::_Bind2<*> >|std::tr1::_Bind_fty<*,*,std::tr1::_Bind2<*> >{ + preview ( + #( + "bind(", $e._Bx._Callee._Object, + ", ", $e._Bx._Vx0, + ", ", $e._Bx._Vx1, + ")" + ) + ) + + children ( + #( + #([f] : $e._Bx._Callee._Object), + #([t1] : $e._Bx._Vx0), + #([t2] : $e._Bx._Vx1) + ) + ) +} +std::tr1::_Bind<*,*,std::tr1::_Bind3<*> >|std::tr1::_Bind_fty<*,*,std::tr1::_Bind3<*> >{ + preview ( + #( + "bind(", $e._Bx._Callee._Object, + ", ", $e._Bx._Vx0, + ", ", $e._Bx._Vx1, + ", ", $e._Bx._Vx2, + ")" + ) + ) + + children ( + #( + #([f] : $e._Bx._Callee._Object), + #([t1] : $e._Bx._Vx0), + #([t2] : $e._Bx._Vx1), + #([t3] : $e._Bx._Vx2) + ) + ) +} +std::tr1::_Bind<*,*,std::tr1::_Bind4<*> >|std::tr1::_Bind_fty<*,*,std::tr1::_Bind4<*> >{ + preview ( + #( + "bind(", $e._Bx._Callee._Object, + ", ", $e._Bx._Vx0, + ", ", $e._Bx._Vx1, + ", ", $e._Bx._Vx2, + ", ", $e._Bx._Vx3, + ")" + ) + ) + + children ( + #( + #([f] : $e._Bx._Callee._Object), + #([t1] : $e._Bx._Vx0), + #([t2] : $e._Bx._Vx1), + #([t3] : $e._Bx._Vx2), + #([t4] : $e._Bx._Vx3) + ) + ) +} +std::tr1::_Bind<*,*,std::tr1::_Bind5<*> >|std::tr1::_Bind_fty<*,*,std::tr1::_Bind5<*> >{ + preview ( + #( + "bind(", $e._Bx._Callee._Object, + ", ", $e._Bx._Vx0, + ", ", $e._Bx._Vx1, + ", ", $e._Bx._Vx2, + ", ", $e._Bx._Vx3, + ", ", $e._Bx._Vx4, + ")" + ) + ) + + children ( + #( + #([f] : $e._Bx._Callee._Object), + #([t1] : $e._Bx._Vx0), + #([t2] : $e._Bx._Vx1), + #([t3] : $e._Bx._Vx2), + #([t4] : $e._Bx._Vx3), + #([t5] : $e._Bx._Vx4) + ) + ) +} +std::tr1::_Bind<*,*,std::tr1::_Bind6<*> >|std::tr1::_Bind_fty<*,*,std::tr1::_Bind6<*> >{ + preview ( + #( + "bind(", $e._Bx._Callee._Object, + ", ", $e._Bx._Vx0, + ", ", $e._Bx._Vx1, + ", ", $e._Bx._Vx2, + ", ", $e._Bx._Vx3, + ", ", $e._Bx._Vx4, + ", ", $e._Bx._Vx5, + ")" + ) + ) + + children ( + #( + #([f] : $e._Bx._Callee._Object), + #([t1] : $e._Bx._Vx0), + #([t2] : $e._Bx._Vx1), + #([t3] : $e._Bx._Vx2), + #([t4] : $e._Bx._Vx3), + #([t5] : $e._Bx._Vx4), + #([t6] : $e._Bx._Vx5) + ) + ) +} +std::tr1::_Bind<*,*,std::tr1::_Bind7<*> >|std::tr1::_Bind_fty<*,*,std::tr1::_Bind7<*> >{ + preview ( + #( + "bind(", $e._Bx._Callee._Object, + ", ", $e._Bx._Vx0, + ", ", $e._Bx._Vx1, + ", ", $e._Bx._Vx2, + ", ", $e._Bx._Vx3, + ", ", $e._Bx._Vx4, + ", ", $e._Bx._Vx5, + ", ", $e._Bx._Vx6, + ")" + ) + ) + + children ( + #( + #([f] : $e._Bx._Callee._Object), + #([t1] : $e._Bx._Vx0), + #([t2] : $e._Bx._Vx1), + #([t3] : $e._Bx._Vx2), + #([t4] : $e._Bx._Vx3), + #([t5] : $e._Bx._Vx4), + #([t6] : $e._Bx._Vx5), + #([t7] : $e._Bx._Vx6) + ) + ) +} +std::tr1::_Bind<*,*,std::tr1::_Bind8<*> >|std::tr1::_Bind_fty<*,*,std::tr1::_Bind8<*> >{ + preview ( + #( + "bind(", $e._Bx._Callee._Object, + ", ", $e._Bx._Vx0, + ", ", $e._Bx._Vx1, + ", ", $e._Bx._Vx2, + ", ", $e._Bx._Vx3, + ", ", $e._Bx._Vx4, + ", ", $e._Bx._Vx5, + ", ", $e._Bx._Vx6, + ", ", $e._Bx._Vx7, + ")" + ) + ) + + children ( + #( + #([f] : $e._Bx._Callee._Object), + #([t1] : $e._Bx._Vx0), + #([t2] : $e._Bx._Vx1), + #([t3] : $e._Bx._Vx2), + #([t4] : $e._Bx._Vx3), + #([t5] : $e._Bx._Vx4), + #([t6] : $e._Bx._Vx5), + #([t7] : $e._Bx._Vx6), + #([t8] : $e._Bx._Vx7) + ) + ) +} +std::tr1::_Bind<*,*,std::tr1::_Bind9<*> >|std::tr1::_Bind_fty<*,*,std::tr1::_Bind9<*> >{ + preview ( + #( + "bind(", $e._Bx._Callee._Object, + ", ", $e._Bx._Vx0, + ", ", $e._Bx._Vx1, + ", ", $e._Bx._Vx2, + ", ", $e._Bx._Vx3, + ", ", $e._Bx._Vx4, + ", ", $e._Bx._Vx5, + ", ", $e._Bx._Vx6, + ", ", $e._Bx._Vx7, + ", ", $e._Bx._Vx8, + ")" + ) + ) + + children ( + #( + #([f] : $e._Bx._Callee._Object), + #([t1] : $e._Bx._Vx0), + #([t2] : $e._Bx._Vx1), + #([t3] : $e._Bx._Vx2), + #([t4] : $e._Bx._Vx3), + #([t5] : $e._Bx._Vx4), + #([t6] : $e._Bx._Vx5), + #([t7] : $e._Bx._Vx6), + #([t8] : $e._Bx._Vx7), + #([t9] : $e._Bx._Vx8) + ) + ) +} +std::tr1::_Bind<*,*,std::tr1::_Bind10<*> >|std::tr1::_Bind_fty<*,*,std::tr1::_Bind10<*> >{ + preview ( + #( + "bind(", $e._Bx._Callee._Object, + ", ", $e._Bx._Vx0, + ", ", $e._Bx._Vx1, + ", ", $e._Bx._Vx2, + ", ", $e._Bx._Vx3, + ", ", $e._Bx._Vx4, + ", ", $e._Bx._Vx5, + ", ", $e._Bx._Vx6, + ", ", $e._Bx._Vx7, + ", ", $e._Bx._Vx8, + ", ", $e._Bx._Vx9, + ")" + ) + ) + + children ( + #( + #([f] : $e._Bx._Callee._Object), + #([t1] : $e._Bx._Vx0), + #([t2] : $e._Bx._Vx1), + #([t3] : $e._Bx._Vx2), + #([t4] : $e._Bx._Vx3), + #([t5] : $e._Bx._Vx4), + #([t6] : $e._Bx._Vx5), + #([t7] : $e._Bx._Vx6), + #([t8] : $e._Bx._Vx7), + #([t9] : $e._Bx._Vx8), + #([t10] : $e._Bx._Vx9) + ) + ) +} + +;------------------------------------------------------------------------------ +; std::tr1::function from +;------------------------------------------------------------------------------ +std::tr1::_Impl_no_alloc0<*>|std::tr1::_Impl_no_alloc1<*>|std::tr1::_Impl_no_alloc2<*>|std::tr1::_Impl_no_alloc3<*>|std::tr1::_Impl_no_alloc4<*>|std::tr1::_Impl_no_alloc5<*>|std::tr1::_Impl_no_alloc6<*>|std::tr1::_Impl_no_alloc7<*>|std::tr1::_Impl_no_alloc8<*>|std::tr1::_Impl_no_alloc9<*>|std::tr1::_Impl_no_alloc10<*>{ + preview ( $e._Callee._Object ) + children ( #([functor] : $e._Callee._Object) ) +} +std::tr1::_Impl0<*>|std::tr1::_Impl1<*>|std::tr1::_Impl2<*>|std::tr1::_Impl3<*>|std::tr1::_Impl4<*>|std::tr1::_Impl5<*>|std::tr1::_Impl6<*>|std::tr1::_Impl7<*>|std::tr1::_Impl8<*>|std::tr1::_Impl9<*>|std::tr1::_Impl10<*>{ + preview ( $e._Callee._Object ) + children ( + #( + #([functor] : $e._Callee._Object), + #([allocator] : $e._Myal) + ) + ) +} +std::tr1::function<*>{ + preview ( + #if ($e._Impl == 0) ( + ; Detecting empty functions is trivial. + "empty" + ) #else ( + *$e._Impl + ) + ) + + children ( + #if ($e._Impl == 0) ( + ; We make empty functions appear to have no children. + #array(expr: 0, size: 0) + ) #else ( + #([functor and allocator] : *$e._Impl) + ) + ) +} + +;------------------------------------------------------------------------------ +; std::tr1::tuple from +;------------------------------------------------------------------------------ +; tuple is visualized like pair, except that we have to give fake names to tuple's children. +std::tr1::tuple{ + preview ( + "()" + ) + + children ( + #array(expr: 0, size: 0) + ) +} +std::tr1::tuple<*,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil>{ + preview ( + #( + "(", $e._Impl._Value, + ")" + ) + ) + + children ( + #( + [0] : $e._Impl._Value + ) + ) +} +std::tr1::tuple<*,*,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil>{ + preview ( + #( + "(", $e._Impl._Value, + ", ", $e._Impl._Tail._Value, + ")" + ) + ) + + children ( + #( + [0] : $e._Impl._Value, + [1] : $e._Impl._Tail._Value + ) + ) +} +std::tr1::tuple<*,*,*,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil>{ + preview ( + #( + "(", $e._Impl._Value, + ", ", $e._Impl._Tail._Value, + ", ", $e._Impl._Tail._Tail._Value, + ")" + ) + ) + + children ( + #( + [0] : $e._Impl._Value, + [1] : $e._Impl._Tail._Value, + [2] : $e._Impl._Tail._Tail._Value + ) + ) +} +std::tr1::tuple<*,*,*,*,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil>{ + preview ( + #( + "(", $e._Impl._Value, + ", ", $e._Impl._Tail._Value, + ", ", $e._Impl._Tail._Tail._Value, + ", ", $e._Impl._Tail._Tail._Tail._Value, + ")" + ) + ) + + children ( + #( + [0] : $e._Impl._Value, + [1] : $e._Impl._Tail._Value, + [2] : $e._Impl._Tail._Tail._Value, + [3] : $e._Impl._Tail._Tail._Tail._Value + ) + ) +} +std::tr1::tuple<*,*,*,*,*,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil>{ + preview ( + #( + "(", $e._Impl._Value, + ", ", $e._Impl._Tail._Value, + ", ", $e._Impl._Tail._Tail._Value, + ", ", $e._Impl._Tail._Tail._Tail._Value, + ", ", $e._Impl._Tail._Tail._Tail._Tail._Value, + ")" + ) + ) + + children ( + #( + [0] : $e._Impl._Value, + [1] : $e._Impl._Tail._Value, + [2] : $e._Impl._Tail._Tail._Value, + [3] : $e._Impl._Tail._Tail._Tail._Value, + [4] : $e._Impl._Tail._Tail._Tail._Tail._Value + ) + ) +} +std::tr1::tuple<*,*,*,*,*,*,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil>{ + preview ( + #( + "(", $e._Impl._Value, + ", ", $e._Impl._Tail._Value, + ", ", $e._Impl._Tail._Tail._Value, + ", ", $e._Impl._Tail._Tail._Tail._Value, + ", ", $e._Impl._Tail._Tail._Tail._Tail._Value, + ", ", $e._Impl._Tail._Tail._Tail._Tail._Tail._Value, + ")" + ) + ) + + children ( + #( + [0] : $e._Impl._Value, + [1] : $e._Impl._Tail._Value, + [2] : $e._Impl._Tail._Tail._Value, + [3] : $e._Impl._Tail._Tail._Tail._Value, + [4] : $e._Impl._Tail._Tail._Tail._Tail._Value, + [5] : $e._Impl._Tail._Tail._Tail._Tail._Tail._Value + ) + ) +} +std::tr1::tuple<*,*,*,*,*,*,*,std::tr1::_Nil,std::tr1::_Nil,std::tr1::_Nil>{ + preview ( + #( + "(", $e._Impl._Value, + ", ", $e._Impl._Tail._Value, + ", ", $e._Impl._Tail._Tail._Value, + ", ", $e._Impl._Tail._Tail._Tail._Value, + ", ", $e._Impl._Tail._Tail._Tail._Tail._Value, + ", ", $e._Impl._Tail._Tail._Tail._Tail._Tail._Value, + ", ", $e._Impl._Tail._Tail._Tail._Tail._Tail._Tail._Value, + ")" + ) + ) + + children ( + #( + [0] : $e._Impl._Value, + [1] : $e._Impl._Tail._Value, + [2] : $e._Impl._Tail._Tail._Value, + [3] : $e._Impl._Tail._Tail._Tail._Value, + [4] : $e._Impl._Tail._Tail._Tail._Tail._Value, + [5] : $e._Impl._Tail._Tail._Tail._Tail._Tail._Value, + [6] : $e._Impl._Tail._Tail._Tail._Tail._Tail._Tail._Value + ) + ) +} +std::tr1::tuple<*,*,*,*,*,*,*,*,std::tr1::_Nil,std::tr1::_Nil>{ + preview ( + #( + "(", $e._Impl._Value, + ", ", $e._Impl._Tail._Value, + ", ", $e._Impl._Tail._Tail._Value, + ", ", $e._Impl._Tail._Tail._Tail._Value, + ", ", $e._Impl._Tail._Tail._Tail._Tail._Value, + ", ", $e._Impl._Tail._Tail._Tail._Tail._Tail._Value, + ", ", $e._Impl._Tail._Tail._Tail._Tail._Tail._Tail._Value, + ", ", $e._Impl._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Value, + ")" + ) + ) + + children ( + #( + [0] : $e._Impl._Value, + [1] : $e._Impl._Tail._Value, + [2] : $e._Impl._Tail._Tail._Value, + [3] : $e._Impl._Tail._Tail._Tail._Value, + [4] : $e._Impl._Tail._Tail._Tail._Tail._Value, + [5] : $e._Impl._Tail._Tail._Tail._Tail._Tail._Value, + [6] : $e._Impl._Tail._Tail._Tail._Tail._Tail._Tail._Value, + [7] : $e._Impl._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Value + ) + ) +} +std::tr1::tuple<*,*,*,*,*,*,*,*,*,std::tr1::_Nil>{ + preview ( + #( + "(", $e._Impl._Value, + ", ", $e._Impl._Tail._Value, + ", ", $e._Impl._Tail._Tail._Value, + ", ", $e._Impl._Tail._Tail._Tail._Value, + ", ", $e._Impl._Tail._Tail._Tail._Tail._Value, + ", ", $e._Impl._Tail._Tail._Tail._Tail._Tail._Value, + ", ", $e._Impl._Tail._Tail._Tail._Tail._Tail._Tail._Value, + ", ", $e._Impl._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Value, + ", ", $e._Impl._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Value, + ")" + ) + ) + + children ( + #( + [0] : $e._Impl._Value, + [1] : $e._Impl._Tail._Value, + [2] : $e._Impl._Tail._Tail._Value, + [3] : $e._Impl._Tail._Tail._Tail._Value, + [4] : $e._Impl._Tail._Tail._Tail._Tail._Value, + [5] : $e._Impl._Tail._Tail._Tail._Tail._Tail._Value, + [6] : $e._Impl._Tail._Tail._Tail._Tail._Tail._Tail._Value, + [7] : $e._Impl._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Value, + [8] : $e._Impl._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Value + ) + ) +} +std::tr1::tuple<*,*,*,*,*,*,*,*,*,*>{ + preview ( + #( + "(", $e._Impl._Value, + ", ", $e._Impl._Tail._Value, + ", ", $e._Impl._Tail._Tail._Value, + ", ", $e._Impl._Tail._Tail._Tail._Value, + ", ", $e._Impl._Tail._Tail._Tail._Tail._Value, + ", ", $e._Impl._Tail._Tail._Tail._Tail._Tail._Value, + ", ", $e._Impl._Tail._Tail._Tail._Tail._Tail._Tail._Value, + ", ", $e._Impl._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Value, + ", ", $e._Impl._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Value, + ", ", $e._Impl._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Value, + ")" + ) + ) + + children ( + #( + [0] : $e._Impl._Value, + [1] : $e._Impl._Tail._Value, + [2] : $e._Impl._Tail._Tail._Value, + [3] : $e._Impl._Tail._Tail._Tail._Value, + [4] : $e._Impl._Tail._Tail._Tail._Tail._Value, + [5] : $e._Impl._Tail._Tail._Tail._Tail._Tail._Value, + [6] : $e._Impl._Tail._Tail._Tail._Tail._Tail._Tail._Value, + [7] : $e._Impl._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Value, + [8] : $e._Impl._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Value, + [9] : $e._Impl._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Value + ) + ) +} + +;------------------------------------------------------------------------------ +; std::tr1::array from +;------------------------------------------------------------------------------ +std::tr1::array<*>{ + preview ( + ; An actual array is previewed with its address. + ; array is previewed like vector. + #( + "[", + $e._EEN_SIZE, + "](", + #array(expr: $e._Elems[$i], size: $e._EEN_SIZE), + ")" + ) + ) + + children ( + ; Just like an actual array. + #array(expr: $e._Elems[$i], size: $e._EEN_SIZE) + ) +} +std::_Array_iterator<*>|std::_Array_const_iterator<*>{ + preview ( + #if ($e._EEN_IDL == 0) ( + *$e._Ptr + ) #else ( + #if ($e._Idx == $e._EEN_SIZE) ( + ; array iterators are represented by _Ptr + _Idx, + ; and they know how large their parent arrays are. Therefore, detecting + ; end iterators is trivial. + "end" + ) #else ( + ; Like vector iterators, array iterators are previewed with what they point to. + $e._Ptr[$e._Idx] + ) + ) + ) + + children ( + #if ($e._EEN_IDL == 0) ( + #([ptr] : $e._Ptr) + ) #else ( + #if ($e._Idx == $e._EEN_SIZE) ( + ; We make end iterators appear to have no children. + #array(expr: 0, size: 0) + ) #else ( + ; An array iterator is conceptually a pointer, so we make it appear to store one. + #([ptr] : $e._Ptr + $e._Idx) + ) + ) + ) +} + +;------------------------------------------------------------------------------ +; stdext::hash_map from +; stdext::hash_multimap from +; stdext::hash_set from +; stdext::hash_multiset from +;------------------------------------------------------------------------------ +stdext::hash_map<*>|stdext::hash_multimap<*>|stdext::hash_set<*>|stdext::hash_multiset<*>{ + preview ( + #( + "[", + $e._List._Mysize, + "](", + #list( + head: $e._List._Myhead->_Next, + size: $e._List._Mysize, + next: _Next + ) : $e._Myval, + ")" + ) + ) + + children ( + #list( + head: $e._List._Myhead->_Next, + size: $e._List._Mysize, + next: _Next + ) : $e._Myval + ) +} + +;------------------------------------------------------------------------------ +; std::tr1::unordered_map from +; std::tr1::unordered_multimap from +; std::tr1::unordered_set from +; std::tr1::unordered_multiset from +;------------------------------------------------------------------------------ +std::hash<*>{ + preview ( "hash" ) + children ( #array(expr: 0, size: 0) ) +} +std::tr1::unordered_map<*>|std::tr1::unordered_multimap<*>|std::tr1::unordered_set<*>|std::tr1::unordered_multiset<*>{ + preview ( + #( + "[", + $e._List._Mysize, + "](", + #list( + head: $e._List._Myhead->_Next, + size: $e._List._Mysize, + next: _Next + ) : $e._Myval, + ")" + ) + ) + + children ( + #( + #([hash] : $e.comp._Hashobj), + #([equal] : $e.comp._Keyeqobj), + #list( + head: $e._List._Myhead->_Next, + size: $e._List._Mysize, + next: _Next + ) : $e._Myval + ) + ) +} + +;------------------------------------------------------------------------------ +; std::tr1::basic_regex from +;------------------------------------------------------------------------------ +std::tr1::basic_regex<*>{ + preview ( + #if ($e._Rep == 0) ( + ; Default construction creates an empty basic_regex. + "empty" + ) #elif ($e._EEN_VIS == 1) ( + ; By default, _ENHANCED_REGEX_VISUALIZER is defined to be 1 in debug and 0 in ship. + ; When it is 1, basic_regex stores the string from which it was constructed. + ; When it is 0, basic_regex stores only the resulting finite state machine. + $e._Visualization + ) #else ( + ; basic_regex contains many static const flags, which would be shown in the preview by default. + ; Its actual members are _Rep and _Traits. _Rep holds the finite state machine, so we + ; use it to preview basic_regex. (It does contain some human-readable information.) + *$e._Rep + ) + ) + + children ( + #if ($e._Rep == 0) ( + ; We make empty basic_regexes appear to have no children. + #array(expr: 0, size: 0) + ) #elif ($e._EEN_VIS == 1) ( + ; We want to hide those static const flags. + ; We also want to give _Visualization a fake name. + #( + #([str] : $e._Visualization), + #(_Rep : $e._Rep), + #(_Traits : $e._Traits) + ) + ) #else ( + ; We want to hide those static const flags. + #( + _Rep : $e._Rep, + _Traits : $e._Traits + ) + ) + ) +} + +;------------------------------------------------------------------------------ +; std::tr1::sub_match from +;------------------------------------------------------------------------------ +std::tr1::sub_match|std::tr1::sub_match|std::tr1::sub_match|std::tr1::sub_match|std::tr1::sub_match|std::tr1::sub_match{ + preview ( + ; It would be nice if we could preview sub_match with its str(). + ; However, visualizers cannot handle strings represented by pointer pairs. + ; Therefore, our preview contains more limited information. + #if ($e.matched) ( + ; If this sub_match participated in a match, + ; we preview it with its length(). + $e.second - $e.first + ) #else ( + ; Otherwise, we preview it with its matched bool (i.e. "false"). + ; (Why not length() (i.e. "0")? It's meaningful to have + ; matched == true and length() == 0. + "false" + ) + ) + + children ( + #( + ; sub_match's three data members are public, but we list them here + ; (a) to display matched before first and second, and + ; (b) to gloss over the fact that sub_match derives from std::pair. + #(matched : $e.matched), + #(first : $e.first), + #(second : $e.second) + ) + ) +} +std::tr1::sub_match >|std::tr1::sub_match >{ + preview ( + #if ($e.matched) ( + ; We visualize ssub_match and wssub_match just like csub_match and wcsub_match, + ; except that when determining the length(), we can't subtract iterators. + ; We have to subtract their stored pointers. + $e.second._Ptr - $e.first._Ptr + ) #else ( + "false" + ) + ) + + children ( + #( + #(matched : $e.matched), + #(first : $e.first), + #(second : $e.second) + ) + ) +} + +;------------------------------------------------------------------------------ +; std::tr1::match_results from +;------------------------------------------------------------------------------ +std::tr1::match_results<*>{ + preview ( + ; A match_results object is empty iff its vector _Matches is empty. + #if ($e._Matches._Myfirst == $e._Matches._Mylast) ( + "empty" + ) #else ( + ; We preview a non-empty match_results object with its vector. + $e._Matches + ) + ) + + children ( + #if ($e._Matches._Myfirst == $e._Matches._Mylast) ( + ; We make empty match_results appear to have no children. + #array(expr: 0, size: 0) + ) #else ( + ; As match_results has operator[](), prefix(), and suffix() member functions, + ; we make it appear to directly contain [0], [1], [2], etc. elements, + ; as well as [prefix] and [suffix] elements. + #( + #array(expr: $e._Matches._Myfirst[$i], size: $e._Matches._Mylast - $e._Matches._Myfirst), + #([prefix] : $e._Prefix), + #([suffix] : $e._Suffix) + ) + ) + ) +} + +;------------------------------------------------------------------------------ +; std::tr1::regex_iterator from +;------------------------------------------------------------------------------ +std::tr1::regex_iterator<*>{ + preview ( + #if ($e._MyRe == 0) ( + ; We represent end-of-sequence regex_iterators with null regex pointers. + "end" + ) #else ( + ; Dereferenceable regex_iterators return match_results when dereferenced, + ; so we'll preview them with that. + $e._MyVal + ) + ) + + children ( + #if ($e._MyRe == 0) ( + ; We make end-of-sequence regex_iterators appear to have no children. + #array(expr: 0, size: 0) + ) #else ( + ; For ease of understanding, we make dereferenceable regex_iterators + ; appear to have data members with the "for exposition only" names from TR1. + #( + #([begin] : $e._Begin), + #([end] : $e._End), + #([pregex] : $e._MyRe), + #([flags] : $e._Flags), + #([match] : $e._MyVal) + ) + ) + ) +} + +;------------------------------------------------------------------------------ +; std::tr1::regex_token_iterator from +;------------------------------------------------------------------------------ +std::tr1::regex_token_iterator<*>{ + preview ( + #if ($e._Res == 0) ( + ; We represent end-of-sequence regex_token_iterators with null result pointers. + "end" + ) #else ( + ; Dereferenceable regex_token_iterators return *result when dereferenced, + ; so we'll preview them with that. + *$e._Res + ) + ) + + children ( + #if ($e._Res == 0) ( + ; We make end-of-sequence regex_token_iterators appear to have no children. + #array(expr: 0, size: 0) + ) #else ( + ; For ease of understanding, we make dereferenceable regex_token_iterators + ; appear to have data members with the "for exposition only" names from TR1. + #( + #([position] : $e._Pos), + #([result] : $e._Res), + #([suffix] : $e._Suffix), + #([N] : $e._Cur), + #([subs] : $e._Subs) + ) + ) + ) +} + +;------------------------------------------------------------------------------ +; std::identity, etc. from +;------------------------------------------------------------------------------ +std::identity<*>{ + preview ( "identity" ) + children ( #array(expr: 0, size: 0) ) +} +std::bit_and<*>{ + preview ( "bit_and" ) + children ( #array(expr: 0, size: 0) ) +} +std::bit_or<*>{ + preview ( "bit_or" ) + children ( #array(expr: 0, size: 0) ) +} +std::bit_xor<*>{ + preview ( "bit_xor" ) + children ( #array(expr: 0, size: 0) ) +} + +;------------------------------------------------------------------------------ +; std::unique_ptr from +;------------------------------------------------------------------------------ +std::unique_ptr<*>{ + preview ( + #if ($e._Myptr == 0) ( + "empty" + ) #else ( + #( + "unique_ptr ", + *$e._Myptr + ) + ) + ) + + children ( + #if ($e._Myptr == 0) ( + #array(expr: 0, size: 0) + ) #else ( + #([ptr] : $e._Myptr) + ) + ) +} + +;------------------------------------------------------------------------------ +; std::forward_list from +;------------------------------------------------------------------------------ +std::forward_list<*>{ + preview ( + #( + "(", + #list( + head: $e._Myhead, + next: _Next + ) : $e._Myval, + ")" + ) + ) + + children ( + #list( + head: $e._Myhead, + next: _Next + ) : $e._Myval + ) +} +std::_Flist_iterator<*>|std::_Flist_const_iterator<*>{ + preview ( + #if ($e._Ptr == 0) ( + "end" + ) #else ( + $e._Ptr->_Myval + ) + ) + + children ( + #if ($e._Ptr == 0) ( + #array(expr: 0, size: 0) + ) #else ( + #([ptr] : &$e._Ptr->_Myval) + ) + ) +} + + +;------------------------------------------------------------------------------ +; PROPVARIANT +;------------------------------------------------------------------------------ +; Visualizers for VT_VECTOR C arrays +tagCAC|tagCAUB|tagCAI|tagCAUI|tagCAL|tagCAUL|tagCAFLT|tagCADBL|tagCACY|tagCADATE|tagCABSTR|tagCABSTRBLOB|tagCABOOL|tagCASCODE|tagCAPROPVARIANT|tagCAH|tagCAUH|tagCALPSTR|tagCALPWSTR|tagCAFILETIME|tagCACLIPDATA|tagCACLSID{ + preview( + #( + "[", $e.cElems , "](", + #array + ( + expr : ($e.pElems)[$i], + size : $e.cElems + ), + ")" + ) + ) + children + ( + #array + ( + expr : ($e.pElems)[$i], + size : $e.cElems + ) + ) +} +; Visualizers for SAFE ARRAY +tagSAFEARRAY|SAFEARRAY{ + preview( + #if ($e.fFeatures & 0x0080) ; FADF_HAVEVARTYPE + ( + ; Switch on the variant type field - which is stored 4 bytes + ; before the beginning of the SAFEARRAY type + #switch( ((unsigned *)&($e))[-1] ) + #case 0x2 ; VT_I2 | VT_ARRAY + ( + #( + "safearray of I2 = [", + ; output the rank array + #array( expr: $e.rgsabound[$i].cElements, size: $e.cDims), + "](", + ; output the data elements + #array( + expr: ((signed short *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ), + ")" + ) + ) + #case 0x3 ; VT_I4 | VT_ARRAY + ( + #( + "safearray of I4 = [", + ; output the rank array + #array( expr: $e.rgsabound[$i].cElements, size: $e.cDims), + "](", + ; output the data elements + #array( + expr: ((signed int *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ), + ")" + ) + ) + #case 0x4 ; VT_R4 | VT_ARRAY + ( + #( + "safearray of R4 = [", + ; output the rank array + #array( expr: $e.rgsabound[$i].cElements, size: $e.cDims), + "](", + ; output the data elements + #array( + expr: ((float *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ), + ")" + ) + ) + #case 0x5 ; VT_R8 | VT_ARRAY + ( + #( + "safearray of R8 = [", + ; output the rank array + #array( expr: $e.rgsabound[$i].cElements, size: $e.cDims), + "](", + ; output the data elements + #array( + expr: ((double *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ), + ")" + ) + ) + #case 0x6 ; VT_CY | VT_ARRAY + ( + #( + "safearray of CY = [", + ; output the rank array + #array( expr: $e.rgsabound[$i].cElements, size: $e.cDims), + "](", + ; output the data elements + #array( + expr: ((CY *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ), + ")" + ) + ) + #case 0x7 ; VT_DATE | VT_ARRAY + ( + #( + "safearray of DATE = [", + ; output the rank array + #array( expr: $e.rgsabound[$i].cElements, size: $e.cDims), + "](", + ; output the data elements + #array( + expr: ((DATE *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ), + ")" + ) + ) + #case 0x8 ; VT_BSTR | VT_ARRAY + ( + #( + "safearray of BSTR = [", + ; output the rank array + #array( expr: $e.rgsabound[$i].cElements, size: $e.cDims), + "](", + ; output the data elements + #array( + expr: ((wchar_t **)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ), + ")" + ) + ) + #case 0xa ; VT_ERROR | VT_ARRAY + ( + #( + "safearray of ERROR = [", + ; output the rank array + #array( expr: $e.rgsabound[$i].cElements, size: $e.cDims), + "](", + ; output the data elements + #array( + expr: ((long *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ), + ")" + ) + ) + #case 0xb ; VT_BOOL | VT_ARRAY + ( + #( + "safearray of BOOL = [", + ; output the rank array + #array( expr: $e.rgsabound[$i].cElements, size: $e.cDims), + "](", + ; output the data elements + #array( + expr: ((short *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ), + ")" + ) + ) + #case 0xc ; VT_VARIANT | VT_ARRAY + ( + #( + "safearray of VARIANT = [", + ; output the rank array + #array( expr: $e.rgsabound[$i].cElements, size: $e.cDims), + "](", + ; output the data elements + #array( + expr: ((tagVARIANT *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ), + ")" + ) + ) + #case 0x10 ; VT_I1 | VT_ARRAY + ( + #( + "safearray of I1 = [", + ; output the rank array + #array( expr: $e.rgsabound[$i].cElements, size: $e.cDims), + "](", + ; output the data elements + #array( + expr: ((signed char *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ), + ")" + ) + ) + #case 0x11 ; VT_UI1 | VT_ARRAY + ( + #( + "safearray of UI1 = [", + ; output the rank array + #array( expr: $e.rgsabound[$i].cElements, size: $e.cDims), + "](", + ; output the data elements + #array( + expr: ((unsigned char *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ), + ")" + ) + ) + #case 0x12 ; VT_UI2 | VT_ARRAY + ( + #( + "safearray of UI2 = [", + ; output the rank array + #array( expr: $e.rgsabound[$i].cElements, size: $e.cDims), + "](", + ; output the data elements + #array( + expr: ((unsigned short *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ), + ")" + ) + ) + #case 0x13 ; VT_UI4 | VT_ARRAY + ( + #( + "safearray of UI4 = [", + ; output the rank array + #array( expr: $e.rgsabound[$i].cElements, size: $e.cDims), + "](", + ; output the data elements + #array( + expr: ((unsigned int *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ), + ")" + ) + ) + #case 0x14 ; VT_I8 | VT_ARRAY + ( + #( + "safearray of I8 = [", + ; output the rank array + #array( expr: $e.rgsabound[$i].cElements, size: $e.cDims), + "](", + ; output the data elements + #array( + expr: ((signed __int64 *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ), + ")" + ) + ) + #case 0x15 ; VT_UI8 | VT_ARRAY + ( + #( + "safearray of UI8 = [", + ; output the rank array + #array( expr: $e.rgsabound[$i].cElements, size: $e.cDims), + "](", + ; output the data elements + #array( + expr: ((unsigned __int64 *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ), + ")" + ) + ) + #case 0x16 ; VT_INT | VT_ARRAY + ( + #( + "safearray of INT = [", + ; output the rank array + #array( expr: $e.rgsabound[$i].cElements, size: $e.cDims), + "](", + ; output the data elements + #array( + expr: ((int *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ), + ")" + ) + ) + #case 0x17 ; VT_UINT | VT_ARRAY + ( + #( + "safearray of UINT = [", + ; output the rank array + #array( expr: $e.rgsabound[$i].cElements, size: $e.cDims), + "](", + ; output the data elements + #array( + expr: ((unsigned *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ), + ")" + ) + ) + #case 0x1e ; VT_LPSTR | VT_ARRAY + ( + #( + "safearray of LPSTR = [", + ; output the rank array + #array( expr: $e.rgsabound[$i].cElements, size: $e.cDims), + "](", + ; output the data elements + #array( + expr: ((char **)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ), + ")" + ) + ) + #case 0x1f ; VT_LPWSTR | VT_ARRAY + ( + #( + "safearray of LPWSTR = [", + ; output the rank array + #array( expr: $e.rgsabound[$i].cElements, size: $e.cDims), + "](", + ; output the data elements + #array( + expr: ((wchar_t **)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ), + ")" + ) + ) + #case 0x40 ; VT_FILETIME | VT_ARRAY + ( + #( + "safearray of FILETIME = [", + ; output the rank array + #array( expr: $e.rgsabound[$i].cElements, size: $e.cDims), + "](", + ; output the data elements + #array( + expr: ((FILETIME *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ), + ")" + ) + ) + #case 0x47 ; VT_CLIPDATA | VT_ARRAY + ( + #( + "safearray of CLIPDATA = [", + ; output the rank array + #array( expr: $e.rgsabound[$i].cElements, size: $e.cDims), + "](", + ; output the data elements + #array( + expr: ((CLIPDATA *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ), + ")" + ) + ) + #case 0x48 ; VT_CLSID | VT_ARRAY + ( + #( + "safearray of CLSID = [", + ; output the rank array + #array( expr: $e.rgsabound[$i].cElements, size: $e.cDims), + "](", + ; output the data elements + #array( + expr: ((CLSID *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ), + ")" + ) + ) + ) + #elif ($e.fFeatures & 0x0100) ; FADF_BSTR + ( + #("safearray of BSTR = ",#array(expr: $e.rgsabound[$i].cElements, size: $e.cDims) : #("[",$e,"]"), "(", #array(expr: ((wchar_t * *)$e.pvData)[$i], size: $e.rgsabound[$r].cElements, rank: $e.cDims, base: $e.rgsabound[$r].lLbound ), ")") + ) + #elif ($e.fFeatures & 0x0200) ; FADF_UNKNOWN + ( + #("safearray of IUnknown* = [",#array(expr: $e.rgsabound[$i].cElements, size: $e.cDims), "](", #array(expr: ((IUnknown * *)$e.pvData)[$i], size: $e.rgsabound[$r].cElements, rank: $e.cDims, base: $e.rgsabound[$r].lLbound ), ")") + ) + #elif ($e.fFeatures & 0x0400) ; FADF_DISPATCH + ( + #("safearray of IDispatch* = [",#array(expr: $e.rgsabound[$i].cElements, size: $e.cDims), "](", #array(expr: ((IDispatch * *)$e.pvData)[$i], size: $e.rgsabound[$r].cElements, rank: $e.cDims, base: $e.rgsabound[$r].lLbound ), ")") + ) + #elif ($e.fFeatures & 0x0800) ; FADF_VARIANT + ( + #("safearray of VARIANT = ",#array(expr: $e.rgsabound[$i].cElements, size: $e.cDims) : #("[",$e,"]"), "(", #array(expr: ((tagVARIANT *)$e.pvData)[$i], size: $e.rgsabound[$r].cElements, rank: $e.cDims, base: $e.rgsabound[$r].lLbound ), ")") + ) + ) + children + ( + #( ;[actual members]: [$e,!], + #if ($e.fFeatures & 0x0080) ; FADF_HAVEVARTYPE + ( + #switch( ((unsigned *)&($e))[-1] ) ; for some reason the VT field is before the SAFEARRAY struct + #case 2 ; VT_I2|VT_ARRAY + ( + #array( + expr: ((signed short *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ) + ) + #case 3 ; VT_I4|VT_ARRAY + ( + #array( + expr: ((signed int *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ) + ) + #case 4 ; VT_R4|VT_ARRAY + ( + #array( + expr: ((float *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ) + ) + #case 5 ; VT_R8|VT_ARRAY + ( + #array( + expr: ((double *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ) + ) + #case 0x10 ; VT_I1|VT_ARRAY + ( + #array( + expr: ((signed char *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ) + ) + #case 0x11 ; VT_UI1|VT_ARRAY + ( + #array( + expr: ((unsigned char *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ) + ) + #case 0x12 ; VT_UI2|VT_ARRAY + ( + #array( + expr: ((unsigned short *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ) + ) + #case 0x13 ; VT_UI4|VT_ARRAY + ( + #array( + expr: ((unsigned int *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ) + ) + #case 0x14 ; VT_I8|VT_ARRAY + ( + #array( + expr: ((signed __int64 *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ) + ) + #case 0x15 ; VT_UI8|VT_ARRAY + ( + #array( + expr: ((unsigned __int64 *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ) + ) + #case 0x1e ; VT_LPSTR|VT_ARRAY + ( + #array( + expr: ((char * *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ) + ) + #case 0x1f ; VT_LPWSTR|VT_ARRAY + ( + #array( + expr: ((wchar_t **)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ) + ) + #case 0xc ; VT_VARIANT|VT_ARRAY + ( + #array( + expr: ((tagVARIANT *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ) + ) + #case 0xb ; VT_BOOL|VT_ARRAY + ( + #array( + expr: ((short *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ) + ) + #case 0xa ; VT_ERROR|VT_ARRAY + ( + #array( + expr: ((long *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ) + ) + #case 6 ; VT_CY|VT_ARRAY + ( + #array( + expr: ((CY *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ) + ) + #case 7 ; VT_DATE|VT_ARRAY + ( + #array( + expr: ((DATE *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ) + ) + #case 0x40 ; VT_FILETIME|VT_ARRAY + ( + #array( + expr: ((FILETIME *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ) + ) + #case 0x48 ; VT_CLSID|VT_ARRAY + ( + #array( + expr: ((CLSID *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ) + ) + #case 0x47 ; VT_CF|VT_ARRAY + ( + #array( + expr: ((CLIPDATA *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ) + ) + #case 8 ; VT_BSTR|VT_ARRAY + ( + #array( + expr: ((wchar_t * *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ) + ) + #case 0x16 ; VT_INT|VT_ARRAY + ( + #array( + expr: ((int *)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ) + ) + #case 0x17 ; VT_UINT|VT_ARRAY + ( + #array( + expr: ((unsigned int*)$e.pvData)[$i], + size: $e.rgsabound[$r].cElements, + rank: $e.cDims, + base: $e.rgsabound[$r].lLbound + ) + ) + #default + ( + #([actual members]: [$e,!]) + ) + #except + ( + #([actual members]: [$e,!]) + ) + ) + #elif ($e.fFeatures & 0x0100) ; FADF_BSTR + ( + #array(expr: ((wchar_t * *)$e.pvData)[$i], size: $e.rgsabound[$r].cElements, rank: $e.cDims, base: $e.rgsabound[$r].lLbound ) + ) + #elif ($e.fFeatures & 0x0200) ; FADF_UNKNOWN + ( + #array(expr: ((IUnknown * *)$e.pvData)[$i], size: $e.rgsabound[$r].cElements, rank: $e.cDims, base: $e.rgsabound[$r].lLbound ) + ) + #elif ($e.fFeatures & 0x0400) ; FADF_DISPATCH + ( + #array(expr: ((IDispatch * *)$e.pvData)[$i], size: $e.rgsabound[$r].cElements, rank: $e.cDims, base: $e.rgsabound[$r].lLbound ) + ) + #elif ($e.fFeatures & 0x0800) ; FADF_VARIANT + ( + #array(expr: ((tagVARIANT *)$e.pvData)[$i], size: $e.rgsabound[$r].cElements, rank: $e.cDims, base: $e.rgsabound[$r].lLbound ) + ) + ) + ) +} +tagPROPVARIANT|tagVARIANT|PROPVARIANT|VARIANT{ + preview( + #switch ($e.vt) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;; Base Types ;; + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + #case 0 ( #("Empty") ) ; VT_EMPTY + #case 1 ( #("NULL") ) ; VT_NULL + #case 2 ( #("I2 = ", $e.iVal) ) ; VT_I2 + #case 3 ( #("I4 = ", $e.lVal) ) ; VT_I4 + #case 4 ( #("R4 = ", $e.fltVal) ) ; VT_R4 + #case 5 ( #("R8 = ", $e.dblVal) ) ; VT_R8 + #case 6 ( #("CY = ", $e.cyVal) ) ; VT_CY + #case 7 ( #("DATE = ", $e.date) ) ; VT_DATE + #case 8 ( #("BSTR = ", $e.bstrVal) ) ; VT_BSTR + #case 9 ( #("DISPATCH = ", $e.pdispVal) ) ; VT_DISPATCH + #case 10 ( #("ERROR = ", $e.scode) ) ; VT_ERROR + #case 0xB ( #("BOOL = ", $e.boolVal) ) ; VT_BOOL + #case 0xC ( #("VARIANT ") ) ; VT_VARIANT + #case 0xD ( #("UNKNOWN = ", $e.punkVal) ) ; VT_UNKOWN + #case 0xE ( #("DECIMAL = ", $e.decVal) ) ; VT_DECIMAL + #case 0x10 ( #("I1 = ", $e.cVal) ) ; VT_I1 + #case 0x11 ( #("UI1 = ", $e.bVal) ) ; VT_UI1 + #case 0x12 ( #("UI2 = ", $e.uiVal) ) ; VT_UI2 + #case 0x13 ( #("UI4 = ", $e.ulVal) ) ; VT_UI4 + #case 0x14 ( #("I8 = ", *(__int64*)&$e.dblVal) ) ; VT_I8 + #case 0x15 ( #("UI8 = ", *(unsigned __int64*)&$e.dblVal) ) ; VT_UI8 + #case 0x16 ( #("INT = ", $e.intVal) ) ; VT_INT + #case 0x17 ( #("UINT = ", $e.uintVal) ) ; VT_UINT + #case 0x18 ( #("VOID ") ) ; VT_VOID + #case 0x19 ( #("HRESULT ") ) ; VT_HRESULT + #case 0x1A ( #("PTR ") ) ; VT_PTR + #case 0x1B ( #("SAFEARRAY ") ) ; VT_SAFEARRAY + #case 0x1C ( #("CARRAY ") ) ; VT_CARRAY + #case 0x1D ( #("USERDEFINED ") ) ; VT_USERDEFINED + #case 0x1E ( #("LPSTR = ", $e.pszVal) ) ; VT_LPSTR + #case 0x1F ( #("LPWSTR = ", $e.pwszVal) ) ; VT_LPWSTR + #case 0x24 ( #("RECORD ") ) ; VT_RECORD + #case 0x26 ( #("UINT_PTR ") ) ; VT_UINT_PTR + #case 0x40 ( #("FILETIME = ", $e.filetime) ) ; VT_FILETIME + #case 0x42 ( #("STREAM = ", $e.pStream) ) ; VT_STREAM + #case 0x43 ( #("STORAGE = ", $e.pStorage) ) ; VT_STORAGE + #case 0x44 ( #("STREAMED_OBJECT = ", $e.pStream) ) ; VT_STREAMED_OBJECT + #case 0x45 ( #("STORED_OBJECT = ", $e.pStorage) ) ; VT_STORED_OBJECT + #case 0x46 ( #("BLOB_OBJECT = ", $e.blob ) ) ; VT_BLOB_OBJECT + #case 0x47 ( #("CF = ", $e.pclipdata) ) ; VT_CF + #case 0x48 ( #("CLSID = ", $e.puuid) ) ; VT_CLSID + #case 0x49 ( #("VERSIONED_STREAM = ", $e.pVersionedStream) ) ; VT_VERSIONED_STREAM + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;; Vector types ;; + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + #case 0x1002 ( #("vector of I2 = ", $e.cai) ) ; VT_I2|VT_VECTOR + #case 0x1003 ( #("vector of I4 = ", $e.cal) ) ; VT_I4|VT_VECTOR + #case 0x1004 ( #("vector of R4 = ", $e.caflt) ) ; VT_R4|VT_VECTOR + #case 0x1005 ( #("vector of R8 = ", $e.cadbl) ) ; VT_R8|VT_VECTOR + #case 0x1010 ( #("vector of I1 = ", $e.cac) ) ; VT_I1|VT_VECTOR + #case 0x1011 ( #("vector of UI1 = ", $e.caub) ) ; VT_UI1|VT_VECTOR + #case 0x1012 ( #("vector of UI2 = ", $e.caui) ) ; VT_UI2|VT_VECTOR + #case 0x1013 ( #("vector of UI4 = ", $e.caul) ) ; VT_UI4|VT_VECTOR + #case 0x1014 ( #("vector of I8 = ", $e.cah) ) ; VT_I8|VT_VECTOR + #case 0x1015 ( #("vector of UI8 = ", $e.cauh) ) ; VT_UI8|VT_VECTOR + #case 0x101E ( #("vector of LPSTR = ", $e.calpstr) ) ; VT_LPSTR|VT_VECTOR + #case 0x101F ( #("vector of LPWSTR = ", $e.calpwstr) ) ; VT_LPWSTR|VT_VECTOR + #case 0x100C ( #("vector of VARIANT ", $e.capropvar) ) ; VT_VARIANT|VT_VECTOR + #case 0x100B ( #("vector of BOOL = ", $e.cabool) ) ; VT_BOOL|VT_VECTOR + #case 0x100A ( #("vector of ERROR = ", $e.cascode) ) ; VT_ERROR|VT_VECTOR + #case 0x1006 ( #("vector of CY = ", $e.cacy) ) ; VT_CY|VT_VECTOR + #case 0x1007 ( #("vector of DATE = ", $e.cadate) ) ; VT_DATE|VT_VECTOR + #case 0x1040 ( #("vector of FILETIME = ", $e.cafiletime) ) ; VT_FILETIME|VT_VECTOR + #case 0x1048 ( #("vector of CLSID = ", $e.cauuid) ) ; VT_CLSID|VT_VECTOR + #case 0x1047 ( #("vector of CF = ", $e.caclipdata) ) ; VT_CF|VT_VECTOR + #case 0x1008 ( #("vector of BSTR = ", $e.cabstr) ) ; VT_BSTR|VT_VECTOR + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;; Byref Types ;; + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + #case 0x4016 ( #("byref of INT = ", $e.pintVal) ) ; VT_INT|VT_BYREF + #case 0x4017 ( #("byref of UINT = ", $e.puintVal) ) ; VT_UINT|VT_BYREF + #case 0x4002 ( #("byref of I2 = ", $e.piVal) ) ; VT_I2|VT_BYREF + #case 0x4003 ( #("byref of I4 = ", $e.plVal) ) ; VT_I4|VT_BYREF + #case 0x4004 ( #("byref of R4 = ", $e.pfltVal) ) ; VT_R4|VT_BYREF + #case 0x4005 ( #("byref of R8 = ", $e.pdblVal) ) ; VT_R8|VT_BYREF + #case 0x4010 ( #("byref of I1 = ", $e.pcVal) ) ; VT_I1|VT_BYREF + #case 0x4011 ( #("byref of UI1 = ", $e.pbVal) ) ; VT_UI1|VT_BYREF + #case 0x4012 ( #("byref of UI2 = ", $e.puiVal) ) ; VT_UI2|VT_BYREF + #case 0x4013 ( #("byref of UI4 = ", $e.pulVal) ) ; VT_UI4|VT_BYREF + #case 0x4014 ( #("byref of I8 = ", (__int64*)$e.pdblVal) ) ; VT_I8|VT_BYREF + #case 0x4015 ( #("byref of UI8 = ", (unsigned __int64*)$e.pudblVal) ) ; VT_UI8|VT_BYREF + #case 0x400C ( #("byref of VARIANT ", $e.pvarVal) ) ; VT_VARIANT|VT_BYREF + #case 0x400B ( #("byref of BOOL = ", $e.pboolVal) ) ; VT_BOOL|VT_BYREF + #case 0x400A ( #("byref of ERROR = ", $e.pscode) ) ; VT_ERROR|VT_BYREF + #case 0x4006 ( #("byref of CY = ", $e.pcyVal) ) ; VT_CY|VT_BYREF + #case 0x4007 ( #("byref of DATE = ", $e.pdate) ) ; VT_DATE|VT_BYREF + #case 0x4008 ( #("byref of BSTR = ", $e.pbstrVal) ) ; VT_BSTR|VT_BYREF + #case 0x400E ( #("byref of DECIMAL = ", $e.pdecVal) ) ; VT_DECIMAL|VT_BYREF + #case 0x400D ( #("byref of UNKNOWN = ", $e.ppunkVal) ) ; VT_UNKOWN|VT_BYREF + #case 0x4009 ( #("byref of DISPATCH = ", $e.ppdispVal) ) ; VT_DISPATCH|VT_BYREF + #case 0x6000 ( #("byref of ARRAY = ", $e.pparray) ) ; VT_ARRAY|VT_BYREF + #default + ( + #if ($e.vt & 0x2000) ( $e.parray) + #else ( #("Unknown vt type = ", $e.vt)) + ) + ) + children( + #( + vt: $e.vt, + #switch ($e.vt) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;; Base Types ;; + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + #case 0x2 ( #(I2 : $e.iVal) ) ; VT_I2 + #case 0x3 ( #(I4 : $e.lVal) ) ; VT_I4 + #case 0x4 ( #(R4 : $e.fltVal) ) ; VT_R4 + #case 0x5 ( #(R8 : $e.dblVal) ) ; VT_R8 + #case 0x6 ( #(CY : $e.cyVal) ) ; VT_CY + #case 0x7 ( #(DATE : $e.date) ) ; VT_DATE + #case 0x8 ( #(BSTR : $e.bstrVal) ) ; VT_BSTR + #case 0x9 ( #(DISPATCH : $e.pdispVal) ) ; VT_DISPATCH + #case 0xA ( #(ERROR : $e.scode) ) ; VT_ERROR + #case 0xB ( #(BOOL : $e.boolVal) ) ; VT_BOOL + #case 0xD ( #(UNKNOWN : $e.punkVal) ) ; VT_UNKOWN + #case 0xE ( #(DECIMAL : $e.decVal) ) ; VT_DECIMAL + #case 0x10 ( #(I1 : $e.cVal) ) ; VT_I1 + #case 0x11 ( #(UI1 : $e.bVal) ) ; VT_UI1 + #case 0x12 ( #(UI2 : $e.uiVal) ) ; VT_UI2 + #case 0x13 ( #(UI4 : $e.ulVal) ) ; VT_UI4 + #case 0x14 ( #(I8 : *(__int64*)&$e.dblVal) ) ; VT_I8 + #case 0x15 ( #(UI8 : *(unsigned __int64*)&$e.dblVal) ) ; VT_UI8 + #case 0x16 ( #(INT : $e.intVal) ) ; VT_INT + #case 0x17 ( #(UINT : $e.uintVal) ) ; VT_UINT + #case 0x1E ( #(LPSTR : $e.pszVal) ) ; VT_LPSTR + #case 0x1F ( #(LPWSTR : $e.pwszVal) ) ; VT_LPWSTR + #case 0x40 ( #(FILETIME : $e.filetime) ) ; VT_FILETIME + #case 0x42 ( #(STREAM : $e.pStream) ) ; VT_STREAM + #case 0x43 ( #(STORAGE : $e.pStorage) ) ; VT_STORAGE + #case 0x44 ( #(STREAMED_OBJECT : $e.pStream) ) ; VT_STREAMED_OBJECT + #case 0x45 ( #(STORED_OBJECT : $e.pStorage) ) ; VT_STORED_OBJECT + #case 0x46 ( #(BLOB_OBJECT : $e.blob ) ) ; VT_BLOB_OBJECT + #case 0x47 ( #(CF : $e.pclipdata) ) ; VT_CF + #case 0x48 ( #(CLSID : $e.puuid) ) ; VT_CLSID + #case 0x49 ( #(VERSIONED_STREAM : $e.pVersionedStream) ) ; VT_VERSIONED_STREAM + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;; Vector types ;; + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + #case 0x1002 ( #(vector of I2 : $e.cai) ) ; VT_I2|VT_VECTOR + #case 0x1003 ( #(vector of I4 : $e.cal) ) ; VT_I4|VT_VECTOR + #case 0x1004 ( #(vector of R4 : $e.caflt) ) ; VT_R4|VT_VECTOR + #case 0x1005 ( #(vector of R8 : $e.cadbl) ) ; VT_R8|VT_VECTOR + #case 0x1010 ( #(vector of I1 : $e.cac) ) ; VT_I1|VT_VECTOR + #case 0x1011 ( #(vector of UI1 : $e.caub) ) ; VT_UI1|VT_VECTOR + #case 0x1012 ( #(vector of UI2 : $e.caui) ) ; VT_UI2|VT_VECTOR + #case 0x1013 ( #(vector of UI4 : $e.caul) ) ; VT_UI4|VT_VECTOR + #case 0x1014 ( #(vector of I8 : $e.cah) ) ; VT_I8|VT_VECTOR + #case 0x1015 ( #(vector of UI8 : $e.cauh) ) ; VT_UI8|VT_VECTOR + #case 0x101E ( #(vector of LPSTR : $e.calpstr) ) ; VT_LPSTR|VT_VECTOR + #case 0x101F ( #(vector of LPWSTR : $e.calpwstr) ) ; VT_LPWSTR|VT_VECTOR + #case 0x100C ( #(vector of VARIANT : $e.capropvar) ) ; VT_VARIANT|VT_VECTOR + #case 0x100B ( #(vector of BOOL : $e.cabool) ) ; VT_BOOL|VT_VECTOR + #case 0x100A ( #(vector of ERROR : $e.cascode) ) ; VT_ERROR|VT_VECTOR + #case 0x1006 ( #(vector of CY : $e.cacy) ) ; VT_CY|VT_VECTOR + #case 0x1007 ( #(vector of DATE : $e.cadate) ) ; VT_DATE|VT_VECTOR + #case 0x1040 ( #(vector of FILETIME : $e.cafiletime) ) ; VT_FILETIME|VT_VECTOR + #case 0x1048 ( #(vector of CLSID : $e.cauuid) ) ; VT_CLSID|VT_VECTOR + #case 0x1047 ( #(vector of CF : $e.caclipdata) ) ; VT_CF|VT_VECTOR + #case 0x1008 ( #(vector of BSTR : $e.cabstr) ) ; VT_BSTR|VT_VECTOR + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;; Byref Types ;; + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + #case 0x4016 ( #(byref of INT : $e.pintVal) ) ; VT_INT|VT_BYREF + #case 0x4017 ( #(byref of UINT : $e.puintVal) ) ; VT_UINT|VT_BYREF + #case 0x4002 ( #(byref of I2 : $e.piVal) ) ; VT_I2|VT_BYREF + #case 0x4003 ( #(byref of I4 : $e.plVal) ) ; VT_I4|VT_BYREF + #case 0x4004 ( #(byref of R4 : $e.pfltVal) ) ; VT_R4|VT_BYREF + #case 0x4005 ( #(byref of R8 : $e.pdblVal) ) ; VT_R8|VT_BYREF + #case 0x4010 ( #(byref of I1 : $e.pcVal) ) ; VT_I1|VT_BYREF + #case 0x4011 ( #(byref of UI1 : $e.pbVal) ) ; VT_UI1|VT_BYREF + #case 0x4012 ( #(byref of UI2 : $e.puiVal) ) ; VT_UI2|VT_BYREF + #case 0x4013 ( #(byref of UI4 : $e.pulVal) ) ; VT_UI4|VT_BYREF + #case 0x4014 ( #(byref of I8 : (__int64*)$e.pdblVal) ) ; VT_I8|VT_BYREF + #case 0x4015 ( #(byref of UI8 : (unsigned __int64*)$e.pdblVal) ) ; VT_UI8|VT_BYREF + #case 0x400C ( #(byref of VARIANT : $e.pvarVal) ) ; VT_VARIANT|VT_BYREF + #case 0x400B ( #(byref of BOOL : $e.pboolVal) ) ; VT_BOOL|VT_BYREF + #case 0x400A ( #(byref of ERROR : $e.pscode) ) ; VT_ERROR|VT_BYREF + #case 0x4006 ( #(byref of CY : $e.pcyVal) ) ; VT_CY|VT_BYREF + #case 0x4007 ( #(byref of DATE : $e.pdate) ) ; VT_DATE|VT_BYREF + #case 0x4008 ( #(byref of BSTR : $e.pbstrVal) ) ; VT_BSTR|VT_BYREF + #case 0x400E ( #(byref of DECIMAL : $e.pdecVal) ) ; VT_DECIMAL|VT_BYREF + #case 0x400D ( #(byref of UNKNOWN : $e.ppunkVal) ) ; VT_UNKOWN|VT_BYREF + #case 0x4009 ( #(byref of DISPATCH : $e.ppdispVal) ) ; VT_DISPATCH|VT_BYREF + #case 0x6000 ( #(byref of ARRAY : $e.pparray) ) ; VT_ARRAY|VT_BYREF + + ; the following are either empty or invalid vt values for a variant + ; #case 0 ( #(Empty :) ) ; VT_EMPTY + ; #case 0x1 ( #(NULL :) ) ; VT_NULL + ; #case 0xC ( #(VARIANT :) ) ; VT_VARIANT + ; #case 0x18 ( #(VOID :) ) ; VT_VOID + ; #case 0x19 ( #(HRESULT :) ) ; VT_HRESULT + ; #case 0x1A ( #(PTR :) ) ; VT_PTR + ; #case 0x1B ( #(SAFEARRAY :) ) ; VT_SAFEARRAY + ; #case 0x1C ( #(CARRAY :) ) ; VT_CARRAY + ; #case 0x1D ( #(USERDEFINED :) ) ; VT_USERDEFINED + ; #case 0x24 ( #(RECORD :) ) ; VT_RECORD + ; #case 0x26 ( #(UINT_PTR :) ) ; VT_UINT_PTR + #default + ( + #if ($e.vt & 0x2000 ) + ( #(safearray: $e.parray)) + #else + ( + #( + [raw members]: [$e,!] ; unformatted data members + ) + ) + ) + #except + ( + #( + [raw members]: [$e,!] ; unformatted data members + ) + ) + ) + ) +} + +; Visualizers for data structures in namespace Concurrency +;------------------------------------------------------------------------------ +; Concurrency::message from +;------------------------------------------------------------------------------ +Concurrency::message<*>{ + preview ( + #( + $e.payload + ) + ) + + children ( + #( + #(payload: $e.payload), + #([msg_id]: $e._M_id) + ) + ) +} + +;------------------------------------------------------------------------------ +; Concurrency::multi_link_registry from +;------------------------------------------------------------------------------ +Concurrency::multi_link_registry<*>{ + preview ( + #( + "[", + $e._M_vector._M_index, + "](", + #array( + expr: *($e._M_vector._M_array[$i]), + size: $e._M_vector._M_index + ), + ")" + ) + ) + + children ( + #( + #([size]: $e._M_vector._M_index), + #array( + expr: *($e._M_vector._M_array[$i]), + size: $e._M_vector._M_index + ) + ) + ) +} + +;------------------------------------------------------------------------------ +; Concurrency::details::_Queue from +;------------------------------------------------------------------------------ +Concurrency::details::_Queue<*>{ + preview ( + #( + "[", + $e._M_count, + "](", + #list( + head: $e._M_pHead, + next: _M_pNext, + size: _M_count + ), + ")" + ) + ) + + children ( + #( + #([size]: $e._M_count), + #list( + head: $e._M_pHead, + next: _M_pNext, + size: _M_count + ) + ) + ) +} + +;------------------------------------------------------------------------------ +; Concurrency::unbounded_buffer from +;------------------------------------------------------------------------------ +Concurrency::unbounded_buffer<*>{ + preview ( + #( + $e._M_messageBuffer + ) + ) + + children ( + #( + #(unprocessed_messages: $e._M_messageProcessor._M_queuedMessages._M_queue), + #(messages: $e._M_messageBuffer), + #(message_filter: *($e._M_pFilter)), + #(linked_sources: $e._M_connectedSources._M_links), + #(linked_targets: $e._M_connectedTargets), + #(reserving_target: *($e._M_pReservedFor)), + #(Scheduler: *($e._M_messageProcessor._M_pScheduler)), + #(ScheduleGroup: *($e._M_messageProcessor._M_pScheduleGroup)) + ) + ) +} + +;------------------------------------------------------------------------------ +; Concurrency::overwrite_buffer from +;------------------------------------------------------------------------------ +Concurrency::overwrite_buffer<*>{ + preview ( + #( + $e._M_pMessage + ) + ) + + children ( + #( + #(value: *($e._M_pMessage)), + #(unprocessed_messages: $e._M_messageProcessor._M_queuedMessages._M_queue), + #(message_filter: *($e._M_pFilter)), + #(linked_sources: $e._M_connectedSources._M_links), + #(linked_targets: $e._M_connectedTargets), + #(reserving_target: *($e._M_pReservedFor)), + #(reserved_message: *($e._M_pReservedMessage)), + #(Scheduler: *($e._M_messageProcessor._M_pScheduler)), + #(ScheduleGroup: *($e._M_messageProcessor._M_pScheduleGroup)) + ) + ) +} + +;------------------------------------------------------------------------------ +; Concurrency::single_assignment from +;------------------------------------------------------------------------------ +Concurrency::single_assignment<*>{ + preview ( + #( + $e._M_pMessage + ) + ) + + children ( + #( + #(value: *($e._M_pMessage)), + #(unprocessed_messages: $e._M_messageProcessor._M_queuedMessages._M_queue), + #(message_filter: *($e._M_pFilter)), + #(linked_sources: $e._M_connectedSources._M_links), + #(linked_targets: $e._M_connectedTargets), + #(reserving_target: *($e._M_pReservedFor)), + #(Scheduler: *($e._M_messageProcessor._M_pScheduler)), + #(ScheduleGroup: *($e._M_messageProcessor._M_pScheduleGroup)) + ) + ) +} + +;------------------------------------------------------------------------------ +; Concurrency::call from +;------------------------------------------------------------------------------ +Concurrency::call<*>{ + preview ( + #( + $e._M_pFunc + ) + ) + + children ( + #( + #(call_method: $e._M_pFunc), + #(unprocessed_messages: $e._M_messageProcessor._M_queuedMessages._M_queue), + #(message_filter: *($e._M_pFilter)), + #(linked_sources: $e._M_connectedSources._M_links), + #(Scheduler: *($e._M_messageProcessor._M_pScheduler)), + #(ScheduleGroup: *($e._M_messageProcessor._M_pScheduleGroup)) + ) + ) +} + +;------------------------------------------------------------------------------ +; Concurrency::transformer from +;------------------------------------------------------------------------------ +Concurrency::transformer<*>{ + preview ( + #( + $e._M_pFunc + ) + ) + + children ( + #( + #(transform_method: $e._M_pFunc), + #(unprocessed_messages: $e._M_messageProcessor._M_queuedMessages._M_queue), + #(messages: $e._M_messageBuffer), + #(message_filter: *($e._M_pFilter)), + #(linked_sources: $e._M_connectedSources._M_links), + #(linked_target: *($e._M_connectedTargets._M_connectedLink)), + #(reserving_target: *($e._M_pReservedFor)), + #(Scheduler: *($e._M_messageProcessor._M_pScheduler)), + #(ScheduleGroup: *($e._M_messageProcessor._M_pScheduleGroup)) + ) + ) +} + +;------------------------------------------------------------------------------ +; Concurrency::choice from +;------------------------------------------------------------------------------ +Concurrency::choice<*>{ + preview ( + #( + "[", + #if ($e._M_pSingleAssignment->_M_fIsInitialized) ("initialized") + #else ("not_initialized"), + "] ", + $e._M_sourceTuple + ) + ) + + children ( + #( + #([input_count]: $e._M_pSingleAssignment->_M_connectedSources._M_links._M_vector._M_index), + #(index: $e._M_pSingleAssignment->_M_pMessage->payload), + #(source_tuple: $e._M_sourceTuple), + #(linked_sources: $e._M_pSingleAssignment->_M_connectedSources._M_links), + #(linked_targets: $e._M_pSingleAssignment->_M_connectedTargets), + #(reserving_target: *($e._M_pSingleAssignment->_M_pReservedFor)), + #(Scheduler: *($e._M_pScheduler)), + #(ScheduleGroup: *($e._M_pScheduleGroup)), + #([raw _M_pSourceChoices] : $e._M_pSourceChoices) + ) + ) +} + +;------------------------------------------------------------------------------ +; Concurrency::join<*,*>::_MessageArray from +;------------------------------------------------------------------------------ +Concurrency::join<*,*>::_MessageArray{ + preview ( + #( + "[", + $e._M_count, + "](", + #array( + expr: *(((Concurrency::message<$T1>**)$e._M_messages)[$i]), + size: $e._M_count + ), + ")" + ) + ) + + children ( + #( + #([size]: $e._M_count), + #array( + expr: *(((Concurrency::message<$T1>**)$e._M_messages)[$i]), + size: $e._M_count + ) + ) + ) +} + +;------------------------------------------------------------------------------ +; Concurrency::join<*,*>::_SavedMessageIdArray from +;------------------------------------------------------------------------------ +Concurrency::join<*,*>::_SavedMessageIdArray{ + preview ( + #( + "[", + $e._M_count, + "](", + #array( + expr: ((int*)$e._M_savedIds)[$i], + size: $e._M_count + ), + ")" + ) + ) + + children ( + #( + #([size]: $e._M_count), + #array( + expr: ((int*)$e._M_savedIds)[$i], + size: $e._M_count + ) + ) + ) +} + +;------------------------------------------------------------------------------ +; Concurrency::join from +;------------------------------------------------------------------------------ +Concurrency::join<*,*>{ + preview ( + #( + "[", + $e._M_messageArray._M_count - $e._M_messagesRemaining, + "/", + $e._M_messageArray._M_count, + "](", + #array( + expr: *($e._M_connectedSources._M_links._M_vector._M_array[$i]), + size: $e._M_connectedSources._M_links._M_vector._M_index + ), + ")" + ) + ) + + children ( + #( + #([join_type]: (Concurrency::join_type)$T2), + #([offer_count]: $e._M_messageArray._M_count - $e._M_messagesRemaining), + #(offer_IDs: $e._M_savedMessageIdArray), + #([input_count]: $e._M_messageArray._M_count), + #(input_values: $e._M_messageArray), + #(messages: $e._M_messageBuffer), + #(message_filter: *($e._M_pFilter)), + #(linked_sources: $e._M_connectedSources._M_links), + #(linked_target: $e._M_connectedTargets._M_connectedLink), + #(reserving_target: *($e._M_pReservedFor)), + #(Scheduler: *($e._M_messageProcessor._M_pScheduler)), + #(ScheduleGroup: *($e._M_messageProcessor._M_pScheduleGroup)) + ) + ) +} + +;------------------------------------------------------------------------------ +; Concurrency::multitype_join from +;------------------------------------------------------------------------------ +Concurrency::multitype_join<*,*>{ + preview ( + #( + "[", + $e._M_pJoinNode->_M_connectedSources._M_links._M_vector._M_index - $e._M_pJoinNode->_M_counter, + "/", + $e._M_pJoinNode->_M_connectedSources._M_links._M_vector._M_index, + "]", + $e._M_sourceTuple + ) + ) + + children ( + #( + #([join_type]: (Concurrency::join_type)$T2), + #([offer_count]: $e._M_pJoinNode->_M_connectedSources._M_links._M_vector._M_index - $e._M_pJoinNode->_M_counter), + #([input_count]: $e._M_pJoinNode->_M_connectedSources._M_links._M_vector._M_index), + #(source_tuple: $e._M_sourceTuple), + #(messages: $e._M_pJoinNode->_M_messageBuffer), + #(linked_sources: $e._M_pJoinNode->_M_connectedSources._M_links), + #(linked_target: $e._M_pJoinNode->_M_connectedTargets._M_connectedLink), + #(reserving_target: *($e._M_pJoinNode->_M_pReservedFor)), + #(Scheduler: *($e._M_pJoinNode->_M_messageProcessor._M_pScheduler)), + #(ScheduleGroup: *($e._M_pJoinNode->_M_messageProcessor._M_pScheduleGroup)), + #([raw _M_pSourceJoins] : $e._M_pSourceJoins) + ) + ) +} + +;------------------------------------------------------------------------------ +; Concurrency::timer from +;------------------------------------------------------------------------------ +Concurrency::timer<*>{ + preview ( + #( + $e._M_state + ) + ) + + children ( + #( + #(state: $e._M_state), + #(value: $e._M_value), + #(repeating: $e._M_fRepeating), + #(interval_ms: $e._M_ms), + #(linked_target: *($e._M_connectedTargets._M_connectedLink)), + #(reserving_target: *($e._M_pReservedFor)), + #(Scheduler: *($e._M_messageProcessor._M_pScheduler)), + #(ScheduleGroup: *($e._M_messageProcessor._M_pScheduleGroup)) + ) + ) +} + +;------------------------------------------------------------------------------ +; Concurrency::details::SchedulerBase from +; Concurrency::details::ThreadScheduler from +; Concurrency::details::UMSThreadScheduler from +;------------------------------------------------------------------------------ +Concurrency::details::SchedulerBase|Concurrency::details::ThreadScheduler|Concurrency::details::UMSThreadScheduler{ + preview ( + #( + "[", + $e.m_id, + "] ", + #if ($e.m_schedulerKind == 0) ("ThreadScheduler") + #else ("UmsScheduler"), + #if ($e.m_id == $e.s_pDefaultScheduler->m_id) (", default") + #else ("") + ) + ) + + children ( + #( + #(ID: $e.m_id), + #(SchedulerPolicy: $e.m_policy), + #(VirtualProcessorCount: $e.m_virtualProcessorCount), + #(ReferenceCount: $e.m_refCount), + #([isDefaultScheduler]: $e.m_id == $e.s_pDefaultScheduler->m_id) + ) + ) +} + +;------------------------------------------------------------------------------ +; Concurrency::details::ScheduleGroupBase from +; Concurrency::details::CacheLocalScheduleGroup from +; Concurrency::details::FairScheduleGroup from +;------------------------------------------------------------------------------ +Concurrency::details::ScheduleGroupBase|Concurrency::details::CacheLocalScheduleGroup|Concurrency::details::FairScheduleGroup{ + preview ( + #( + "[", + $e.m_id, + "]", + #if ($e.m_kind & 4) (" AnonymousScheduleGroup") + #else ("") + ) + ) + + children ( + #( + #(ID: $e.m_id), + #(Scheduler: *($e.m_pScheduler)) + ) + ) +} + +;------------------------------------------------------------------------------ +; Concurrency::details::ContextBase from +; Concurrency::details::InternalContextBase from +; Concurrency::details::ThreadInternalContext from +; Concurrency::details::UMSThreadInternalContext from +;------------------------------------------------------------------------------ +Concurrency::details::ContextBase|Concurrency::details::InternalContextBase|Concurrency::details::ThreadInternalContext|Concurrency::details::UMSThreadInternalContext{ + preview ( + #( + "[", + $e.m_threadId, + "] ", + #if ($e.m_blockedState == 0) ("not_concrt_blocked") + #elif ($e.m_blockedState == 1) ("concrt_blocked") + #elif ($e.m_blockedState == 2) ("ums_sync_blocked") + #elif ($e.m_blockedState == 4) ("ums_async_blocked") + #else ("") + ) + ) + + children ( + #( + #(ID: $e.m_id), + #(ThreadID: $e.m_threadId), + #(Scheduler: *($e.m_pScheduler)), + #(ScheduleGroup: *($e.m_pGroup)) + ) + ) +} + +;------------------------------------------------------------------------------ +; Concurrency::details::ExternalContextBase from +;------------------------------------------------------------------------------ +Concurrency::details::ExternalContextBase{ + preview ( + #( + "[", + $e.m_threadId, + "] ", + #if ($e.m_contextSwitchingFence == 1) ("concrt_blocked") + #else ("not_concrt_blocked") + ) + ) + + children ( + #( + #(ID: $e.m_id), + #(ThreadID: $e.m_threadId), + #(Scheduler: *($e.m_pScheduler)), + #(ScheduleGroup: *($e.m_pGroup)) + ) + ) +} + +;------------------------------------------------------------------------------ +; Concurrency::SchedulerPolicy from +;------------------------------------------------------------------------------ +Concurrency::SchedulerPolicy{ + preview ( + #( + $e._M_pPolicyBag->_M_values._M_specificValues._M_schedulerKind, + ", Min=", + $e._M_pPolicyBag->_M_values._M_specificValues._M_minConcurrency, + ", Max=", + $e._M_pPolicyBag->_M_values._M_specificValues._M_maxConcurrency + ) + ) + + children ( + #( + #(SchedulerKind: $e._M_pPolicyBag->_M_values._M_specificValues._M_schedulerKind), + #(MinConcurrency: $e._M_pPolicyBag->_M_values._M_specificValues._M_minConcurrency), + #(MaxConcurrency: $e._M_pPolicyBag->_M_values._M_specificValues._M_maxConcurrency), + #(TargetOversubscriptionFactor: $e._M_pPolicyBag->_M_values._M_specificValues._M_targetOversubscriptionFactor), + #(LocalContextCacheSize: $e._M_pPolicyBag->_M_values._M_specificValues._M_localContextCacheSize), + #(ContextStackSize: $e._M_pPolicyBag->_M_values._M_specificValues._M_contextStackSize), + #(ContextPriority: $e._M_pPolicyBag->_M_values._M_specificValues._M_contextPriority), + #(SchedulingProtocol: $e._M_pPolicyBag->_M_values._M_specificValues._M_schedulingProtocol), + #(DynamicProgressFeedback: $e._M_pPolicyBag->_M_values._M_specificValues._M_dynamicProgressFeedback) + ) + ) +} + +;------------------------------------------------------------------------------ +; Concurrency::event from +;------------------------------------------------------------------------------ +Concurrency::event{ + preview ( + #( + #if ($e._M_pWaitChain == 1) ("set") + #else ("not_set") + ) + ) + + children ( + #( + #([is_set]: ($e._M_pWaitChain == 1)), + #([has_waiters]: (($e._M_pWaitChain != 0) && ($e._M_pWaitChain != 1))) + ) + ) +} + +;------------------------------------------------------------------------------ +; Concurrency::critical_section from +;------------------------------------------------------------------------------ +Concurrency::critical_section{ + preview ( + #( + #if ($e._M_pHead != 0) ("locked") + #else ("not_locked") + ) + ) + + children ( + #( + #([is_locked]: ($e._M_pHead != 0)), + #(OwningContext: *((Concurrency::Context*)($e._M_activeNode[0]))) + ) + ) +} + +;------------------------------------------------------------------------------ +; Concurrency::critical_section::scoped_lock from +;------------------------------------------------------------------------------ +Concurrency::critical_section::scoped_lock{ + preview ( + #( + $e._M_critical_section + ) + ) + + children ( + #( + CriticalSection: $e._M_critical_section + ) + ) +} + +;------------------------------------------------------------------------------ +; Concurrency::reader_writer_lock from +;------------------------------------------------------------------------------ +Concurrency::reader_writer_lock{ + preview ( + #( + #if (($e._M_lockState < 8) && ($e._M_lockState & 2)) ("held_by_writer") + #elif ($e._M_lockState >= 8) ( + #( + "held_by_reader(s) [", + ($e._M_lockState / 8), + "]" + ) + ) + #else ("not_held") + ) + ) + + children ( + #( + #([is_reader_lock_held]: ($e._M_lockState >= 8)), + #([num_reader_lock_holders]: ($e._M_lockState / 8)), + #([is_writer_lock_held]: ($e._M_lockState < 8) && ($e._M_lockState & 2)), + #(OwningWriterContext: *((Concurrency::Context*)($e._M_activeWriter[0]))) + ) + ) +} + +;------------------------------------------------------------------------------ +; Concurrency::reader_writer_lock::scoped_lock from +; Concurrency::reader_writer_lock::scoped_lock_read from +;------------------------------------------------------------------------------ +Concurrency::reader_writer_lock::scoped_lock|Concurrency::reader_writer_lock::scoped_lock_read{ + preview ( + #( + $e._M_reader_writer_lock + ) + ) + + children ( + #( + ReaderWriterLock: $e._M_reader_writer_lock + ) + ) +} + +;------------------------------------------------------------------------------ +; Concurrency::details::_TaskCollectionBase from +;------------------------------------------------------------------------------ +Concurrency::details::_TaskCollectionBase{ + preview ( + #( + #if ((((int)$e._M_pException & ~0x3) != 0) && (((int)$e._M_pException & ~0x3) != 0xC)) ("exception") + #else ("no_exception") + ) + ) + + children ( + #( + #([has_exception]: (((int)$e._M_pException & ~0x3) != 0) && (((int)$e._M_pException & ~0x3) != 0xC)), + #(CreatingContext: *((Concurrency::Context*)$e._M_pOwningContext)) + ) + ) +} + +;------------------------------------------------------------------------------ +; Concurrency::task_group from +; Concurrency::structured_task_group from +;------------------------------------------------------------------------------ +Concurrency::task_group|Concurrency::structured_task_group{ + preview ( + #( + #if ((((int)$e._M_task_collection._M_pException & ~0x3) != 0) && (((int)$e._M_task_collection._M_pException & ~0x3) != 0xC)) ("exception") + #else ("no_exception") + ) + ) + + children ( + #( + #([has_exception]: (((int)$e._M_task_collection._M_pException & ~0x3) != 0) && (((int)$e._M_task_collection._M_pException & ~0x3) != 0xC)), + #(CreatingContext: *((Concurrency::Context*)$e._M_task_collection._M_pOwningContext)) + ) + ) +} + +;------------------------------------------------------------------------------ +; Concurrency::task_handle from +;------------------------------------------------------------------------------ +Concurrency::task_handle<*>{ + preview ( + #( + $e._M_function + ) + ) + + children ( + #( + #(Function: $e._M_function), + #(RuntimeOwnsLifetime: $e._M_fRuntimeOwnsLifetime), + #(TaskCollection: *($e._M_pTaskCollection)) + ) + ) +} + +;------------------------------------------------------------------------------ +; Concurrency::combinable from +;------------------------------------------------------------------------------ +Concurrency::combinable<*>{ + preview( + #( + "(", + #array( + expr: *($e._M_buckets[$i]), + size: $e._M_size + ) : #list( + head: $e, + next: _M_chain + ) : $e._M_value, + ")" + ) + ) + children( + #( + #array( + expr: *($e._M_buckets[$i]), + size: $e._M_size + ) : #list( + head: $e, + next: _M_chain + ) : $e._M_value, + #(InitFunction : $e._M_fnInitialize) + ) + ) +} + +;------------------------------------------------------------------------------ +; Concurrency::concurrent_vector from +;------------------------------------------------------------------------------ +Concurrency::concurrent_vector<*,*>{ + preview( + #( + "[", + $e._My_early_size._M_value, + "](", + #array ( + expr: #( + #if (($i >> 1) == 0) ((($T1*)$e._My_segment._M_value[0]._My_array)[$i]) + #else ((($T1*)$e._My_segment._M_value[__log2($i)]._My_array)[$i - (0x1 << __log2($i))]) + ), + size: $e._My_early_size._M_value + ), + ")" + ) + ) + children( + #( + [size] : $e._My_early_size._M_value, + #array ( + expr: #( + #if (($i >> 1) == 0) ((($T1*)$e._My_segment._M_value[0]._My_array)[$i]) + #else ((($T1*)$e._My_segment._M_value[__log2($i)]._My_array)[$i - (0x1 << __log2($i))]) + ), + size: $e._My_early_size._M_value + ) + ) + ) +} + +;------------------------------------------------------------------------------ +; Concurrency::details::_Vector_iterator from +;------------------------------------------------------------------------------ +Concurrency::details::_Vector_iterator,*>{ + preview( + #( + #if (($e._My_index >> 1) == 0) ((($T1*)$e._My_vector->_My_segment._M_value[0]._My_array)[$e._My_index]) + #else ((($T1*)$e._My_vector->_My_segment._M_value[__log2($e._My_index)]._My_array)[$e._My_index - (0x1 << __log2($e._My_index))]) + ) + ) + children( + #( + [ptr]: #if (($e._My_index >> 1) == 0) (&((($T1*)$e._My_vector->_My_segment._M_value[0]._My_array)[$e._My_index])) + #else (&((($T1*)$e._My_vector->_My_segment._M_value[__log2($e._My_index)]._My_array)[$e._My_index - (0x1 << __log2($e._My_index))])) + + ) + ) +} + +;------------------------------------------------------------------------------ +; Concurrency::concurrent_queue from +;------------------------------------------------------------------------------ +Concurrency::concurrent_queue<*,*>{ + preview + ( + #( + "[", + $e._My_rep->_Tail_counter._M_value - $e._My_rep->_Head_counter._M_value, + "](", + #array + ( + expr : #if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 0) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 1) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 2) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 3) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 4) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 5) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 6) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 7) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next->_Next->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 8) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 9) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 10) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 11) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 12) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 13) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 14) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 15) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 16) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 17) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 18) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 19) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1])))))))))))))))))))), + size : #if ($e._My_rep->_Tail_counter._M_value-$e._My_rep->_Head_counter._M_value < 20*8*$e._Items_per_page) ($e._My_rep->_Tail_counter._M_value-$e._My_rep->_Head_counter._M_value) + #else (20*8*$e._Items_per_page) + ), + ")" + ) + ) + children + ( + #( + #([unsafe_size]: $e._My_rep->_Tail_counter._M_value-$e._My_rep->_Head_counter._M_value), + #array + ( + expr : #if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 0) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 1) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 2) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 3) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 4) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 5) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 6) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 7) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next->_Next->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 8) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 9) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 10) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 11) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 12) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 13) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 14) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 15) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 16) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 17) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 18) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else (#if (($i+($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)))/(8*$e._Items_per_page)-($e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>(8*($e._Items_per_page-1)))*($i%8+$e._My_rep->_Head_counter._M_value%(8*$e._Items_per_page)>=(8*$e._Items_per_page)) == 19) ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1]) + #else ((($T1*)(($e._My_rep->_Array[(($i+$e._My_rep->_Head_counter._M_value)*3%8)]._Head_page._M_value->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next->_Next) + 1))[(($i+$e._My_rep->_Head_counter._M_value)&-8)/8&$e._Items_per_page-1])))))))))))))))))))), + size : #if ($e._My_rep->_Tail_counter._M_value-$e._My_rep->_Head_counter._M_value < 20*8*$e._Items_per_page) ($e._My_rep->_Tail_counter._M_value-$e._My_rep->_Head_counter._M_value) + #else (20*8*$e._Items_per_page) + ) + ) + ) +} + +;------------------------------------------------------------------------------ +; Concurrency::details::_Concurrent_queue_iterator from +;------------------------------------------------------------------------------ +Concurrency::details::_Concurrent_queue_iterator,*>{ + preview( + #( + *(($T1*)$e._My_item) + ) + ) + children( + #( + [ptr]: (($T1*)$e._My_item) + + ) + ) +} + +; This section lets you define your own errors for the HRESULT display. +; You need to list the error code in unsigned decimal, followed by the message. +; Changes will take effect the next time you redisplay the variable. + +[hresult] +;1234=my custom error code + +[Visualizer] + +glm::detail::tvec2<*>{ + preview ( + #(#($c.x,$c.y)) + ) + children ( + #([x]: $c.x,[y]: $c.y) + ) +} + +glm::detail::tvec3<*>{ + preview ( + #($e.x,$e.y,$e.z) + ) + children ( + #([x]: $e.x,[y]: $e.y,[z]: $e.z) + ) +} + +glm::detail::tvec4<*>{ + preview ( + #($c.x,$c.y,$c.z,$c.w) + ) + children ( + #([x]: $e.x,[y]: $e.y,[z]: $e.z, #([w]: $e.w)) + ) +} diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/util/glm.natvis b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/util/glm.natvis new file mode 100644 index 0000000000000000000000000000000000000000..4db2418e402bd7eec8a8dd273e14c24c57733353 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/util/glm.natvis @@ -0,0 +1,555 @@ + + + + + + + + [{x,g}] + + x,g + + + + + [{x,g} {y,g}] + + x,g + y,g + + + + + [{x,g} {y,g} {z,g}] + + x,g + y,g + z,g + + + + + [{x,g} {y,g} {z,g} {w,g}] + + x,g + y,g + z,g + w,g + + + + + [{(int)x}] + + x + + + + + [{(int)x} {(int)y}] + + x + y + + + + + [{(int)x,g} {(int)y,g} {(int)z,g}] + + x + y + z + + + + + [{(int)x,g} {(int)y,g} {(int)z,g} {(int)w,g}] + + x + y + z + w + + + + + [{x,g} {y,g}] + + + + + + + + k = *(float *)&i + k = k * (1.5f - (n * k * k)) + k = k * (1.5f - (n * k * k)) + k = k * (1.5f - (n * k * k)) + 1/k,g + + + 0.0f,g + + + x,g + y,g + + + + + [{x,g} {y,g} {z,g}] + + + + + + + + k = *(float *)&i + k = k * (1.5f - (n * k * k)) + k = k * (1.5f - (n * k * k)) + k = k * (1.5f - (n * k * k)) + 1/k,g + + + 0.0f,g + + + + + + #{ + (unsigned((x<0?0:(x>1?1:x))*255.5f) << 24) | + (unsigned((y<0?0:(y>1?1:y))*255.5f) << 16) | + (unsigned((z<0?0:(z>1?1:z))*255.5f) << 8) | 0xFF,Xb + } + + + x,g + y,g + z,g + + + + + [{x,g} {y,g} {z,g} {w,g}] + + + + + + + + k = *(float *)&i + k = k * (1.5f - (n * k * k)) + k = k * (1.5f - (n * k * k)) + k = k * (1.5f - (n * k * k)) + 1/k,g + + + 0.0f,g + + + + + + #{ + (unsigned((x<0?0:(x>1?1:x))*255.5f) << 24) | + (unsigned((y<0?0:(y>1?1:y))*255.5f) << 16) | + (unsigned((z<0?0:(z>1?1:z))*255.5f) << 8) | + (unsigned((w<0?0:(w>1?1:w))*255.5f) << 0),Xb + } + + + x,g + y,g + z,g + w,g + + + + + [{x,g} {y,g}] + + + + + + + + k = *(double *)&i + k = k * (1.5 - (n * k * k)) + k = k * (1.5 - (n * k * k)) + k = k * (1.5 - (n * k * k)) + 1/k,g + + + 0.0,g + + + x,g + y,g + + + + + [{x,g} {y,g} {z,g}] + + + + + + + + k = *(double *)&i + k = k * (1.5 - (n * k * k)) + k = k * (1.5 - (n * k * k)) + k = k * (1.5 - (n * k * k)) + 1/k,g + + + 0.0,g + + + x,g + y,g + z,g + + + + + [{x,g} {y,g} {z,g} {w,g}] + + + + + + + + k = *(double *)&i + k = k * (1.5 - (n * k * k)) + k = k * (1.5 - (n * k * k)) + k = k * (1.5 - (n * k * k)) + 1/k,g + + + 0.0,g + + + x,g + y,g + z,g + w,g + + + + + {w,g} + {x,g}i + {y,g}j + {z,g}k + + x,g + y,g + z,g + w,g + + + + + {w,g} + {x,g}i + {y,g}j + {z,g}k + + + + + + + + k = *(float *)&i + k = k * (1.5f - (n * k * k)) + k = k * (1.5f - (n * k * k)) + k = k * (1.5f - (n * k * k)) + 1/k,g + + + 0.0f,g + + + x,g + y,g + z,g + w,g + + + + + {w,g} + {x,g}i + {y,g}j + {z,g}k + + + + + + + + k = *(double *)&i + k = k * (1.5 - (n * k * k)) + k = k * (1.5 - (n * k * k)) + k = k * (1.5 - (n * k * k)) + 1/k,g + + + 0.0,g + + + x,g + y,g + z,g + w,g + + + + + [{value[0]} {value[1]}] + + + + [{value[0].x,g} {value[1].x,g}] + + + [{value[0].y,g} {value[1].y,g}] + + + + value[0] + value[1] + + + + + + + [{value[0]} {value[1]}] + + + + [{value[0].x,g} {value[1].x,g}] + + + [{value[0].y,g} {value[1].y,g}] + + + [{value[0].z,g} {value[1].z,g}] + + + + value[0] + value[1] + + + + + + + [{value[0]} {value[1]}] + + + + [{value[0].x,g} {value[1].x,g}] + + + [{value[0].y,g} {value[1].y,g}] + + + [{value[0].z,g} {value[1].z,g}] + + + [{value[0].w,g} {value[1].w,g}] + + + + value[0] + value[1] + + + + + + + [{value[0]} {value[1]} {value[2]}] + + + + [{value[0].x,g} {value[1].x,g} {value[2].x,g}] + + + [{value[0].y,g} {value[1].y,g} {value[2].y,g}] + + + + value[0] + value[1] + value[2] + + + + + + + [{value[0]} {value[1]} {value[2]}] + + + + [{value[0].x,g} {value[1].x,g} {value[2].x,g}] + + + [{value[0].y,g} {value[1].y,g} {value[2].y,g}] + + + [{value[0].z,g} {value[1].z,g} {value[2].z,g}] + + + + value[0] + value[1] + value[2] + + + + + + + [{value[0]} {value[1]} {value[2]}] + + + + [{value[0].x,g} {value[1].x,g} {value[2].x,g}] + + + [{value[0].y,g} {value[1].y,g} {value[2].y,g}] + + + [{value[0].z,g} {value[1].z,g} {value[2].z,g}] + + + [{value[0].w,g} {value[1].w,g} {value[2].w,g}] + + + + value[0] + value[1] + value[2] + + + + + + + [{value[0]} {value[1]} {value[2]} {value[3]}] + + + + [{value[0].x,g} {value[1].x,g} {value[2].x,g} {value[3].x,g}] + + + [{value[0].y,g} {value[1].y,g} {value[2].y,g} {value[3].y,g}] + + + + value[0] + value[1] + value[2] + value[3] + + + + + + + [{value[0]} {value[1]} {value[2]} {value[3]}] + + + + [{value[0].x,g} {value[1].x,g} {value[2].x,g} {value[3].x,g}] + + + [{value[0].y,g} {value[1].y,g} {value[2].y,g} {value[3].y,g}] + + + [{value[0].z,g} {value[1].z,g} {value[2].z,g} {value[3].z,g}] + + + + value[0] + value[1] + value[2] + value[3] + + + + + + + [{value[0]} {value[1]} {value[2]} {value[3]}] + + + + [{value[0].x,g} {value[1].x,g} {value[2].x,g} {value[3].x,g}] + + + [{value[0].y,g} {value[1].y,g} {value[2].y,g} {value[3].y,g}] + + + [{value[0].z,g} {value[1].z,g} {value[2].z,g} {value[3].z,g}] + + + [{value[0].w,g} {value[1].w,g} {value[2].w,g} {value[3].w,g}] + + + + value[0] + value[1] + value[2] + value[3] + + + + + + + [r: {real}] [d: {dual}] + + real + dual + + + + \ No newline at end of file diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/util/usertype.dat b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/util/usertype.dat new file mode 100644 index 0000000000000000000000000000000000000000..cb44de3f22d6d080278aeea3ebfe74f0e35f3247 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/glm/util/usertype.dat @@ -0,0 +1,407 @@ +attribute +const +uniform +varying +break +continue +do +for +while +if +else +in +out +inout +float +int +void +bool +true +false +discard +return +mat2 +mat3 +mat4 +mat2x2 +mat3x3 +mat4x4 +mat2x3 +mat3x2 +mat2x4 +mat4x2 +mat3x4 +mat4x3 +vec2 +vec3 +vec4 +ivec2 +ivec3 +ivec4 +uvec2 +uvec3 +uvec4 +bvec2 +bvec3 +bvec4 +sampler1D +sampler2D +sampler3D +samplerCube +sampler1DShadow +sampler2DShadow +struct + +asm +class +union +enum +typedef +template +this +packed +goto +switch +default +inline +noinline +volatile +public +static +extern +external +interface +long +short +double +half +fixed +unsigned +input +output +sampler2DRect +sampler3DRect +sampler2DRectShadow +sizeof +cast +namespace +using + +layout +location +smooth +flat +noperspective +centroid +invariant +lowp +mediump +highp +precision +patch +sample +subroutine + +hvec2 +hvec3 +hvec4 +fvec2 +fvec3 +fvec4 +dvec2 +dvec3 +dvec4 + +on + +final +abstract +limited +access +self + +uchar +schar +uint +sint + +int8 +int16 +int32 +int64 + +sint8 +sint16 +sint32 +sint64 + +uint8 +uint16 +uint32 +uint64 + +float16 +float32 +float64 + +quat +hquat +fquat +dquat + +handle +handle8 +handle16 +handle32 +handle64 + +flag +flag8 +flag16 +flag32 +flag64 + +import +export + +hmat2 +hmat3 +hmat4 + +fmat2 +fmat3 +fmat4 + +dmat2 +dmat3 +dmat4 + +hmat2x3 +hmat3x2 +hmat2x4 +hmat4x2 +hmat3x4 +hmat4x3 + +fmat2x3 +fmat3x2 +fmat2x4 +fmat4x2 +fmat3x4 +fmat4x3 + +dmat2x3 +dmat3x2 +dmat2x4 +dmat4x2 +dmat3x4 +dmat4x3 + +null +pi +epsilon +infinite +self + +byte +word +dword +qword + +new_object +new_array +delete_object +delete_array + +int8 +int16 +int32 +int64 + +i8 +i16 +i32 +i64 + +i8vec2 +i8vec3 +i8vec4 + +i16vec2 +i16vec3 +i16vec4 + +i32vec2 +i32vec3 +i32vec4 + +i64vec2 +i64vec3 +i64vec4 + +uint8 +uint16 +uint32 +uint64 + +u8 +u16 +u32 +u64 + +u8vec2 +u8vec3 +u8vec4 + +u16vec2 +u16vec3 +u16vec4 + +u32vec2 +u32vec3 +u32vec4 + +u64vec2 +u64vec3 +u64vec4 + +float16 +float32 +float64 + +f16 +f32 +f64 + +f16vec2 +f16vec3 +f16vec4 + +f32vec2 +f32vec3 +f32vec4 + +f64vec2 +f64vec3 +f64vec4 + +f16mat2 +f16mat3 +f16mat4 + +f16mat2x3 +f16mat2x4 +f16mat3x2 +f16mat3x4 +f16mat4x2 +f16mat4x3 + +f32mat2 +f32mat3 +f32mat4 + +f32mat2x3 +f32mat2x4 +f32mat3x2 +f32mat3x4 +f32mat4x2 +f32mat4x3 + +f64mat2 +f64mat3 +f64mat4 + +f64mat2x3 +f64mat2x4 +f64mat3x2 +f64mat3x4 +f64mat4x2 +f64mat4x3 + +f16quat +f32quat +f64quat + +bool1 +bool2 +bool3 +bool4 + +bool1x1 +bool2x2 +bool3x3 +bool4x4 + +bool2x3 +bool2x4 +bool3x2 +bool3x4 +bool4x2 +bool4x3 + +int1 +int2 +int3 +int4 + +int1x1 +int2x2 +int3x3 +int4x4 + +int2x3 +int2x4 +int3x2 +int3x4 +int4x2 +int4x3 + +half1 +half2 +half3 +half4 + +half2x2 +half3x3 +half4x4 + +half2x3 +half2x4 +half3x2 +half3x4 +half4x2 +half4x3 + +float1 +float2 +float3 +float4 + +float1x1 +float2x2 +float3x3 +float4x4 + +float2x3 +float2x4 +float3x2 +float3x4 +float4x2 +float4x3 + +double1 +double2 +double3 +double4 + +double1x1 +double2x2 +double3x3 +double4x4 + +double2x3 +double2x4 +double3x2 +double3x4 +double4x2 +double4x3 diff --git a/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/stbi_image_write.h b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/stbi_image_write.h new file mode 100644 index 0000000000000000000000000000000000000000..023d71e460f4f2d8265d7519a9e3a2c1858fadb0 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/diff-gaussian-rasterization/third_party/stbi_image_write.h @@ -0,0 +1,1724 @@ +/* stb_image_write - v1.16 - public domain - http://nothings.org/stb + writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015 + no warranty implied; use at your own risk + + Before #including, + + #define STB_IMAGE_WRITE_IMPLEMENTATION + + in the file that you want to have the implementation. + + Will probably not work correctly with strict-aliasing optimizations. + +ABOUT: + + This header file is a library for writing images to C stdio or a callback. + + The PNG output is not optimal; it is 20-50% larger than the file + written by a decent optimizing implementation; though providing a custom + zlib compress function (see STBIW_ZLIB_COMPRESS) can mitigate that. + This library is designed for source code compactness and simplicity, + not optimal image file size or run-time performance. + +BUILDING: + + You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h. + You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace + malloc,realloc,free. + You can #define STBIW_MEMMOVE() to replace memmove() + You can #define STBIW_ZLIB_COMPRESS to use a custom zlib-style compress function + for PNG compression (instead of the builtin one), it must have the following signature: + unsigned char * my_compress(unsigned char *data, int data_len, int *out_len, int quality); + The returned data will be freed with STBIW_FREE() (free() by default), + so it must be heap allocated with STBIW_MALLOC() (malloc() by default), + +UNICODE: + + If compiling for Windows and you wish to use Unicode filenames, compile + with + #define STBIW_WINDOWS_UTF8 + and pass utf8-encoded filenames. Call stbiw_convert_wchar_to_utf8 to convert + Windows wchar_t filenames to utf8. + +USAGE: + + There are five functions, one for each image file format: + + int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); + int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); + int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); + int stbi_write_jpg(char const *filename, int w, int h, int comp, const void *data, int quality); + int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); + + void stbi_flip_vertically_on_write(int flag); // flag is non-zero to flip data vertically + + There are also five equivalent functions that use an arbitrary write function. You are + expected to open/close your file-equivalent before and after calling these: + + int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); + int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); + int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); + int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); + int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); + + where the callback is: + void stbi_write_func(void *context, void *data, int size); + + You can configure it with these global variables: + int stbi_write_tga_with_rle; // defaults to true; set to 0 to disable RLE + int stbi_write_png_compression_level; // defaults to 8; set to higher for more compression + int stbi_write_force_png_filter; // defaults to -1; set to 0..5 to force a filter mode + + + You can define STBI_WRITE_NO_STDIO to disable the file variant of these + functions, so the library will not use stdio.h at all. However, this will + also disable HDR writing, because it requires stdio for formatted output. + + Each function returns 0 on failure and non-0 on success. + + The functions create an image file defined by the parameters. The image + is a rectangle of pixels stored from left-to-right, top-to-bottom. + Each pixel contains 'comp' channels of data stored interleaved with 8-bits + per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is + monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall. + The *data pointer points to the first byte of the top-left-most pixel. + For PNG, "stride_in_bytes" is the distance in bytes from the first byte of + a row of pixels to the first byte of the next row of pixels. + + PNG creates output files with the same number of components as the input. + The BMP format expands Y to RGB in the file format and does not + output alpha. + + PNG supports writing rectangles of data even when the bytes storing rows of + data are not consecutive in memory (e.g. sub-rectangles of a larger image), + by supplying the stride between the beginning of adjacent rows. The other + formats do not. (Thus you cannot write a native-format BMP through the BMP + writer, both because it is in BGR order and because it may have padding + at the end of the line.) + + PNG allows you to set the deflate compression level by setting the global + variable 'stbi_write_png_compression_level' (it defaults to 8). + + HDR expects linear float data. Since the format is always 32-bit rgb(e) + data, alpha (if provided) is discarded, and for monochrome data it is + replicated across all three channels. + + TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed + data, set the global variable 'stbi_write_tga_with_rle' to 0. + + JPEG does ignore alpha channels in input data; quality is between 1 and 100. + Higher quality looks better but results in a bigger image. + JPEG baseline (no JPEG progressive). + +CREDITS: + + + Sean Barrett - PNG/BMP/TGA + Baldur Karlsson - HDR + Jean-Sebastien Guay - TGA monochrome + Tim Kelsey - misc enhancements + Alan Hickman - TGA RLE + Emmanuel Julien - initial file IO callback implementation + Jon Olick - original jo_jpeg.cpp code + Daniel Gibson - integrate JPEG, allow external zlib + Aarni Koskela - allow choosing PNG filter + + bugfixes: + github:Chribba + Guillaume Chereau + github:jry2 + github:romigrou + Sergio Gonzalez + Jonas Karlsson + Filip Wasil + Thatcher Ulrich + github:poppolopoppo + Patrick Boettcher + github:xeekworx + Cap Petschulat + Simon Rodriguez + Ivan Tikhonov + github:ignotion + Adam Schackart + Andrew Kensler + +LICENSE + + See end of file for license information. + +*/ + +#ifndef INCLUDE_STB_IMAGE_WRITE_H +#define INCLUDE_STB_IMAGE_WRITE_H + +#include + +// if STB_IMAGE_WRITE_STATIC causes problems, try defining STBIWDEF to 'inline' or 'static inline' +#ifndef STBIWDEF +#ifdef STB_IMAGE_WRITE_STATIC +#define STBIWDEF static +#else +#ifdef __cplusplus +#define STBIWDEF extern "C" +#else +#define STBIWDEF extern +#endif +#endif +#endif + +#ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations +STBIWDEF int stbi_write_tga_with_rle; +STBIWDEF int stbi_write_png_compression_level; +STBIWDEF int stbi_write_force_png_filter; +#endif + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); +STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); +STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality); + +#ifdef STBIW_WINDOWS_UTF8 +STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); +#endif +#endif + +typedef void stbi_write_func(void *context, void *data, int size); + +STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); +STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); +STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); + +STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean); + +#endif//INCLUDE_STB_IMAGE_WRITE_H + +#ifdef STB_IMAGE_WRITE_IMPLEMENTATION + +#ifdef _WIN32 + #ifndef _CRT_SECURE_NO_WARNINGS + #define _CRT_SECURE_NO_WARNINGS + #endif + #ifndef _CRT_NONSTDC_NO_DEPRECATE + #define _CRT_NONSTDC_NO_DEPRECATE + #endif +#endif + +#ifndef STBI_WRITE_NO_STDIO +#include +#endif // STBI_WRITE_NO_STDIO + +#include +#include +#include +#include + +#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED)) +// ok +#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED) +// ok +#else +#error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)." +#endif + +#ifndef STBIW_MALLOC +#define STBIW_MALLOC(sz) malloc(sz) +#define STBIW_REALLOC(p,newsz) realloc(p,newsz) +#define STBIW_FREE(p) free(p) +#endif + +#ifndef STBIW_REALLOC_SIZED +#define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz) +#endif + + +#ifndef STBIW_MEMMOVE +#define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz) +#endif + + +#ifndef STBIW_ASSERT +#include +#define STBIW_ASSERT(x) assert(x) +#endif + +#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff) + +#ifdef STB_IMAGE_WRITE_STATIC +static int stbi_write_png_compression_level = 8; +static int stbi_write_tga_with_rle = 1; +static int stbi_write_force_png_filter = -1; +#else +int stbi_write_png_compression_level = 8; +int stbi_write_tga_with_rle = 1; +int stbi_write_force_png_filter = -1; +#endif + +static int stbi__flip_vertically_on_write = 0; + +STBIWDEF void stbi_flip_vertically_on_write(int flag) +{ + stbi__flip_vertically_on_write = flag; +} + +typedef struct +{ + stbi_write_func *func; + void *context; + unsigned char buffer[64]; + int buf_used; +} stbi__write_context; + +// initialize a callback-based context +static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context) +{ + s->func = c; + s->context = context; +} + +#ifndef STBI_WRITE_NO_STDIO + +static void stbi__stdio_write(void *context, void *data, int size) +{ + fwrite(data,1,size,(FILE*) context); +} + +#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8) +#ifdef __cplusplus +#define STBIW_EXTERN extern "C" +#else +#define STBIW_EXTERN extern +#endif +STBIW_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); +STBIW_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); + +STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) +{ + return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); +} +#endif + +static FILE *stbiw__fopen(char const *filename, char const *mode) +{ + FILE *f; +#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8) + wchar_t wMode[64]; + wchar_t wFilename[1024]; + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename))) + return 0; + + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) + return 0; + +#if defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != _wfopen_s(&f, wFilename, wMode)) + f = 0; +#else + f = _wfopen(wFilename, wMode); +#endif + +#elif defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != fopen_s(&f, filename, mode)) + f=0; +#else + f = fopen(filename, mode); +#endif + return f; +} + +static int stbi__start_write_file(stbi__write_context *s, const char *filename) +{ + FILE *f = stbiw__fopen(filename, "wb"); + stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f); + return f != NULL; +} + +static void stbi__end_write_file(stbi__write_context *s) +{ + fclose((FILE *)s->context); +} + +#endif // !STBI_WRITE_NO_STDIO + +typedef unsigned int stbiw_uint32; +typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1]; + +static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v) +{ + while (*fmt) { + switch (*fmt++) { + case ' ': break; + case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int)); + s->func(s->context,&x,1); + break; } + case '2': { int x = va_arg(v,int); + unsigned char b[2]; + b[0] = STBIW_UCHAR(x); + b[1] = STBIW_UCHAR(x>>8); + s->func(s->context,b,2); + break; } + case '4': { stbiw_uint32 x = va_arg(v,int); + unsigned char b[4]; + b[0]=STBIW_UCHAR(x); + b[1]=STBIW_UCHAR(x>>8); + b[2]=STBIW_UCHAR(x>>16); + b[3]=STBIW_UCHAR(x>>24); + s->func(s->context,b,4); + break; } + default: + STBIW_ASSERT(0); + return; + } + } +} + +static void stbiw__writef(stbi__write_context *s, const char *fmt, ...) +{ + va_list v; + va_start(v, fmt); + stbiw__writefv(s, fmt, v); + va_end(v); +} + +static void stbiw__write_flush(stbi__write_context *s) +{ + if (s->buf_used) { + s->func(s->context, &s->buffer, s->buf_used); + s->buf_used = 0; + } +} + +static void stbiw__putc(stbi__write_context *s, unsigned char c) +{ + s->func(s->context, &c, 1); +} + +static void stbiw__write1(stbi__write_context *s, unsigned char a) +{ + if ((size_t)s->buf_used + 1 > sizeof(s->buffer)) + stbiw__write_flush(s); + s->buffer[s->buf_used++] = a; +} + +static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c) +{ + int n; + if ((size_t)s->buf_used + 3 > sizeof(s->buffer)) + stbiw__write_flush(s); + n = s->buf_used; + s->buf_used = n+3; + s->buffer[n+0] = a; + s->buffer[n+1] = b; + s->buffer[n+2] = c; +} + +static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d) +{ + unsigned char bg[3] = { 255, 0, 255}, px[3]; + int k; + + if (write_alpha < 0) + stbiw__write1(s, d[comp - 1]); + + switch (comp) { + case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case + case 1: + if (expand_mono) + stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp + else + stbiw__write1(s, d[0]); // monochrome TGA + break; + case 4: + if (!write_alpha) { + // composite against pink background + for (k = 0; k < 3; ++k) + px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255; + stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]); + break; + } + /* FALLTHROUGH */ + case 3: + stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]); + break; + } + if (write_alpha > 0) + stbiw__write1(s, d[comp - 1]); +} + +static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono) +{ + stbiw_uint32 zero = 0; + int i,j, j_end; + + if (y <= 0) + return; + + if (stbi__flip_vertically_on_write) + vdir *= -1; + + if (vdir < 0) { + j_end = -1; j = y-1; + } else { + j_end = y; j = 0; + } + + for (; j != j_end; j += vdir) { + for (i=0; i < x; ++i) { + unsigned char *d = (unsigned char *) data + (j*x+i)*comp; + stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d); + } + stbiw__write_flush(s); + s->func(s->context, &zero, scanline_pad); + } +} + +static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...) +{ + if (y < 0 || x < 0) { + return 0; + } else { + va_list v; + va_start(v, fmt); + stbiw__writefv(s, fmt, v); + va_end(v); + stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono); + return 1; + } +} + +static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data) +{ + if (comp != 4) { + // write RGB bitmap + int pad = (-x*3) & 3; + return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad, + "11 4 22 4" "4 44 22 444444", + 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header + 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header + } else { + // RGBA bitmaps need a v4 header + // use BI_BITFIELDS mode with 32bpp and alpha mask + // (straight BI_RGB with alpha mask doesn't work in most readers) + return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *)data,1,0, + "11 4 22 4" "4 44 22 444444 4444 4 444 444 444 444", + 'B', 'M', 14+108+x*y*4, 0, 0, 14+108, // file header + 108, x,y, 1,32, 3,0,0,0,0,0, 0xff0000,0xff00,0xff,0xff000000u, 0, 0,0,0, 0,0,0, 0,0,0, 0,0,0); // bitmap V4 header + } +} + +STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) +{ + stbi__write_context s = { 0 }; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_bmp_core(&s, x, y, comp, data); +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data) +{ + stbi__write_context s = { 0 }; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_bmp_core(&s, x, y, comp, data); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif //!STBI_WRITE_NO_STDIO + +static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data) +{ + int has_alpha = (comp == 2 || comp == 4); + int colorbytes = has_alpha ? comp-1 : comp; + int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3 + + if (y < 0 || x < 0) + return 0; + + if (!stbi_write_tga_with_rle) { + return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0, + "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8); + } else { + int i,j,k; + int jend, jdir; + + stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8); + + if (stbi__flip_vertically_on_write) { + j = 0; + jend = y; + jdir = 1; + } else { + j = y-1; + jend = -1; + jdir = -1; + } + for (; j != jend; j += jdir) { + unsigned char *row = (unsigned char *) data + j * x * comp; + int len; + + for (i = 0; i < x; i += len) { + unsigned char *begin = row + i * comp; + int diff = 1; + len = 1; + + if (i < x - 1) { + ++len; + diff = memcmp(begin, row + (i + 1) * comp, comp); + if (diff) { + const unsigned char *prev = begin; + for (k = i + 2; k < x && len < 128; ++k) { + if (memcmp(prev, row + k * comp, comp)) { + prev += comp; + ++len; + } else { + --len; + break; + } + } + } else { + for (k = i + 2; k < x && len < 128; ++k) { + if (!memcmp(begin, row + k * comp, comp)) { + ++len; + } else { + break; + } + } + } + } + + if (diff) { + unsigned char header = STBIW_UCHAR(len - 1); + stbiw__write1(s, header); + for (k = 0; k < len; ++k) { + stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp); + } + } else { + unsigned char header = STBIW_UCHAR(len - 129); + stbiw__write1(s, header); + stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin); + } + } + } + stbiw__write_flush(s); + } + return 1; +} + +STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) +{ + stbi__write_context s = { 0 }; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_tga_core(&s, x, y, comp, (void *) data); +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data) +{ + stbi__write_context s = { 0 }; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_tga_core(&s, x, y, comp, (void *) data); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif + +// ************************************************************************************************* +// Radiance RGBE HDR writer +// by Baldur Karlsson + +#define stbiw__max(a, b) ((a) > (b) ? (a) : (b)) + +#ifndef STBI_WRITE_NO_STDIO + +static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) +{ + int exponent; + float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2])); + + if (maxcomp < 1e-32f) { + rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0; + } else { + float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp; + + rgbe[0] = (unsigned char)(linear[0] * normalize); + rgbe[1] = (unsigned char)(linear[1] * normalize); + rgbe[2] = (unsigned char)(linear[2] * normalize); + rgbe[3] = (unsigned char)(exponent + 128); + } +} + +static void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte) +{ + unsigned char lengthbyte = STBIW_UCHAR(length+128); + STBIW_ASSERT(length+128 <= 255); + s->func(s->context, &lengthbyte, 1); + s->func(s->context, &databyte, 1); +} + +static void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data) +{ + unsigned char lengthbyte = STBIW_UCHAR(length); + STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code + s->func(s->context, &lengthbyte, 1); + s->func(s->context, data, length); +} + +static void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline) +{ + unsigned char scanlineheader[4] = { 2, 2, 0, 0 }; + unsigned char rgbe[4]; + float linear[3]; + int x; + + scanlineheader[2] = (width&0xff00)>>8; + scanlineheader[3] = (width&0x00ff); + + /* skip RLE for images too small or large */ + if (width < 8 || width >= 32768) { + for (x=0; x < width; x++) { + switch (ncomp) { + case 4: /* fallthrough */ + case 3: linear[2] = scanline[x*ncomp + 2]; + linear[1] = scanline[x*ncomp + 1]; + linear[0] = scanline[x*ncomp + 0]; + break; + default: + linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; + break; + } + stbiw__linear_to_rgbe(rgbe, linear); + s->func(s->context, rgbe, 4); + } + } else { + int c,r; + /* encode into scratch buffer */ + for (x=0; x < width; x++) { + switch(ncomp) { + case 4: /* fallthrough */ + case 3: linear[2] = scanline[x*ncomp + 2]; + linear[1] = scanline[x*ncomp + 1]; + linear[0] = scanline[x*ncomp + 0]; + break; + default: + linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; + break; + } + stbiw__linear_to_rgbe(rgbe, linear); + scratch[x + width*0] = rgbe[0]; + scratch[x + width*1] = rgbe[1]; + scratch[x + width*2] = rgbe[2]; + scratch[x + width*3] = rgbe[3]; + } + + s->func(s->context, scanlineheader, 4); + + /* RLE each component separately */ + for (c=0; c < 4; c++) { + unsigned char *comp = &scratch[width*c]; + + x = 0; + while (x < width) { + // find first run + r = x; + while (r+2 < width) { + if (comp[r] == comp[r+1] && comp[r] == comp[r+2]) + break; + ++r; + } + if (r+2 >= width) + r = width; + // dump up to first run + while (x < r) { + int len = r-x; + if (len > 128) len = 128; + stbiw__write_dump_data(s, len, &comp[x]); + x += len; + } + // if there's a run, output it + if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd + // find next byte after run + while (r < width && comp[r] == comp[x]) + ++r; + // output run up to r + while (x < r) { + int len = r-x; + if (len > 127) len = 127; + stbiw__write_run_data(s, len, comp[x]); + x += len; + } + } + } + } + } +} + +static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data) +{ + if (y <= 0 || x <= 0 || data == NULL) + return 0; + else { + // Each component is stored separately. Allocate scratch space for full output scanline. + unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4); + int i, len; + char buffer[128]; + char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; + s->func(s->context, header, sizeof(header)-1); + +#ifdef __STDC_LIB_EXT1__ + len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); +#else + len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); +#endif + s->func(s->context, buffer, len); + + for(i=0; i < y; i++) + stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*x*(stbi__flip_vertically_on_write ? y-1-i : i)); + STBIW_FREE(scratch); + return 1; + } +} + +STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data) +{ + stbi__write_context s = { 0 }; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_hdr_core(&s, x, y, comp, (float *) data); +} + +STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data) +{ + stbi__write_context s = { 0 }; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif // STBI_WRITE_NO_STDIO + + +////////////////////////////////////////////////////////////////////////////// +// +// PNG writer +// + +#ifndef STBIW_ZLIB_COMPRESS +// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size() +#define stbiw__sbraw(a) ((int *) (void *) (a) - 2) +#define stbiw__sbm(a) stbiw__sbraw(a)[0] +#define stbiw__sbn(a) stbiw__sbraw(a)[1] + +#define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a)) +#define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0) +#define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a))) + +#define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v)) +#define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0) +#define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0) + +static void *stbiw__sbgrowf(void **arr, int increment, int itemsize) +{ + int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1; + void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2); + STBIW_ASSERT(p); + if (p) { + if (!*arr) ((int *) p)[1] = 0; + *arr = (void *) ((int *) p + 2); + stbiw__sbm(*arr) = m; + } + return *arr; +} + +static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount) +{ + while (*bitcount >= 8) { + stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer)); + *bitbuffer >>= 8; + *bitcount -= 8; + } + return data; +} + +static int stbiw__zlib_bitrev(int code, int codebits) +{ + int res=0; + while (codebits--) { + res = (res << 1) | (code & 1); + code >>= 1; + } + return res; +} + +static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit) +{ + int i; + for (i=0; i < limit && i < 258; ++i) + if (a[i] != b[i]) break; + return i; +} + +static unsigned int stbiw__zhash(unsigned char *data) +{ + stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16); + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 4; + hash += hash >> 17; + hash ^= hash << 25; + hash += hash >> 6; + return hash; +} + +#define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount)) +#define stbiw__zlib_add(code,codebits) \ + (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush()) +#define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c) +// default huffman tables +#define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8) +#define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9) +#define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7) +#define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8) +#define stbiw__zlib_huff(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n)) +#define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n)) + +#define stbiw__ZHASH 16384 + +#endif // STBIW_ZLIB_COMPRESS + +STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) +{ +#ifdef STBIW_ZLIB_COMPRESS + // user provided a zlib compress implementation, use that + return STBIW_ZLIB_COMPRESS(data, data_len, out_len, quality); +#else // use builtin + static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 }; + static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; + static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 }; + static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 }; + unsigned int bitbuf=0; + int i,j, bitcount=0; + unsigned char *out = NULL; + unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(unsigned char**)); + if (hash_table == NULL) + return NULL; + if (quality < 5) quality = 5; + + stbiw__sbpush(out, 0x78); // DEFLATE 32K window + stbiw__sbpush(out, 0x5e); // FLEVEL = 1 + stbiw__zlib_add(1,1); // BFINAL = 1 + stbiw__zlib_add(1,2); // BTYPE = 1 -- fixed huffman + + for (i=0; i < stbiw__ZHASH; ++i) + hash_table[i] = NULL; + + i=0; + while (i < data_len-3) { + // hash next 3 bytes of data to be compressed + int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3; + unsigned char *bestloc = 0; + unsigned char **hlist = hash_table[h]; + int n = stbiw__sbcount(hlist); + for (j=0; j < n; ++j) { + if (hlist[j]-data > i-32768) { // if entry lies within window + int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i); + if (d >= best) { best=d; bestloc=hlist[j]; } + } + } + // when hash table entry is too long, delete half the entries + if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) { + STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality); + stbiw__sbn(hash_table[h]) = quality; + } + stbiw__sbpush(hash_table[h],data+i); + + if (bestloc) { + // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal + h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1); + hlist = hash_table[h]; + n = stbiw__sbcount(hlist); + for (j=0; j < n; ++j) { + if (hlist[j]-data > i-32767) { + int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1); + if (e > best) { // if next match is better, bail on current match + bestloc = NULL; + break; + } + } + } + } + + if (bestloc) { + int d = (int) (data+i - bestloc); // distance back + STBIW_ASSERT(d <= 32767 && best <= 258); + for (j=0; best > lengthc[j+1]-1; ++j); + stbiw__zlib_huff(j+257); + if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]); + for (j=0; d > distc[j+1]-1; ++j); + stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5); + if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]); + i += best; + } else { + stbiw__zlib_huffb(data[i]); + ++i; + } + } + // write out final bytes + for (;i < data_len; ++i) + stbiw__zlib_huffb(data[i]); + stbiw__zlib_huff(256); // end of block + // pad with 0 bits to byte boundary + while (bitcount) + stbiw__zlib_add(0,1); + + for (i=0; i < stbiw__ZHASH; ++i) + (void) stbiw__sbfree(hash_table[i]); + STBIW_FREE(hash_table); + + // store uncompressed instead if compression was worse + if (stbiw__sbn(out) > data_len + 2 + ((data_len+32766)/32767)*5) { + stbiw__sbn(out) = 2; // truncate to DEFLATE 32K window and FLEVEL = 1 + for (j = 0; j < data_len;) { + int blocklen = data_len - j; + if (blocklen > 32767) blocklen = 32767; + stbiw__sbpush(out, data_len - j == blocklen); // BFINAL = ?, BTYPE = 0 -- no compression + stbiw__sbpush(out, STBIW_UCHAR(blocklen)); // LEN + stbiw__sbpush(out, STBIW_UCHAR(blocklen >> 8)); + stbiw__sbpush(out, STBIW_UCHAR(~blocklen)); // NLEN + stbiw__sbpush(out, STBIW_UCHAR(~blocklen >> 8)); + memcpy(out+stbiw__sbn(out), data+j, blocklen); + stbiw__sbn(out) += blocklen; + j += blocklen; + } + } + + { + // compute adler32 on input + unsigned int s1=1, s2=0; + int blocklen = (int) (data_len % 5552); + j=0; + while (j < data_len) { + for (i=0; i < blocklen; ++i) { s1 += data[j+i]; s2 += s1; } + s1 %= 65521; s2 %= 65521; + j += blocklen; + blocklen = 5552; + } + stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8)); + stbiw__sbpush(out, STBIW_UCHAR(s2)); + stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8)); + stbiw__sbpush(out, STBIW_UCHAR(s1)); + } + *out_len = stbiw__sbn(out); + // make returned pointer freeable + STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len); + return (unsigned char *) stbiw__sbraw(out); +#endif // STBIW_ZLIB_COMPRESS +} + +static unsigned int stbiw__crc32(unsigned char *buffer, int len) +{ +#ifdef STBIW_CRC32 + return STBIW_CRC32(buffer, len); +#else + static unsigned int crc_table[256] = + { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D + }; + + unsigned int crc = ~0u; + int i; + for (i=0; i < len; ++i) + crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; + return ~crc; +#endif +} + +#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4) +#define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v)); +#define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3]) + +static void stbiw__wpcrc(unsigned char **data, int len) +{ + unsigned int crc = stbiw__crc32(*data - len - 4, len+4); + stbiw__wp32(*data, crc); +} + +static unsigned char stbiw__paeth(int a, int b, int c) +{ + int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c); + if (pa <= pb && pa <= pc) return STBIW_UCHAR(a); + if (pb <= pc) return STBIW_UCHAR(b); + return STBIW_UCHAR(c); +} + +// @OPTIMIZE: provide an option that always forces left-predict or paeth predict +static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int width, int height, int y, int n, int filter_type, signed char *line_buffer) +{ + static int mapping[] = { 0,1,2,3,4 }; + static int firstmap[] = { 0,1,0,5,6 }; + int *mymap = (y != 0) ? mapping : firstmap; + int i; + int type = mymap[filter_type]; + unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y); + int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes; + + if (type==0) { + memcpy(line_buffer, z, width*n); + return; + } + + // first loop isn't optimized since it's just one pixel + for (i = 0; i < n; ++i) { + switch (type) { + case 1: line_buffer[i] = z[i]; break; + case 2: line_buffer[i] = z[i] - z[i-signed_stride]; break; + case 3: line_buffer[i] = z[i] - (z[i-signed_stride]>>1); break; + case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-signed_stride],0)); break; + case 5: line_buffer[i] = z[i]; break; + case 6: line_buffer[i] = z[i]; break; + } + } + switch (type) { + case 1: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-n]; break; + case 2: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-signed_stride]; break; + case 3: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - ((z[i-n] + z[i-signed_stride])>>1); break; + case 4: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-signed_stride], z[i-signed_stride-n]); break; + case 5: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - (z[i-n]>>1); break; + case 6: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break; + } +} + +STBIWDEF unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) +{ + int force_filter = stbi_write_force_png_filter; + int ctype[5] = { -1, 0, 4, 2, 6 }; + unsigned char sig[8] = { 137,80,78,71,13,10,26,10 }; + unsigned char *out,*o, *filt, *zlib; + signed char *line_buffer; + int j,zlen; + + if (stride_bytes == 0) + stride_bytes = x * n; + + if (force_filter >= 5) { + force_filter = -1; + } + + filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0; + line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; } + for (j=0; j < y; ++j) { + int filter_type; + if (force_filter > -1) { + filter_type = force_filter; + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, force_filter, line_buffer); + } else { // Estimate the best filter by running through all of them: + int best_filter = 0, best_filter_val = 0x7fffffff, est, i; + for (filter_type = 0; filter_type < 5; filter_type++) { + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, filter_type, line_buffer); + + // Estimate the entropy of the line using this filter; the less, the better. + est = 0; + for (i = 0; i < x*n; ++i) { + est += abs((signed char) line_buffer[i]); + } + if (est < best_filter_val) { + best_filter_val = est; + best_filter = filter_type; + } + } + if (filter_type != best_filter) { // If the last iteration already got us the best filter, don't redo it + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, best_filter, line_buffer); + filter_type = best_filter; + } + } + // when we get here, filter_type contains the filter type, and line_buffer contains the data + filt[j*(x*n+1)] = (unsigned char) filter_type; + STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n); + } + STBIW_FREE(line_buffer); + zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, stbi_write_png_compression_level); + STBIW_FREE(filt); + if (!zlib) return 0; + + // each tag requires 12 bytes of overhead + out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12); + if (!out) return 0; + *out_len = 8 + 12+13 + 12+zlen + 12; + + o=out; + STBIW_MEMMOVE(o,sig,8); o+= 8; + stbiw__wp32(o, 13); // header length + stbiw__wptag(o, "IHDR"); + stbiw__wp32(o, x); + stbiw__wp32(o, y); + *o++ = 8; + *o++ = STBIW_UCHAR(ctype[n]); + *o++ = 0; + *o++ = 0; + *o++ = 0; + stbiw__wpcrc(&o,13); + + stbiw__wp32(o, zlen); + stbiw__wptag(o, "IDAT"); + STBIW_MEMMOVE(o, zlib, zlen); + o += zlen; + STBIW_FREE(zlib); + stbiw__wpcrc(&o, zlen); + + stbiw__wp32(o,0); + stbiw__wptag(o, "IEND"); + stbiw__wpcrc(&o,0); + + STBIW_ASSERT(o == out + *out_len); + + return out; +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes) +{ + FILE *f; + int len; + unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); + if (png == NULL) return 0; + + f = stbiw__fopen(filename, "wb"); + if (!f) { STBIW_FREE(png); return 0; } + fwrite(png, 1, len, f); + fclose(f); + STBIW_FREE(png); + return 1; +} +#endif + +STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes) +{ + int len; + unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); + if (png == NULL) return 0; + func(context, png, len); + STBIW_FREE(png); + return 1; +} + + +/* *************************************************************************** + * + * JPEG writer + * + * This is based on Jon Olick's jo_jpeg.cpp: + * public domain Simple, Minimalistic JPEG writer - http://www.jonolick.com/code.html + */ + +static const unsigned char stbiw__jpg_ZigZag[] = { 0,1,5,6,14,15,27,28,2,4,7,13,16,26,29,42,3,8,12,17,25,30,41,43,9,11,18, + 24,31,40,44,53,10,19,23,32,39,45,52,54,20,22,33,38,46,51,55,60,21,34,37,47,50,56,59,61,35,36,48,49,57,58,62,63 }; + +static void stbiw__jpg_writeBits(stbi__write_context *s, int *bitBufP, int *bitCntP, const unsigned short *bs) { + int bitBuf = *bitBufP, bitCnt = *bitCntP; + bitCnt += bs[1]; + bitBuf |= bs[0] << (24 - bitCnt); + while(bitCnt >= 8) { + unsigned char c = (bitBuf >> 16) & 255; + stbiw__putc(s, c); + if(c == 255) { + stbiw__putc(s, 0); + } + bitBuf <<= 8; + bitCnt -= 8; + } + *bitBufP = bitBuf; + *bitCntP = bitCnt; +} + +static void stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float *d4p, float *d5p, float *d6p, float *d7p) { + float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, d6 = *d6p, d7 = *d7p; + float z1, z2, z3, z4, z5, z11, z13; + + float tmp0 = d0 + d7; + float tmp7 = d0 - d7; + float tmp1 = d1 + d6; + float tmp6 = d1 - d6; + float tmp2 = d2 + d5; + float tmp5 = d2 - d5; + float tmp3 = d3 + d4; + float tmp4 = d3 - d4; + + // Even part + float tmp10 = tmp0 + tmp3; // phase 2 + float tmp13 = tmp0 - tmp3; + float tmp11 = tmp1 + tmp2; + float tmp12 = tmp1 - tmp2; + + d0 = tmp10 + tmp11; // phase 3 + d4 = tmp10 - tmp11; + + z1 = (tmp12 + tmp13) * 0.707106781f; // c4 + d2 = tmp13 + z1; // phase 5 + d6 = tmp13 - z1; + + // Odd part + tmp10 = tmp4 + tmp5; // phase 2 + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + // The rotator is modified from fig 4-8 to avoid extra negations. + z5 = (tmp10 - tmp12) * 0.382683433f; // c6 + z2 = tmp10 * 0.541196100f + z5; // c2-c6 + z4 = tmp12 * 1.306562965f + z5; // c2+c6 + z3 = tmp11 * 0.707106781f; // c4 + + z11 = tmp7 + z3; // phase 5 + z13 = tmp7 - z3; + + *d5p = z13 + z2; // phase 6 + *d3p = z13 - z2; + *d1p = z11 + z4; + *d7p = z11 - z4; + + *d0p = d0; *d2p = d2; *d4p = d4; *d6p = d6; +} + +static void stbiw__jpg_calcBits(int val, unsigned short bits[2]) { + int tmp1 = val < 0 ? -val : val; + val = val < 0 ? val-1 : val; + bits[1] = 1; + while(tmp1 >>= 1) { + ++bits[1]; + } + bits[0] = val & ((1<0)&&(DU[end0pos]==0); --end0pos) { + } + // end0pos = first element in reverse order !=0 + if(end0pos == 0) { + stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); + return DU[0]; + } + for(i = 1; i <= end0pos; ++i) { + int startpos = i; + int nrzeroes; + unsigned short bits[2]; + for (; DU[i]==0 && i<=end0pos; ++i) { + } + nrzeroes = i-startpos; + if ( nrzeroes >= 16 ) { + int lng = nrzeroes>>4; + int nrmarker; + for (nrmarker=1; nrmarker <= lng; ++nrmarker) + stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes); + nrzeroes &= 15; + } + stbiw__jpg_calcBits(DU[i], bits); + stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes<<4)+bits[1]]); + stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits); + } + if(end0pos != 63) { + stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); + } + return DU[0]; +} + +static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void* data, int quality) { + // Constants that don't pollute global namespace + static const unsigned char std_dc_luminance_nrcodes[] = {0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0}; + static const unsigned char std_dc_luminance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; + static const unsigned char std_ac_luminance_nrcodes[] = {0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d}; + static const unsigned char std_ac_luminance_values[] = { + 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08, + 0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28, + 0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59, + 0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89, + 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6, + 0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2, + 0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa + }; + static const unsigned char std_dc_chrominance_nrcodes[] = {0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0}; + static const unsigned char std_dc_chrominance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; + static const unsigned char std_ac_chrominance_nrcodes[] = {0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77}; + static const unsigned char std_ac_chrominance_values[] = { + 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91, + 0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26, + 0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58, + 0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87, + 0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4, + 0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda, + 0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa + }; + // Huffman tables + static const unsigned short YDC_HT[256][2] = { {0,2},{2,3},{3,3},{4,3},{5,3},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9}}; + static const unsigned short UVDC_HT[256][2] = { {0,2},{1,2},{2,2},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9},{1022,10},{2046,11}}; + static const unsigned short YAC_HT[256][2] = { + {10,4},{0,2},{1,2},{4,3},{11,4},{26,5},{120,7},{248,8},{1014,10},{65410,16},{65411,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {12,4},{27,5},{121,7},{502,9},{2038,11},{65412,16},{65413,16},{65414,16},{65415,16},{65416,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {28,5},{249,8},{1015,10},{4084,12},{65417,16},{65418,16},{65419,16},{65420,16},{65421,16},{65422,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {58,6},{503,9},{4085,12},{65423,16},{65424,16},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {59,6},{1016,10},{65430,16},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {122,7},{2039,11},{65438,16},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {123,7},{4086,12},{65446,16},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {250,8},{4087,12},{65454,16},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {504,9},{32704,15},{65462,16},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {505,9},{65470,16},{65471,16},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {506,9},{65479,16},{65480,16},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {1017,10},{65488,16},{65489,16},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {1018,10},{65497,16},{65498,16},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {2040,11},{65506,16},{65507,16},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {65515,16},{65516,16},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{0,0},{0,0},{0,0},{0,0},{0,0}, + {2041,11},{65525,16},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} + }; + static const unsigned short UVAC_HT[256][2] = { + {0,2},{1,2},{4,3},{10,4},{24,5},{25,5},{56,6},{120,7},{500,9},{1014,10},{4084,12},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {11,4},{57,6},{246,8},{501,9},{2038,11},{4085,12},{65416,16},{65417,16},{65418,16},{65419,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {26,5},{247,8},{1015,10},{4086,12},{32706,15},{65420,16},{65421,16},{65422,16},{65423,16},{65424,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {27,5},{248,8},{1016,10},{4087,12},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{65430,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {58,6},{502,9},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{65438,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {59,6},{1017,10},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{65446,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {121,7},{2039,11},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{65454,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {122,7},{2040,11},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{65462,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {249,8},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{65470,16},{65471,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {503,9},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{65479,16},{65480,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {504,9},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{65488,16},{65489,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {505,9},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{65497,16},{65498,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {506,9},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{65506,16},{65507,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {2041,11},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{65515,16},{65516,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {16352,14},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{65525,16},{0,0},{0,0},{0,0},{0,0},{0,0}, + {1018,10},{32707,15},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} + }; + static const int YQT[] = {16,11,10,16,24,40,51,61,12,12,14,19,26,58,60,55,14,13,16,24,40,57,69,56,14,17,22,29,51,87,80,62,18,22, + 37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99}; + static const int UVQT[] = {17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99, + 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99}; + static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f, + 1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f }; + + int row, col, i, k, subsample; + float fdtbl_Y[64], fdtbl_UV[64]; + unsigned char YTable[64], UVTable[64]; + + if(!data || !width || !height || comp > 4 || comp < 1) { + return 0; + } + + quality = quality ? quality : 90; + subsample = quality <= 90 ? 1 : 0; + quality = quality < 1 ? 1 : quality > 100 ? 100 : quality; + quality = quality < 50 ? 5000 / quality : 200 - quality * 2; + + for(i = 0; i < 64; ++i) { + int uvti, yti = (YQT[i]*quality+50)/100; + YTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (yti < 1 ? 1 : yti > 255 ? 255 : yti); + uvti = (UVQT[i]*quality+50)/100; + UVTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (uvti < 1 ? 1 : uvti > 255 ? 255 : uvti); + } + + for(row = 0, k = 0; row < 8; ++row) { + for(col = 0; col < 8; ++col, ++k) { + fdtbl_Y[k] = 1 / (YTable [stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); + fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); + } + } + + // Write Headers + { + static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 }; + static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 }; + const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width), + 3,1,(unsigned char)(subsample?0x22:0x11),0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 }; + s->func(s->context, (void*)head0, sizeof(head0)); + s->func(s->context, (void*)YTable, sizeof(YTable)); + stbiw__putc(s, 1); + s->func(s->context, UVTable, sizeof(UVTable)); + s->func(s->context, (void*)head1, sizeof(head1)); + s->func(s->context, (void*)(std_dc_luminance_nrcodes+1), sizeof(std_dc_luminance_nrcodes)-1); + s->func(s->context, (void*)std_dc_luminance_values, sizeof(std_dc_luminance_values)); + stbiw__putc(s, 0x10); // HTYACinfo + s->func(s->context, (void*)(std_ac_luminance_nrcodes+1), sizeof(std_ac_luminance_nrcodes)-1); + s->func(s->context, (void*)std_ac_luminance_values, sizeof(std_ac_luminance_values)); + stbiw__putc(s, 1); // HTUDCinfo + s->func(s->context, (void*)(std_dc_chrominance_nrcodes+1), sizeof(std_dc_chrominance_nrcodes)-1); + s->func(s->context, (void*)std_dc_chrominance_values, sizeof(std_dc_chrominance_values)); + stbiw__putc(s, 0x11); // HTUACinfo + s->func(s->context, (void*)(std_ac_chrominance_nrcodes+1), sizeof(std_ac_chrominance_nrcodes)-1); + s->func(s->context, (void*)std_ac_chrominance_values, sizeof(std_ac_chrominance_values)); + s->func(s->context, (void*)head2, sizeof(head2)); + } + + // Encode 8x8 macroblocks + { + static const unsigned short fillBits[] = {0x7F, 7}; + int DCY=0, DCU=0, DCV=0; + int bitBuf=0, bitCnt=0; + // comp == 2 is grey+alpha (alpha is ignored) + int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0; + const unsigned char *dataR = (const unsigned char *)data; + const unsigned char *dataG = dataR + ofsG; + const unsigned char *dataB = dataR + ofsB; + int x, y, pos; + if(subsample) { + for(y = 0; y < height; y += 16) { + for(x = 0; x < width; x += 16) { + float Y[256], U[256], V[256]; + for(row = y, pos = 0; row < y+16; ++row) { + // row >= height => use last input row + int clamped_row = (row < height) ? row : height - 1; + int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; + for(col = x; col < x+16; ++col, ++pos) { + // if col >= width => use pixel from last input column + int p = base_p + ((col < width) ? col : (width-1))*comp; + float r = dataR[p], g = dataG[p], b = dataB[p]; + Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; + U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; + V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; + } + } + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+0, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+8, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+128, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+136, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + + // subsample U,V + { + float subU[64], subV[64]; + int yy, xx; + for(yy = 0, pos = 0; yy < 8; ++yy) { + for(xx = 0; xx < 8; ++xx, ++pos) { + int j = yy*32+xx*2; + subU[pos] = (U[j+0] + U[j+1] + U[j+16] + U[j+17]) * 0.25f; + subV[pos] = (V[j+0] + V[j+1] + V[j+16] + V[j+17]) * 0.25f; + } + } + DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subU, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); + DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subV, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); + } + } + } + } else { + for(y = 0; y < height; y += 8) { + for(x = 0; x < width; x += 8) { + float Y[64], U[64], V[64]; + for(row = y, pos = 0; row < y+8; ++row) { + // row >= height => use last input row + int clamped_row = (row < height) ? row : height - 1; + int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; + for(col = x; col < x+8; ++col, ++pos) { + // if col >= width => use pixel from last input column + int p = base_p + ((col < width) ? col : (width-1))*comp; + float r = dataR[p], g = dataG[p], b = dataB[p]; + Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; + U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; + V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; + } + } + + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y, 8, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, U, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); + DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, V, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); + } + } + } + + // Do the bit alignment of the EOI marker + stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits); + } + + // EOI + stbiw__putc(s, 0xFF); + stbiw__putc(s, 0xD9); + + return 1; +} + +STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality) +{ + stbi__write_context s = { 0 }; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality); +} + + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality) +{ + stbi__write_context s = { 0 }; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_jpg_core(&s, x, y, comp, data, quality); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif + +#endif // STB_IMAGE_WRITE_IMPLEMENTATION + +/* Revision history + 1.16 (2021-07-11) + make Deflate code emit uncompressed blocks when it would otherwise expand + support writing BMPs with alpha channel + 1.15 (2020-07-13) unknown + 1.14 (2020-02-02) updated JPEG writer to downsample chroma channels + 1.13 + 1.12 + 1.11 (2019-08-11) + + 1.10 (2019-02-07) + support utf8 filenames in Windows; fix warnings and platform ifdefs + 1.09 (2018-02-11) + fix typo in zlib quality API, improve STB_I_W_STATIC in C++ + 1.08 (2018-01-29) + add stbi__flip_vertically_on_write, external zlib, zlib quality, choose PNG filter + 1.07 (2017-07-24) + doc fix + 1.06 (2017-07-23) + writing JPEG (using Jon Olick's code) + 1.05 ??? + 1.04 (2017-03-03) + monochrome BMP expansion + 1.03 ??? + 1.02 (2016-04-02) + avoid allocating large structures on the stack + 1.01 (2016-01-16) + STBIW_REALLOC_SIZED: support allocators with no realloc support + avoid race-condition in crc initialization + minor compile issues + 1.00 (2015-09-14) + installable file IO function + 0.99 (2015-09-13) + warning fixes; TGA rle support + 0.98 (2015-04-08) + added STBIW_MALLOC, STBIW_ASSERT etc + 0.97 (2015-01-18) + fixed HDR asserts, rewrote HDR rle logic + 0.96 (2015-01-17) + add HDR output + fix monochrome BMP + 0.95 (2014-08-17) + add monochrome TGA output + 0.94 (2014-05-31) + rename private functions to avoid conflicts with stb_image.h + 0.93 (2014-05-27) + warning fixes + 0.92 (2010-08-01) + casts to unsigned char to fix warnings + 0.91 (2010-07-17) + first public release + 0.90 first internal release +*/ + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ \ No newline at end of file diff --git a/submodules/gaussian-splatting/submodules/fused-ssim/.gitignore b/submodules/gaussian-splatting/submodules/fused-ssim/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..7ede7fe4117ec80ae327dd85159c37ed90e28784 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/fused-ssim/.gitignore @@ -0,0 +1,2 @@ +build/ +fused_ssim.egg-info/ diff --git a/submodules/gaussian-splatting/submodules/fused-ssim/LICENSE b/submodules/gaussian-splatting/submodules/fused-ssim/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..541f73944912fde14ffb971f22ba516042b95ab7 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/fused-ssim/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Rahul Goel + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/submodules/gaussian-splatting/submodules/fused-ssim/README.md b/submodules/gaussian-splatting/submodules/fused-ssim/README.md new file mode 100644 index 0000000000000000000000000000000000000000..e1c44e2d8b50a0dda269bd7b906a421ec01c821e --- /dev/null +++ b/submodules/gaussian-splatting/submodules/fused-ssim/README.md @@ -0,0 +1,49 @@ +# Fully Fused Differentiable SSIM + +This repository contains an efficient fully-fused implementation of [SSIM](https://en.wikipedia.org/wiki/Structural_similarity_index_measure) which is differentiable in nature. There are several factors that contribute to an efficient implementation: +- Convolutions in SSIM are spatially localized leading to fully-fused implementation without touching global memory for intermediate steps. +- Backpropagation through Gaussian Convolution is simply another Gaussian Convolution itself. +- Gaussian Convolutions are separable leading to reduced computation. + +As per the original SSIM paper, this implementation uses `11x11` sized convolution kernel. The weights for it have been hardcoded and this is another reason for it's speed. This implementation currently only supports **2D images** but with **variable number of channels** and **batch size**. + +## PyTorch Installation Instructions +- You must have CUDA and PyTorch+CUDA installed in you Python 3.X environment. This project has currently been tested with PyTorch `2.3.1+cu118` and CUDA `11.8` on Ubuntu 24.04 LTS. +- Run `pip install git+https://github.com/rahul-goel/fused-ssim/` or clone the repository and run `pip install .` from the root of this project. + +## Usage +```python +import torch +from fused_ssim import fused_ssim + +# predicted_image, gt_image: [BS, CH, H, W] +# predicted_image is differentiable +gt_image = torch.rand(2, 3, 1080, 1920) +predicted_image = torch.nn.Parameter(torch.rand_like(gt_image)) +ssim_value = fused_ssim(predicted_image, gt_image) +``` + +By default, `same` padding is used. To use `valid` padding which is the kind of padding used by [pytorch-mssim](https://github.com/VainF/pytorch-msssim): +```python +ssim_value = fused_ssim(predicted_image, gt_image, padding="valid") +``` + +If you don't want to train and use this only for inference, use the following for even faster speed: +```python +with torch.no_grad(): + ssim_value = fused_ssim(predicted_image, gt_image, train=False) +``` + +## Constraints +- Currently, only one of the images is allowed to be differentiable i.e. only the first image can be `nn.Parameter`. +- Limited to 2D images. +- Images must be normalized to range `[0, 1]`. +- Standard `11x11` convolutions supported. + +## Performance +This implementation is 5-8x faster than the previous fastest (to the best of my knowledge) differentiable SSIM implementation [pytorch-mssim](https://github.com/VainF/pytorch-msssim). + + + +## Acknowledgements +Thanks to [Bernhard](https://snosixtyboo.github.io) for the idea. diff --git a/submodules/gaussian-splatting/submodules/fused-ssim/ext.cpp b/submodules/gaussian-splatting/submodules/fused-ssim/ext.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3eeece12ad64d46e79c810ba7569325f96e35573 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/fused-ssim/ext.cpp @@ -0,0 +1,7 @@ +#include +#include "ssim.h" + +PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { + m.def("fusedssim", &fusedssim); + m.def("fusedssim_backward", &fusedssim_backward); +} diff --git a/submodules/gaussian-splatting/submodules/fused-ssim/fused_ssim/__init__.py b/submodules/gaussian-splatting/submodules/fused-ssim/fused_ssim/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..16d92c58d0bc811ce5bda4927ca628ee30392200 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/fused-ssim/fused_ssim/__init__.py @@ -0,0 +1,41 @@ +from typing import NamedTuple +import torch.nn as nn +import torch +from fused_ssim_cuda import fusedssim, fusedssim_backward + +allowed_padding = ["same", "valid"] + +class FusedSSIMMap(torch.autograd.Function): + @staticmethod + def forward(ctx, C1, C2, img1, img2, padding="same", train=True): + ssim_map, dm_dmu1, dm_dsigma1_sq, dm_dsigma12 = fusedssim(C1, C2, img1, img2, train) + + if padding == "valid": + ssim_map = ssim_map[:, :, 5:-5, 5:-5] + + ctx.save_for_backward(img1.detach(), img2, dm_dmu1, dm_dsigma1_sq, dm_dsigma12) + ctx.C1 = C1 + ctx.C2 = C2 + ctx.padding = padding + + return ssim_map + + @staticmethod + def backward(ctx, opt_grad): + img1, img2, dm_dmu1, dm_dsigma1_sq, dm_dsigma12 = ctx.saved_tensors + C1, C2, padding = ctx.C1, ctx.C2, ctx.padding + dL_dmap = opt_grad + if padding == "valid": + dL_dmap = torch.zeros_like(img1) + dL_dmap[:, :, 5:-5, 5:-5] = opt_grad + grad = fusedssim_backward(C1, C2, img1, img2, dL_dmap, dm_dmu1, dm_dsigma1_sq, dm_dsigma12) + return None, None, grad, None, None, None + +def fused_ssim(img1, img2, padding="same", train=True): + C1 = 0.01 ** 2 + C2 = 0.03 ** 2 + + assert padding in allowed_padding + + map = FusedSSIMMap.apply(C1, C2, img1, img2, padding, train) + return map.mean() diff --git a/submodules/gaussian-splatting/submodules/fused-ssim/setup.py b/submodules/gaussian-splatting/submodules/fused-ssim/setup.py new file mode 100644 index 0000000000000000000000000000000000000000..fcffbbe94743628332ab52a5ece45a5eb680f846 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/fused-ssim/setup.py @@ -0,0 +1,17 @@ +from setuptools import setup +from torch.utils.cpp_extension import CUDAExtension, BuildExtension + +setup( + name="fused_ssim", + packages=['fused_ssim'], + ext_modules=[ + CUDAExtension( + name="fused_ssim_cuda", + sources=[ + "ssim.cu", + "ext.cpp"]) + ], + cmdclass={ + 'build_ext': BuildExtension + } +) diff --git a/submodules/gaussian-splatting/submodules/fused-ssim/ssim.cu b/submodules/gaussian-splatting/submodules/fused-ssim/ssim.cu new file mode 100644 index 0000000000000000000000000000000000000000..7d211fca8cf4a09874be9f786c82764a76140b4d --- /dev/null +++ b/submodules/gaussian-splatting/submodules/fused-ssim/ssim.cu @@ -0,0 +1,444 @@ +#include +#include +#include +#include +#include + +namespace cg = cooperative_groups; + +#define G_00 0.001028380123898387f +#define G_01 0.0075987582094967365f +#define G_02 0.036000773310661316f +#define G_03 0.10936068743467331f +#define G_04 0.21300552785396576f +#define G_05 0.26601171493530273f +#define G_06 0.21300552785396576f +#define G_07 0.10936068743467331f +#define G_08 0.036000773310661316f +#define G_09 0.0075987582094967365f +#define G_10 0.001028380123898387f + +// block size +#define BX 32 +#define BY 32 + +// shared memory size +#define SX (BX + 10) +#define SSX (BX + 10) +#define SY (BY + 10) + +// convolution scratchpad size +#define CX (BX) +#define CCX (BX + 0) +#define CY (BY + 10) + + +__device__ float get_pix_value(const float* img, const int b, const int c, const int y, const int x, const int CH, const int H, const int W) { + if (x >= W || y >= H || x < 0 || y < 0) { + return 0.0f; + } else { + return img[b * CH * H * W + c * H * W + y * W + x]; + } +} + +__device__ void load_into_shared(float pixels[SY][SSX], const float *inp, const int CH, const int H, const int W, const int i) { + auto block = cg::this_thread_block(); + const int batch = block.group_index().z; + const int start_y = block.group_index().y * BY; + const int start_x = block.group_index().x * BX; + + const int cnt = SY * SX; + const int num_blocks = (cnt + BX * BY - 1) / (BX * BY); + for (int b = 0; b < num_blocks; ++b) { + int tid = b * (BX * BY) + block.thread_rank(); + if (tid < cnt) { + int local_y = tid / SX; + int local_x = tid % SX; + int y = start_y + local_y; + int x = start_x + local_x; + float one = get_pix_value(inp, batch, i, y - 5, x - 5, CH, H, W); + pixels[local_y][local_x] = one; + } + } +} + +__device__ void multiply_shared_mem(float pix1[SY][SSX], float pix2[SY][SSX]) { + auto block = cg::this_thread_block(); + const int cnt = SY * SX; + const int num_blocks = (cnt + BX * BY - 1) / (BX * BY); + for (int b = 0; b < num_blocks; ++b) { + int tid = b * (BX * BY) + block.thread_rank(); + if (tid < cnt) { + int local_y = tid / SX; + int local_x = tid % SX; + float one = pix1[local_y][local_x]; + float two = pix2[local_y][local_x]; + pix1[local_y][local_x] = one * two; + } + } +} + +__device__ inline float do_sq(float val) { + return val * val; +} + +__device__ void +flush_conv_scratch(float buf[CY][CCX]) { + auto block = cg::this_thread_block(); + const int cnt = CY * CX; + const int num_blocks = (cnt + BX * BY - 1) / (BX * BY); + for (int b = 0; b < num_blocks; ++b) { + const int tid = b * (BX * BY) + block.thread_rank(); + if (tid < cnt) { + const int local_y = tid / CX; + const int local_x = tid % CX; + buf[local_y][local_x] = 0.0f; + } + } +} + +__device__ void do_separable_conv_x(float pixels[SY][SSX], float opt[CY][CCX], int H, int W, bool sq = false) { + auto block = cg::this_thread_block(); + + int local_y = block.thread_index().y; + int local_x = block.thread_index().x + 5; + float val = 0.0f; + + if (sq) { + val += G_00 * do_sq(pixels[local_y][local_x - 5]); + val += G_01 * do_sq(pixels[local_y][local_x - 4]); + val += G_02 * do_sq(pixels[local_y][local_x - 3]); + val += G_03 * do_sq(pixels[local_y][local_x - 2]); + val += G_04 * do_sq(pixels[local_y][local_x - 1]); + val += G_05 * do_sq(pixels[local_y][local_x ]); + val += G_06 * do_sq(pixels[local_y][local_x + 1]); + val += G_07 * do_sq(pixels[local_y][local_x + 2]); + val += G_08 * do_sq(pixels[local_y][local_x + 3]); + val += G_09 * do_sq(pixels[local_y][local_x + 4]); + val += G_10 * do_sq(pixels[local_y][local_x + 5]); + } else { + val += G_00 * pixels[local_y][local_x - 5]; + val += G_01 * pixels[local_y][local_x - 4]; + val += G_02 * pixels[local_y][local_x - 3]; + val += G_03 * pixels[local_y][local_x - 2]; + val += G_04 * pixels[local_y][local_x - 1]; + val += G_05 * pixels[local_y][local_x ]; + val += G_06 * pixels[local_y][local_x + 1]; + val += G_07 * pixels[local_y][local_x + 2]; + val += G_08 * pixels[local_y][local_x + 3]; + val += G_09 * pixels[local_y][local_x + 4]; + val += G_10 * pixels[local_y][local_x + 5]; + } + opt[local_y][local_x] = val; + + val = 0.0f; + local_y = block.thread_index().y + BY; + if (local_y < SY) { + if (sq) { + val += G_00 * do_sq(pixels[local_y][local_x - 5]); + val += G_01 * do_sq(pixels[local_y][local_x - 4]); + val += G_02 * do_sq(pixels[local_y][local_x - 3]); + val += G_03 * do_sq(pixels[local_y][local_x - 2]); + val += G_04 * do_sq(pixels[local_y][local_x - 1]); + val += G_05 * do_sq(pixels[local_y][local_x ]); + val += G_06 * do_sq(pixels[local_y][local_x + 1]); + val += G_07 * do_sq(pixels[local_y][local_x + 2]); + val += G_08 * do_sq(pixels[local_y][local_x + 3]); + val += G_09 * do_sq(pixels[local_y][local_x + 4]); + val += G_10 * do_sq(pixels[local_y][local_x + 5]); + } else { + val += G_00 * pixels[local_y][local_x - 5]; + val += G_01 * pixels[local_y][local_x - 4]; + val += G_02 * pixels[local_y][local_x - 3]; + val += G_03 * pixels[local_y][local_x - 2]; + val += G_04 * pixels[local_y][local_x - 1]; + val += G_05 * pixels[local_y][local_x ]; + val += G_06 * pixels[local_y][local_x + 1]; + val += G_07 * pixels[local_y][local_x + 2]; + val += G_08 * pixels[local_y][local_x + 3]; + val += G_09 * pixels[local_y][local_x + 4]; + val += G_10 * pixels[local_y][local_x + 5]; + } + opt[local_y][local_x] = val; + } +} + +__device__ float do_separable_conv_y(float pixels[CY][CCX], int H, int W, bool sq = false) { + auto block = cg::this_thread_block(); + int local_y = block.thread_index().y + 5; + int local_x = block.thread_index().x + 5; + float val = 0.0f; + + val += G_00 * pixels[local_y - 5][local_x]; + val += G_01 * pixels[local_y - 4][local_x]; + val += G_02 * pixels[local_y - 3][local_x]; + val += G_03 * pixels[local_y - 2][local_x]; + val += G_04 * pixels[local_y - 1][local_x]; + val += G_05 * pixels[local_y ][local_x]; + val += G_06 * pixels[local_y + 1][local_x]; + val += G_07 * pixels[local_y + 2][local_x]; + val += G_08 * pixels[local_y + 3][local_x]; + val += G_09 * pixels[local_y + 4][local_x]; + val += G_10 * pixels[local_y + 5][local_x]; + + return val; +} + +__global__ void fusedssimCUDA( + int H, + int W, + int CH, + float C1, + float C2, + float* img1, + float* img2, + float* ssim_map, + float* dm_dmu1 = nullptr, + float* dm_dsigma1_sq = nullptr, + float* dm_dsigma12 = nullptr +) +{ + auto block = cg::this_thread_block(); + const int pix_y = block.group_index().y * BY + block.thread_index().y; + const int pix_x = block.group_index().x * BX + block.thread_index().x; + const int pix_id = pix_y * W + pix_x; + const int num_pix = H * W; + const int batch = block.group_index().z; + + // shared memory that will be used to load pixels temporarily + __shared__ float buf1[SY][SSX]; + __shared__ float buf2[SY][SSX]; + __shared__ float buf3[CY][CCX]; + + for (int i = 0; i < CH; ++i) { + // load into shared + load_into_shared(buf1, img1, CH, H, W, i); + block.sync(); + + // calculate mu1 + flush_conv_scratch(buf3); + block.sync(); + do_separable_conv_x(buf1, buf3, H, W); + block.sync(); + float mu1 = do_separable_conv_y(buf3, H, W); + block.sync(); + + // calculate sigma1_sq + flush_conv_scratch(buf3); + block.sync(); + do_separable_conv_x(buf1, buf3, H, W, true); + block.sync(); + float sigma1_sq = do_separable_conv_y(buf3, H, W) - mu1 * mu1; + block.sync(); + + // calculate mu2 + load_into_shared(buf2, img2, CH, H, W, i); + block.sync(); + flush_conv_scratch(buf3); + block.sync(); + do_separable_conv_x(buf2, buf3, H, W); + block.sync(); + float mu2 = do_separable_conv_y(buf3, H, W); + block.sync(); + + // calculate sigma2_sq + flush_conv_scratch(buf3); + block.sync(); + do_separable_conv_x(buf2, buf3, H, W, true); + block.sync(); + float sigma2_sq = do_separable_conv_y(buf3, H, W) - mu2 * mu2; + block.sync(); + + // calculate sigma12 + multiply_shared_mem(buf1, buf2); + block.sync(); + flush_conv_scratch(buf3); + block.sync(); + do_separable_conv_x(buf1, buf3, H, W); + block.sync(); + float sigma12 = do_separable_conv_y(buf3, H, W) - mu1 * mu2; + block.sync(); + + float mu1_sq = mu1 * mu1; + float mu2_sq = mu2 * mu2; + float mu1_mu2 = mu1 * mu2; + float C = (2.0f * mu1_mu2 + C1); + float D = (2.0f * sigma12 + C2); + float A = (mu1_sq + mu2_sq + C1); + float B = (sigma1_sq + sigma2_sq + C2); + float m = (C * D) / (A * B); + if (pix_x < W && pix_y < H) { + const int global_idx = batch * CH * num_pix + i * num_pix + pix_id; + ssim_map[global_idx] = m; + + if (dm_dmu1) { + dm_dmu1[global_idx] = ( + (mu2 * 2.0f * D) / (A * B) + -(mu2 * 2.0f * C) / (A * B) + -(mu1 * 2.0f * C * D) / ( A * A * B) + +(mu1 * 2.0f * C * D) / (A * B * B) + ); + dm_dsigma1_sq[global_idx] = ((-C * D) / (A * B * B)); + dm_dsigma12[global_idx] = ((2 * C) / (A * B)); + } + } + } +} + +__global__ void fusedssim_backwardCUDA( + int H, + int W, + int CH, + float C1, + float C2, + float* img1, + float* img2, + float *dL_dmap, + float *dL_dimg1, + float* dm_dmu1 = nullptr, + float* dm_dsigma1_sq = nullptr, + float* dm_dsigma12 = nullptr +) +{ + auto block = cg::this_thread_block(); + const int pix_y = block.group_index().y * BY + block.thread_index().y; + const int pix_x = block.group_index().x * BX + block.thread_index().x; + const int pix_id = pix_y * W + pix_x; + const int num_pix = H * W; + const int batch = block.group_index().z; + + // shared memory that will be used to load pixels temporarily + __shared__ float buf1[SY][SSX]; + __shared__ float buf2[SY][SSX]; + __shared__ float buf3[CY][CCX]; + + for (int i = 0; i < CH; ++i) { + float dL_dpix = 0.0f; + float tmp = 0.0f; + float pix1 = get_pix_value(img1, batch, i, pix_y, pix_x, CH, H, W); + float pix2 = get_pix_value(img2, batch, i, pix_y, pix_x, CH, H, W); + load_into_shared(buf1, dL_dmap, CH, H, W, i); + + // gradient from mu1 + load_into_shared(buf2, dm_dmu1, CH, H, W, i); + block.sync(); + multiply_shared_mem(buf2, buf1); + block.sync(); + flush_conv_scratch(buf3); + block.sync(); + do_separable_conv_x(buf2, buf3, H, W); + block.sync(); + tmp = do_separable_conv_y(buf3, H, W); + block.sync(); + dL_dpix += tmp; + + // gradient from sigma1_sq + load_into_shared(buf2, dm_dsigma1_sq, CH, H, W, i); + block.sync(); + multiply_shared_mem(buf2, buf1); + block.sync(); + flush_conv_scratch(buf3); + block.sync(); + do_separable_conv_x(buf2, buf3, H, W); + block.sync(); + tmp = pix1 * 2.0f * do_separable_conv_y(buf3, H, W); + block.sync(); + dL_dpix += tmp; + + // gradient from sigma12 + load_into_shared(buf2, dm_dsigma12, CH, H, W, i); + block.sync(); + multiply_shared_mem(buf2, buf1); + block.sync(); + flush_conv_scratch(buf3); + block.sync(); + do_separable_conv_x(buf2, buf3, H, W); + block.sync(); + tmp = pix2 * do_separable_conv_y(buf3, H, W); + block.sync(); + dL_dpix += tmp; + + if (pix_x < W && pix_y < H) { + const int global_idx = batch * CH * num_pix + i * num_pix + pix_id; + dL_dimg1[global_idx] = dL_dpix; + } + } +} + +std::tuple +fusedssim( + float C1, + float C2, + torch::Tensor &img1, + torch::Tensor &img2, + bool train +) +{ + const at::cuda::OptionalCUDAGuard device_guard(device_of(img1)); + int B = img1.size(0); + int CH = img1.size(1); + int H = img1.size(2); + int W = img1.size(3); + dim3 grid((W + BX - 1) / BX, (H + BY - 1) / BY, B); + dim3 block(BX, BY, 1); + + torch::Tensor target = torch::zeros_like(img1).contiguous(); + torch::Tensor dm_dmu1 = train ? torch::zeros_like(img1).contiguous() : torch::empty(0); + torch::Tensor dm_dsigma1_sq = train ? torch::zeros_like(img1).contiguous() : torch::empty(0); + torch::Tensor dm_dsigma12 = train ? torch::zeros_like(img1).contiguous() : torch::empty(0); + fusedssimCUDA<<>>( + H, + W, + CH, + C1, + C2, + img1.contiguous().data(), + img2.contiguous().data(), + target.contiguous().data(), + dm_dmu1.contiguous().data(), + dm_dsigma1_sq.contiguous().data(), + dm_dsigma12.contiguous().data() + ); + + return std::make_tuple(target, dm_dmu1, dm_dsigma1_sq, dm_dsigma12); +} + +torch::Tensor +fusedssim_backward( + float C1, + float C2, + torch::Tensor &img1, + torch::Tensor &img2, + torch::Tensor &dL_dmap, + torch::Tensor &dm_dmu1, + torch::Tensor &dm_dsigma1_sq, + torch::Tensor &dm_dsigma12 +) +{ + const at::cuda::OptionalCUDAGuard device_guard(device_of(img1)); + int B = img1.size(0); + int CH = img1.size(1); + int H = img1.size(2); + int W = img1.size(3); + + torch::Tensor dL_dimg1 = torch::zeros_like(img1).contiguous(); + + dim3 grid((W + BX - 1) / BX, (H + BY - 1) / BY, B); + dim3 block(BX, BY, 1); + fusedssim_backwardCUDA<<>>( + H, + W, + CH, + C1, + C2, + img1.contiguous().data(), + img2.contiguous().data(), + dL_dmap.contiguous().data(), + dL_dimg1.contiguous().data(), + dm_dmu1.contiguous().data(), + dm_dsigma1_sq.contiguous().data(), + dm_dsigma12.contiguous().data() + ); + + return dL_dimg1; +} diff --git a/submodules/gaussian-splatting/submodules/fused-ssim/ssim.h b/submodules/gaussian-splatting/submodules/fused-ssim/ssim.h new file mode 100644 index 0000000000000000000000000000000000000000..adb00543b71403bd5350b0734f1ced0bee8da2fe --- /dev/null +++ b/submodules/gaussian-splatting/submodules/fused-ssim/ssim.h @@ -0,0 +1,26 @@ +#pragma once +#include +#include +#include +#include + +std::tuple +fusedssim( + float C1, + float C2, + torch::Tensor &img1, + torch::Tensor &img2, + bool train +); + +torch::Tensor +fusedssim_backward( + float C1, + float C2, + torch::Tensor &img1, + torch::Tensor &img2, + torch::Tensor &dL_dmap, + torch::Tensor &dm_dmu1, + torch::Tensor &dm_dsigma1_sq, + torch::Tensor &dm_dsigma12 +); diff --git a/submodules/gaussian-splatting/submodules/fused-ssim/tests/genplot.py b/submodules/gaussian-splatting/submodules/fused-ssim/tests/genplot.py new file mode 100644 index 0000000000000000000000000000000000000000..f5b841c6faaa614deefc89735da7261b7e3a9ece --- /dev/null +++ b/submodules/gaussian-splatting/submodules/fused-ssim/tests/genplot.py @@ -0,0 +1,100 @@ +import torch +from fused_ssim import fused_ssim +from pytorch_msssim import SSIM +import matplotlib.pyplot as plt +import numpy as np +import time +import os + +plt.style.use('ggplot') +gpu = torch.cuda.get_device_name() + +if __name__ == "__main__": + torch.manual_seed(0) + + B, CH = 5, 1 + dimensions = list(range(50, 1550, 50)) + iterations = 50 + + data = { + "pytorch_mssim": [], + "fused-ssim": [] + } + + pm_ssim = SSIM(data_range=1.0, channel=CH) + + for d in dimensions: + with torch.no_grad(): + img1_og = torch.rand([B, CH, d, d], device="cuda") + img2_og = torch.rand([B, CH, d, d], device="cuda") + + img1_mine_same = torch.nn.Parameter(img1_og.clone()) + img2_mine_same = img2_og.clone() + + img1_pm = torch.nn.Parameter(img1_og.clone()) + img2_pm = img2_og.clone() + + begin = time.time() + for _ in range(iterations): + pm_ssim_val = pm_ssim(img1_pm, img2_pm) + pm_ssim_val.backward() + torch.cuda.synchronize() + end = time.time() + data["pytorch_mssim"].append((end - begin) / iterations * 1000) + + begin = time.time() + for _ in range(iterations): + mine_ssim_val_same = fused_ssim(img1_mine_same, img2_mine_same) + mine_ssim_val_same.backward() + torch.cuda.synchronize() + end = time.time() + data["fused-ssim"].append((end - begin) / iterations * 1000) + + num_pixels = (B * np.array(dimensions) ** 2) / 1e6 + plt.plot(num_pixels, data["pytorch_mssim"], label="pytorch_mssim") + plt.plot(num_pixels, data["fused-ssim"], label="fused-ssim") + plt.legend() + plt.xlabel("Number of pixels (in millions).") + plt.ylabel("Time for one training iteration (ms).") + plt.title(f"Training Benchmark on {gpu}.") + plt.savefig(os.path.join("..", "images", "training_time.png"), dpi=300) + + data = { + "pytorch_mssim": [], + "fused-ssim": [] + } + + plt.clf() + for d in dimensions: + with torch.no_grad(): + img1_og = torch.rand([B, CH, d, d], device="cuda") + img2_og = torch.rand([B, CH, d, d], device="cuda") + + img1_mine_same = torch.nn.Parameter(img1_og.clone()) + img2_mine_same = img2_og.clone() + + img1_pm = torch.nn.Parameter(img1_og.clone()) + img2_pm = img2_og.clone() + + begin = time.time() + for _ in range(iterations): + pm_ssim_val = pm_ssim(img1_pm, img2_pm) + torch.cuda.synchronize() + end = time.time() + data["pytorch_mssim"].append((end - begin) / iterations * 1000) + + begin = time.time() + for _ in range(iterations): + mine_ssim_val_same = fused_ssim(img1_mine_same, img2_mine_same, train=False) + torch.cuda.synchronize() + end = time.time() + data["fused-ssim"].append((end - begin) / iterations * 1000) + + num_pixels = (B * np.array(dimensions) ** 2) / 1e6 + plt.plot(num_pixels, data["pytorch_mssim"], label="pytorch_mssim") + plt.plot(num_pixels, data["fused-ssim"], label="fused-ssim") + plt.legend() + plt.xlabel("Number of pixels (in millions).") + plt.ylabel("Time for one inference iteration (ms).") + plt.title(f"Inference Benchmark on {gpu}.") + plt.savefig(os.path.join("..", "images", "inference_time.png"), dpi=300) diff --git a/submodules/gaussian-splatting/submodules/fused-ssim/tests/test.py b/submodules/gaussian-splatting/submodules/fused-ssim/tests/test.py new file mode 100644 index 0000000000000000000000000000000000000000..4bd85d5fd36f56ed7d80c085468adaae8cd71cda --- /dev/null +++ b/submodules/gaussian-splatting/submodules/fused-ssim/tests/test.py @@ -0,0 +1,157 @@ +import torch +import torch.nn.functional as F +import torch.nn as nn +from torch.autograd import Variable +from math import exp +from fused_ssim import fused_ssim +from pytorch_msssim import SSIM +import time + +# Reference Implementation is taken from the following: +# https://github.com/Po-Hsun-Su/pytorch-ssim/blob/master/pytorch_ssim/__init__.py +# https://github.com/graphdeco-inria/gaussian-splatting/blob/main/utils/loss_utils.py + +def gaussian(window_size, sigma): + gauss = torch.Tensor([exp(-(x - window_size // 2) ** 2 / float(2 * sigma ** 2)) for x in range(window_size)]) + return gauss / gauss.sum() + +def create_window(window_size, channel): + _1D_window = gaussian(window_size, 1.5).unsqueeze(1) + _2D_window = _1D_window.mm(_1D_window.t()).float().unsqueeze(0).unsqueeze(0) + window = Variable(_2D_window.expand(channel, 1, window_size, window_size).contiguous()) + return window + +def ssim(img1, img2, window_size=11, size_average=True): + channel = img1.size(-3) + window = create_window(window_size, channel) + + if img1.is_cuda: + window = window.cuda(img1.get_device()) + window = window.type_as(img1) + + return _ssim(img1, img2, window, window_size, channel, size_average) + +def _ssim(img1, img2, window, window_size, channel, size_average=True): + mu1 = F.conv2d(img1, window, padding=window_size // 2, groups=channel) + mu2 = F.conv2d(img2, window, padding=window_size // 2, groups=channel) + + mu1_sq = mu1.pow(2) + mu2_sq = mu2.pow(2) + mu1_mu2 = mu1 * mu2 + + sigma1_sq = F.conv2d(img1 * img1, window, padding=window_size // 2, groups=channel) - mu1_sq + sigma2_sq = F.conv2d(img2 * img2, window, padding=window_size // 2, groups=channel) - mu2_sq + sigma12 = F.conv2d(img1 * img2, window, padding=window_size // 2, groups=channel) - mu1_mu2 + + C1 = 0.01 ** 2 + C2 = 0.03 ** 2 + + ssim_map = ((2 * mu1_mu2 + C1) * (2 * sigma12 + C2)) / ((mu1_sq + mu2_sq + C1) * (sigma1_sq + sigma2_sq + C2)) + + if size_average: + return ssim_map.mean() + else: + return ssim_map.mean(1).mean(1).mean(1) + + +if __name__ == "__main__": + torch.manual_seed(0) + B, CH, H, W = 5, 5, 1080, 1920 + pm_ssim = SSIM(data_range=1.0, channel=CH) + iterations = 100 + + for _ in range(iterations): + with torch.no_grad(): + img1_og = nn.Parameter(torch.rand([B, CH, H, W], device="cuda")) + img2_og = torch.rand([B, CH, H, W], device="cuda") + + img1_mine_same = nn.Parameter(img1_og.clone()) + img2_mine_same = img2_og.clone() + + img1_mine_valid = nn.Parameter(img1_og.clone()) + img2_mine_valid = img2_og.clone() + + img1_pm = nn.Parameter(img1_og.clone()) + img2_pm = img2_og.clone() + + og_ssim_val = ssim(img1_og, img2_og) + mine_ssim_val_same = fused_ssim(img1_mine_same, img2_mine_same) + mine_ssim_val_valid = fused_ssim(img1_mine_valid, img2_mine_valid, "valid") + pm_ssim_val = pm_ssim(img1_pm, img2_pm) + + assert torch.isclose(og_ssim_val, mine_ssim_val_same) + assert torch.isclose(mine_ssim_val_valid, pm_ssim_val) + + og_ssim_val.backward() + mine_ssim_val_same.backward() + mine_ssim_val_valid.backward() + pm_ssim_val.backward() + + assert torch.isclose(img1_og.grad, img1_mine_same.grad).all() + assert torch.isclose(img1_mine_valid.grad, img1_pm.grad).all() + + img1 = nn.Parameter(torch.rand([B, CH, H, W], device="cuda")) + img2 = torch.rand([B, CH, H, W], device="cuda") + + # benchmark og + begin = time.time() + for _ in range(iterations): + og_ssim_val = ssim(img1, img2) + torch.cuda.synchronize() + end = time.time() + og_time_forward = (end - begin) / iterations * 1000 + print("Reference Time (Forward):", og_time_forward, "ms") + + begin = time.time() + for _ in range(iterations): + og_ssim_val = ssim(img1, img2) + og_ssim_val.backward() + torch.cuda.synchronize() + end = time.time() + og_time_backward = (end - begin) / iterations * 1000 - og_time_forward + print("Reference Time (Backward):", og_time_backward, "ms") + + # benchmark pytorch_mssim (pm) + begin = time.time() + for _ in range(iterations): + pm_ssim_val = pm_ssim(img1, img2) + torch.cuda.synchronize() + end = time.time() + pm_time_forward = (end - begin) / iterations * 1000 + print("pytorch_mssim Time (Forward):", pm_time_forward, "ms") + + begin = time.time() + for _ in range(iterations): + pm_ssim_val = pm_ssim(img1, img2) + pm_ssim_val.backward() + torch.cuda.synchronize() + end = time.time() + pm_time_backward = (end - begin) / iterations * 1000 - pm_time_forward + print("pytorch_mssim Time (Backward):", pm_time_backward, "ms") + + + # benchmark mine + begin = time.time() + for _ in range(iterations): + mine_ssim_val = fused_ssim(img1, img2) + torch.cuda.synchronize() + end = time.time() + mine_time_forward = (end - begin) / iterations * 1000 + print("fused-ssim Time (Forward):", mine_time_forward, "ms") + + begin = time.time() + for _ in range(iterations): + mine_ssim_val = fused_ssim(img1, img2) + mine_ssim_val.backward() + torch.cuda.synchronize() + end = time.time() + mine_time_backward = (end - begin) / iterations * 1000 - mine_time_forward + print("fused-ssim Time (Backward):", mine_time_backward, "ms") + + begin = time.time() + for _ in range(iterations): + mine_ssim_val = fused_ssim(img1, img2, train=False) + torch.cuda.synchronize() + end = time.time() + mine_time_infer = (end - begin) / iterations * 1000 + print("fused-ssim Time (Inference):", mine_time_infer, "ms") diff --git a/submodules/gaussian-splatting/submodules/fused-ssim/tests/train_image.py b/submodules/gaussian-splatting/submodules/fused-ssim/tests/train_image.py new file mode 100644 index 0000000000000000000000000000000000000000..3af09a455c3bff3b2cd9933abe7d6acb1d9a8360 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/fused-ssim/tests/train_image.py @@ -0,0 +1,29 @@ +import torch +import numpy as np +import os +from PIL import Image +from fused_ssim import fused_ssim + +gt_image = torch.tensor(np.array(Image.open(os.path.join("..", "images", "albert.jpg"))), dtype=torch.float32, device="cuda").unsqueeze(0).unsqueeze(0) / 255.0 +pred_image = torch.nn.Parameter(torch.rand_like(gt_image)) + +with torch.no_grad(): + ssim_value = fused_ssim(pred_image, gt_image, train=False) + print("Starting with SSIM value:", ssim_value) + + +optimizer = torch.optim.Adam([pred_image]) + +while ssim_value < 0.9999: + optimizer.zero_grad() + loss = 1.0 - fused_ssim(pred_image, gt_image) + loss.backward() + optimizer.step() + + with torch.no_grad(): + ssim_value = fused_ssim(pred_image, gt_image, train=False) + print("SSIM value:", ssim_value) + +pred_image = (pred_image * 255.0).squeeze(0).squeeze(0) +to_save = pred_image.detach().cpu().numpy().astype(np.uint8) +Image.fromarray(to_save).save(os.path.join("..", "images", "predicted.jpg")) diff --git a/submodules/gaussian-splatting/submodules/simple-knn/LICENSE.md b/submodules/gaussian-splatting/submodules/simple-knn/LICENSE.md new file mode 100644 index 0000000000000000000000000000000000000000..18445c6d34aedbf1ab9d282223f8f10ce38cd79a --- /dev/null +++ b/submodules/gaussian-splatting/submodules/simple-knn/LICENSE.md @@ -0,0 +1,91 @@ +Gaussian-Splatting License +=========================== + +**Inria** and **the Max Planck Institut for Informatik (MPII)** hold all the ownership rights on the *Software* named **gaussian-splatting**. +The *Software* is in the process of being registered with the Agence pour la Protection des +Programmes (APP). + +The *Software* is still being developed by the *Licensor*. + +*Licensor*'s goal is to allow the research community to use, test and evaluate +the *Software*. + +## 1. Definitions + +*Licensee* means any person or entity that uses the *Software* and distributes +its *Work*. + +*Licensor* means the owners of the *Software*, i.e Inria and MPII + +*Software* means the original work of authorship made available under this +License ie gaussian-splatting. + +*Work* means the *Software* and any additions to or derivative works of the +*Software* that are made available under this License. + + +## 2. Purpose +This license is intended to define the rights granted to the *Licensee* by +Licensors under the *Software*. + +## 3. Rights granted + +For the above reasons Licensors have decided to distribute the *Software*. +Licensors grant non-exclusive rights to use the *Software* for research purposes +to research users (both academic and industrial), free of charge, without right +to sublicense.. The *Software* may be used "non-commercially", i.e., for research +and/or evaluation purposes only. + +Subject to the terms and conditions of this License, you are granted a +non-exclusive, royalty-free, license to reproduce, prepare derivative works of, +publicly display, publicly perform and distribute its *Work* and any resulting +derivative works in any form. + +## 4. Limitations + +**4.1 Redistribution.** You may reproduce or distribute the *Work* only if (a) you do +so under this License, (b) you include a complete copy of this License with +your distribution, and (c) you retain without modification any copyright, +patent, trademark, or attribution notices that are present in the *Work*. + +**4.2 Derivative Works.** You may specify that additional or different terms apply +to the use, reproduction, and distribution of your derivative works of the *Work* +("Your Terms") only if (a) Your Terms provide that the use limitation in +Section 2 applies to your derivative works, and (b) you identify the specific +derivative works that are subject to Your Terms. Notwithstanding Your Terms, +this License (including the redistribution requirements in Section 3.1) will +continue to apply to the *Work* itself. + +**4.3** Any other use without of prior consent of Licensors is prohibited. Research +users explicitly acknowledge having received from Licensors all information +allowing to appreciate the adequacy between of the *Software* and their needs and +to undertake all necessary precautions for its execution and use. + +**4.4** The *Software* is provided both as a compiled library file and as source +code. In case of using the *Software* for a publication or other results obtained +through the use of the *Software*, users are strongly encouraged to cite the +corresponding publications as explained in the documentation of the *Software*. + +## 5. Disclaimer + +THE USER CANNOT USE, EXPLOIT OR DISTRIBUTE THE *SOFTWARE* FOR COMMERCIAL PURPOSES +WITHOUT PRIOR AND EXPLICIT CONSENT OF LICENSORS. YOU MUST CONTACT INRIA FOR ANY +UNAUTHORIZED USE: stip-sophia.transfert@inria.fr . ANY SUCH ACTION WILL +CONSTITUTE A FORGERY. THIS *SOFTWARE* IS PROVIDED "AS IS" WITHOUT ANY WARRANTIES +OF ANY NATURE AND ANY EXPRESS OR IMPLIED WARRANTIES, WITH REGARDS TO COMMERCIAL +USE, PROFESSIONNAL USE, LEGAL OR NOT, OR OTHER, OR COMMERCIALISATION OR +ADAPTATION. UNLESS EXPLICITLY PROVIDED BY LAW, IN NO EVENT, SHALL INRIA OR THE +AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES, LOSS OF USE, DATA, OR PROFITS OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING FROM, OUT OF OR +IN CONNECTION WITH THE *SOFTWARE* OR THE USE OR OTHER DEALINGS IN THE *SOFTWARE*. + +## 6. Files subject to permissive licenses +The contents of the file ```utils/loss_utils.py``` are based on publicly available code authored by Evan Su, which falls under the permissive MIT license. + +Title: pytorch-ssim\ +Project code: https://github.com/Po-Hsun-Su/pytorch-ssim\ +Copyright Evan Su, 2017\ +License: https://github.com/Po-Hsun-Su/pytorch-ssim/blob/master/LICENSE.txt (MIT) \ No newline at end of file diff --git a/submodules/gaussian-splatting/submodules/simple-knn/ext.cpp b/submodules/gaussian-splatting/submodules/simple-knn/ext.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ae6cefe6ce61a38352a88d07b69a8e6cb9de5b31 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/simple-knn/ext.cpp @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2023, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact george.drettakis@inria.fr + */ + +#include +#include "spatial.h" + +PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { + m.def("distCUDA2", &distCUDA2); +} diff --git a/submodules/gaussian-splatting/submodules/simple-knn/setup.py b/submodules/gaussian-splatting/submodules/simple-knn/setup.py new file mode 100644 index 0000000000000000000000000000000000000000..580d2bd8dc190ce642d87501d53de4f6d9d46c64 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/simple-knn/setup.py @@ -0,0 +1,35 @@ +# +# Copyright (C) 2023, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact george.drettakis@inria.fr +# + +from setuptools import setup +from torch.utils.cpp_extension import CUDAExtension, BuildExtension +import os + +cxx_compiler_flags = [] + +if os.name == 'nt': + cxx_compiler_flags.append("/wd4624") + +setup( + name="simple_knn", + ext_modules=[ + CUDAExtension( + name="simple_knn._C", + sources=[ + "spatial.cu", + "simple_knn.cu", + "ext.cpp"], + extra_compile_args={"nvcc": [], "cxx": cxx_compiler_flags}) + ], + cmdclass={ + 'build_ext': BuildExtension + } +) diff --git a/submodules/gaussian-splatting/submodules/simple-knn/simple_knn.cu b/submodules/gaussian-splatting/submodules/simple-knn/simple_knn.cu new file mode 100644 index 0000000000000000000000000000000000000000..d7f85592a39f955eafe7b8d1c3a453c1303c752b --- /dev/null +++ b/submodules/gaussian-splatting/submodules/simple-knn/simple_knn.cu @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2023, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact george.drettakis@inria.fr + */ + +#define BOX_SIZE 1024 + +#include "cuda_runtime.h" +#include "device_launch_parameters.h" +#include "simple_knn.h" +#include +#include +#include +#include +#include +#include +#include +#define __CUDACC__ +#include +#include + +namespace cg = cooperative_groups; + +struct CustomMin +{ + __device__ __forceinline__ + float3 operator()(const float3& a, const float3& b) const { + return { min(a.x, b.x), min(a.y, b.y), min(a.z, b.z) }; + } +}; + +struct CustomMax +{ + __device__ __forceinline__ + float3 operator()(const float3& a, const float3& b) const { + return { max(a.x, b.x), max(a.y, b.y), max(a.z, b.z) }; + } +}; + +__host__ __device__ uint32_t prepMorton(uint32_t x) +{ + x = (x | (x << 16)) & 0x030000FF; + x = (x | (x << 8)) & 0x0300F00F; + x = (x | (x << 4)) & 0x030C30C3; + x = (x | (x << 2)) & 0x09249249; + return x; +} + +__host__ __device__ uint32_t coord2Morton(float3 coord, float3 minn, float3 maxx) +{ + uint32_t x = prepMorton(((coord.x - minn.x) / (maxx.x - minn.x)) * ((1 << 10) - 1)); + uint32_t y = prepMorton(((coord.y - minn.y) / (maxx.y - minn.y)) * ((1 << 10) - 1)); + uint32_t z = prepMorton(((coord.z - minn.z) / (maxx.z - minn.z)) * ((1 << 10) - 1)); + + return x | (y << 1) | (z << 2); +} + +__global__ void coord2Morton(int P, const float3* points, float3 minn, float3 maxx, uint32_t* codes) +{ + auto idx = cg::this_grid().thread_rank(); + if (idx >= P) + return; + + codes[idx] = coord2Morton(points[idx], minn, maxx); +} + +struct MinMax +{ + float3 minn; + float3 maxx; +}; + +__global__ void boxMinMax(uint32_t P, float3* points, uint32_t* indices, MinMax* boxes) +{ + auto idx = cg::this_grid().thread_rank(); + + MinMax me; + if (idx < P) + { + me.minn = points[indices[idx]]; + me.maxx = points[indices[idx]]; + } + else + { + me.minn = { FLT_MAX, FLT_MAX, FLT_MAX }; + me.maxx = { -FLT_MAX,-FLT_MAX,-FLT_MAX }; + } + + __shared__ MinMax redResult[BOX_SIZE]; + + for (int off = BOX_SIZE / 2; off >= 1; off /= 2) + { + if (threadIdx.x < 2 * off) + redResult[threadIdx.x] = me; + __syncthreads(); + + if (threadIdx.x < off) + { + MinMax other = redResult[threadIdx.x + off]; + me.minn.x = min(me.minn.x, other.minn.x); + me.minn.y = min(me.minn.y, other.minn.y); + me.minn.z = min(me.minn.z, other.minn.z); + me.maxx.x = max(me.maxx.x, other.maxx.x); + me.maxx.y = max(me.maxx.y, other.maxx.y); + me.maxx.z = max(me.maxx.z, other.maxx.z); + } + __syncthreads(); + } + + if (threadIdx.x == 0) + boxes[blockIdx.x] = me; +} + +__device__ __host__ float distBoxPoint(const MinMax& box, const float3& p) +{ + float3 diff = { 0, 0, 0 }; + if (p.x < box.minn.x || p.x > box.maxx.x) + diff.x = min(abs(p.x - box.minn.x), abs(p.x - box.maxx.x)); + if (p.y < box.minn.y || p.y > box.maxx.y) + diff.y = min(abs(p.y - box.minn.y), abs(p.y - box.maxx.y)); + if (p.z < box.minn.z || p.z > box.maxx.z) + diff.z = min(abs(p.z - box.minn.z), abs(p.z - box.maxx.z)); + return diff.x * diff.x + diff.y * diff.y + diff.z * diff.z; +} + +template +__device__ void updateKBest(const float3& ref, const float3& point, float* knn) +{ + float3 d = { point.x - ref.x, point.y - ref.y, point.z - ref.z }; + float dist = d.x * d.x + d.y * d.y + d.z * d.z; + for (int j = 0; j < K; j++) + { + if (knn[j] > dist) + { + float t = knn[j]; + knn[j] = dist; + dist = t; + } + } +} + +__global__ void boxMeanDist(uint32_t P, float3* points, uint32_t* indices, MinMax* boxes, float* dists) +{ + int idx = cg::this_grid().thread_rank(); + if (idx >= P) + return; + + float3 point = points[indices[idx]]; + float best[3] = { FLT_MAX, FLT_MAX, FLT_MAX }; + + for (int i = max(0, idx - 3); i <= min(P - 1, idx + 3); i++) + { + if (i == idx) + continue; + updateKBest<3>(point, points[indices[i]], best); + } + + float reject = best[2]; + best[0] = FLT_MAX; + best[1] = FLT_MAX; + best[2] = FLT_MAX; + + for (int b = 0; b < (P + BOX_SIZE - 1) / BOX_SIZE; b++) + { + MinMax box = boxes[b]; + float dist = distBoxPoint(box, point); + if (dist > reject || dist > best[2]) + continue; + + for (int i = b * BOX_SIZE; i < min(P, (b + 1) * BOX_SIZE); i++) + { + if (i == idx) + continue; + updateKBest<3>(point, points[indices[i]], best); + } + } + dists[indices[idx]] = (best[0] + best[1] + best[2]) / 3.0f; +} + +void SimpleKNN::knn(int P, float3* points, float* meanDists) +{ + float3* result; + cudaMalloc(&result, sizeof(float3)); + size_t temp_storage_bytes; + + float3 init = { 0, 0, 0 }, minn, maxx; + + cub::DeviceReduce::Reduce(nullptr, temp_storage_bytes, points, result, P, CustomMin(), init); + thrust::device_vector temp_storage(temp_storage_bytes); + + cub::DeviceReduce::Reduce(temp_storage.data().get(), temp_storage_bytes, points, result, P, CustomMin(), init); + cudaMemcpy(&minn, result, sizeof(float3), cudaMemcpyDeviceToHost); + + cub::DeviceReduce::Reduce(temp_storage.data().get(), temp_storage_bytes, points, result, P, CustomMax(), init); + cudaMemcpy(&maxx, result, sizeof(float3), cudaMemcpyDeviceToHost); + + thrust::device_vector morton(P); + thrust::device_vector morton_sorted(P); + coord2Morton << <(P + 255) / 256, 256 >> > (P, points, minn, maxx, morton.data().get()); + + thrust::device_vector indices(P); + thrust::sequence(indices.begin(), indices.end()); + thrust::device_vector indices_sorted(P); + + cub::DeviceRadixSort::SortPairs(nullptr, temp_storage_bytes, morton.data().get(), morton_sorted.data().get(), indices.data().get(), indices_sorted.data().get(), P); + temp_storage.resize(temp_storage_bytes); + + cub::DeviceRadixSort::SortPairs(temp_storage.data().get(), temp_storage_bytes, morton.data().get(), morton_sorted.data().get(), indices.data().get(), indices_sorted.data().get(), P); + + uint32_t num_boxes = (P + BOX_SIZE - 1) / BOX_SIZE; + thrust::device_vector boxes(num_boxes); + boxMinMax << > > (P, points, indices_sorted.data().get(), boxes.data().get()); + boxMeanDist << > > (P, points, indices_sorted.data().get(), boxes.data().get(), meanDists); + + cudaFree(result); +} \ No newline at end of file diff --git a/submodules/gaussian-splatting/submodules/simple-knn/simple_knn.h b/submodules/gaussian-splatting/submodules/simple-knn/simple_knn.h new file mode 100644 index 0000000000000000000000000000000000000000..3fcfdb87c53faaadc1fd820d5deeb1b2b5c21a86 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/simple-knn/simple_knn.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2023, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact george.drettakis@inria.fr + */ + +#ifndef SIMPLEKNN_H_INCLUDED +#define SIMPLEKNN_H_INCLUDED + +class SimpleKNN +{ +public: + static void knn(int P, float3* points, float* meanDists); +}; + +#endif \ No newline at end of file diff --git a/submodules/gaussian-splatting/submodules/simple-knn/simple_knn/.gitkeep b/submodules/gaussian-splatting/submodules/simple-knn/simple_knn/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/submodules/gaussian-splatting/submodules/simple-knn/spatial.cu b/submodules/gaussian-splatting/submodules/simple-knn/spatial.cu new file mode 100644 index 0000000000000000000000000000000000000000..1a6a654ba6f8c6a1856a40d14fb7a53c96602bad --- /dev/null +++ b/submodules/gaussian-splatting/submodules/simple-knn/spatial.cu @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2023, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact george.drettakis@inria.fr + */ + +#include "spatial.h" +#include "simple_knn.h" + +torch::Tensor +distCUDA2(const torch::Tensor& points) +{ + const int P = points.size(0); + + auto float_opts = points.options().dtype(torch::kFloat32); + torch::Tensor means = torch::full({P}, 0.0, float_opts); + + SimpleKNN::knn(P, (float3*)points.contiguous().data(), means.contiguous().data()); + + return means; +} \ No newline at end of file diff --git a/submodules/gaussian-splatting/submodules/simple-knn/spatial.h b/submodules/gaussian-splatting/submodules/simple-knn/spatial.h new file mode 100644 index 0000000000000000000000000000000000000000..280c953a0321a769e433a43535fd36c251b730f0 --- /dev/null +++ b/submodules/gaussian-splatting/submodules/simple-knn/spatial.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2023, Inria + * GRAPHDECO research group, https://team.inria.fr/graphdeco + * All rights reserved. + * + * This software is free for non-commercial, research and evaluation use + * under the terms of the LICENSE.md file. + * + * For inquiries contact george.drettakis@inria.fr + */ + +#include + +torch::Tensor distCUDA2(const torch::Tensor& points); \ No newline at end of file diff --git a/submodules/gaussian-splatting/train.py b/submodules/gaussian-splatting/train.py new file mode 100644 index 0000000000000000000000000000000000000000..820690305a52dc80c93603bb08c9e5dbc24e55e5 --- /dev/null +++ b/submodules/gaussian-splatting/train.py @@ -0,0 +1,285 @@ +# +# Copyright (C) 2023, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact george.drettakis@inria.fr +# + +import os +import torch +from random import randint +from utils.loss_utils import l1_loss, ssim +from gaussian_renderer import render, network_gui +import sys +from scene import Scene, GaussianModel +from utils.general_utils import safe_state, get_expon_lr_func +import uuid +from tqdm import tqdm +from utils.image_utils import psnr +from argparse import ArgumentParser, Namespace +from arguments import ModelParams, PipelineParams, OptimizationParams +try: + from torch.utils.tensorboard import SummaryWriter + TENSORBOARD_FOUND = True +except ImportError: + TENSORBOARD_FOUND = False + +try: + from fused_ssim import fused_ssim + FUSED_SSIM_AVAILABLE = True +except: + FUSED_SSIM_AVAILABLE = False + +try: + from diff_gaussian_rasterization import SparseGaussianAdam + SPARSE_ADAM_AVAILABLE = True +except: + SPARSE_ADAM_AVAILABLE = False + +def training(dataset, opt, pipe, testing_iterations, saving_iterations, checkpoint_iterations, checkpoint, debug_from): + + if not SPARSE_ADAM_AVAILABLE and opt.optimizer_type == "sparse_adam": + sys.exit(f"Trying to use sparse adam but it is not installed, please install the correct rasterizer using pip install [3dgs_accel].") + + first_iter = 0 + tb_writer = prepare_output_and_logger(dataset) + gaussians = GaussianModel(dataset.sh_degree, opt.optimizer_type) + scene = Scene(dataset, gaussians) + gaussians.training_setup(opt) + if checkpoint: + (model_params, first_iter) = torch.load(checkpoint) + gaussians.restore(model_params, opt) + + bg_color = [1, 1, 1] if dataset.white_background else [0, 0, 0] + background = torch.tensor(bg_color, dtype=torch.float32, device="cuda") + + iter_start = torch.cuda.Event(enable_timing = True) + iter_end = torch.cuda.Event(enable_timing = True) + + use_sparse_adam = opt.optimizer_type == "sparse_adam" and SPARSE_ADAM_AVAILABLE + depth_l1_weight = get_expon_lr_func(opt.depth_l1_weight_init, opt.depth_l1_weight_final, max_steps=opt.iterations) + + viewpoint_stack = scene.getTrainCameras().copy() + viewpoint_indices = list(range(len(viewpoint_stack))) + ema_loss_for_log = 0.0 + ema_Ll1depth_for_log = 0.0 + + progress_bar = tqdm(range(first_iter, opt.iterations), desc="Training progress") + first_iter += 1 + for iteration in range(first_iter, opt.iterations + 1): + if network_gui.conn == None: + network_gui.try_connect() + while network_gui.conn != None: + try: + net_image_bytes = None + custom_cam, do_training, pipe.convert_SHs_python, pipe.compute_cov3D_python, keep_alive, scaling_modifer = network_gui.receive() + if custom_cam != None: + net_image = render(custom_cam, gaussians, pipe, background, scaling_modifier=scaling_modifer, use_trained_exp=dataset.train_test_exp, separate_sh=SPARSE_ADAM_AVAILABLE)["render"] + net_image_bytes = memoryview((torch.clamp(net_image, min=0, max=1.0) * 255).byte().permute(1, 2, 0).contiguous().cpu().numpy()) + network_gui.send(net_image_bytes, dataset.source_path) + if do_training and ((iteration < int(opt.iterations)) or not keep_alive): + break + except Exception as e: + network_gui.conn = None + + iter_start.record() + + gaussians.update_learning_rate(iteration) + + # Every 1000 its we increase the levels of SH up to a maximum degree + if iteration % 1000 == 0: + gaussians.oneupSHdegree() + + # Pick a random Camera + if not viewpoint_stack: + viewpoint_stack = scene.getTrainCameras().copy() + viewpoint_indices = list(range(len(viewpoint_stack))) + rand_idx = randint(0, len(viewpoint_indices) - 1) + viewpoint_cam = viewpoint_stack.pop(rand_idx) + vind = viewpoint_indices.pop(rand_idx) + + # Render + if (iteration - 1) == debug_from: + pipe.debug = True + + bg = torch.rand((3), device="cuda") if opt.random_background else background + + render_pkg = render(viewpoint_cam, gaussians, pipe, bg, use_trained_exp=dataset.train_test_exp, separate_sh=SPARSE_ADAM_AVAILABLE) + image, viewspace_point_tensor, visibility_filter, radii = render_pkg["render"], render_pkg["viewspace_points"], render_pkg["visibility_filter"], render_pkg["radii"] + + if viewpoint_cam.alpha_mask is not None: + alpha_mask = viewpoint_cam.alpha_mask.cuda() + image *= alpha_mask + + # Loss + gt_image = viewpoint_cam.original_image.cuda() + Ll1 = l1_loss(image, gt_image) + if FUSED_SSIM_AVAILABLE: + ssim_value = fused_ssim(image.unsqueeze(0), gt_image.unsqueeze(0)) + else: + ssim_value = ssim(image, gt_image) + + loss = (1.0 - opt.lambda_dssim) * Ll1 + opt.lambda_dssim * (1.0 - ssim_value) + + # Depth regularization + Ll1depth_pure = 0.0 + if depth_l1_weight(iteration) > 0 and viewpoint_cam.depth_reliable: + invDepth = render_pkg["depth"] + mono_invdepth = viewpoint_cam.invdepthmap.cuda() + depth_mask = viewpoint_cam.depth_mask.cuda() + + Ll1depth_pure = torch.abs((invDepth - mono_invdepth) * depth_mask).mean() + Ll1depth = depth_l1_weight(iteration) * Ll1depth_pure + loss += Ll1depth + Ll1depth = Ll1depth.item() + else: + Ll1depth = 0 + + loss.backward() + + iter_end.record() + + with torch.no_grad(): + # Progress bar + ema_loss_for_log = 0.4 * loss.item() + 0.6 * ema_loss_for_log + ema_Ll1depth_for_log = 0.4 * Ll1depth + 0.6 * ema_Ll1depth_for_log + + if iteration % 10 == 0: + progress_bar.set_postfix({"Loss": f"{ema_loss_for_log:.{7}f}", "Depth Loss": f"{ema_Ll1depth_for_log:.{7}f}"}) + progress_bar.update(10) + if iteration == opt.iterations: + progress_bar.close() + + # Log and save + training_report(tb_writer, iteration, Ll1, loss, l1_loss, iter_start.elapsed_time(iter_end), testing_iterations, scene, render, (pipe, background, 1., SPARSE_ADAM_AVAILABLE, None, dataset.train_test_exp), dataset.train_test_exp) + if (iteration in saving_iterations): + print("\n[ITER {}] Saving Gaussians".format(iteration)) + scene.save(iteration) + + # Densification + if iteration < opt.densify_until_iter: + # Keep track of max radii in image-space for pruning + gaussians.max_radii2D[visibility_filter] = torch.max(gaussians.max_radii2D[visibility_filter], radii[visibility_filter]) + gaussians.add_densification_stats(viewspace_point_tensor, visibility_filter) + + if iteration > opt.densify_from_iter and iteration % opt.densification_interval == 0: + size_threshold = 20 if iteration > opt.opacity_reset_interval else None + gaussians.densify_and_prune(opt.densify_grad_threshold, 0.005, scene.cameras_extent, size_threshold, radii) + + if iteration % opt.opacity_reset_interval == 0 or (dataset.white_background and iteration == opt.densify_from_iter): + gaussians.reset_opacity() + + # Optimizer step + if iteration < opt.iterations: + gaussians.exposure_optimizer.step() + gaussians.exposure_optimizer.zero_grad(set_to_none = True) + if use_sparse_adam: + visible = radii > 0 + gaussians.optimizer.step(visible, radii.shape[0]) + gaussians.optimizer.zero_grad(set_to_none = True) + else: + gaussians.optimizer.step() + gaussians.optimizer.zero_grad(set_to_none = True) + + if (iteration in checkpoint_iterations): + print("\n[ITER {}] Saving Checkpoint".format(iteration)) + torch.save((gaussians.capture(), iteration), scene.model_path + "/chkpnt" + str(iteration) + ".pth") + +def prepare_output_and_logger(args): + if not args.model_path: + if os.getenv('OAR_JOB_ID'): + unique_str=os.getenv('OAR_JOB_ID') + else: + unique_str = str(uuid.uuid4()) + args.model_path = os.path.join("./output/", unique_str[0:10]) + + # Set up output folder + print("Output folder: {}".format(args.model_path)) + os.makedirs(args.model_path, exist_ok = True) + with open(os.path.join(args.model_path, "cfg_args"), 'w') as cfg_log_f: + cfg_log_f.write(str(Namespace(**vars(args)))) + + # Create Tensorboard writer + tb_writer = None + if TENSORBOARD_FOUND: + tb_writer = SummaryWriter(args.model_path) + else: + print("Tensorboard not available: not logging progress") + return tb_writer + +def training_report(tb_writer, iteration, Ll1, loss, l1_loss, elapsed, testing_iterations, scene : Scene, renderFunc, renderArgs, train_test_exp): + if tb_writer: + tb_writer.add_scalar('train_loss_patches/l1_loss', Ll1.item(), iteration) + tb_writer.add_scalar('train_loss_patches/total_loss', loss.item(), iteration) + tb_writer.add_scalar('iter_time', elapsed, iteration) + + # Report test and samples of training set + if iteration in testing_iterations: + torch.cuda.empty_cache() + validation_configs = ({'name': 'test', 'cameras' : scene.getTestCameras()}, + {'name': 'train', 'cameras' : [scene.getTrainCameras()[idx % len(scene.getTrainCameras())] for idx in range(5, 30, 5)]}) + + for config in validation_configs: + if config['cameras'] and len(config['cameras']) > 0: + l1_test = 0.0 + psnr_test = 0.0 + for idx, viewpoint in enumerate(config['cameras']): + image = torch.clamp(renderFunc(viewpoint, scene.gaussians, *renderArgs)["render"], 0.0, 1.0) + gt_image = torch.clamp(viewpoint.original_image.to("cuda"), 0.0, 1.0) + if train_test_exp: + image = image[..., image.shape[-1] // 2:] + gt_image = gt_image[..., gt_image.shape[-1] // 2:] + if tb_writer and (idx < 5): + tb_writer.add_images(config['name'] + "_view_{}/render".format(viewpoint.image_name), image[None], global_step=iteration) + if iteration == testing_iterations[0]: + tb_writer.add_images(config['name'] + "_view_{}/ground_truth".format(viewpoint.image_name), gt_image[None], global_step=iteration) + l1_test += l1_loss(image, gt_image).mean().double() + psnr_test += psnr(image, gt_image).mean().double() + psnr_test /= len(config['cameras']) + l1_test /= len(config['cameras']) + print("\n[ITER {}] Evaluating {}: L1 {} PSNR {}".format(iteration, config['name'], l1_test, psnr_test)) + if tb_writer: + tb_writer.add_scalar(config['name'] + '/loss_viewpoint - l1_loss', l1_test, iteration) + tb_writer.add_scalar(config['name'] + '/loss_viewpoint - psnr', psnr_test, iteration) + + if tb_writer: + tb_writer.add_histogram("scene/opacity_histogram", scene.gaussians.get_opacity, iteration) + tb_writer.add_scalar('total_points', scene.gaussians.get_xyz.shape[0], iteration) + torch.cuda.empty_cache() + +if __name__ == "__main__": + # Set up command line argument parser + parser = ArgumentParser(description="Training script parameters") + lp = ModelParams(parser) + op = OptimizationParams(parser) + pp = PipelineParams(parser) + parser.add_argument('--ip', type=str, default="127.0.0.1") + parser.add_argument('--port', type=int, default=6009) + parser.add_argument('--debug_from', type=int, default=-1) + parser.add_argument('--detect_anomaly', action='store_true', default=False) + parser.add_argument("--test_iterations", nargs="+", type=int, default=[7_000, 30_000]) + parser.add_argument("--save_iterations", nargs="+", type=int, default=[7_000, 30_000]) + parser.add_argument("--quiet", action="store_true") + parser.add_argument('--disable_viewer', action='store_true', default=False) + parser.add_argument("--checkpoint_iterations", nargs="+", type=int, default=[]) + parser.add_argument("--start_checkpoint", type=str, default = None) + args = parser.parse_args(sys.argv[1:]) + args.save_iterations.append(args.iterations) + + print("Optimizing " + args.model_path) + + # Initialize system state (RNG) + safe_state(args.quiet) + + # Start GUI server, configure and run training + if not args.disable_viewer: + network_gui.init(args.ip, args.port) + torch.autograd.set_detect_anomaly(args.detect_anomaly) + training(lp.extract(args), op.extract(args), pp.extract(args), args.test_iterations, args.save_iterations, args.checkpoint_iterations, args.start_checkpoint, args.debug_from) + + # All done + print("\nTraining complete.") diff --git a/submodules/gaussian-splatting/utils/camera_utils.py b/submodules/gaussian-splatting/utils/camera_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..590b1e621fd90f1714f35b6ab2dbd997576431fc --- /dev/null +++ b/submodules/gaussian-splatting/utils/camera_utils.py @@ -0,0 +1,97 @@ +# +# Copyright (C) 2023, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact george.drettakis@inria.fr +# + +from scene.cameras import Camera +import numpy as np +from utils.graphics_utils import fov2focal +from PIL import Image +import cv2 + +WARNED = False + +def loadCam(args, id, cam_info, resolution_scale, is_nerf_synthetic, is_test_dataset): + image = Image.open(cam_info.image_path) + + if cam_info.depth_path != "": + try: + if is_nerf_synthetic: + invdepthmap = cv2.imread(cam_info.depth_path, -1).astype(np.float32) / 512 + else: + invdepthmap = cv2.imread(cam_info.depth_path, -1).astype(np.float32) / float(2**16) + + except FileNotFoundError: + print(f"Error: The depth file at path '{cam_info.depth_path}' was not found.") + raise + except IOError: + print(f"Error: Unable to open the image file '{cam_info.depth_path}'. It may be corrupted or an unsupported format.") + raise + except Exception as e: + print(f"An unexpected error occurred when trying to read depth at {cam_info.depth_path}: {e}") + raise + else: + invdepthmap = None + + orig_w, orig_h = image.size + if args.resolution in [1, 2, 4, 8]: + resolution = round(orig_w/(resolution_scale * args.resolution)), round(orig_h/(resolution_scale * args.resolution)) + else: # should be a type that converts to float + if args.resolution == -1: + if orig_w > 1600: + global WARNED + if not WARNED: + print("[ INFO ] Encountered quite large input images (>1.6K pixels width), rescaling to 1.6K.\n " + "If this is not desired, please explicitly specify '--resolution/-r' as 1") + WARNED = True + global_down = orig_w / 1600 + else: + global_down = 1 + else: + global_down = orig_w / args.resolution + + + scale = float(global_down) * float(resolution_scale) + resolution = (int(orig_w / scale), int(orig_h / scale)) + + return Camera(resolution, colmap_id=cam_info.uid, R=cam_info.R, T=cam_info.T, + FoVx=cam_info.FovX, FoVy=cam_info.FovY, depth_params=cam_info.depth_params, + image=image, invdepthmap=invdepthmap, + image_name=cam_info.image_name, uid=id, data_device=args.data_device, + train_test_exp=args.train_test_exp, is_test_dataset=is_test_dataset, is_test_view=cam_info.is_test) + +def cameraList_from_camInfos(cam_infos, resolution_scale, args, is_nerf_synthetic, is_test_dataset): + camera_list = [] + + for id, c in enumerate(cam_infos): + camera_list.append(loadCam(args, id, c, resolution_scale, is_nerf_synthetic, is_test_dataset)) + + return camera_list + +def camera_to_JSON(id, camera : Camera): + Rt = np.zeros((4, 4)) + Rt[:3, :3] = camera.R.transpose() + Rt[:3, 3] = camera.T + Rt[3, 3] = 1.0 + + W2C = np.linalg.inv(Rt) + pos = W2C[:3, 3] + rot = W2C[:3, :3] + serializable_array_2d = [x.tolist() for x in rot] + camera_entry = { + 'id' : id, + 'img_name' : camera.image_name, + 'width' : camera.width, + 'height' : camera.height, + 'position': pos.tolist(), + 'rotation': serializable_array_2d, + 'fy' : fov2focal(camera.FovY, camera.height), + 'fx' : fov2focal(camera.FovX, camera.width) + } + return camera_entry \ No newline at end of file diff --git a/submodules/gaussian-splatting/utils/general_utils.py b/submodules/gaussian-splatting/utils/general_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..541c0825229a2d86e84460b765879f86f724a59d --- /dev/null +++ b/submodules/gaussian-splatting/utils/general_utils.py @@ -0,0 +1,133 @@ +# +# Copyright (C) 2023, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact george.drettakis@inria.fr +# + +import torch +import sys +from datetime import datetime +import numpy as np +import random + +def inverse_sigmoid(x): + return torch.log(x/(1-x)) + +def PILtoTorch(pil_image, resolution): + resized_image_PIL = pil_image.resize(resolution) + resized_image = torch.from_numpy(np.array(resized_image_PIL)) / 255.0 + if len(resized_image.shape) == 3: + return resized_image.permute(2, 0, 1) + else: + return resized_image.unsqueeze(dim=-1).permute(2, 0, 1) + +def get_expon_lr_func( + lr_init, lr_final, lr_delay_steps=0, lr_delay_mult=1.0, max_steps=1000000 +): + """ + Copied from Plenoxels + + Continuous learning rate decay function. Adapted from JaxNeRF + The returned rate is lr_init when step=0 and lr_final when step=max_steps, and + is log-linearly interpolated elsewhere (equivalent to exponential decay). + If lr_delay_steps>0 then the learning rate will be scaled by some smooth + function of lr_delay_mult, such that the initial learning rate is + lr_init*lr_delay_mult at the beginning of optimization but will be eased back + to the normal learning rate when steps>lr_delay_steps. + :param conf: config subtree 'lr' or similar + :param max_steps: int, the number of steps during optimization. + :return HoF which takes step as input + """ + + def helper(step): + if step < 0 or (lr_init == 0.0 and lr_final == 0.0): + # Disable this parameter + return 0.0 + if lr_delay_steps > 0: + # A kind of reverse cosine decay. + delay_rate = lr_delay_mult + (1 - lr_delay_mult) * np.sin( + 0.5 * np.pi * np.clip(step / lr_delay_steps, 0, 1) + ) + else: + delay_rate = 1.0 + t = np.clip(step / max_steps, 0, 1) + log_lerp = np.exp(np.log(lr_init) * (1 - t) + np.log(lr_final) * t) + return delay_rate * log_lerp + + return helper + +def strip_lowerdiag(L): + uncertainty = torch.zeros((L.shape[0], 6), dtype=torch.float, device="cuda") + + uncertainty[:, 0] = L[:, 0, 0] + uncertainty[:, 1] = L[:, 0, 1] + uncertainty[:, 2] = L[:, 0, 2] + uncertainty[:, 3] = L[:, 1, 1] + uncertainty[:, 4] = L[:, 1, 2] + uncertainty[:, 5] = L[:, 2, 2] + return uncertainty + +def strip_symmetric(sym): + return strip_lowerdiag(sym) + +def build_rotation(r): + norm = torch.sqrt(r[:,0]*r[:,0] + r[:,1]*r[:,1] + r[:,2]*r[:,2] + r[:,3]*r[:,3]) + + q = r / norm[:, None] + + R = torch.zeros((q.size(0), 3, 3), device='cuda') + + r = q[:, 0] + x = q[:, 1] + y = q[:, 2] + z = q[:, 3] + + R[:, 0, 0] = 1 - 2 * (y*y + z*z) + R[:, 0, 1] = 2 * (x*y - r*z) + R[:, 0, 2] = 2 * (x*z + r*y) + R[:, 1, 0] = 2 * (x*y + r*z) + R[:, 1, 1] = 1 - 2 * (x*x + z*z) + R[:, 1, 2] = 2 * (y*z - r*x) + R[:, 2, 0] = 2 * (x*z - r*y) + R[:, 2, 1] = 2 * (y*z + r*x) + R[:, 2, 2] = 1 - 2 * (x*x + y*y) + return R + +def build_scaling_rotation(s, r): + L = torch.zeros((s.shape[0], 3, 3), dtype=torch.float, device="cuda") + R = build_rotation(r) + + L[:,0,0] = s[:,0] + L[:,1,1] = s[:,1] + L[:,2,2] = s[:,2] + + L = R @ L + return L + +def safe_state(silent): + old_f = sys.stdout + class F: + def __init__(self, silent): + self.silent = silent + + def write(self, x): + if not self.silent: + if x.endswith("\n"): + old_f.write(x.replace("\n", " [{}]\n".format(str(datetime.now().strftime("%d/%m %H:%M:%S"))))) + else: + old_f.write(x) + + def flush(self): + old_f.flush() + + sys.stdout = F(silent) + + random.seed(0) + np.random.seed(0) + torch.manual_seed(0) + torch.cuda.set_device(torch.device("cuda:0")) diff --git a/submodules/gaussian-splatting/utils/graphics_utils.py b/submodules/gaussian-splatting/utils/graphics_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..b4627d837c74fcdffc898fa0c3071cb7b316802b --- /dev/null +++ b/submodules/gaussian-splatting/utils/graphics_utils.py @@ -0,0 +1,77 @@ +# +# Copyright (C) 2023, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact george.drettakis@inria.fr +# + +import torch +import math +import numpy as np +from typing import NamedTuple + +class BasicPointCloud(NamedTuple): + points : np.array + colors : np.array + normals : np.array + +def geom_transform_points(points, transf_matrix): + P, _ = points.shape + ones = torch.ones(P, 1, dtype=points.dtype, device=points.device) + points_hom = torch.cat([points, ones], dim=1) + points_out = torch.matmul(points_hom, transf_matrix.unsqueeze(0)) + + denom = points_out[..., 3:] + 0.0000001 + return (points_out[..., :3] / denom).squeeze(dim=0) + +def getWorld2View(R, t): + Rt = np.zeros((4, 4)) + Rt[:3, :3] = R.transpose() + Rt[:3, 3] = t + Rt[3, 3] = 1.0 + return np.float32(Rt) + +def getWorld2View2(R, t, translate=np.array([.0, .0, .0]), scale=1.0): + Rt = np.zeros((4, 4)) + Rt[:3, :3] = R.transpose() + Rt[:3, 3] = t + Rt[3, 3] = 1.0 + + C2W = np.linalg.inv(Rt) + cam_center = C2W[:3, 3] + cam_center = (cam_center + translate) * scale + C2W[:3, 3] = cam_center + Rt = np.linalg.inv(C2W) + return np.float32(Rt) + +def getProjectionMatrix(znear, zfar, fovX, fovY): + tanHalfFovY = math.tan((fovY / 2)) + tanHalfFovX = math.tan((fovX / 2)) + + top = tanHalfFovY * znear + bottom = -top + right = tanHalfFovX * znear + left = -right + + P = torch.zeros(4, 4) + + z_sign = 1.0 + + P[0, 0] = 2.0 * znear / (right - left) + P[1, 1] = 2.0 * znear / (top - bottom) + P[0, 2] = (right + left) / (right - left) + P[1, 2] = (top + bottom) / (top - bottom) + P[3, 2] = z_sign + P[2, 2] = z_sign * zfar / (zfar - znear) + P[2, 3] = -(zfar * znear) / (zfar - znear) + return P + +def fov2focal(fov, pixels): + return pixels / (2 * math.tan(fov / 2)) + +def focal2fov(focal, pixels): + return 2*math.atan(pixels/(2*focal)) \ No newline at end of file diff --git a/submodules/gaussian-splatting/utils/image_utils.py b/submodules/gaussian-splatting/utils/image_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..cdeaa1b6d250e549181ab165070f82ccd31b3eb9 --- /dev/null +++ b/submodules/gaussian-splatting/utils/image_utils.py @@ -0,0 +1,19 @@ +# +# Copyright (C) 2023, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact george.drettakis@inria.fr +# + +import torch + +def mse(img1, img2): + return (((img1 - img2)) ** 2).view(img1.shape[0], -1).mean(1, keepdim=True) + +def psnr(img1, img2): + mse = (((img1 - img2)) ** 2).view(img1.shape[0], -1).mean(1, keepdim=True) + return 20 * torch.log10(1.0 / torch.sqrt(mse)) diff --git a/submodules/gaussian-splatting/utils/loss_utils.py b/submodules/gaussian-splatting/utils/loss_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..60cf1f70c9ab15e6767dd566a29a464b7826c849 --- /dev/null +++ b/submodules/gaussian-splatting/utils/loss_utils.py @@ -0,0 +1,91 @@ +# +# Copyright (C) 2023, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact george.drettakis@inria.fr +# + +import torch +import torch.nn.functional as F +from torch.autograd import Variable +from math import exp +try: + from diff_gaussian_rasterization._C import fusedssim, fusedssim_backward +except: + pass + +C1 = 0.01 ** 2 +C2 = 0.03 ** 2 + +class FusedSSIMMap(torch.autograd.Function): + @staticmethod + def forward(ctx, C1, C2, img1, img2): + ssim_map = fusedssim(C1, C2, img1, img2) + ctx.save_for_backward(img1.detach(), img2) + ctx.C1 = C1 + ctx.C2 = C2 + return ssim_map + + @staticmethod + def backward(ctx, opt_grad): + img1, img2 = ctx.saved_tensors + C1, C2 = ctx.C1, ctx.C2 + grad = fusedssim_backward(C1, C2, img1, img2, opt_grad) + return None, None, grad, None + +def l1_loss(network_output, gt): + return torch.abs((network_output - gt)).mean() + +def l2_loss(network_output, gt): + return ((network_output - gt) ** 2).mean() + +def gaussian(window_size, sigma): + gauss = torch.Tensor([exp(-(x - window_size // 2) ** 2 / float(2 * sigma ** 2)) for x in range(window_size)]) + return gauss / gauss.sum() + +def create_window(window_size, channel): + _1D_window = gaussian(window_size, 1.5).unsqueeze(1) + _2D_window = _1D_window.mm(_1D_window.t()).float().unsqueeze(0).unsqueeze(0) + window = Variable(_2D_window.expand(channel, 1, window_size, window_size).contiguous()) + return window + +def ssim(img1, img2, window_size=11, size_average=True): + channel = img1.size(-3) + window = create_window(window_size, channel) + + if img1.is_cuda: + window = window.cuda(img1.get_device()) + window = window.type_as(img1) + + return _ssim(img1, img2, window, window_size, channel, size_average) + +def _ssim(img1, img2, window, window_size, channel, size_average=True): + mu1 = F.conv2d(img1, window, padding=window_size // 2, groups=channel) + mu2 = F.conv2d(img2, window, padding=window_size // 2, groups=channel) + + mu1_sq = mu1.pow(2) + mu2_sq = mu2.pow(2) + mu1_mu2 = mu1 * mu2 + + sigma1_sq = F.conv2d(img1 * img1, window, padding=window_size // 2, groups=channel) - mu1_sq + sigma2_sq = F.conv2d(img2 * img2, window, padding=window_size // 2, groups=channel) - mu2_sq + sigma12 = F.conv2d(img1 * img2, window, padding=window_size // 2, groups=channel) - mu1_mu2 + + C1 = 0.01 ** 2 + C2 = 0.03 ** 2 + + ssim_map = ((2 * mu1_mu2 + C1) * (2 * sigma12 + C2)) / ((mu1_sq + mu2_sq + C1) * (sigma1_sq + sigma2_sq + C2)) + + if size_average: + return ssim_map.mean() + else: + return ssim_map.mean(1).mean(1).mean(1) + + +def fast_ssim(img1, img2): + ssim_map = FusedSSIMMap.apply(C1, C2, img1, img2) + return ssim_map.mean() diff --git a/submodules/gaussian-splatting/utils/make_depth_scale.py b/submodules/gaussian-splatting/utils/make_depth_scale.py new file mode 100644 index 0000000000000000000000000000000000000000..3a20c32d8e8c3f534551bc4f742f38b9d6442c6a --- /dev/null +++ b/submodules/gaussian-splatting/utils/make_depth_scale.py @@ -0,0 +1,94 @@ +import numpy as np +import argparse +import cv2 +from joblib import delayed, Parallel +import json +from read_write_model import * + +def get_scales(key, cameras, images, points3d_ordered, args): + image_meta = images[key] + cam_intrinsic = cameras[image_meta.camera_id] + + pts_idx = images_metas[key].point3D_ids + + mask = pts_idx >= 0 + mask *= pts_idx < len(points3d_ordered) + + pts_idx = pts_idx[mask] + valid_xys = image_meta.xys[mask] + + if len(pts_idx) > 0: + pts = points3d_ordered[pts_idx] + else: + pts = np.array([0, 0, 0]) + + R = qvec2rotmat(image_meta.qvec) + pts = np.dot(pts, R.T) + image_meta.tvec + + invcolmapdepth = 1. / pts[..., 2] + n_remove = len(image_meta.name.split('.')[-1]) + 1 + invmonodepthmap = cv2.imread(f"{args.depths_dir}/{image_meta.name[:-n_remove]}.png", cv2.IMREAD_UNCHANGED) + + if invmonodepthmap is None: + return None + + if invmonodepthmap.ndim != 2: + invmonodepthmap = invmonodepthmap[..., 0] + + invmonodepthmap = invmonodepthmap.astype(np.float32) / (2**16) + s = invmonodepthmap.shape[0] / cam_intrinsic.height + + maps = (valid_xys * s).astype(np.float32) + valid = ( + (maps[..., 0] >= 0) * + (maps[..., 1] >= 0) * + (maps[..., 0] < cam_intrinsic.width * s) * + (maps[..., 1] < cam_intrinsic.height * s) * (invcolmapdepth > 0)) + + if valid.sum() > 10 and (invcolmapdepth.max() - invcolmapdepth.min()) > 1e-3: + maps = maps[valid, :] + invcolmapdepth = invcolmapdepth[valid] + invmonodepth = cv2.remap(invmonodepthmap, maps[..., 0], maps[..., 1], interpolation=cv2.INTER_LINEAR, borderMode=cv2.BORDER_REPLICATE)[..., 0] + + ## Median / dev + t_colmap = np.median(invcolmapdepth) + s_colmap = np.mean(np.abs(invcolmapdepth - t_colmap)) + + t_mono = np.median(invmonodepth) + s_mono = np.mean(np.abs(invmonodepth - t_mono)) + scale = s_colmap / s_mono + offset = t_colmap - t_mono * scale + else: + scale = 0 + offset = 0 + return {"image_name": image_meta.name[:-n_remove], "scale": scale, "offset": offset} + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--base_dir', default="../data/big_gaussians/standalone_chunks/campus") + parser.add_argument('--depths_dir', default="../data/big_gaussians/standalone_chunks/campus/depths_any") + parser.add_argument('--model_type', default="bin") + args = parser.parse_args() + + + cam_intrinsics, images_metas, points3d = read_model(os.path.join(args.base_dir, "sparse", "0"), ext=f".{args.model_type}") + + pts_indices = np.array([points3d[key].id for key in points3d]) + pts_xyzs = np.array([points3d[key].xyz for key in points3d]) + points3d_ordered = np.zeros([pts_indices.max()+1, 3]) + points3d_ordered[pts_indices] = pts_xyzs + + # depth_param_list = [get_scales(key, cam_intrinsics, images_metas, points3d_ordered, args) for key in images_metas] + depth_param_list = Parallel(n_jobs=-1, backend="threading")( + delayed(get_scales)(key, cam_intrinsics, images_metas, points3d_ordered, args) for key in images_metas + ) + + depth_params = { + depth_param["image_name"]: {"scale": depth_param["scale"], "offset": depth_param["offset"]} + for depth_param in depth_param_list if depth_param != None + } + + with open(f"{args.base_dir}/sparse/0/depth_params.json", "w") as f: + json.dump(depth_params, f, indent=2) + + print(0) diff --git a/submodules/gaussian-splatting/utils/read_write_model.py b/submodules/gaussian-splatting/utils/read_write_model.py new file mode 100644 index 0000000000000000000000000000000000000000..f3f7585356920f9513dc1e11815d1d7d1aae681b --- /dev/null +++ b/submodules/gaussian-splatting/utils/read_write_model.py @@ -0,0 +1,604 @@ +# Copyright (c) 2023, ETH Zurich and UNC Chapel Hill. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of +# its contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + + +import os +import collections +import numpy as np +import struct +import argparse + + +CameraModel = collections.namedtuple( + "CameraModel", ["model_id", "model_name", "num_params"] +) +Camera = collections.namedtuple( + "Camera", ["id", "model", "width", "height", "params"] +) +BaseImage = collections.namedtuple( + "Image", ["id", "qvec", "tvec", "camera_id", "name", "xys", "point3D_ids"] +) +Point3D = collections.namedtuple( + "Point3D", ["id", "xyz", "rgb", "error", "image_ids", "point2D_idxs"] +) + + +class Image(BaseImage): + def qvec2rotmat(self): + return qvec2rotmat(self.qvec) + + +CAMERA_MODELS = { + CameraModel(model_id=0, model_name="SIMPLE_PINHOLE", num_params=3), + CameraModel(model_id=1, model_name="PINHOLE", num_params=4), + CameraModel(model_id=2, model_name="SIMPLE_RADIAL", num_params=4), + CameraModel(model_id=3, model_name="RADIAL", num_params=5), + CameraModel(model_id=4, model_name="OPENCV", num_params=8), + CameraModel(model_id=5, model_name="OPENCV_FISHEYE", num_params=8), + CameraModel(model_id=6, model_name="FULL_OPENCV", num_params=12), + CameraModel(model_id=7, model_name="FOV", num_params=5), + CameraModel(model_id=8, model_name="SIMPLE_RADIAL_FISHEYE", num_params=4), + CameraModel(model_id=9, model_name="RADIAL_FISHEYE", num_params=5), + CameraModel(model_id=10, model_name="THIN_PRISM_FISHEYE", num_params=12), +} +CAMERA_MODEL_IDS = dict( + [(camera_model.model_id, camera_model) for camera_model in CAMERA_MODELS] +) +CAMERA_MODEL_NAMES = dict( + [(camera_model.model_name, camera_model) for camera_model in CAMERA_MODELS] +) + + +def read_next_bytes(fid, num_bytes, format_char_sequence, endian_character="<"): + """Read and unpack the next bytes from a binary file. + :param fid: + :param num_bytes: Sum of combination of {2, 4, 8}, e.g. 2, 6, 16, 30, etc. + :param format_char_sequence: List of {c, e, f, d, h, H, i, I, l, L, q, Q}. + :param endian_character: Any of {@, =, <, >, !} + :return: Tuple of read and unpacked values. + """ + data = fid.read(num_bytes) + return struct.unpack(endian_character + format_char_sequence, data) + + +def write_next_bytes(fid, data, format_char_sequence, endian_character="<"): + """pack and write to a binary file. + :param fid: + :param data: data to send, if multiple elements are sent at the same time, + they should be encapsuled either in a list or a tuple + :param format_char_sequence: List of {c, e, f, d, h, H, i, I, l, L, q, Q}. + should be the same length as the data list or tuple + :param endian_character: Any of {@, =, <, >, !} + """ + if isinstance(data, (list, tuple)): + bytes = struct.pack(endian_character + format_char_sequence, *data) + else: + bytes = struct.pack(endian_character + format_char_sequence, data) + fid.write(bytes) + + +def read_cameras_text(path): + """ + see: src/colmap/scene/reconstruction.cc + void Reconstruction::WriteCamerasText(const std::string& path) + void Reconstruction::ReadCamerasText(const std::string& path) + """ + cameras = {} + with open(path, "r") as fid: + while True: + line = fid.readline() + if not line: + break + line = line.strip() + if len(line) > 0 and line[0] != "#": + elems = line.split() + camera_id = int(elems[0]) + model = elems[1] + width = int(elems[2]) + height = int(elems[3]) + params = np.array(tuple(map(float, elems[4:]))) + cameras[camera_id] = Camera( + id=camera_id, + model=model, + width=width, + height=height, + params=params, + ) + return cameras + + +def read_cameras_binary(path_to_model_file): + """ + see: src/colmap/scene/reconstruction.cc + void Reconstruction::WriteCamerasBinary(const std::string& path) + void Reconstruction::ReadCamerasBinary(const std::string& path) + """ + cameras = {} + with open(path_to_model_file, "rb") as fid: + num_cameras = read_next_bytes(fid, 8, "Q")[0] + for _ in range(num_cameras): + camera_properties = read_next_bytes( + fid, num_bytes=24, format_char_sequence="iiQQ" + ) + camera_id = camera_properties[0] + model_id = camera_properties[1] + model_name = CAMERA_MODEL_IDS[camera_properties[1]].model_name + width = camera_properties[2] + height = camera_properties[3] + num_params = CAMERA_MODEL_IDS[model_id].num_params + params = read_next_bytes( + fid, + num_bytes=8 * num_params, + format_char_sequence="d" * num_params, + ) + cameras[camera_id] = Camera( + id=camera_id, + model=model_name, + width=width, + height=height, + params=np.array(params), + ) + assert len(cameras) == num_cameras + return cameras + + +def write_cameras_text(cameras, path): + """ + see: src/colmap/scene/reconstruction.cc + void Reconstruction::WriteCamerasText(const std::string& path) + void Reconstruction::ReadCamerasText(const std::string& path) + """ + HEADER = ( + "# Camera list with one line of data per camera:\n" + + "# CAMERA_ID, MODEL, WIDTH, HEIGHT, PARAMS[]\n" + + "# Number of cameras: {}\n".format(len(cameras)) + ) + with open(path, "w") as fid: + fid.write(HEADER) + for _, cam in cameras.items(): + to_write = [cam.id, cam.model, cam.width, cam.height, *cam.params] + line = " ".join([str(elem) for elem in to_write]) + fid.write(line + "\n") + + +def write_cameras_binary(cameras, path_to_model_file): + """ + see: src/colmap/scene/reconstruction.cc + void Reconstruction::WriteCamerasBinary(const std::string& path) + void Reconstruction::ReadCamerasBinary(const std::string& path) + """ + with open(path_to_model_file, "wb") as fid: + write_next_bytes(fid, len(cameras), "Q") + for _, cam in cameras.items(): + model_id = CAMERA_MODEL_NAMES[cam.model].model_id + camera_properties = [cam.id, model_id, cam.width, cam.height] + write_next_bytes(fid, camera_properties, "iiQQ") + for p in cam.params: + write_next_bytes(fid, float(p), "d") + return cameras + + +def read_images_text(path): + """ + see: src/colmap/scene/reconstruction.cc + void Reconstruction::ReadImagesText(const std::string& path) + void Reconstruction::WriteImagesText(const std::string& path) + """ + images = {} + with open(path, "r") as fid: + while True: + line = fid.readline() + if not line: + break + line = line.strip() + if len(line) > 0 and line[0] != "#": + elems = line.split() + image_id = int(elems[0]) + qvec = np.array(tuple(map(float, elems[1:5]))) + tvec = np.array(tuple(map(float, elems[5:8]))) + camera_id = int(elems[8]) + image_name = elems[9] + elems = fid.readline().split() + xys = np.column_stack( + [ + tuple(map(float, elems[0::3])), + tuple(map(float, elems[1::3])), + ] + ) + point3D_ids = np.array(tuple(map(int, elems[2::3]))) + images[image_id] = Image( + id=image_id, + qvec=qvec, + tvec=tvec, + camera_id=camera_id, + name=image_name, + xys=xys, + point3D_ids=point3D_ids, + ) + return images + + +def read_images_binary(path_to_model_file): + """ + see: src/colmap/scene/reconstruction.cc + void Reconstruction::ReadImagesBinary(const std::string& path) + void Reconstruction::WriteImagesBinary(const std::string& path) + """ + images = {} + with open(path_to_model_file, "rb") as fid: + num_reg_images = read_next_bytes(fid, 8, "Q")[0] + for _ in range(num_reg_images): + binary_image_properties = read_next_bytes( + fid, num_bytes=64, format_char_sequence="idddddddi" + ) + image_id = binary_image_properties[0] + qvec = np.array(binary_image_properties[1:5]) + tvec = np.array(binary_image_properties[5:8]) + camera_id = binary_image_properties[8] + image_name = "" + current_char = read_next_bytes(fid, 1, "c")[0] + while current_char != b"\x00": # look for the ASCII 0 entry + image_name += current_char.decode("utf-8") + current_char = read_next_bytes(fid, 1, "c")[0] + num_points2D = read_next_bytes( + fid, num_bytes=8, format_char_sequence="Q" + )[0] + x_y_id_s = read_next_bytes( + fid, + num_bytes=24 * num_points2D, + format_char_sequence="ddq" * num_points2D, + ) + xys = np.column_stack( + [ + tuple(map(float, x_y_id_s[0::3])), + tuple(map(float, x_y_id_s[1::3])), + ] + ) + point3D_ids = np.array(tuple(map(int, x_y_id_s[2::3]))) + images[image_id] = Image( + id=image_id, + qvec=qvec, + tvec=tvec, + camera_id=camera_id, + name=image_name, + xys=xys, + point3D_ids=point3D_ids, + ) + return images + + +def write_images_text(images, path): + """ + see: src/colmap/scene/reconstruction.cc + void Reconstruction::ReadImagesText(const std::string& path) + void Reconstruction::WriteImagesText(const std::string& path) + """ + if len(images) == 0: + mean_observations = 0 + else: + mean_observations = sum( + (len(img.point3D_ids) for _, img in images.items()) + ) / len(images) + HEADER = ( + "# Image list with two lines of data per image:\n" + + "# IMAGE_ID, QW, QX, QY, QZ, TX, TY, TZ, CAMERA_ID, NAME\n" + + "# POINTS2D[] as (X, Y, POINT3D_ID)\n" + + "# Number of images: {}, mean observations per image: {}\n".format( + len(images), mean_observations + ) + ) + + with open(path, "w") as fid: + fid.write(HEADER) + for _, img in images.items(): + image_header = [ + img.id, + *img.qvec, + *img.tvec, + img.camera_id, + img.name, + ] + first_line = " ".join(map(str, image_header)) + fid.write(first_line + "\n") + + points_strings = [] + for xy, point3D_id in zip(img.xys, img.point3D_ids): + points_strings.append(" ".join(map(str, [*xy, point3D_id]))) + fid.write(" ".join(points_strings) + "\n") + + +def write_images_binary(images, path_to_model_file): + """ + see: src/colmap/scene/reconstruction.cc + void Reconstruction::ReadImagesBinary(const std::string& path) + void Reconstruction::WriteImagesBinary(const std::string& path) + """ + with open(path_to_model_file, "wb") as fid: + write_next_bytes(fid, len(images), "Q") + for _, img in images.items(): + write_next_bytes(fid, img.id, "i") + write_next_bytes(fid, img.qvec.tolist(), "dddd") + write_next_bytes(fid, img.tvec.tolist(), "ddd") + write_next_bytes(fid, img.camera_id, "i") + for char in img.name: + write_next_bytes(fid, char.encode("utf-8"), "c") + write_next_bytes(fid, b"\x00", "c") + write_next_bytes(fid, len(img.point3D_ids), "Q") + for xy, p3d_id in zip(img.xys, img.point3D_ids): + write_next_bytes(fid, [*xy, p3d_id], "ddq") + + +def read_points3D_text(path): + """ + see: src/colmap/scene/reconstruction.cc + void Reconstruction::ReadPoints3DText(const std::string& path) + void Reconstruction::WritePoints3DText(const std::string& path) + """ + points3D = {} + with open(path, "r") as fid: + while True: + line = fid.readline() + if not line: + break + line = line.strip() + if len(line) > 0 and line[0] != "#": + elems = line.split() + point3D_id = int(elems[0]) + xyz = np.array(tuple(map(float, elems[1:4]))) + rgb = np.array(tuple(map(int, elems[4:7]))) + error = float(elems[7]) + image_ids = np.array(tuple(map(int, elems[8::2]))) + point2D_idxs = np.array(tuple(map(int, elems[9::2]))) + points3D[point3D_id] = Point3D( + id=point3D_id, + xyz=xyz, + rgb=rgb, + error=error, + image_ids=image_ids, + point2D_idxs=point2D_idxs, + ) + return points3D + + +def read_points3D_binary(path_to_model_file): + """ + see: src/colmap/scene/reconstruction.cc + void Reconstruction::ReadPoints3DBinary(const std::string& path) + void Reconstruction::WritePoints3DBinary(const std::string& path) + """ + points3D = {} + with open(path_to_model_file, "rb") as fid: + num_points = read_next_bytes(fid, 8, "Q")[0] + for _ in range(num_points): + binary_point_line_properties = read_next_bytes( + fid, num_bytes=43, format_char_sequence="QdddBBBd" + ) + point3D_id = binary_point_line_properties[0] + xyz = np.array(binary_point_line_properties[1:4]) + rgb = np.array(binary_point_line_properties[4:7]) + error = np.array(binary_point_line_properties[7]) + track_length = read_next_bytes( + fid, num_bytes=8, format_char_sequence="Q" + )[0] + track_elems = read_next_bytes( + fid, + num_bytes=8 * track_length, + format_char_sequence="ii" * track_length, + ) + image_ids = np.array(tuple(map(int, track_elems[0::2]))) + point2D_idxs = np.array(tuple(map(int, track_elems[1::2]))) + points3D[point3D_id] = Point3D( + id=point3D_id, + xyz=xyz, + rgb=rgb, + error=error, + image_ids=image_ids, + point2D_idxs=point2D_idxs, + ) + return points3D + + +def write_points3D_text(points3D, path): + """ + see: src/colmap/scene/reconstruction.cc + void Reconstruction::ReadPoints3DText(const std::string& path) + void Reconstruction::WritePoints3DText(const std::string& path) + """ + if len(points3D) == 0: + mean_track_length = 0 + else: + mean_track_length = sum( + (len(pt.image_ids) for _, pt in points3D.items()) + ) / len(points3D) + HEADER = ( + "# 3D point list with one line of data per point:\n" + + "# POINT3D_ID, X, Y, Z, R, G, B, ERROR, TRACK[] as (IMAGE_ID, POINT2D_IDX)\n" + + "# Number of points: {}, mean track length: {}\n".format( + len(points3D), mean_track_length + ) + ) + + with open(path, "w") as fid: + fid.write(HEADER) + for _, pt in points3D.items(): + point_header = [pt.id, *pt.xyz, *pt.rgb, pt.error] + fid.write(" ".join(map(str, point_header)) + " ") + track_strings = [] + for image_id, point2D in zip(pt.image_ids, pt.point2D_idxs): + track_strings.append(" ".join(map(str, [image_id, point2D]))) + fid.write(" ".join(track_strings) + "\n") + + +def write_points3D_binary(points3D, path_to_model_file): + """ + see: src/colmap/scene/reconstruction.cc + void Reconstruction::ReadPoints3DBinary(const std::string& path) + void Reconstruction::WritePoints3DBinary(const std::string& path) + """ + with open(path_to_model_file, "wb") as fid: + write_next_bytes(fid, len(points3D), "Q") + for _, pt in points3D.items(): + write_next_bytes(fid, pt.id, "Q") + write_next_bytes(fid, pt.xyz.tolist(), "ddd") + write_next_bytes(fid, pt.rgb.tolist(), "BBB") + write_next_bytes(fid, pt.error, "d") + track_length = pt.image_ids.shape[0] + write_next_bytes(fid, track_length, "Q") + for image_id, point2D_id in zip(pt.image_ids, pt.point2D_idxs): + write_next_bytes(fid, [image_id, point2D_id], "ii") + + +def detect_model_format(path, ext): + if ( + os.path.isfile(os.path.join(path, "cameras" + ext)) + and os.path.isfile(os.path.join(path, "images" + ext)) + and os.path.isfile(os.path.join(path, "points3D" + ext)) + ): + print("Detected model format: '" + ext + "'") + return True + + return False + + +def read_model(path, ext=""): + # try to detect the extension automatically + if ext == "": + if detect_model_format(path, ".bin"): + ext = ".bin" + elif detect_model_format(path, ".txt"): + ext = ".txt" + else: + print("Provide model format: '.bin' or '.txt'") + return + + if ext == ".txt": + cameras = read_cameras_text(os.path.join(path, "cameras" + ext)) + images = read_images_text(os.path.join(path, "images" + ext)) + points3D = read_points3D_text(os.path.join(path, "points3D") + ext) + else: + cameras = read_cameras_binary(os.path.join(path, "cameras" + ext)) + images = read_images_binary(os.path.join(path, "images" + ext)) + points3D = read_points3D_binary(os.path.join(path, "points3D") + ext) + return cameras, images, points3D + + +def write_model(cameras, images, points3D, path, ext=".bin"): + if ext == ".txt": + write_cameras_text(cameras, os.path.join(path, "cameras" + ext)) + write_images_text(images, os.path.join(path, "images" + ext)) + write_points3D_text(points3D, os.path.join(path, "points3D") + ext) + else: + write_cameras_binary(cameras, os.path.join(path, "cameras" + ext)) + write_images_binary(images, os.path.join(path, "images" + ext)) + write_points3D_binary(points3D, os.path.join(path, "points3D") + ext) + return cameras, images, points3D + + +def qvec2rotmat(qvec): + return np.array( + [ + [ + 1 - 2 * qvec[2] ** 2 - 2 * qvec[3] ** 2, + 2 * qvec[1] * qvec[2] - 2 * qvec[0] * qvec[3], + 2 * qvec[3] * qvec[1] + 2 * qvec[0] * qvec[2], + ], + [ + 2 * qvec[1] * qvec[2] + 2 * qvec[0] * qvec[3], + 1 - 2 * qvec[1] ** 2 - 2 * qvec[3] ** 2, + 2 * qvec[2] * qvec[3] - 2 * qvec[0] * qvec[1], + ], + [ + 2 * qvec[3] * qvec[1] - 2 * qvec[0] * qvec[2], + 2 * qvec[2] * qvec[3] + 2 * qvec[0] * qvec[1], + 1 - 2 * qvec[1] ** 2 - 2 * qvec[2] ** 2, + ], + ] + ) + + +def rotmat2qvec(R): + Rxx, Ryx, Rzx, Rxy, Ryy, Rzy, Rxz, Ryz, Rzz = R.flat + K = ( + np.array( + [ + [Rxx - Ryy - Rzz, 0, 0, 0], + [Ryx + Rxy, Ryy - Rxx - Rzz, 0, 0], + [Rzx + Rxz, Rzy + Ryz, Rzz - Rxx - Ryy, 0], + [Ryz - Rzy, Rzx - Rxz, Rxy - Ryx, Rxx + Ryy + Rzz], + ] + ) + / 3.0 + ) + eigvals, eigvecs = np.linalg.eigh(K) + qvec = eigvecs[[3, 0, 1, 2], np.argmax(eigvals)] + if qvec[0] < 0: + qvec *= -1 + return qvec + + +# def main(): +# parser = argparse.ArgumentParser( +# description="Read and write COLMAP binary and text models" +# ) +# parser.add_argument("--input_model", help="path to input model folder") +# parser.add_argument( +# "--input_format", +# choices=[".bin", ".txt"], +# help="input model format", +# default="", +# ) +# parser.add_argument("--output_model", help="path to output model folder") +# parser.add_argument( +# "--output_format", +# choices=[".bin", ".txt"], +# help="outut model format", +# default=".txt", +# ) +# args = parser.parse_args() + +# cameras, images, points3D = read_model( +# path=args.input_model, ext=args.input_format +# ) + +# print("num_cameras:", len(cameras)) +# print("num_images:", len(images)) +# print("num_points3D:", len(points3D)) + +# if args.output_model is not None: +# write_model( +# cameras, +# images, +# points3D, +# path=args.output_model, +# ext=args.output_format, +# ) + + +# if __name__ == "__main__": +# main() diff --git a/submodules/gaussian-splatting/utils/sh_utils.py b/submodules/gaussian-splatting/utils/sh_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..bbca7d192aa3a7edf8c5b2d24dee535eac765785 --- /dev/null +++ b/submodules/gaussian-splatting/utils/sh_utils.py @@ -0,0 +1,118 @@ +# Copyright 2021 The PlenOctree Authors. +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import torch + +C0 = 0.28209479177387814 +C1 = 0.4886025119029199 +C2 = [ + 1.0925484305920792, + -1.0925484305920792, + 0.31539156525252005, + -1.0925484305920792, + 0.5462742152960396 +] +C3 = [ + -0.5900435899266435, + 2.890611442640554, + -0.4570457994644658, + 0.3731763325901154, + -0.4570457994644658, + 1.445305721320277, + -0.5900435899266435 +] +C4 = [ + 2.5033429417967046, + -1.7701307697799304, + 0.9461746957575601, + -0.6690465435572892, + 0.10578554691520431, + -0.6690465435572892, + 0.47308734787878004, + -1.7701307697799304, + 0.6258357354491761, +] + + +def eval_sh(deg, sh, dirs): + """ + Evaluate spherical harmonics at unit directions + using hardcoded SH polynomials. + Works with torch/np/jnp. + ... Can be 0 or more batch dimensions. + Args: + deg: int SH deg. Currently, 0-3 supported + sh: jnp.ndarray SH coeffs [..., C, (deg + 1) ** 2] + dirs: jnp.ndarray unit directions [..., 3] + Returns: + [..., C] + """ + assert deg <= 4 and deg >= 0 + coeff = (deg + 1) ** 2 + assert sh.shape[-1] >= coeff + + result = C0 * sh[..., 0] + if deg > 0: + x, y, z = dirs[..., 0:1], dirs[..., 1:2], dirs[..., 2:3] + result = (result - + C1 * y * sh[..., 1] + + C1 * z * sh[..., 2] - + C1 * x * sh[..., 3]) + + if deg > 1: + xx, yy, zz = x * x, y * y, z * z + xy, yz, xz = x * y, y * z, x * z + result = (result + + C2[0] * xy * sh[..., 4] + + C2[1] * yz * sh[..., 5] + + C2[2] * (2.0 * zz - xx - yy) * sh[..., 6] + + C2[3] * xz * sh[..., 7] + + C2[4] * (xx - yy) * sh[..., 8]) + + if deg > 2: + result = (result + + C3[0] * y * (3 * xx - yy) * sh[..., 9] + + C3[1] * xy * z * sh[..., 10] + + C3[2] * y * (4 * zz - xx - yy)* sh[..., 11] + + C3[3] * z * (2 * zz - 3 * xx - 3 * yy) * sh[..., 12] + + C3[4] * x * (4 * zz - xx - yy) * sh[..., 13] + + C3[5] * z * (xx - yy) * sh[..., 14] + + C3[6] * x * (xx - 3 * yy) * sh[..., 15]) + + if deg > 3: + result = (result + C4[0] * xy * (xx - yy) * sh[..., 16] + + C4[1] * yz * (3 * xx - yy) * sh[..., 17] + + C4[2] * xy * (7 * zz - 1) * sh[..., 18] + + C4[3] * yz * (7 * zz - 3) * sh[..., 19] + + C4[4] * (zz * (35 * zz - 30) + 3) * sh[..., 20] + + C4[5] * xz * (7 * zz - 3) * sh[..., 21] + + C4[6] * (xx - yy) * (7 * zz - 1) * sh[..., 22] + + C4[7] * xz * (xx - 3 * yy) * sh[..., 23] + + C4[8] * (xx * (xx - 3 * yy) - yy * (3 * xx - yy)) * sh[..., 24]) + return result + +def RGB2SH(rgb): + return (rgb - 0.5) / C0 + +def SH2RGB(sh): + return sh * C0 + 0.5 \ No newline at end of file diff --git a/submodules/gaussian-splatting/utils/system_utils.py b/submodules/gaussian-splatting/utils/system_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..90ca6d7f77610c967affe313398777cd86920e8e --- /dev/null +++ b/submodules/gaussian-splatting/utils/system_utils.py @@ -0,0 +1,28 @@ +# +# Copyright (C) 2023, Inria +# GRAPHDECO research group, https://team.inria.fr/graphdeco +# All rights reserved. +# +# This software is free for non-commercial, research and evaluation use +# under the terms of the LICENSE.md file. +# +# For inquiries contact george.drettakis@inria.fr +# + +from errno import EEXIST +from os import makedirs, path +import os + +def mkdir_p(folder_path): + # Creates a directory. equivalent to using mkdir -p on the command line + try: + makedirs(folder_path) + except OSError as exc: # Python >2.5 + if exc.errno == EEXIST and path.isdir(folder_path): + pass + else: + raise + +def searchForMaxIteration(folder): + saved_iters = [int(fname.split("_")[-1]) for fname in os.listdir(folder)] + return max(saved_iters) diff --git a/wheels/diff_gaussian_rasterization-0.0.0-cp310-cp310-linux_x86_64.whl b/wheels/diff_gaussian_rasterization-0.0.0-cp310-cp310-linux_x86_64.whl new file mode 100644 index 0000000000000000000000000000000000000000..a36030d44330fa7c279fe4d69aa5655475f84946 --- /dev/null +++ b/wheels/diff_gaussian_rasterization-0.0.0-cp310-cp310-linux_x86_64.whl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:49f729c2d9b5ec0bea094ceb99e80ba846b35966da59f670b3e72de10060c332 +size 676206 diff --git a/wheels/simple_knn-0.0.0-cp310-cp310-linux_x86_64.whl b/wheels/simple_knn-0.0.0-cp310-cp310-linux_x86_64.whl new file mode 100644 index 0000000000000000000000000000000000000000..e23e12178d2d66407d719cc829ea4140d24c24ed --- /dev/null +++ b/wheels/simple_knn-0.0.0-cp310-cp310-linux_x86_64.whl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b518d182526675f5ed0d5335b2abfabc5832baefa783d477cca2868c5ec9f37e +size 569607