Class: Nuklear::Renderer

Inherits:
Object
  • Object
show all
Defined in:
lib/nuklear/renderer.rb,
lib/nuklear/renderer/opengl24.rb,
ext/nuklear/nkrb_renderer.c,
ext/nuklear_renderer_opengl2/nuklear_renderer_opengl2.c,
ext/nuklear_renderer_opengl4/nuklear_renderer_opengl4.c

Overview

This base class provides a pure-Ruby renderer implementation for Nuklear. Importantly, it doesn’t actually draw anything. Instead it provides a generic renderer implementation where subclasses need only override the #draw method to draw something.

In most cases, subclasses will also have to override #initialize to set up one-time state (e.g. compiling shaders), and also #render to set up per-frame state (e.g. activating shaders). In both cases, subclasses should call ‘super`.

Direct Known Subclasses

OpenGL2, OpenGL4

Defined Under Namespace

Classes: OpenGL2, OpenGL4

Constant Summary collapse

Vertex =
Fiddle::Importer.struct [
  'float position[3]',
  'float uv[3]',
  'unsigned char color[4]'
]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeRenderer

For all renderer implementations, override #initialize to set up your initial state (e.g. compiling shaders) and call ‘super`.



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/nuklear/renderer.rb', line 49

def initialize
  @commands = Nuklear::Buffer.new
  @vertices = Nuklear::Buffer.new
  @vertex_indices = Nuklear::Buffer.new
  @window_size = [640, 480]
  @drawable_size = nil
  @null_texture_handle = 0
  @convert_config = {
    vertex_layout: [
      [:position, :float,    Vertex.offsetof('position')],
      [:texcoord, :float,    Vertex.offsetof('uv')],
      [:color,    :r8g8b8a8, Vertex.offsetof('color')]
    ],
    vertex_size: Vertex.size,
    vertex_alignment: Vertex.alignment,
    null: null_texture_handle,
    circle_segment_count: 22,
    curve_segment_count: 22,
    arc_segment_count: 22,
    global_alpha: 1.0,
    shape_aa: true,
    line_aa: true
  }
end

Instance Attribute Details

#commandsObject (readonly)

Nuklear::Buffer containing command data



36
37
38
# File 'lib/nuklear/renderer.rb', line 36

def commands
  @commands
end

#contextObject (readonly)

Nuklear::Context for this renderer



39
40
41
# File 'lib/nuklear/renderer.rb', line 39

def context
  @context
end

#convert_configObject

Returns the configuration necessary for converting a Nuklear rendering pass into a renderer-specific one. This data can be changed at run-time; it is not cached.



21
22
23
# File 'lib/nuklear/renderer.rb', line 21

def convert_config
  @convert_config
end

#drawable_sizeObject



79
80
81
# File 'lib/nuklear/renderer.rb', line 79

def drawable_size
  @drawable_size || window_size
end

#null_texture_handleObject

Assign the handle for a 1x1 white texture to this accessor. It doesn’t matter what format this takes, (GL texture ID, memory address of texture data, etc), as long as the renderer can decode this into a usable result when it’s passed back to it later on.



27
28
29
# File 'lib/nuklear/renderer.rb', line 27

def null_texture_handle
  @null_texture_handle
end

#vertex_indicesObject (readonly)

Nuklear::Buffer containing vertex index data



33
34
35
# File 'lib/nuklear/renderer.rb', line 33

def vertex_indices
  @vertex_indices
end

#verticesObject (readonly)

Nuklear::Buffer containing vertex data



30
31
32
# File 'lib/nuklear/renderer.rb', line 30

def vertices
  @vertices
end

#window_sizeObject

Returns the value of attribute window_size.



15
16
17
# File 'lib/nuklear/renderer.rb', line 15

def window_size
  @window_size
end

Class Method Details

.renderer_classObject



3
4
5
6
7
8
9
10
11
# File 'lib/nuklear/renderer/opengl24.rb', line 3

def self.renderer_class
  if SDL2::GL.get_attribute(SDL2::GL::CONTEXT_MAJOR_VERSION) > 2
    require 'nuklear_renderer_opengl4'
    Nuklear::Renderer::OpenGL4
  else
    require 'nuklear_renderer_opengl2'
    Nuklear::Renderer::OpenGL2
  end
end

Instance Method Details

#draw(cmd) ⇒ Object

Called for each Nuklear draw command, numerous times per render pass. Renderers should override this method to actually draw something, but keep this method as lightweight as possible.

‘element_count`: The number of elements to be drawn. `clip_rect`: An array containing the x, y, width and height

(in that order) of the region to be drawn to.

‘texture_handle`: The handle of a texture to be drawn. See

#null_texture_handle.

‘offset`: The number of elements already drawn, not including the

current command.


103
104
105
# File 'lib/nuklear/renderer.rb', line 103

def draw(cmd)

end

#nk_convert(rcontext) ⇒ Object



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'ext/nuklear/nkrb_renderer.c', line 36

VALUE nkrb_renderer_convert(VALUE self, VALUE rcontext) {
  struct nk_context *context = NULL;
  struct nk_buffer *commands = NULL;
  struct nk_buffer *vertices = NULL;
  struct nk_buffer *indices  = NULL;
  Data_Get_Struct(rcontext, struct nk_context, context);
  Data_Get_Struct(rb_funcall(self, rb_intern("commands"), 0),       struct nk_buffer,  commands);
  Data_Get_Struct(rb_funcall(self, rb_intern("vertices"), 0),       struct nk_buffer,  vertices);
  Data_Get_Struct(rb_funcall(self, rb_intern("vertex_indices"), 0), struct nk_buffer,  indices);
  VALUE rconfig = rb_funcall(self, rb_intern("convert_config"), 0);
  VALUE rvertex_layout = rb_hash_aref(rconfig, ID2SYM(rb_intern("vertex_layout")));
  struct nk_convert_config config;
  struct nk_draw_vertex_layout_element *vertex_layout = alloca((RARRAY_LEN(rvertex_layout) + 1) * sizeof(struct nk_draw_vertex_layout_element));
  for (int i = 0; i < RARRAY_LEN(rvertex_layout); i++) {
    VALUE rlayout = RARRAY_AREF(rvertex_layout, i);
    vertex_layout[i].attribute = rb2nk_attribute(RARRAY_AREF(rlayout, 0));
    vertex_layout[i].format    = rb2nk_format(RARRAY_AREF(rlayout, 1));
    vertex_layout[i].offset    = FIX2INT(RARRAY_AREF(rlayout, 2));
  }
  vertex_layout[RARRAY_LEN(rvertex_layout)].attribute = NK_VERTEX_LAYOUT_END;
  memset(&config, 0, sizeof(config));
  config.vertex_layout = vertex_layout;
  config.vertex_size = FIX2INT(rb_hash_aref(rconfig, ID2SYM(rb_intern("vertex_size"))));
  config.vertex_alignment = FIX2INT(rb_hash_aref(rconfig, ID2SYM(rb_intern("vertex_alignment"))));
  config.null.texture = (nk_handle) (void *) NUM2ULL(rb_hash_aref(rconfig, ID2SYM(rb_intern("null"))));
  config.circle_segment_count = NUM2UINT(rb_hash_aref(rconfig, ID2SYM(rb_intern("circle_segment_count"))));
  config.curve_segment_count = NUM2UINT(rb_hash_aref(rconfig, ID2SYM(rb_intern("curve_segment_count"))));
  config.arc_segment_count = NUM2UINT(rb_hash_aref(rconfig, ID2SYM(rb_intern("arc_segment_count"))));
  config.global_alpha = (float) NUM2DBL(rb_hash_aref(rconfig, ID2SYM(rb_intern("global_alpha"))));
  config.shape_AA = RTEST(rb_hash_aref(rconfig, ID2SYM(rb_intern("shape_aa")))) ? NK_ANTI_ALIASING_ON : NK_ANTI_ALIASING_OFF;
  config.line_AA = RTEST(rb_hash_aref(rconfig, ID2SYM(rb_intern("line_aa")))) ? NK_ANTI_ALIASING_ON : NK_ANTI_ALIASING_OFF;
  // all that for this
  nk_flags result = nk_convert(context, commands, vertices, indices, &config);
  switch(result) {
    case NK_CONVERT_SUCCESS: break; // OK
    case NK_CONVERT_INVALID_PARAM: rb_raise(rb_eRuntimeError, "Nuklear error: INVALID_PARAM");
    case NK_CONVERT_COMMAND_BUFFER_FULL: rb_raise(rb_eRuntimeError, "Nuklear error: COMMAND_BUFFER_FULL");
    case NK_CONVERT_VERTEX_BUFFER_FULL: rb_raise(rb_eRuntimeError, "Nuklear error: VERTEX_BUFFER_FULL");
    case NK_CONVERT_ELEMENT_BUFFER_FULL: rb_raise(rb_eRuntimeError, "Nuklear error: ELEMENT_BUFFER_FULL");
    default: rb_raise(rb_eRuntimeError, "Nuklear error: %d (unknown)", result);
  }
  return self;
}

#nk_draw_foreach(rcontext) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'ext/nuklear/nkrb_renderer.c', line 80

VALUE nkrb_renderer_draw_foreach(VALUE self, VALUE rcontext) {
  struct nk_context *context = NULL;
  struct nk_buffer *commands = NULL;
  Data_Get_Struct(rcontext, struct nk_context, context);
  Data_Get_Struct(rb_funcall(self, rb_intern("commands"), 0), struct nk_buffer,  commands);

  /* convert from command queue into draw list and draw to screen */
  const struct nk_draw_command *cmd;
  // const nk_draw_index *offset = NULL;
  /* iterate over and execute each draw command */
  int offset = 0;
  nk_draw_foreach(cmd, context, commands) {
    if (!cmd->elem_count) continue;
    VALUE rcmd = rb_hash_new();
    VALUE rclip_rect = rb_ary_new2(4);
    rb_ary_store(rclip_rect, 0, DBL2NUM(cmd->clip_rect.x));
    rb_ary_store(rclip_rect, 1, DBL2NUM(cmd->clip_rect.y));
    rb_ary_store(rclip_rect, 2, DBL2NUM(cmd->clip_rect.w));
    rb_ary_store(rclip_rect, 3, DBL2NUM(cmd->clip_rect.h));
    rb_hash_aset(rcmd, ID2SYM(rb_intern("element_count")),  INT2NUM(cmd->elem_count));
    rb_hash_aset(rcmd, ID2SYM(rb_intern("texture_handle")), ULL2NUM((unsigned long long) cmd->texture.ptr));
    rb_hash_aset(rcmd, ID2SYM(rb_intern("clip_rect")), rclip_rect);
    rb_hash_aset(rcmd, ID2SYM(rb_intern("offset")), INT2NUM(offset));
    rb_yield(rcmd);
    offset += cmd->elem_count;
  }

  return self;
}

#render(context) ⇒ Object

Called at the start of a render pass. Renderers may wish to override this method to apply once-per-frame state updates. They should call ‘super` when they are ready to proceed.



86
87
88
89
# File 'lib/nuklear/renderer.rb', line 86

def render(context)
  nk_convert(context)
  nk_draw_foreach(context) { |command| draw(command) }
end