retrograph 0.5 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +21 -3
- data/Rakefile +1 -1
- data/ext/retrograph/retrograph.c +28 -30
- data/spec/retrograph_spec.rb +7 -1
- data/src/retrograph.c +69 -16
- data/src/retrograph.h +3 -0
- metadata +2 -2
data/README
CHANGED
@@ -6,8 +6,22 @@ console. It is similar in capability to the Sega Master
|
|
6
6
|
System's VDP, with some additional features and direct
|
7
7
|
support for text modes.
|
8
8
|
|
9
|
-
Retrograph
|
10
|
-
|
9
|
+
Retrograph doesn't do its own screen output but rather
|
10
|
+
works with other libraries. Currently, it supports
|
11
|
+
Ruby/SDL, but other output targets are planned for the
|
12
|
+
future.
|
13
|
+
|
14
|
+
== Where can I get it? ==
|
15
|
+
|
16
|
+
Retrograph is available via RubyGems, or via Rubyforge
|
17
|
+
downloads:
|
18
|
+
|
19
|
+
http://rubyforge.org/frs/?group_id=8410
|
20
|
+
|
21
|
+
Cursory documentation is available on the
|
22
|
+
corresponding github wiki:
|
23
|
+
|
24
|
+
http://wiki.github.com/mental/retrograph
|
11
25
|
|
12
26
|
== Feature Overview ==
|
13
27
|
|
@@ -52,12 +66,16 @@ of the display, we could write:
|
|
52
66
|
|
53
67
|
require 'retrograph/sdl'
|
54
68
|
|
69
|
+
vdu = Retrograph::VDU.new
|
70
|
+
vdu.write_byte(0x7f00, 0x03)
|
55
71
|
output = vdu.render_frame_sdl do
|
56
|
-
vdu.write_byte(0x7f00, 0x03)
|
57
72
|
vdu.wait_scanlines(Retrograph::DISPLAY_HEIGHT/2)
|
58
73
|
vdu.write_byte(0x7f00, 0x30)
|
59
74
|
end
|
60
75
|
|
76
|
+
(It is still necessary at this point to copy output to the
|
77
|
+
screen.)
|
78
|
+
|
61
79
|
== Important Notes ==
|
62
80
|
|
63
81
|
Nothing is displayed by default. To be shown, the
|
data/Rakefile
CHANGED
data/ext/retrograph/retrograph.c
CHANGED
@@ -36,10 +36,6 @@
|
|
36
36
|
#define RSTRING_PTR(str) RSTRING(str)->ptr
|
37
37
|
#endif
|
38
38
|
|
39
|
-
#define UPSCALE_FACTOR 2
|
40
|
-
#define UPSCALE_REPEAT(stmts) stmts; stmts;
|
41
|
-
#define UPSCALE_REPEAT_MINUS1(stmts) stmts;
|
42
|
-
|
43
39
|
/* First few fields of SDL_Surface */
|
44
40
|
typedef struct surface_header_tag {
|
45
41
|
uint32_t flags;
|
@@ -57,7 +53,6 @@ typedef struct rubysdl2_surface_tag {
|
|
57
53
|
typedef struct vdu_wrapper_tag {
|
58
54
|
retrograph_vdu_t vdu;
|
59
55
|
VALUE surface;
|
60
|
-
retrograph_pixel_t buffer[RETROGRAPH_DISPLAY_WIDTH];
|
61
56
|
int scanline;
|
62
57
|
} vdu_wrapper_t;
|
63
58
|
|
@@ -142,8 +137,8 @@ void alloc_sdl_surface(vdu_wrapper_t *vdu) {
|
|
142
137
|
VALUE surface;
|
143
138
|
surface = rb_funcall(cSurface, SYM2ID(CREATE_SURFACE_METHOD_NAME), 8,
|
144
139
|
INT2FIX(0), /* flags */
|
145
|
-
INT2FIX(RETROGRAPH_DISPLAY_WIDTH *
|
146
|
-
INT2FIX(RETROGRAPH_DISPLAY_HEIGHT *
|
140
|
+
INT2FIX(RETROGRAPH_DISPLAY_WIDTH * 2),
|
141
|
+
INT2FIX(RETROGRAPH_DISPLAY_HEIGHT * 2),
|
147
142
|
INT2FIX(RETROGRAPH_BITS_PER_PIXEL),
|
148
143
|
INT2FIX(RETROGRAPH_RED_MASK),
|
149
144
|
INT2FIX(RETROGRAPH_GREEN_MASK),
|
@@ -152,6 +147,19 @@ void alloc_sdl_surface(vdu_wrapper_t *vdu) {
|
|
152
147
|
vdu->surface = surface;
|
153
148
|
}
|
154
149
|
|
150
|
+
static VALUE vdu_initialize_copy(VALUE self, VALUE from) {
|
151
|
+
vdu_wrapper_t *vdu;
|
152
|
+
vdu_wrapper_t *from_vdu;
|
153
|
+
if (CLASS_OF(self) != CLASS_OF(from)) {
|
154
|
+
rb_raise(rb_eTypeError, "Mismatched class for copy");
|
155
|
+
}
|
156
|
+
Data_Get_Struct(self, vdu_wrapper_t, vdu);
|
157
|
+
Data_Get_Struct(from, vdu_wrapper_t, from_vdu);
|
158
|
+
retrograph_clone(vdu->vdu, from_vdu->vdu);
|
159
|
+
check_errors(vdu->vdu);
|
160
|
+
return Qnil;
|
161
|
+
}
|
162
|
+
|
155
163
|
static VALUE vdu_write(VALUE self, VALUE start_address_r, VALUE data_r) {
|
156
164
|
vdu_wrapper_t *vdu;
|
157
165
|
retrograph_addr_t start_address;
|
@@ -160,6 +168,7 @@ static VALUE vdu_write(VALUE self, VALUE start_address_r, VALUE data_r) {
|
|
160
168
|
start_address = (retrograph_addr_t)NUM2INT(start_address_r);
|
161
169
|
retrograph_write(vdu->vdu, start_address, RSTRING_PTR(data_r),
|
162
170
|
(size_t)RSTRING_LEN(data_r));
|
171
|
+
check_errors(vdu->vdu);
|
163
172
|
return Qnil;
|
164
173
|
}
|
165
174
|
|
@@ -171,19 +180,10 @@ static VALUE vdu_write_byte(VALUE self, VALUE start_address_r, VALUE byte_r) {
|
|
171
180
|
start_address = (retrograph_addr_t)NUM2INT(start_address_r);
|
172
181
|
byte = (uint8_t)NUM2INT(byte_r);
|
173
182
|
retrograph_write(vdu->vdu, start_address, &byte, 1);
|
183
|
+
check_errors(vdu->vdu);
|
174
184
|
return Qnil;
|
175
185
|
}
|
176
186
|
|
177
|
-
static inline copy_upscale(uint8_t *output, uint8_t const * input, size_t count) {
|
178
|
-
for (; count; count--) {
|
179
|
-
UPSCALE_REPEAT(
|
180
|
-
memcpy(output, input, RETROGRAPH_BYTES_PER_PIXEL);
|
181
|
-
output += RETROGRAPH_BYTES_PER_PIXEL;
|
182
|
-
)
|
183
|
-
input += RETROGRAPH_BYTES_PER_PIXEL;
|
184
|
-
}
|
185
|
-
}
|
186
|
-
|
187
187
|
static VALUE vdu_render_scanlines(VALUE self, VALUE n_scanlines_r) {
|
188
188
|
vdu_wrapper_t *vdu;
|
189
189
|
surface_header_t *surface;
|
@@ -203,21 +203,18 @@ static VALUE vdu_render_scanlines(VALUE self, VALUE n_scanlines_r) {
|
|
203
203
|
max_scanline = RETROGRAPH_DISPLAY_HEIGHT;
|
204
204
|
}
|
205
205
|
|
206
|
-
current_line = (uint8_t *)surface->pixels +
|
206
|
+
current_line = (uint8_t *)surface->pixels +
|
207
|
+
vdu->scanline * surface->pitch * 2;
|
207
208
|
for (; vdu->scanline < max_scanline; vdu->scanline++) {
|
208
209
|
uint8_t *output;
|
209
210
|
uint8_t const *input;
|
210
|
-
|
211
|
+
retrograph_render_scanline_2x(vdu->vdu, current_line,
|
212
|
+
RETROGRAPH_DISPLAY_WIDTH *
|
213
|
+
RETROGRAPH_BYTES_PER_PIXEL * 2);
|
211
214
|
check_errors(vdu->vdu);
|
212
|
-
|
213
|
-
|
214
|
-
current_line += surface->pitch;
|
215
|
-
UPSCALE_REPEAT_MINUS1(
|
216
|
-
memcpy(current_line, current_line - surface->pitch,
|
217
|
-
RETROGRAPH_DISPLAY_WIDTH * RETROGRAPH_BYTES_PER_PIXEL *
|
218
|
-
UPSCALE_FACTOR);
|
219
|
-
current_line += surface->pitch;
|
220
|
-
)
|
215
|
+
memcpy(current_line + surface->pitch, current_line,
|
216
|
+
RETROGRAPH_DISPLAY_WIDTH * RETROGRAPH_BYTES_PER_PIXEL * 2);
|
217
|
+
current_line += surface->pitch * 2;
|
221
218
|
}
|
222
219
|
|
223
220
|
return Qnil;
|
@@ -304,9 +301,9 @@ void Init_retrograph(void) {
|
|
304
301
|
#undef DEFINE_CONSTANT
|
305
302
|
|
306
303
|
rb_const_set(mRetrograph, rb_intern("OUTPUT_WIDTH"),
|
307
|
-
INT2FIX(RETROGRAPH_DISPLAY_WIDTH *
|
304
|
+
INT2FIX(RETROGRAPH_DISPLAY_WIDTH * 2));
|
308
305
|
rb_const_set(mRetrograph, rb_intern("OUTPUT_HEIGHT"),
|
309
|
-
INT2FIX(RETROGRAPH_DISPLAY_HEIGHT *
|
306
|
+
INT2FIX(RETROGRAPH_DISPLAY_HEIGHT * 2));
|
310
307
|
|
311
308
|
rb_global_variable(&cVDU);
|
312
309
|
cVDU = rb_define_class_under(mRetrograph, "VDU", rb_cObject);
|
@@ -316,6 +313,7 @@ void Init_retrograph(void) {
|
|
316
313
|
rb_eRuntimeError);
|
317
314
|
|
318
315
|
rb_define_alloc_func(cVDU, alloc_vdu);
|
316
|
+
rb_define_method(cVDU, "initialize_copy", vdu_initialize_copy, 1);
|
319
317
|
rb_define_method(cVDU, "write", vdu_write, 2);
|
320
318
|
rb_define_method(cVDU, "write_byte", vdu_write_byte, 2);
|
321
319
|
rb_define_method(cVDU, "wait_scanlines", vdu_render_scanlines, 1);
|
data/spec/retrograph_spec.rb
CHANGED
@@ -82,7 +82,7 @@ module ImageTests
|
|
82
82
|
SDL::Surface.blit(raw_image, 0, 0, 0, 0, reference_image, 0, 0)
|
83
83
|
raw_image = nil
|
84
84
|
if output_image.pixels != reference_image.pixels
|
85
|
-
raise "Output does not match."
|
85
|
+
raise "Output file #{output_file} does not match."
|
86
86
|
end
|
87
87
|
end
|
88
88
|
end
|
@@ -114,6 +114,12 @@ describe Retrograph::VDU do
|
|
114
114
|
@vdu.write_byte(0x0001, 42)
|
115
115
|
end
|
116
116
|
|
117
|
+
it "should clone VDU state when dup-ed" do
|
118
|
+
@vdu.write_byte(0x7f00, 0x33);
|
119
|
+
vdu2 = @vdu.dup
|
120
|
+
@vdu.render_frame_sdl.pixels.should == vdu2.render_frame_sdl.pixels
|
121
|
+
end
|
122
|
+
|
117
123
|
it "should not allow nested calls to #render_frame_sdl" do
|
118
124
|
lambda {
|
119
125
|
@vdu.render_frame_sdl { @vdu.render_frame_sdl }
|
data/src/retrograph.c
CHANGED
@@ -143,6 +143,28 @@ retrograph_vdu_t retrograph_new() {
|
|
143
143
|
return vdu;
|
144
144
|
}
|
145
145
|
|
146
|
+
void retrograph_clone(retrograph_vdu_t vdu, retrograph_vdu_t from_vdu) {
|
147
|
+
if (!vdu || vdu->error) {
|
148
|
+
return;
|
149
|
+
}
|
150
|
+
if (from_vdu->error) {
|
151
|
+
/* XXX is this desirable? */
|
152
|
+
vdu->error = from_vdu->error;
|
153
|
+
return;
|
154
|
+
}
|
155
|
+
memcpy(vdu->vram, from_vdu->vram, sizeof(vdu->vram));
|
156
|
+
memcpy(vdu->sprites, from_vdu->sprites, sizeof(vdu->sprites));
|
157
|
+
memcpy(vdu->palette, from_vdu->palette, sizeof(vdu->palette));
|
158
|
+
vdu->enable_bg = from_vdu->enable_bg;
|
159
|
+
vdu->enable_sprites = from_vdu->enable_sprites;
|
160
|
+
vdu->mode = from_vdu->mode;
|
161
|
+
vdu->text_pattern_base = from_vdu->text_pattern_base;
|
162
|
+
vdu->bg_pattern_base = from_vdu->bg_pattern_base;
|
163
|
+
vdu->name_base = from_vdu->name_base;
|
164
|
+
vdu->bg_scroll_x = from_vdu->bg_scroll_x;
|
165
|
+
vdu->bg_scroll_y = from_vdu->bg_scroll_y;
|
166
|
+
}
|
167
|
+
|
146
168
|
void retrograph_ref(retrograph_vdu_t vdu) {
|
147
169
|
if (vdu && !is_singleton_vdu(vdu)) {
|
148
170
|
vdu->refcount++;
|
@@ -574,7 +596,8 @@ static void render_line_graphics_b(retrograph_pixel_t *out_buffer, uint8_t const
|
|
574
596
|
}
|
575
597
|
}
|
576
598
|
|
577
|
-
static void render_line(retrograph_vdu_t vdu, unsigned scanline,
|
599
|
+
static void render_line(retrograph_vdu_t vdu, unsigned scanline,
|
600
|
+
retrograph_pixel_t *row_buffer)
|
578
601
|
{
|
579
602
|
uint8_t const *name_row;
|
580
603
|
uint8_t bg_x_coarse;
|
@@ -618,8 +641,6 @@ static void render_line(retrograph_vdu_t vdu, unsigned scanline, uint8_t *dest)
|
|
618
641
|
bg_y_fine = (uint8_t)(bg_y % 8);
|
619
642
|
}
|
620
643
|
|
621
|
-
update_palette_cache(vdu);
|
622
|
-
|
623
644
|
switch (vdu->mode) {
|
624
645
|
case TEXT_A:
|
625
646
|
/* stride is 40 2-byte cells */
|
@@ -630,25 +651,25 @@ static void render_line(retrograph_vdu_t vdu, unsigned scanline, uint8_t *dest)
|
|
630
651
|
name_row = vdu->vram + vdu->name_base + bg_y_coarse * (32 * 2);
|
631
652
|
}
|
632
653
|
|
633
|
-
clear_row_buffer(
|
654
|
+
clear_row_buffer(row_buffer, vdu->palette_cache[0]);
|
634
655
|
switch (vdu->mode) {
|
635
656
|
case TEXT_A:
|
636
657
|
/* 12px padding above and below display */
|
637
658
|
if (scanline >= 12 ||
|
638
659
|
scanline < RETROGRAPH_DISPLAY_HEIGHT - 12)
|
639
660
|
{
|
640
|
-
render_line_text_a(
|
661
|
+
render_line_text_a(row_buffer, name_row, bg_y_fine,
|
641
662
|
vdu->vram + vdu->text_pattern_base,
|
642
663
|
vdu->palette_cache, vdu->enable_bg);
|
643
664
|
}
|
644
665
|
break;
|
645
666
|
case TEXT_B:
|
646
|
-
render_line_text_b(
|
667
|
+
render_line_text_b(row_buffer, name_row, bg_y_fine,
|
647
668
|
vdu->vram + vdu->text_pattern_base,
|
648
669
|
vdu->palette_cache, vdu->enable_bg);
|
649
670
|
break;
|
650
671
|
case GRAPHICS_A:
|
651
|
-
render_line_graphics_a(
|
672
|
+
render_line_graphics_a(row_buffer, name_row,
|
652
673
|
bg_x_coarse, bg_x_fine, bg_y_fine,
|
653
674
|
scanline, vdu->vram,
|
654
675
|
vdu->bg_pattern_base,
|
@@ -657,7 +678,7 @@ static void render_line(retrograph_vdu_t vdu, unsigned scanline, uint8_t *dest)
|
|
657
678
|
vdu->enable_bg, vdu->enable_sprites);
|
658
679
|
break;
|
659
680
|
case GRAPHICS_B:
|
660
|
-
render_line_graphics_b(
|
681
|
+
render_line_graphics_b(row_buffer, name_row,
|
661
682
|
bg_x_coarse, bg_x_fine, bg_y_fine,
|
662
683
|
scanline, vdu->vram,
|
663
684
|
vdu->bg_pattern_base,
|
@@ -666,7 +687,6 @@ static void render_line(retrograph_vdu_t vdu, unsigned scanline, uint8_t *dest)
|
|
666
687
|
vdu->enable_bg, vdu->enable_sprites);
|
667
688
|
break;
|
668
689
|
}
|
669
|
-
memcpy(dest, vdu->row_buffer, ROW_BYTES);
|
670
690
|
}
|
671
691
|
|
672
692
|
void retrograph_begin_frame(retrograph_vdu_t vdu) {
|
@@ -676,6 +696,30 @@ void retrograph_begin_frame(retrograph_vdu_t vdu) {
|
|
676
696
|
vdu->current_scanline = 0;
|
677
697
|
}
|
678
698
|
|
699
|
+
static void retrograph_render_scanline_inner(retrograph_vdu_t vdu,
|
700
|
+
retrograph_pixel_t *row_buffer)
|
701
|
+
{
|
702
|
+
update_palette_cache(vdu);
|
703
|
+
if (vdu->current_scanline < RETROGRAPH_DISPLAY_HEIGHT) {
|
704
|
+
render_line(vdu, vdu->current_scanline, row_buffer);
|
705
|
+
vdu->current_scanline++;
|
706
|
+
} else {
|
707
|
+
clear_row_buffer(row_buffer, vdu->palette_cache[0]);
|
708
|
+
}
|
709
|
+
}
|
710
|
+
|
711
|
+
static inline void copy_line_2x(uint8_t *output, uint8_t const *input,
|
712
|
+
size_t count)
|
713
|
+
{
|
714
|
+
for (; count; count--) {
|
715
|
+
memcpy(output, input, RETROGRAPH_BYTES_PER_PIXEL);
|
716
|
+
output += RETROGRAPH_BYTES_PER_PIXEL;
|
717
|
+
memcpy(output, input, RETROGRAPH_BYTES_PER_PIXEL);
|
718
|
+
output += RETROGRAPH_BYTES_PER_PIXEL;
|
719
|
+
input += RETROGRAPH_BYTES_PER_PIXEL;
|
720
|
+
}
|
721
|
+
}
|
722
|
+
|
679
723
|
void retrograph_render_scanline(retrograph_vdu_t vdu, void *dest,
|
680
724
|
size_t dest_size)
|
681
725
|
{
|
@@ -686,12 +730,21 @@ void retrograph_render_scanline(retrograph_vdu_t vdu, void *dest,
|
|
686
730
|
return;
|
687
731
|
}
|
688
732
|
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
733
|
+
retrograph_render_scanline_inner(vdu, vdu->row_buffer);
|
734
|
+
memcpy(dest, vdu->row_buffer, ROW_BYTES);
|
735
|
+
}
|
736
|
+
|
737
|
+
void retrograph_render_scanline_2x(retrograph_vdu_t vdu, void *dest,
|
738
|
+
size_t dest_size)
|
739
|
+
{
|
740
|
+
if (!vdu || vdu->error) {
|
741
|
+
return;
|
742
|
+
}
|
743
|
+
if (dest_size < ROW_BYTES * 2) {
|
744
|
+
return;
|
696
745
|
}
|
746
|
+
|
747
|
+
retrograph_render_scanline_inner(vdu, vdu->row_buffer);
|
748
|
+
copy_line_2x(dest, (uint8_t const *)vdu->row_buffer,
|
749
|
+
ROW_BYTES / RETROGRAPH_BYTES_PER_PIXEL);
|
697
750
|
}
|
data/src/retrograph.h
CHANGED
@@ -58,10 +58,13 @@ void retrograph_destroy(retrograph_vdu_t vdu);
|
|
58
58
|
|
59
59
|
retrograph_error_t retrograph_get_error(retrograph_vdu_t vdu);
|
60
60
|
|
61
|
+
void retrograph_clone(retrograph_vdu_t vdu, retrograph_vdu_t from_vdu);
|
61
62
|
void retrograph_write(retrograph_vdu_t vdu, retrograph_addr_t start_address,
|
62
63
|
void const *data, size_t n_bytes);
|
63
64
|
void retrograph_begin_frame(retrograph_vdu_t vdu);
|
64
65
|
void retrograph_render_scanline(retrograph_vdu_t vdu, void *dest,
|
65
66
|
size_t dest_size);
|
67
|
+
void retrograph_render_scanline_2x(retrograph_vdu_t vdu, void *dest,
|
68
|
+
size_t dest_size);
|
66
69
|
|
67
70
|
#endif
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: retrograph
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 0.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- MenTaLguY <mental@rydia.net>
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-07-
|
12
|
+
date: 2009-07-26 00:00:00 -04:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|