Module: Rugl::Util

Defined in:
lib/rugl/util.rb

Constant Summary collapse

FALLBACK_GL_CONST =
{
  NO_ERROR: 0,
  COLOR_BUFFER_BIT: 0x4000,
  DEPTH_BUFFER_BIT: 0x0100,
  STENCIL_BUFFER_BIT: 0x0400,
  RGBA: 0x1908,
  UNSIGNED_BYTE: 0x1401,
  FLOAT: 0x1406,
  UNSIGNED_SHORT: 0x1403,
  UNSIGNED_INT: 0x1405,
  ARRAY_BUFFER: 0x8892,
  ELEMENT_ARRAY_BUFFER: 0x8893,
  STATIC_DRAW: 0x88E4,
  DYNAMIC_DRAW: 0x88E8,
  STREAM_DRAW: 0x88E0,
  TRIANGLES: 0x0004,
  LINES: 0x0001,
  POINTS: 0x0000,
  LINE_STRIP: 0x0003,
  TRIANGLE_STRIP: 0x0005,
  TRIANGLE_FAN: 0x0006,
  TEXTURE_2D: 0x0DE1,
  TEXTURE_MIN_FILTER: 0x2801,
  TEXTURE_MAG_FILTER: 0x2800,
  TEXTURE_WRAP_S: 0x2802,
  TEXTURE_WRAP_T: 0x2803,
  NEAREST: 0x2600,
  LINEAR: 0x2601,
  NEAREST_MIPMAP_NEAREST: 0x2700,
  LINEAR_MIPMAP_NEAREST: 0x2701,
  NEAREST_MIPMAP_LINEAR: 0x2702,
  LINEAR_MIPMAP_LINEAR: 0x2703,
  REPEAT: 0x2901,
  CLAMP_TO_EDGE: 0x812F,
  MIRRORED_REPEAT: 0x8370,
  TEXTURE0: 0x84C0,
  FRAMEBUFFER: 0x8D40,
  RENDERBUFFER: 0x8D41,
  COLOR_ATTACHMENT0: 0x8CE0,
  DEPTH_ATTACHMENT: 0x8D00,
  STENCIL_ATTACHMENT: 0x8D20,
  DEPTH_STENCIL_ATTACHMENT: 0x821A,
  DEPTH_COMPONENT24: 0x81A6,
  DEPTH24_STENCIL8: 0x88F0,
  RGBA8: 0x8058,
  FRAMEBUFFER_COMPLETE: 0x8CD5,
  VERTEX_SHADER: 0x8B31,
  FRAGMENT_SHADER: 0x8B30,
  COMPILE_STATUS: 0x8B81,
  LINK_STATUS: 0x8B82,
  INFO_LOG_LENGTH: 0x8B84,
  ACTIVE_UNIFORMS: 0x8B86,
  MAX_TEXTURE_SIZE: 0x0D33,
  MAX_VIEWPORT_DIMS: 0x0D3A,
  MAX_VERTEX_ATTRIBS: 0x8869,
  VERSION: 0x1F02,
  EXTENSIONS: 0x1F03,
  NUM_EXTENSIONS: 0x821D,
  BLEND: 0x0BE2,
  DEPTH_TEST: 0x0B71,
  STENCIL_TEST: 0x0B90,
  SCISSOR_TEST: 0x0C11,
  CULL_FACE: 0x0B44,
  POLYGON_OFFSET_FILL: 0x8037,
  DITHER: 0x0BD0,
  SAMPLE_ALPHA_TO_COVERAGE: 0x809E,
  FRONT: 0x0404,
  BACK: 0x0405,
  FRONT_AND_BACK: 0x0408,
  CW: 0x0900,
  CCW: 0x0901,
  KEEP: 0x1E00,
  ZERO: 0,
  ONE: 1,
  REPLACE: 0x1E01,
  INCR: 0x1E02,
  DECR: 0x1E03,
  INVERT: 0x150A,
  INCR_WRAP: 0x8507,
  DECR_WRAP: 0x8508,
  NEVER: 0x0200,
  LESS: 0x0201,
  EQUAL: 0x0202,
  LEQUAL: 0x0203,
  GREATER: 0x0204,
  NOTEQUAL: 0x0205,
  GEQUAL: 0x0206,
  ALWAYS: 0x0207,
  FUNC_ADD: 0x8006,
  FUNC_SUBTRACT: 0x800A,
  FUNC_REVERSE_SUBTRACT: 0x800B,
  MIN: 0x8007,
  MAX: 0x8008,
  SRC_COLOR: 0x0300,
  ONE_MINUS_SRC_COLOR: 0x0301,
  DST_COLOR: 0x0306,
  ONE_MINUS_DST_COLOR: 0x0307,
  SRC_ALPHA: 0x0302,
  ONE_MINUS_SRC_ALPHA: 0x0303,
  DST_ALPHA: 0x0304,
  ONE_MINUS_DST_ALPHA: 0x0305,
  CONSTANT_COLOR: 0x8001,
  ONE_MINUS_CONSTANT_COLOR: 0x8002,
  CONSTANT_ALPHA: 0x8003,
  ONE_MINUS_CONSTANT_ALPHA: 0x8004,
  SRC_ALPHA_SATURATE: 0x0308,
  FALSE: 0,
  TRUE: 1
}.freeze
USAGE_MAP =
{
  static: :STATIC_DRAW,
  dynamic: :DYNAMIC_DRAW,
  stream: :STREAM_DRAW
}.freeze
BUFFER_TYPE_MAP =
{
  float: :FLOAT,
  uint8: :UNSIGNED_BYTE,
  uint16: :UNSIGNED_SHORT,
  uint32: :UNSIGNED_INT
}.freeze
PRIMITIVE_MAP =
{
  triangles: :TRIANGLES,
  lines: :LINES,
  points: :POINTS,
  line_strip: :LINE_STRIP,
  triangle_strip: :TRIANGLE_STRIP,
  triangle_fan: :TRIANGLE_FAN
}.freeze
TEXTURE_FILTER_MAP =
{
  nearest: :NEAREST,
  linear: :LINEAR,
  nearest_mipmap_nearest: :NEAREST_MIPMAP_NEAREST,
  linear_mipmap_nearest: :LINEAR_MIPMAP_NEAREST,
  nearest_mipmap_linear: :NEAREST_MIPMAP_LINEAR,
  linear_mipmap_linear: :LINEAR_MIPMAP_LINEAR
}.freeze
TEXTURE_WRAP_MAP =
{
  repeat: :REPEAT,
  clamp_to_edge: :CLAMP_TO_EDGE,
  mirrored_repeat: :MIRRORED_REPEAT
}.freeze
TEXTURE_FORMAT_MAP =
{
  rgba: :RGBA
}.freeze
DEPTH_FUNC_MAP =
{
  never: :NEVER,
  less: :LESS,
  equal: :EQUAL,
  lequal: :LEQUAL,
  greater: :GREATER,
  notequal: :NOTEQUAL,
  gequal: :GEQUAL,
  always: :ALWAYS
}.freeze
BLEND_EQUATION_MAP =
{
  add: :FUNC_ADD,
  subtract: :FUNC_SUBTRACT,
  reverse_subtract: :FUNC_REVERSE_SUBTRACT,
  min: :MIN,
  max: :MAX
}.freeze
BLEND_FUNC_MAP =
{
  zero: :ZERO,
  one: :ONE,
  src_color: :SRC_COLOR,
  one_minus_src_color: :ONE_MINUS_SRC_COLOR,
  dst_color: :DST_COLOR,
  one_minus_dst_color: :ONE_MINUS_DST_COLOR,
  src_alpha: :SRC_ALPHA,
  one_minus_src_alpha: :ONE_MINUS_SRC_ALPHA,
  dst_alpha: :DST_ALPHA,
  one_minus_dst_alpha: :ONE_MINUS_DST_ALPHA,
  constant_color: :CONSTANT_COLOR,
  one_minus_constant_color: :ONE_MINUS_CONSTANT_COLOR,
  constant_alpha: :CONSTANT_ALPHA,
  one_minus_constant_alpha: :ONE_MINUS_CONSTANT_ALPHA,
  src_alpha_saturate: :SRC_ALPHA_SATURATE
}.freeze
STENCIL_OP_MAP =
{
  keep: :KEEP,
  zero: :ZERO,
  replace: :REPLACE,
  incr: :INCR,
  decr: :DECR,
  invert: :INVERT,
  incr_wrap: :INCR_WRAP,
  decr_wrap: :DECR_WRAP
}.freeze
CULL_FACE_MAP =
{
  front: :FRONT,
  back: :BACK,
  front_and_back: :FRONT_AND_BACK
}.freeze
FRONT_FACE_MAP =
{
  cw: :CW,
  ccw: :CCW
}.freeze
BUFFER_TYPE_BYTE_SIZE =
{
  float: 4,
  uint8: 1,
  uint16: 2,
  uint32: 4
}.freeze

Class Method Summary collapse

Class Method Details

.check_gl_error!(gl:, debug: true, message: nil) ⇒ Object

Raises:



327
328
329
330
331
332
333
334
335
336
337
# File 'lib/rugl/util.rb', line 327

def check_gl_error!(gl:, debug: true, message: nil)
  return if !debug || gl.nil?
  return unless gl.respond_to?(:GetError) || gl.respond_to?(:get_error)

  error_code = gl_call(gl, :GetError)
  return if error_code.nil?
  return if error_code == gl_const(:NO_ERROR, gl: gl)

  prefix = message ? "#{message}: " : ""
  raise Rugl::Error, "#{prefix}OpenGL error code=#{error_code}"
end

.flatten_array(nested) ⇒ Object



224
225
226
# File 'lib/rugl/util.rb', line 224

def flatten_array(nested)
  Array(nested).flatten.map(&:to_f)
end

.flatten_int_array(nested) ⇒ Object



228
229
230
# File 'lib/rugl/util.rb', line 228

def flatten_int_array(nested)
  Array(nested).flatten.map(&:to_i)
end

.gl_call(gl, name, *args) ⇒ Object

Raises:

  • (NoMethodError)


318
319
320
321
322
323
324
325
# File 'lib/rugl/util.rb', line 318

def gl_call(gl, name, *args)
  return gl.public_send(name, *args) if gl.respond_to?(name)

  snake_name = underscore(name)
  return gl.public_send(snake_name, *args) if gl.respond_to?(snake_name)

  raise NoMethodError, "#{gl} does not respond to #{name} or #{snake_name}"
end

.gl_const(name, gl: nil) ⇒ Object



310
311
312
313
314
315
316
# File 'lib/rugl/util.rb', line 310

def gl_const(name, gl: nil)
  return gl.const_get(name) if gl && gl.const_defined?(name)

  FALLBACK_GL_CONST.fetch(name) do
    raise ArgumentError, "Unknown OpenGL constant #{name}"
  end
end

.normalize_symbol(value) ⇒ Object

Raises:

  • (ArgumentError)


303
304
305
306
307
308
# File 'lib/rugl/util.rb', line 303

def normalize_symbol(value)
  return value if value.is_a?(Symbol)
  return value.strip.downcase.to_sym if value.is_a?(String)

  raise ArgumentError, "Expected Symbol/String enum, got #{value.class}"
end

.pack_float(array) ⇒ Object



232
233
234
# File 'lib/rugl/util.rb', line 232

def pack_float(array)
  flatten_array(array).pack("f*")
end

.pack_unsigned_int(array) ⇒ Object



240
241
242
# File 'lib/rugl/util.rb', line 240

def pack_unsigned_int(array)
  flatten_int_array(array).pack("L*")
end

.pack_unsigned_short(array) ⇒ Object



236
237
238
# File 'lib/rugl/util.rb', line 236

def pack_unsigned_short(array)
  flatten_int_array(array).pack("S*")
end

.to_gl_blend_equation(value, gl: nil) ⇒ Object



272
273
274
# File 'lib/rugl/util.rb', line 272

def to_gl_blend_equation(value, gl: nil)
  to_gl_enum(value, map: BLEND_EQUATION_MAP, gl: gl)
end

.to_gl_blend_func(value, gl: nil) ⇒ Object



276
277
278
# File 'lib/rugl/util.rb', line 276

def to_gl_blend_func(value, gl: nil)
  to_gl_enum(value, map: BLEND_FUNC_MAP, gl: gl)
end

.to_gl_buffer_type(value, gl: nil) ⇒ Object



248
249
250
# File 'lib/rugl/util.rb', line 248

def to_gl_buffer_type(value, gl: nil)
  to_gl_enum(value, map: BUFFER_TYPE_MAP, gl: gl)
end

.to_gl_cull_face(value, gl: nil) ⇒ Object



284
285
286
# File 'lib/rugl/util.rb', line 284

def to_gl_cull_face(value, gl: nil)
  to_gl_enum(value, map: CULL_FACE_MAP, gl: gl)
end

.to_gl_depth_func(value, gl: nil) ⇒ Object



268
269
270
# File 'lib/rugl/util.rb', line 268

def to_gl_depth_func(value, gl: nil)
  to_gl_enum(value, map: DEPTH_FUNC_MAP, gl: gl)
end

.to_gl_enum(value, map:, gl: nil) ⇒ Object



292
293
294
295
296
297
298
299
300
301
# File 'lib/rugl/util.rb', line 292

def to_gl_enum(value, map:, gl: nil)
  return value if value.is_a?(Integer)

  key = normalize_symbol(value)
  constant_name = map.fetch(key) do
    expected = map.keys.map(&:inspect).join(", ")
    raise ArgumentError, "Unsupported enum #{value.inspect}. Expected one of #{expected}"
  end
  gl_const(constant_name, gl: gl)
end

.to_gl_front_face(value, gl: nil) ⇒ Object



288
289
290
# File 'lib/rugl/util.rb', line 288

def to_gl_front_face(value, gl: nil)
  to_gl_enum(value, map: FRONT_FACE_MAP, gl: gl)
end

.to_gl_primitive(value, gl: nil) ⇒ Object



252
253
254
# File 'lib/rugl/util.rb', line 252

def to_gl_primitive(value, gl: nil)
  to_gl_enum(value, map: PRIMITIVE_MAP, gl: gl)
end

.to_gl_stencil_op(value, gl: nil) ⇒ Object



280
281
282
# File 'lib/rugl/util.rb', line 280

def to_gl_stencil_op(value, gl: nil)
  to_gl_enum(value, map: STENCIL_OP_MAP, gl: gl)
end

.to_gl_texture_filter(value, gl: nil) ⇒ Object



256
257
258
# File 'lib/rugl/util.rb', line 256

def to_gl_texture_filter(value, gl: nil)
  to_gl_enum(value, map: TEXTURE_FILTER_MAP, gl: gl)
end

.to_gl_texture_format(value, gl: nil) ⇒ Object



264
265
266
# File 'lib/rugl/util.rb', line 264

def to_gl_texture_format(value, gl: nil)
  to_gl_enum(value, map: TEXTURE_FORMAT_MAP, gl: gl)
end

.to_gl_texture_wrap(value, gl: nil) ⇒ Object



260
261
262
# File 'lib/rugl/util.rb', line 260

def to_gl_texture_wrap(value, gl: nil)
  to_gl_enum(value, map: TEXTURE_WRAP_MAP, gl: gl)
end

.to_gl_usage(value, gl: nil) ⇒ Object



244
245
246
# File 'lib/rugl/util.rb', line 244

def to_gl_usage(value, gl: nil)
  to_gl_enum(value, map: USAGE_MAP, gl: gl)
end

.underscore(name) ⇒ Object



339
340
341
342
343
344
345
# File 'lib/rugl/util.rb', line 339

def underscore(name)
  name
    .to_s
    .gsub(/([a-z\d])([A-Z])/, '\\1_\\2')
    .downcase
    .to_sym
end