diff --git a/src/utils/viewer/ProggyClean.ttf b/data/fonts/ProggyClean.ttf similarity index 100% rename from src/utils/viewer/ProggyClean.ttf rename to data/fonts/ProggyClean.ttf diff --git a/data/fonts/README.txt b/data/fonts/README.txt new file mode 100644 index 0000000000..f43c8e7843 --- /dev/null +++ b/data/fonts/README.txt @@ -0,0 +1,100 @@ +---------------------------------------------------------------------- + habitat-sim/data/fonts/README.txt + This is the Readme dedicated to fonts.Right now just credits + Tristan Grimmer for 'ProggyClean.ttf'and gives and example + of how to use it in python with Magnum +---------------------------------------------------------------------- + +--------------------------------------- + CREDITS/LICENSES FOR FONTS INCLUDED IN THIS FOLDER +--------------------------------------- + +ProggyClean.ttf + + Copyright (c) 2004, 2005 Tristan Grimmer + MIT License + recommended loading setting: Size = 13.0, DisplayOffset.Y = +1 + http://www.proggyfonts.net/ + +--------------------------------------- +FONTS PYTHON EXAMPLE WITH MAGNUM +--------------------------------------- +import string +import magnum as mn +from magnum import shaders, text + +. +. +. + +DISPLAY_FONT_SIZE = 16.0 +viewport_size: mn.Vector2i = mn.gl.default_framebuffer.viewport.size() + +# how much to displace window text relative to the center of the +# app window +TEXT_DELTA_FROM_CENTER = 0.5 + +# the maximum number of chars displayable in the app window +# using the magnum text module. +MAX_DISPLAY_TEXT_CHARS = 256 + +# Load a TrueTypeFont plugin and open the font file +display_font = text.FontManager().load_and_instantiate("TrueTypeFont") +relative_path_to_font = "../data/fonts/ProggyClean.ttf" +display_font.open_file( + os.path.join(os.path.dirname(__file__), relative_path_to_font), + 13, +) + +# Glyphs we need to render everything +glyph_cache = text.GlyphCache(mn.Vector2i(256)) +display_font.fill_glyph_cache( + glyph_cache, + string.ascii_lowercase + + string.ascii_uppercase + + string.digits + + ":-_+,.! %µ", +) + +# magnum text object that displays CPU/GPU usage data in the app window +window_text = text.Renderer2D( + display_font, + glyph_cache, + DISPLAY_FONT_SIZE, + text.Alignment.TOP_LEFT, +) +window_text.reserve(MAX_DISPLAY_TEXT_CHARS) + +# text object transform in window space is Projection matrix times Translation Matrix +window_text_transform = mn.Matrix3.projection( + mn.Vector2(viewport_size) +) @ mn.Matrix3.translation( + mn.Vector2( + viewport_size[0] + * -TEXT_DELTA_FROM_CENTER, + viewport_size[1] + * TEXT_DELTA_FROM_CENTER, + ) +) +shader = shaders.VectorGL2D() + +# make magnum text background transparent +mn.gl.Renderer.enable(mn.gl.Renderer.Feature.BLENDING) +mn.gl.Renderer.set_blend_function( + mn.gl.Renderer.BlendFunction.ONE, + mn.gl.Renderer.BlendFunction.ONE_MINUS_SOURCE_ALPHA, +) +mn.gl.Renderer.set_blend_equation( + mn.gl.Renderer.BlendEquation.ADD, mn.gl.Renderer.BlendEquation.ADD +) + +# draw text +shader.bind_vector_texture(glyph_cache.texture) +shader.transformation_projection_matrix = window_text_transform +shader.color = [1.0, 1.0, 1.0] +window_text.render( + f""" +Hello World + """ +) +shader.draw(window_text.mesh) diff --git a/examples/viewer.py b/examples/viewer.py index 2facad9543..1a4d892944 100644 --- a/examples/viewer.py +++ b/examples/viewer.py @@ -5,6 +5,7 @@ import ctypes import math import os +import string import sys import time from enum import Enum @@ -15,6 +16,7 @@ import magnum as mn import numpy as np +from magnum import shaders, text from magnum.platform.glfw import Application import habitat_sim @@ -25,12 +27,31 @@ class HabitatSimInteractiveViewer(Application): + + # the maximum number of chars displayable in the app window + # using the magnum text module. These chars are used to + # display the CPU/GPU usage data + MAX_DISPLAY_TEXT_CHARS = 256 + + # how much to displace window text relative to the center of the + # app window (e.g if you want the display text in the top left of + # the app window, you will displace the text + # window width * -TEXT_DELTA_FROM_CENTER in the x axis and + # widnow height * TEXT_DELTA_FROM_CENTER in the y axis, as the text + # position defaults to the middle of the app window) + TEXT_DELTA_FROM_CENTER = 0.49 + + # font size of the magnum in-window display text that displays + # CPU and GPU usage info + DISPLAY_FONT_SIZE = 16.0 + def __init__(self, sim_settings: Dict[str, Any]) -> None: configuration = self.Configuration() configuration.title = "Habitat Sim Interactive Viewer" Application.__init__(self, configuration) self.sim_settings: Dict[str:Any] = sim_settings self.fps: float = 60.0 + # draw Bullet debug line visualizations (e.g. collision meshes) self.debug_bullet_draw = False # draw active contact point debug line visualizations @@ -73,6 +94,60 @@ def __init__(self, sim_settings: Dict[str, Any]) -> None: key.Z: "move_up", } + # Load a TrueTypeFont plugin and open the font file + self.display_font = text.FontManager().load_and_instantiate("TrueTypeFont") + relative_path_to_font = "../data/fonts/ProggyClean.ttf" + self.display_font.open_file( + os.path.join(os.path.dirname(__file__), relative_path_to_font), + 13, + ) + + # Glyphs we need to render everything + self.glyph_cache = text.GlyphCache(mn.Vector2i(256)) + self.display_font.fill_glyph_cache( + self.glyph_cache, + string.ascii_lowercase + + string.ascii_uppercase + + string.digits + + ":-_+,.! %µ", + ) + + # magnum text object that displays CPU/GPU usage data in the app window + self.window_text = text.Renderer2D( + self.display_font, + self.glyph_cache, + HabitatSimInteractiveViewer.DISPLAY_FONT_SIZE, + text.Alignment.TOP_LEFT, + ) + self.window_text.reserve(HabitatSimInteractiveViewer.MAX_DISPLAY_TEXT_CHARS) + + # text object transform in window space is Projection matrix times Translation Matrix + # put text in top left of window + self.window_text_transform = mn.Matrix3.projection( + mn.Vector2(self.viewport_size) + ) @ mn.Matrix3.translation( + mn.Vector2( + self.viewport_size[0] + * -HabitatSimInteractiveViewer.TEXT_DELTA_FROM_CENTER, + self.viewport_size[1] + * HabitatSimInteractiveViewer.TEXT_DELTA_FROM_CENTER, + ) + ) + self.shader = shaders.VectorGL2D() + + # make magnum text background transparent + mn.gl.Renderer.enable(mn.gl.Renderer.Feature.BLENDING) + mn.gl.Renderer.set_blend_function( + mn.gl.Renderer.BlendFunction.ONE, + mn.gl.Renderer.BlendFunction.ONE_MINUS_SOURCE_ALPHA, + ) + mn.gl.Renderer.set_blend_equation( + mn.gl.Renderer.BlendEquation.ADD, mn.gl.Renderer.BlendEquation.ADD + ) + + # variables that track app data and CPU/GPU usage + self.num_frames_to_track = 60 + # Cycle mouse utilities self.mouse_interaction = MouseMode.LOOK self.mouse_grabber: Optional[MouseGrabber] = None @@ -195,6 +270,9 @@ def draw_event( self.render_camera.render_target.blit_rgba_to_default() mn.gl.default_framebuffer.bind() + # draw CPU/GPU usage data and other info to the app window + self.draw_text(self.render_camera.specification()) + self.swap_buffers() Timer.next_frame() self.redraw() @@ -733,6 +811,27 @@ def exit_event(self, event: Application.ExitEvent): event.accepted = True exit(0) + def draw_text(self, sensor_spec): + self.shader.bind_vector_texture(self.glyph_cache.texture) + self.shader.transformation_projection_matrix = self.window_text_transform + self.shader.color = [1.0, 1.0, 1.0] + + sensor_type_string = str(sensor_spec.sensor_type.name) + sensor_subtype_string = str(sensor_spec.sensor_subtype.name) + if self.mouse_interaction == MouseMode.LOOK: + mouse_mode_string = "LOOK" + elif self.mouse_interaction == MouseMode.GRAB: + mouse_mode_string = "GRAB" + self.window_text.render( + f""" +{self.fps} FPS +Sensor Type: {sensor_type_string} +Sensor Subtype: {sensor_subtype_string} +Mouse Interaction Mode: {mouse_mode_string} + """ + ) + self.shader.draw(self.window_text.mesh) + def print_help_text(self) -> None: """ Print the Key Command help text. @@ -916,16 +1015,16 @@ def next_frame() -> None: # optional arguments parser.add_argument( "--scene", - default="NONE", + default="./data/test_assets/scenes/simple_room.glb", type=str, - help='scene/stage file to load (default: "NONE")', + help='scene/stage file to load (default: "./data/test_assets/scenes/simple_room.glb")', ) parser.add_argument( "--dataset", - default="default", + default="./data/objects/ycb/ycb.scene_dataset_config.json", type=str, metavar="DATASET", - help="dataset configuration file to use (default: default)", + help='dataset configuration file to use (default: "./data/objects/ycb/ycb.scene_dataset_config.json")', ) parser.add_argument( "--disable_physics", @@ -947,4 +1046,5 @@ def next_frame() -> None: sim_settings["enable_physics"] = not args.disable_physics sim_settings["stage_requires_lighting"] = args.stage_requires_lighting + # start the application HabitatSimInteractiveViewer(sim_settings).exec() diff --git a/src/utils/viewer/resources.conf b/src/utils/viewer/resources.conf index 258868ccad..e2a46f74a5 100644 --- a/src/utils/viewer/resources.conf +++ b/src/utils/viewer/resources.conf @@ -1,4 +1,5 @@ group=fonts [file] -filename=ProggyClean.ttf +filename=../../../data/fonts/ProggyClean.ttf +alias=ProggyClean.ttf diff --git a/src_python/habitat_sim/utils/settings.py b/src_python/habitat_sim/utils/settings.py index b1b1301270..3fa4b16f3d 100644 --- a/src_python/habitat_sim/utils/settings.py +++ b/src_python/habitat_sim/utils/settings.py @@ -13,12 +13,12 @@ "default_agent": 0, "sensor_height": 1.5, "hfov": 90, - "color_sensor": True, # RGB sensor (default: ON) - "semantic_sensor": False, # semantic sensor (default: OFF) - "depth_sensor": False, # depth sensor (default: OFF) - "ortho_rgba_sensor": False, # Orthographic RGB sensor (default: OFF) - "ortho_depth_sensor": False, # Orthographic depth sensor (default: OFF) - "ortho_semantic_sensor": False, # Orthographic semantic sensor (default: OFF) + "color_sensor": True, + "semantic_sensor": False, + "depth_sensor": False, + "ortho_rgba_sensor": False, + "ortho_depth_sensor": False, + "ortho_semantic_sensor": False, "fisheye_rgba_sensor": False, "fisheye_depth_sensor": False, "fisheye_semantic_sensor": False,