/[VRac]/Screen.pm
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /Screen.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 106 - (show annotations)
Fri Aug 3 08:44:45 2007 UTC (16 years, 8 months ago) by dpavlin
Original Path: M6502/Screen.pm
File size: 6418 byte(s)
disable video memory rendering on each access and enable frame-by-frame
rendering resulting in *massive* speed improvement and allmost usable
scrolling. Downside is: screen is now flipped :-)
1 package Screen;
2
3 # Dobrica Pavlinusic, <dpavlin@rot13.org> 07/30/07 17:58:55 CEST
4
5 use strict;
6 use warnings;
7
8 use SDL::App;
9 use SDL::Rect;
10 use SDL::Color;
11 use SDL::Constants;
12
13 use Carp qw/confess/;
14 use Data::Dump qw/dump/;
15 use M6502 qw'@mem';
16
17 use base qw(Class::Accessor Prefs);
18 __PACKAGE__->mk_accessors(qw(app event));
19
20 =head1 NAME
21
22 Screen - simulated 256*256 pixels monochrome screen using SDL
23
24 =head2 open_screen
25
26 Open simulated screen
27
28 =cut
29
30 our $app;
31
32 sub open_screen {
33 my $self = shift;
34
35 $self->prefs;
36
37 if ( ! $self->scale ) {
38 $self->scale( 1 );
39 warn "using default unscaled display\n";
40 }
41
42 $app = SDL::App->new(
43 -width => 256 * $self->scale + ( $self->show_mem ? 256 : 0 ),
44 -height => 256 * $self->scale,
45 -depth => 16,
46 );
47 #$app->grab_input( SDL_GRAB_QUERY );
48 $app->grab_input( SDL_GRAB_OFF );
49
50 $self->app( $app );
51
52 my $event = SDL::Event->new();
53 $self->event( $event );
54
55 warn "# created SDL::App\n";
56 }
57
58 my $white = SDL::Color->new( -r => 0xff, -g => 0xff, -b => 0xff );
59 my $black = SDL::Color->new( -r => 0x80, -g => 0x80, -b => 0x80 );
60
61 my $red = SDL::Color->new( -r => 0xff, -g => 0x00, -b => 0x00 );
62 my $green = SDL::Color->new( -r => 0x00, -g => 0xff, -b => 0x00 );
63 my $blue = SDL::Color->new( -r => 0x00, -g => 0x00, -b => 0xff );
64
65 my $rect_screen = SDL::Rect->new( -x => 0, -y => 0, -width => 256, -height => 256 );
66 my $rect_mem = SDL::Rect->new( -x => 256, -y => 0, -width => 256, -height => 256 );
67
68 =head2 p
69
70 $screen->p( $x, $y, 1 );
71
72 =cut
73
74 sub p {
75 my $self = shift;
76
77 my ($x,$y,$w) = (@_);
78
79 warn "p($x,$y,$w)\n" if $self->debug;
80
81 my $scale = $self->scale;
82 my $rect = SDL::Rect->new(
83 -height => $scale,
84 -width => $scale,
85 -x => $x * $scale,
86 -y => $y * $scale,
87 );
88
89 $app->fill( $rect, $w ? $white : $black );
90 $app->update( $rect );
91 }
92
93 =head2 mem_xy
94
95 Helper to return x and y coordinates in memory map
96
97 my ( $x,$y ) = $screen->mem_xy( $address );
98
99 =cut
100
101 sub mem_xy {
102 my $self = shift;
103 my $offset = shift;
104 my $x = $offset & 0xff;
105 $x += 256 * $self->scale;
106 my $y = $offset >> 8;
107 return ($x,$y);
108 }
109
110 =head2 vram
111
112 Push byte to video memory and draw it
113
114 $screen->vram( $offset, $byte );
115
116 =cut
117
118 my $_vram_counter;
119
120 sub vram {
121
122 return;
123
124 my ( $self, $offset, $byte ) = @_;
125 my $x = ( $offset % 32 ) << 3;
126 my $y = $offset >> 5;
127 my $mask = 1;
128 my $scale = $self->scale;
129
130 printf "## vram %04x %02x*%02x %02x\n", $offset, $x, $y, $byte if $self->trace;
131
132 foreach ( 0 .. 7 ) {
133 my $on = $byte & $mask;
134 if ( $scale == 1 ) {
135 $app->pixel( $x + $_, $y, $on ? $white : $black );
136 } else {
137 $self->p($x + $_, $y, $on );
138 }
139 $mask = $mask << 1;
140 }
141
142 $app->sync if ( $_vram_counter++ % 10 == 0 );
143 }
144
145 =head2 mmap_pixel
146
147 Draw pixel in memory map
148
149 $self->mmap_pixel( $addr, $r, $g, $b );
150
151 =cut
152
153 # keep accesses to memory
154 my $_mem_stat;
155
156 sub mmap_pixel {
157 my ( $self, $addr, $r, $g, $b ) = @_;
158 return unless $self->show_mem && $self->app;
159
160 my ( $x, $y ) = $self->mem_xy( $addr );
161 warn sprintf "## mem %04x %02x %02x %02d*%02d\n", $addr, $r, $g, $x, $y if $self->debug;
162
163 my $col = SDL::Color->new( -r => $r, -g => $g, -b => $b );
164 $self->app->pixel( $x, $y, $col );
165
166 $_mem_stat++;
167 if ( $_mem_stat % 1000 == 0 ) {
168 $self->app->sync;
169 }
170 }
171
172
173 =head2 sync
174
175 $self->sync;
176
177 =cut
178
179 sub sync {
180 $app->sync;
181 }
182
183 =head2 render
184
185 Render one frame of video ram
186
187 $self->render( @video_memory );
188
189 =cut
190
191 sub render {
192 my $self = shift;
193
194 return unless $self->booted;
195
196 die "this function isn't supported if scale isn't 1" unless $self->scale == 1;
197
198 confess "no data?" unless (@_);
199 confess "screen size not 256*256/8 but ",($#_+1) unless (($#_+1) == (256*256/8));
200
201 my $pixels = pack("C*", @_);
202
203 my $vram = SDL::Surface->new(
204 -width => 256,
205 -height => 256,
206 -depth => 1, # 1 bit per pixel
207 -pitch => 32, # bytes per line
208 -from => $pixels,
209 );
210 $vram->set_colors( 0, $black, $white, $red );
211 $vram->display_format;
212
213 my $rect = SDL::Rect->new( -x => 0, -y => 0, -width => 256, -height => 256 );
214 $vram->blit( $rect, $app, $rect_screen );
215
216 $app->sync;
217 }
218
219 =head2 render_mem
220
221 $self->render_mem( @ram );
222
223 =cut
224
225 sub render_mem {
226 my $self = shift;
227
228 return unless $self->show_mem;
229
230 my $pixels = pack("C*", @_);
231
232 my $vram = SDL::Surface->new(
233 -width => 256,
234 -height => 256,
235 -depth => 8, # 1 bit per pixel
236 -pitch => 256, # bytes per line
237 -from => $pixels,
238 -Rmask => 0xffff00ff,
239 -Gmask => 0xffff00ff,
240 -Bmask => 0xffff00ff,
241 );
242
243 $vram->display_format;
244
245 my $rect = SDL::Rect->new( -x => 0, -y => 0, -width => 256, -height => 256 );
246 $vram->blit( $rect, $app, $rect_mem );
247
248 $app->sync;
249 }
250
251 =head2 key_pressed
252
253 Check SDL event loop if there are any pending keys
254
255 my $key = $self->key_pressed;
256
257 if ( $self->key_pressed( 1 ) ) {
258 # just to check other events, don't process
259 # key
260 }
261
262 =cut
263
264 my $pending_key;
265 my $run_for = 2000;
266
267 my $key_down;
268
269 sub key_down {
270 my $self = shift;
271 my $key = shift;
272 warn "key_down($key) = ",$key_down->{$key}, "\n" if $self->debug;
273 return $key_down->{$key};
274 }
275
276 sub key_pressed {
277 my $self = shift;
278
279 # don't take key, just pull event
280 my $just_checking = shift || 0;
281
282 my $event = $self->event || confess "no event?";
283
284 $event->poll || return $pending_key;
285
286 my $type = $event->type();
287
288 exit if ($type == SDL_QUIT);
289
290 my $k = $pending_key;
291
292 if ($type == SDL_KEYDOWN) {
293 $k = $event->key_name();
294 $key_down->{$k}++;
295 if ( $k eq 'escape' ) {
296 $run_for = $self->cli;
297 warn "will check event loop every $run_for cycles\n";
298 $pending_key = '~';
299 } else {
300 warn "SDL_KEYDOWN ($type) = '$k'", $just_checking ? ' fake' : '', "\n";
301 $pending_key = $k;
302 }
303 } elsif ( $type == SDL_KEYUP ) {
304 my $up = $event->key_name();
305 $key_down->{$up} = 0;
306 warn "SDL_KEYUP ($type) = '$up'", $just_checking ? ' fake' : '', "\n";
307 undef $pending_key;
308 }
309
310 warn "key_pressed = $pending_key\n" if $pending_key;
311
312 return $pending_key;
313 }
314
315 =head2 loop
316
317 Implement SDL event loop
318
319 =cut
320
321 sub loop {
322 my $self = shift;
323 my $event = SDL::Event->new();
324
325
326 MAIN_LOOP:
327 while ( 1 ) {
328 $self->key_pressed( 1 );
329 M6502::exec($run_for);
330 $self->render( @mem[ 0x6000 .. 0x7fff ] );
331 }
332 }
333
334 =head1 SEE ALSO
335
336 L<Orao> is sample implementation using this module
337
338 =head1 AUTHOR
339
340 Dobrica Pavlinusic, C<< <dpavlin@rot13.org> >>
341
342 =head1 COPYRIGHT & LICENSE
343
344 Copyright 2007 Dobrica Pavlinusic, All Rights Reserved.
345
346 This program is free software; you can redistribute it and/or modify it
347 under the same terms as Perl itself.
348
349 =cut
350 1;

  ViewVC Help
Powered by ViewVC 1.1.26