Class: RGame::Core::Recording

Inherits:
Object
  • Object
show all
Defined in:
lib/rgame/core/recording.rb,
ext/rgame_core/ruby/recording_ext.c

Overview

A block of drawing baked once and replayed cheaply.

ground = renderer.record do
tiles.each { |tile| renderer.image(tile.image, tile.x, tile.y) }
end

def draw
ground.draw(-camera.x, -camera.y)
end

A screen of tiles is a couple of thousand quads that have not changed since the level loaded. Baking them turns the per-frame cost from "walk every tile and transform four corners" into one call per texture — the work happens at bake time and never again.

Recordings come from Renderer#record; there is no new.

What is baked in and what is not

Positions, texture coordinates and colours are baked, and so are any transforms applied inside the block. The transform in effect when the recording is drawn is applied on top, which is what lets a baked layer scroll under a camera without being rebuilt.

Clipping is not baked — it happens when pixels are rasterised, so a clip rectangle captured in one place would be wrong everywhere else the recording is drawn. Pushing a clip inside a record block raises. Clip the replay instead:

renderer.clipped(0, 0, 400, 600) { ground.draw(0, 0) }

Constant Summary collapse

Color =
RGame::Util::Color

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.new(*args) ⇒ Object



167
168
169
170
171
172
# File 'ext/rgame_core/ruby/recording_ext.c', line 167

static VALUE recording_s_new(int argc, VALUE *argv, VALUE klass) {
    (void)argc;
    (void)argv;
    rb_raise(rb_eNoMethodError, "%" PRIsVALUE " is created by Renderer#record, not by .new",
             klass);
}

Instance Method Details

#batch_countObject



127
128
129
# File 'ext/rgame_core/ruby/recording_ext.c', line 127

static VALUE recording_batch_count(VALUE self) {
    return UINT2NUM(rgame_recording_batch_count(recording_unwrap(self)->recording));
}

#draw(x = 0, y = 0, z: 0, color: nil) ⇒ Object

Replays everything that was recorded, with the recording's origin at (x, y).

color tints what was baked: each recorded colour is multiplied by it, so white (the default) draws the recording unchanged and a colour with alpha fades the whole layer out at once.



47
48
49
# File 'lib/rgame/core/recording.rb', line 47

def draw(x = 0, y = 0, z: 0, color: nil)
  draw_at(x, y, z, Color.coerce(color).packed)
end

#draw_at(x, y, z, color) ⇒ Object



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'ext/rgame_core/ruby/recording_ext.c', line 109

static VALUE recording_draw_at(VALUE self, VALUE x, VALUE y, VALUE z, VALUE color) {
    rgame_recording_ref *ref = recording_unwrap(self);

    /* The app that owns these textures has to be the one mid-frame. Anything
     * else would append to a canvas nobody is about to submit, and draw
     * nothing at all. */
    if (!rgame_app_is_drawing(ref->app)) {
        rb_raise(rb_eRuntimeError,
                 "drawing is only allowed inside #draw (the frame is not open)");
    }

    rgame_app_draw_recording(ref->app, ref->recording, (float)NUM2DBL(x), (float)NUM2DBL(y),
                             (unsigned int)(NUM2ULONG(color) & 0xFFFFFFFFul), NUM2DBL(z));
    return self;
}

#empty?Boolean

Returns:

  • (Boolean)


135
136
137
# File 'ext/rgame_core/ruby/recording_ext.c', line 135

static VALUE recording_empty_p(VALUE self) {
    return rgame_recording_vertex_count(recording_unwrap(self)->recording) == 0 ? Qtrue : Qfalse;
}

#heightObject



147
148
149
150
151
# File 'ext/rgame_core/ruby/recording_ext.c', line 147

static VALUE recording_height(VALUE self) {
    float min_y = 0.0f, max_y = 0.0f;
    rgame_recording_bounds(recording_unwrap(self)->recording, NULL, &min_y, NULL, &max_y);
    return DBL2NUM((double)(max_y - min_y));
}

#inspectObject



153
154
155
156
157
158
159
160
161
162
163
# File 'ext/rgame_core/ruby/recording_ext.c', line 153

static VALUE recording_inspect(VALUE self) {
    rgame_recording_ref *ref;
    TypedData_Get_Struct(self, rgame_recording_ref, &recording_data_type, ref);
    if (!ref->recording) {
        return rb_sprintf("#<%" PRIsVALUE " (uninitialized)>", rb_obj_class(self));
    }

    return rb_sprintf("#<%" PRIsVALUE " %u batches, %u vertices>", rb_obj_class(self),
                      rgame_recording_batch_count(ref->recording),
                      rgame_recording_vertex_count(ref->recording));
}

#vertex_countObject



131
132
133
# File 'ext/rgame_core/ruby/recording_ext.c', line 131

static VALUE recording_vertex_count(VALUE self) {
    return UINT2NUM(rgame_recording_vertex_count(recording_unwrap(self)->recording));
}

#widthObject



141
142
143
144
145
# File 'ext/rgame_core/ruby/recording_ext.c', line 141

static VALUE recording_width(VALUE self) {
    float min_x = 0.0f, max_x = 0.0f;
    rgame_recording_bounds(recording_unwrap(self)->recording, &min_x, NULL, &max_x, NULL);
    return DBL2NUM((double)(max_x - min_x));
}