/[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

Annotation of /Screen.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 106 - (hide 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 dpavlin 29 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 dpavlin 75 use SDL::Constants;
12 dpavlin 29
13 dpavlin 33 use Carp qw/confess/;
14 dpavlin 75 use Data::Dump qw/dump/;
15 dpavlin 106 use M6502 qw'@mem';
16 dpavlin 33
17 dpavlin 56 use base qw(Class::Accessor Prefs);
18 dpavlin 98 __PACKAGE__->mk_accessors(qw(app event));
19 dpavlin 29
20 dpavlin 55 =head1 NAME
21    
22     Screen - simulated 256*256 pixels monochrome screen using SDL
23    
24 dpavlin 30 =head2 open_screen
25 dpavlin 29
26     Open simulated screen
27    
28     =cut
29    
30     our $app;
31    
32 dpavlin 30 sub open_screen {
33 dpavlin 29 my $self = shift;
34 dpavlin 31
35 dpavlin 56 $self->prefs;
36    
37 dpavlin 31 if ( ! $self->scale ) {
38     $self->scale( 1 );
39     warn "using default unscaled display\n";
40     }
41    
42 dpavlin 29 $app = SDL::App->new(
43     -width => 256 * $self->scale + ( $self->show_mem ? 256 : 0 ),
44     -height => 256 * $self->scale,
45     -depth => 16,
46     );
47 dpavlin 75 #$app->grab_input( SDL_GRAB_QUERY );
48     $app->grab_input( SDL_GRAB_OFF );
49 dpavlin 29
50 dpavlin 98 $self->app( $app );
51    
52     my $event = SDL::Event->new();
53     $self->event( $event );
54    
55 dpavlin 29 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 dpavlin 76 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 dpavlin 29 =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 dpavlin 37 my $_vram_counter;
119    
120 dpavlin 29 sub vram {
121 dpavlin 106
122     return;
123    
124 dpavlin 29 my ( $self, $offset, $byte ) = @_;
125     my $x = ( $offset % 32 ) << 3;
126     my $y = $offset >> 5;
127     my $mask = 1;
128 dpavlin 37 my $scale = $self->scale;
129 dpavlin 29
130 dpavlin 45 printf "## vram %04x %02x*%02x %02x\n", $offset, $x, $y, $byte if $self->trace;
131 dpavlin 29
132     foreach ( 0 .. 7 ) {
133 dpavlin 37 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 dpavlin 29 $mask = $mask << 1;
140     }
141 dpavlin 37
142     $app->sync if ( $_vram_counter++ % 10 == 0 );
143 dpavlin 29 }
144    
145 dpavlin 32 =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 dpavlin 33 return unless $self->show_mem && $self->app;
159 dpavlin 32
160 dpavlin 33 my ( $x, $y ) = $self->mem_xy( $addr );
161 dpavlin 41 warn sprintf "## mem %04x %02x %02x %02d*%02d\n", $addr, $r, $g, $x, $y if $self->debug;
162 dpavlin 32
163 dpavlin 33 my $col = SDL::Color->new( -r => $r, -g => $g, -b => $b );
164     $self->app->pixel( $x, $y, $col );
165 dpavlin 32
166     $_mem_stat++;
167     if ( $_mem_stat % 1000 == 0 ) {
168 dpavlin 33 $self->app->sync;
169 dpavlin 32 }
170     }
171    
172 dpavlin 33
173     =head2 sync
174    
175     $self->sync;
176    
177     =cut
178    
179     sub sync {
180     $app->sync;
181     }
182    
183 dpavlin 73 =head2 render
184    
185 dpavlin 76 Render one frame of video ram
186    
187 dpavlin 73 $self->render( @video_memory );
188    
189     =cut
190    
191     sub render {
192     my $self = shift;
193    
194 dpavlin 106 return unless $self->booted;
195    
196 dpavlin 73 die "this function isn't supported if scale isn't 1" unless $self->scale == 1;
197    
198 dpavlin 106 confess "no data?" unless (@_);
199     confess "screen size not 256*256/8 but ",($#_+1) unless (($#_+1) == (256*256/8));
200    
201 dpavlin 75 my $pixels = pack("C*", @_);
202 dpavlin 73
203 dpavlin 75 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 dpavlin 73
213 dpavlin 75 my $rect = SDL::Rect->new( -x => 0, -y => 0, -width => 256, -height => 256 );
214 dpavlin 76 $vram->blit( $rect, $app, $rect_screen );
215 dpavlin 73
216     $app->sync;
217     }
218    
219 dpavlin 76 =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 dpavlin 98 =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 dpavlin 103 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 dpavlin 98 sub key_pressed {
277     my $self = shift;
278    
279     # don't take key, just pull event
280 dpavlin 101 my $just_checking = shift || 0;
281 dpavlin 98
282     my $event = $self->event || confess "no event?";
283    
284 dpavlin 99 $event->poll || return $pending_key;
285 dpavlin 98
286     my $type = $event->type();
287    
288     exit if ($type == SDL_QUIT);
289    
290 dpavlin 99 my $k = $pending_key;
291 dpavlin 98
292     if ($type == SDL_KEYDOWN) {
293     $k = $event->key_name();
294 dpavlin 103 $key_down->{$k}++;
295 dpavlin 98 if ( $k eq 'escape' ) {
296     $run_for = $self->cli;
297     warn "will check event loop every $run_for cycles\n";
298 dpavlin 101 $pending_key = '~';
299 dpavlin 98 } else {
300 dpavlin 101 warn "SDL_KEYDOWN ($type) = '$k'", $just_checking ? ' fake' : '', "\n";
301     $pending_key = $k;
302 dpavlin 98 }
303     } elsif ( $type == SDL_KEYUP ) {
304     my $up = $event->key_name();
305 dpavlin 103 $key_down->{$up} = 0;
306 dpavlin 101 warn "SDL_KEYUP ($type) = '$up'", $just_checking ? ' fake' : '', "\n";
307 dpavlin 99 undef $pending_key;
308 dpavlin 98 }
309    
310 dpavlin 99 warn "key_pressed = $pending_key\n" if $pending_key;
311    
312     return $pending_key;
313 dpavlin 98 }
314    
315 dpavlin 96 =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 dpavlin 98 $self->key_pressed( 1 );
329 dpavlin 96 M6502::exec($run_for);
330 dpavlin 106 $self->render( @mem[ 0x6000 .. 0x7fff ] );
331 dpavlin 96 }
332     }
333    
334 dpavlin 55 =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 dpavlin 32 1;

  ViewVC Help
Powered by ViewVC 1.1.26