Skip to content

Latest commit

 

History

History
295 lines (184 loc) · 6.3 KB

window.md

File metadata and controls

295 lines (184 loc) · 6.3 KB

Window and renderer

Introduction

Rationale

The idea is to provide a window class that can handle events (window management, input devices) and provide either a simple renderer (see below) or a context for another graphics library in a portable way.

Prior art

Libraries with the same purpose (and more):

Events

Rationale

Events are generated by the operating system and are catched by the application. In the meantime, they are put in an event queue, waiting to be processed. Generally, this queue can be accessed in two ways: polling an event in the queue (non-blocking), waiting for an event in the queue (blocking).

There can be many event types. For now, we only consider basic window events, keyboard/mouse events. So no controller, no touch events.

Generally, all event structures are put in a tagged union. For this proposal, we use std::variant (C++17).

See also:

Synopsis

enum class keyboard_keycode {
  // see http://wiki.libsdl.org/SDL_Scancode
};

enum class keyboard_scancode {
  // see http://wiki.libsdl.org/SDL_Keycode
};

enum class keyboard_modifiers { // BitmakType
  none      = /* unspecfied */,
  alt       = /* unspecfied */,
  control   = /* unspecfied */,
  shift     = /* unspecfied */,
  super     = /* unspecfied */,
};

enum class mouse_button {
  left,
  middle,
  right,
  x1,
  x2,
  other,
};

namespace window_events {

  struct resized {
    vec2i size;
  };

  struct closed {

  };

  struct focus_gained {

  };

  struct focus_lost {

  };

  struct keyboard_event_data {
    keyboard_keycode keycode;
    keyboard_scancode scancode;
    keyboard_modifiers modifiers;
  };

  struct keyboard_key_pressed : keyboard_event_data {

  };

  struct keyboard_key_repeated : keyboard_event_data {

  };

  struct keyboard_key_released : keyboard_event_data {

  };

  struct mouse_button_data {
    mouse_button button;
    vec2i position;
  };

  struct mouse_button_pressed : mouse_button_data {

  };

  struct mouse_button_released : mouse_button_data {

  };

  struct mouse_moved {
    vec2i position;
  };

  struct mouse_wheel_scrolled {
    vec2i offset;
  };

  struct mouse_entered {

  };

  struct mouse_left {

  };

}

using window_event = std::variant<
  window_events::resized,
  window_events::closed,
  window_events::focus_gained,
  window_events::focus_lost,
  window_events::keyboard_key_pressed,
  window_events::keyboard_key_repeated,
  window_events::keyboard_key_released,
  window_events::mouse_button_pressed,
  window_events::mouse_button_released,
  window_events::mouse_moved,
  window_events::mouse_wheel_scrolled,
  window_events::mouse_entered,
  window_events::mouse_left
>;

Window

Rationale

A window is provided by the operating system and can handle events. It can also create a renderer. A window is created with a title, a size and some properties (resizable, visible, decorated) that can be changed later.

The close() method indicates that the user intends to close the window. The real shutdown of the window happens in the destructor. This is done to simplify the window lifetime which is the same as the object lifetime.

Event handling uses std::optional<window_event>. A std::nullopt value indicates that no event is available.

See also:

Synopsis

enum class window_flags { // BitmakType
  none        = /* unspecfied */,
  resizable   = /* unspecfied */,
  visible     = /* unspecfied */,
  decorated   = /* unspecfied */,
  fullscreen  = /* unspecfied */,
};

inline constexpr window_flags default_window_flags = /* unspecfied */;

class window {
public:
  window(std::string_view title, vec2i size, window_flags hints = default_window_flags);

  ~window();

  window(const window&) = delete;

  window& operator=(const window&) = delete;

  window(window&& other);

  window& operator=(window&& other);

  // lifetime

  bool is_open() const;

  void close();

  // properties

  std::string_view get_title() const;

  void set_title(std::string_view title);

  vec2i get_position() const;

  void set_position(vec2i position);

  vec2i get_size() const;

  void set_size(vec2i size);

  window_flags get_flags() const;

  void set_resizable(bool resizable = true);

  void set_visible(bool visible = true);

  void set_decorated(bool decorated = true);

  void set_fullscreen(bool fullscreen = true);

  // state

  bool is_minimized() const;

  void minimize();

  bool is_maximized() const;

  void mazimize();

  void restore();

  // events

  std::optional<window_event> poll_event();

  std::optional<window_event> wait_event();

  // renderer

  renderer get_renderer();
};

Renderer

Rationale

The idea is to provide a very simple renderer. Simple means that you can only draw:

  • rectangles (filled or not)
  • circles (filled or not)

With a std::span type, it would be easy to also handle:

  • list of rectangles
  • list of circles
  • list of points to draw a line

No special types are provided for rectangles and circles.

The renderer makes a difference between a position on the screen (vec2i in pixels) and coordinates in the world (vec2f in arbitrary dimensions). To translate from coordinates to position, a view is defined by the center of the view and the size of the view that should be displayed on the screen.

See also:

Synopsis

class renderer {
public:
  ~renderer();

  vec2i get_size();

  void set_view_center(vec2f center);
  vec2f get_view_center() const;

  void set_view_size(vec2f size);
  vec2f get_view_size() const;

  vec2f get_coords_from_position(vec2i position);

  void clear(color4f color);

  void fill_rectangle(vec2f coords, vec2f size, color4f color);
  void draw_rectangle(vec2f coords, vec2f size, color4f color);

  void fill_circle(vec2f center, float radius, color4f color);
  void draw_circle(vec2f center, float radius, color4f color);

  void display();

private:
  renderer(/* implementation defined */);
};