ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/DC/UI.pm
Revision: 1.37
Committed: Sun Apr 9 21:05:50 2006 UTC (18 years, 1 month ago) by root
Branch: MAIN
Changes since 1.36: +1 -1 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 elmex 1.6 package Crossfire::Client::Widget;
2 root 1.8
3 elmex 1.1 use strict;
4 root 1.18
5     use Scalar::Util;
6    
7 elmex 1.11 use SDL::OpenGL;
8     use SDL::OpenGL::Constants;
9 elmex 1.1
10     our $FOCUS; # the widget with current focus
11    
12     # class methods for events
13     sub feed_sdl_key_down_event { $FOCUS->key_down ($_[0]) if $FOCUS }
14     sub feed_sdl_key_up_event { $FOCUS->key_up ($_[0]) if $FOCUS }
15 elmex 1.32 sub feed_sdl_button_down_event { }
16     sub feed_sdl_button_up_event { }
17 elmex 1.1
18     sub new {
19     my $class = shift;
20 root 1.10
21     bless { @_ }, $class
22 elmex 1.1 }
23    
24 root 1.18 sub move {
25     my ($self, $x, $y, $z) = @_;
26     $self->{x} = $x;
27     $self->{y} = $y;
28     $self->{z} = $z if defined $z;
29     }
30    
31 elmex 1.20 sub needs_redraw {
32     0
33     }
34    
35 root 1.14 sub size_request {
36 elmex 1.36 require Carp;
37     Carp::confess "size_request is abtract";
38     }
39    
40     sub size_allocate {
41     my ($self, $w, $h) = @_;
42     $self->w ($w);
43     $self->h ($h);
44 root 1.14 }
45    
46 elmex 1.1 sub focus_in {
47     my ($widget) = @_;
48     $FOCUS = $widget;
49     }
50 root 1.4
51 elmex 1.1 sub focus_out {
52     my ($widget) = @_;
53     }
54 root 1.4
55 elmex 1.1 sub key_down {
56     my ($widget, $sdlev) = @_;
57     }
58 root 1.4
59 elmex 1.1 sub key_up {
60     my ($widget, $sdlev) = @_;
61     }
62 root 1.4
63 elmex 1.1 sub button_down {
64     my ($widget, $sdlev) = @_;
65     }
66 root 1.4
67 elmex 1.1 sub button_up {
68     my ($widget, $sdlev) = @_;
69     }
70 root 1.4
71 elmex 1.36 sub w { $_[0]->{w} = $_[1] if $_[1]; $_[0]->{w} }
72     sub h { $_[0]->{h} = $_[1] if $_[1]; $_[0]->{h} }
73 elmex 1.11 sub x { $_[0]->{x} = $_[1] if $_[1]; $_[0]->{x} }
74     sub y { $_[0]->{y} = $_[1] if $_[1]; $_[0]->{y} }
75 elmex 1.13 sub z { $_[0]->{z} = $_[1] if $_[1]; $_[0]->{z} }
76 elmex 1.11
77 elmex 1.1 sub draw {
78 elmex 1.11 my ($self) = @_;
79    
80     glPushMatrix;
81 root 1.12 glTranslate $self->{x}, $self->{y}, 0;
82 elmex 1.11 $self->_draw;
83     glPopMatrix;
84     }
85    
86     sub _draw {
87 elmex 1.1 my ($widget) = @_;
88     }
89 root 1.4
90 elmex 1.1 sub bbox {
91 elmex 1.32 my ($self) = @_;
92     my ($w, $h) = $self->size_request;
93     (
94     $self->{x},
95     $self->{y},
96     $self->{x} = $w,
97     $self->{y} = $h
98     )
99     }
100    
101     sub del_parent { $_[0]->{parent} = undef }
102    
103     sub set_parent {
104     my ($self, $par) = @_;
105    
106     $self->{parent} = $par;
107     Scalar::Util::weaken $self->{parent};
108     }
109    
110     sub get_parent {
111     $_[0]->{parent}
112     }
113    
114     sub update {
115     my ($self) = @_;
116    
117     $self->{parent}->update
118     if $self->{parent};
119 elmex 1.1 }
120 elmex 1.2
121 root 1.18 sub DESTROY {
122     my ($self) = @_;
123    
124 elmex 1.32 #$self->deactivate;
125 root 1.18 }
126    
127 root 1.35 package Crossfire::Client::Widget::Bin;
128 elmex 1.15
129     our @ISA = Crossfire::Client::Widget::;
130    
131 elmex 1.36 sub add { $_[0]->{child} = $_[1]; $_[1]->set_parent ($_[0]); $_[1]->{expand} = $_[2] }
132 elmex 1.15 sub get { $_[0]->{child} }
133 root 1.35
134 elmex 1.32 sub remove {
135     my ($self, $chld) = @_;
136     delete $self->{child}
137     if $self->{child} == $chld;
138     }
139 elmex 1.15
140 root 1.35 sub size_request {
141     $_[0]->{child}->size_request if $_[0]->{child}
142     }
143 elmex 1.36 sub size_allocate {
144     my ($self, $w, $h) = @_;
145     $self->SUPER::size_allocate ($w, $h);
146     $self->{child}->size_allocate ($w, $h)
147     if $self->{child}
148     }
149 elmex 1.15
150 root 1.35 sub _draw {
151     my ($self) = @_;
152    
153     $self->{child}->draw;
154     }
155 elmex 1.15
156 elmex 1.32 package Crossfire::Client::Widget::Toplevel;
157    
158     our @ISA = Crossfire::Client::Widget::;
159    
160     use SDL::OpenGL;
161    
162     sub add {
163     my ($self, $chld) = @_;
164    
165     push @{$self->{childs}}, $chld;
166     @{$self->{childs}} =
167     sort { $a->{z} <=> $b->{z} }
168     @{$self->{childs}};
169    
170     $chld->set_parent ($self);
171 elmex 1.36 $chld->size_allocate ($chld->size_request);
172 elmex 1.32 }
173    
174     sub remove {
175     my ($self, $chld) = @_;
176     @{$self->{childs}} =
177     sort { $a->{z} <=> $b->{z} }
178     grep { $_ && $_ != $_[0] }
179     @{$self->{childs}}
180     }
181    
182     sub update {
183     my ($self) = @_;
184     ::refresh ();
185     }
186    
187     sub _draw {
188     my ($self) = @_;
189    
190     $_->draw for @{$self->{childs}};
191     }
192    
193 elmex 1.20 package Crossfire::Client::Widget::Window;
194    
195 root 1.35 our @ISA = Crossfire::Client::Widget::Bin::;
196 elmex 1.20
197     use SDL::OpenGL;
198    
199     sub add {
200     my ($self, $chld) = @_;
201 elmex 1.36 warn "ADD $chld\n";
202 elmex 1.20 $self->SUPER::add ($chld);
203 elmex 1.32 $chld->set_parent ($self);
204     }
205    
206     sub remove {
207     my ($self) = @_;
208     # TODO FIXME: removing a child from a window will crash, see render_chld
209 elmex 1.36 # $self->update;
210 elmex 1.32 }
211    
212     sub update {
213     my ($self) = @_;
214     $self->render_chld;
215 elmex 1.20 }
216    
217     sub render_chld {
218     my ($self) = @_;
219     my $chld = $self->get;
220     my ($w, $h) = $self->size_request;
221    
222 elmex 1.36 require Carp;
223     Carp::cluck "RENDERCHI $w $h";
224     warn "RENDERCHI $w $h\n";
225 elmex 1.20 $self->{texture} =
226     Crossfire::Client::Texture->new_from_opengl (
227 root 1.23 $w, $h, sub { $chld->draw }
228 elmex 1.20 );
229     $self->{texture}->upload;
230     }
231    
232     sub size_request {
233     my ($self) = @_;
234 elmex 1.36 ($self->w, $self->h)
235     }
236    
237     sub size_allocate {
238     my ($self, $w, $h) = @_;
239    
240     $self->w ($w);
241     $self->h ($h);
242     $self->get->size_allocate ($w, $h);
243    
244     $self->update; #TODO: Move this to the size_request event propably?
245 elmex 1.20 }
246    
247     sub _draw {
248     my ($self) = @_;
249    
250 elmex 1.36 my ($w, $h) = ($self->w, $self->h);
251 root 1.29
252 elmex 1.20 my $tex = $self->{texture}
253     or return;
254    
255     glEnable GL_BLEND;
256     glEnable GL_TEXTURE_2D;
257 root 1.35 glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE;
258 elmex 1.20 glBindTexture GL_TEXTURE_2D, $tex->{name};
259    
260     glBegin GL_QUADS;
261 root 1.23 glTexCoord 0, 0; glVertex 0, 0;
262     glTexCoord 0, 1; glVertex 0, $h;
263     glTexCoord 1, 1; glVertex $w, $h;
264     glTexCoord 1, 0; glVertex $w, 0;
265 elmex 1.20 glEnd;
266    
267     glDisable GL_BLEND;
268     glDisable GL_TEXTURE_2D;
269     }
270    
271 elmex 1.15 package Crossfire::Client::Widget::Frame;
272    
273 root 1.35 our @ISA = Crossfire::Client::Widget::Bin::;
274 elmex 1.15
275     use SDL::OpenGL;
276    
277     sub size_request {
278     my ($self) = @_;
279     my $chld = $self->get
280     or return (0, 0);
281 root 1.30
282     $chld->move (2, 2);
283    
284 elmex 1.15 map { $_ + 4 } $chld->size_request;
285     }
286    
287 elmex 1.36 sub size_allocate {
288     my ($self, $w, $h) = @_;
289    
290     $self->w ($w);
291     $self->h ($h);
292    
293     $self->get->size_allocate ($w - 4, $h - 4);
294     $self->get->move (2, 2);
295     }
296    
297 elmex 1.15 sub _draw {
298     my ($self) = @_;
299    
300     my $chld = $self->get;
301    
302     my ($w, $h) = $chld->size_request;
303    
304     glBegin GL_QUADS;
305 root 1.30 glColor 0, 0, 0;
306 elmex 1.15 glTexCoord 0, 0; glVertex 0 , 0;
307     glTexCoord 0, 1; glVertex 0 , $h + 4;
308     glTexCoord 1, 1; glVertex $w + 4 , $h + 4;
309     glTexCoord 1, 0; glVertex $w + 4 , 0;
310     glEnd;
311    
312 root 1.23 $chld->draw;
313 elmex 1.15 }
314    
315 elmex 1.31 package Crossfire::Client::Widget::FancyFrame;
316    
317     our @ISA = Crossfire::Client::Widget::Frame::;
318    
319     use SDL::OpenGL;
320    
321 elmex 1.34 sub new {
322     my ($self, $theme) = @_;
323     $self = $self->SUPER::new;
324    
325     $self->{txts} = [
326     map { new_from_file Crossfire::Client::Texture Crossfire::Client::find_rcfile $_ }
327     qw/d1_bg.png d1_border_top.png d1_border_right.png d1_border_left.png d1_border_bottom.png/
328     ];
329     $self
330     }
331    
332     sub size_request {
333     my ($self) = @_;
334     my ($w, $h) = $self->get->size_request;
335    
336     $h += $self->{txts}->[1]->{height};
337     $h += $self->{txts}->[4]->{height};
338     $w += $self->{txts}->[2]->{width};
339     $w += $self->{txts}->[3]->{width};
340    
341 elmex 1.36 ($w, $h)
342     }
343    
344     sub size_allocate {
345     my ($self, $w, $h) = @_;
346    
347     $self->w ($w);
348     $self->h ($h);
349     $h -= $self->{txts}->[1]->{height};
350     $h -= $self->{txts}->[4]->{height};
351     $w -= $self->{txts}->[2]->{width};
352     $w -= $self->{txts}->[3]->{width};
353    
354     $h = $h < 0 ? 0 : $h;
355     $w = $w < 0 ? 0 : $w;
356     warn "CHILD:$w $h\n";
357     $self->get->size_allocate ($w, $h);
358 elmex 1.34 $self->get->move ($self->{txts}->[3]->{width}, $self->{txts}->[1]->{height});
359     }
360    
361     sub _draw {
362     my ($self) = @_;
363    
364 elmex 1.36 my ($w, $h) = ($self->w, $self->h);
365     my ($cw, $ch) = ($self->get->w, $self->get->h);
366 elmex 1.34
367     glEnable GL_BLEND;
368     glEnable GL_TEXTURE_2D;
369     glBlendFunc GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA;
370 elmex 1.36 glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE;
371 elmex 1.34
372     my $top = $self->{txts}->[1];
373 elmex 1.36 glBindTexture GL_TEXTURE_2D, $top->{name};
374 elmex 1.34
375 elmex 1.36 glBegin GL_QUADS;
376     glTexCoord 0, 0; glVertex 0 , 0;
377     glTexCoord 0, 1; glVertex 0 , $top->{height};
378     glTexCoord 1, 1; glVertex $w , $top->{height};
379     glTexCoord 1, 0; glVertex $w , 0;
380     glEnd;
381 elmex 1.34
382     my $left = $self->{txts}->[3];
383 elmex 1.36 glBindTexture GL_TEXTURE_2D, $left->{name};
384 elmex 1.34
385 elmex 1.36 glBegin GL_QUADS;
386     glTexCoord 0, 0; glVertex 0 , $top->{height};
387     glTexCoord 0, 1; glVertex 0 , $top->{height} + $ch;
388     glTexCoord 1, 1; glVertex $left->{width}, $top->{height} + $ch;
389     glTexCoord 1, 0; glVertex $left->{width}, $top->{height};
390     glEnd;
391 elmex 1.34
392     my $right = $self->{txts}->[2];
393 elmex 1.36 glBindTexture GL_TEXTURE_2D, $right->{name};
394 elmex 1.34
395 elmex 1.36 glBegin GL_QUADS;
396     glTexCoord 0, 0; glVertex $w - $right->{width}, $top->{height};
397     glTexCoord 0, 1; glVertex $w - $right->{width}, $top->{height} + $ch;
398     glTexCoord 1, 1; glVertex $w , $top->{height} + $ch;
399     glTexCoord 1, 0; glVertex $w , $top->{height};
400     glEnd;
401 elmex 1.34
402     my $bottom = $self->{txts}->[4];
403 elmex 1.36 glBindTexture GL_TEXTURE_2D, $bottom->{name};
404 elmex 1.34
405 elmex 1.36 glBegin GL_QUADS;
406     glTexCoord 0, 0; glVertex 0 , $h - $bottom->{height};
407     glTexCoord 0, 1; glVertex 0 , $h;
408     glTexCoord 1, 1; glVertex $w , $h;
409     glTexCoord 1, 0; glVertex $w , $h - $bottom->{height};
410     glEnd;
411 elmex 1.34
412 elmex 1.36 my $bg = $self->{txts}->[0];
413     glBindTexture GL_TEXTURE_2D, $bg->{name};
414     glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE;
415     glTexParameter GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT;
416     glTexParameter GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT;
417 elmex 1.34
418 elmex 1.36 my $rep_x = $cw / $bg->{width};
419     my $rep_y = $ch / $bg->{height};
420 elmex 1.34
421 elmex 1.36 glBegin GL_QUADS;
422     glTexCoord 0, 0; glVertex $left->{width}, $top->{height};
423     glTexCoord 0, $rep_y; glVertex $left->{width}, $top->{height} + $ch;
424     glTexCoord $rep_x, $rep_y; glVertex $left->{width} + $cw , $top->{height} + $ch;
425     glTexCoord $rep_x, 0; glVertex $left->{width} + $cw , $top->{height};
426     glEnd;
427 elmex 1.34
428     glDisable GL_BLEND;
429     glDisable GL_TEXTURE_2D;
430 elmex 1.36
431     $self->get->draw;
432    
433 elmex 1.34 }
434 elmex 1.31
435 elmex 1.15 package Crossfire::Client::Widget::Table;
436    
437 root 1.35 our @ISA = Crossfire::Client::Widget::Bin::;
438 elmex 1.15
439     use SDL::OpenGL;
440    
441     sub add {
442     my ($self, $x, $y, $chld) = @_;
443 elmex 1.32 my $old_chld = $self->{childs}[$y][$x];
444    
445 elmex 1.15 $self->{childs}[$y][$x] = $chld;
446 elmex 1.32 $chld->set_parent ($self);
447     $self->update;
448 elmex 1.15 }
449    
450     sub max_row_height {
451     my ($self, $row) = @_;
452    
453     my $hs = 0;
454     for (my $xi = 0; $xi <= $#{$self->{childs}->[$row] || []}; $xi++) {
455     my $c = $self->{childs}->[$row]->[$xi];
456 elmex 1.17 if ($c) {
457     my ($w, $h) = $c->size_request;
458     if ($hs < $h) { $hs = $h }
459     }
460 elmex 1.15 }
461     return $hs;
462     }
463    
464     sub max_col_width {
465     my ($self, $col) = @_;
466    
467     my $ws = 0;
468     for (my $yi = 0; $yi <= $#{$self->{childs} || []}; $yi++) {
469     my $c = ($self->{childs}->[$yi] || [])->[$col];
470 elmex 1.17 if ($c) {
471     my ($w, $h) = $c->size_request;
472     if ($ws < $w) { $ws = $w }
473     }
474 elmex 1.15 }
475     return $ws;
476     }
477    
478     sub size_request {
479     my ($self) = @_;
480    
481     my ($hs, $ws) = (0, 0);
482    
483     for (my $yi = 0; $yi <= $#{$self->{childs}}; $yi++) {
484     $hs += $self->max_row_height ($yi);
485     }
486    
487     for (my $yi = 0; $yi <= $#{$self->{childs}}; $yi++) {
488     my $wm = 0;
489     for (my $xi = 0; $xi <= $#{$self->{childs}->[$yi]}; $xi++) {
490     $wm += $self->max_col_width ($xi)
491     }
492     if ($ws < $wm) { $ws = $wm }
493     }
494    
495     return ($ws, $hs);
496     }
497    
498     sub _draw {
499     my ($self) = @_;
500    
501     my $y = 0;
502     for (my $yi = 0; $yi <= $#{$self->{childs}}; $yi++) {
503     my $x = 0;
504    
505     for (my $xi = 0; $xi <= $#{$self->{childs}->[$yi]}; $xi++) {
506    
507     my $c = $self->{childs}->[$yi]->[$xi];
508 elmex 1.26 if ($c) {
509     $c->move ($x, $y, 0); #TODO: Move to size_request
510     $c->draw if $c;
511     }
512 elmex 1.15
513     $x += $self->max_col_width ($xi);
514     }
515    
516     $y += $self->max_row_height ($yi);
517     }
518     }
519    
520     package Crossfire::Client::Widget::VBox;
521    
522 root 1.35 our @ISA = Crossfire::Client::Widget::Bin::;
523 elmex 1.15
524     use SDL::OpenGL;
525    
526     sub add {
527 elmex 1.36 my ($self, $chld, $expand) = @_;
528 elmex 1.15 push @{$self->{childs}}, $chld;
529 elmex 1.36 $chld->{expand} = $expand;
530 elmex 1.32 $chld->set_parent ($self);
531     $self->update;
532 elmex 1.15 }
533    
534     sub size_request {
535     my ($self) = @_;
536    
537     my ($hs, $ws) = (0, 0);
538     for (@{$self->{childs} || []}) {
539     my ($w, $h) = $_->size_request;
540     $hs += $h;
541     if ($ws < $w) { $ws = $w }
542     }
543    
544     return ($ws, $hs);
545     }
546    
547 elmex 1.36 sub size_allocate {
548     my ($self, $w, $h) = @_;
549    
550     $self->w ($w);
551     $self->h ($h);
552    
553     my $exp;
554     my @oth;
555     # find expand widget
556     for (@{$self->{childs}}) {
557     if ($_->{expand}) {
558     $exp = $_;
559     last;
560     }
561     push @oth, $_;
562     }
563    
564     my ($ow, $oh);
565    
566     # get sizes of other widgets
567     for (@oth) {
568     my ($w, $h) = $_->size_request;
569     $oh += $h;
570     if ($ow < $w) { $ow = $w }
571     }
572    
573     my $y = 0;
574     for (@{$self->{childs}}) {
575     $_->move (0, $y);
576    
577     if ($_ == $exp) {
578     $_->size_allocate ($w, $h - $oh);
579     $y += $h - $oh;
580     } else {
581     my ($cw, $h) = $_->size_request;
582     $_->size_allocate ($w, $h);
583     $y += $h;
584     }
585     }
586     }
587    
588 elmex 1.15 sub _draw {
589     my ($self) = @_;
590    
591     my ($x, $y);
592     for (@{$self->{childs} || []}) {
593 root 1.23 $_->draw;
594 elmex 1.36 $y += $_->h;
595 elmex 1.15 }
596     }
597    
598 root 1.10 package Crossfire::Client::Widget::Label;
599    
600 root 1.12 our @ISA = Crossfire::Client::Widget::;
601    
602 root 1.10 use SDL::OpenGL;
603    
604     sub new {
605 root 1.28 my ($class, $x, $y, $z, $height, $text) = @_;
606 root 1.10
607 root 1.33 # TODO: color, and make height, xyz etc. optional
608 root 1.28 my $self = $class->SUPER::new (x => $x, y => $y, z => $z, height => $height);
609 root 1.10
610 elmex 1.15 $self->set_text ($text);
611 root 1.10
612     $self
613     }
614    
615 elmex 1.15 sub set_text {
616     my ($self, $text) = @_;
617 root 1.28
618     $self->{text} = $text;
619 elmex 1.32 $self->{texture} = new_from_text Crossfire::Client::Texture $text, $self->{height};
620 root 1.28
621 elmex 1.32 $self->update;
622 elmex 1.15 }
623    
624     sub get_text {
625     my ($self, $text) = @_;
626 root 1.28
627 elmex 1.15 $self->{text}
628     }
629    
630 root 1.14 sub size_request {
631     my ($self) = @_;
632    
633     (
634     $self->{texture}{width},
635     $self->{texture}{height},
636     )
637     }
638    
639 elmex 1.11 sub _draw {
640 root 1.10 my ($self) = @_;
641    
642     my $tex = $self->{texture};
643    
644 root 1.12 glEnable GL_BLEND;
645 root 1.10 glEnable GL_TEXTURE_2D;
646 root 1.30 glBlendFunc GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA;
647 root 1.28 glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE;
648 root 1.10 glBindTexture GL_TEXTURE_2D, $tex->{name};
649    
650 elmex 1.36 glColor 1, 0, 0, 1; # TODO color
651 root 1.12
652 root 1.10 glBegin GL_QUADS;
653     glTexCoord 0, 0; glVertex 0 , 0;
654     glTexCoord 0, 1; glVertex 0 , $tex->{height};
655     glTexCoord 1, 1; glVertex $tex->{width}, $tex->{height};
656     glTexCoord 1, 0; glVertex $tex->{width}, 0;
657     glEnd;
658    
659 root 1.12 glDisable GL_BLEND;
660 root 1.10 glDisable GL_TEXTURE_2D;
661     }
662    
663 elmex 1.31 package Crossfire::Client::Widget::TextEntry;
664    
665     our @ISA = Crossfire::Client::Widget::Label::;
666    
667     use SDL;
668     use SDL::OpenGL;
669    
670     sub key_down {
671     my ($self, $ev) = @_;
672    
673     my $mod = $ev->key_mod;
674     my $sym = $ev->key_sym;
675    
676     $ev->set_unicode (1);
677     my $uni = $ev->key_unicode;
678    
679     my $text = $self->get_text;
680    
681     if ($sym == SDLK_BACKSPACE) {
682     substr $text, -1, 1, '';
683    
684     } elsif ($uni) {
685     $text .= chr $uni;
686     }
687     $self->set_text ($text);
688     }
689    
690 elmex 1.9 package Crossfire::Client::Widget::MapWidget;
691 root 1.4
692 elmex 1.2 use strict;
693 elmex 1.7
694 root 1.25 use List::Util qw(min max);
695 elmex 1.2
696 root 1.16 use SDL;
697 elmex 1.2 use SDL::OpenGL;
698     use SDL::OpenGL::Constants;
699    
700 root 1.25 our @ISA = Crossfire::Client::Widget::;
701    
702 elmex 1.2 sub key_down {
703     print "MAPKEYDOWN\n";
704     }
705    
706     sub key_up {
707     }
708    
709 elmex 1.36 sub size_request {
710    
711     }
712    
713     sub size_allocate {
714     }
715    
716 elmex 1.11 sub _draw {
717 root 1.21 my ($self) = @_;
718    
719 root 1.25 my $mx = $::CONN->{mapx};
720     my $my = $::CONN->{mapy};
721    
722     my $map = $::CONN->{map};
723    
724     my ($xofs, $yofs);
725    
726     my $sw = 1 + int $::WIDTH / 32;
727     my $sh = 1 + int $::HEIGHT / 32;
728    
729     if ($::CONN->{mapw} > $sw) {
730 root 1.27 $xofs = $mx + ($::CONN->{mapw} - $sw) * 0.5;
731 root 1.25 } else {
732     $xofs = $self->{xofs} = min $mx, max $mx + $::CONN->{mapw} - $sw + 1, $self->{xofs};
733     }
734    
735     if ($::CONN->{maph} > $sh) {
736 root 1.27 $yofs = $my + ($::CONN->{maph} - $sh) * 0.5;
737 root 1.25 } else {
738     $yofs = $self->{yofs} = min $my, max $my + $::CONN->{maph} - $sh + 1, $self->{yofs};
739     }
740    
741 elmex 1.2 glEnable GL_TEXTURE_2D;
742     glEnable GL_BLEND;
743 root 1.35 glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE;
744    
745     my $sw4 = ($sw + 3) & ~3;
746     my $lighting = "\x00" x ($sw4 * $sh);
747 elmex 1.2
748 root 1.25 for my $x (0 .. $sw - 1) {
749     for my $y (0 .. $sh - 1) {
750 elmex 1.2
751 root 1.25 my $cell = $map->[$x + $xofs][$y + $yofs]
752 elmex 1.2 or next;
753    
754 root 1.21 my $darkness = $cell->[0] * (1 / 255);
755     if ($darkness < 0) {
756 root 1.35 $darkness = 0.15;
757 root 1.21 }
758 root 1.35 substr $lighting, $y * $sw4 + $x, 1, chr 255 - $darkness * 255;
759 elmex 1.2
760 root 1.21 for my $num (grep $_, @$cell[1,2,3]) {
761 root 1.4 my $tex = $::CONN->{face}[$num]{texture} || next;
762 elmex 1.2
763 root 1.4 glBindTexture GL_TEXTURE_2D, $tex->{name};
764 elmex 1.2
765 root 1.19 my $w = $tex->{width};
766     my $h = $tex->{height};
767    
768     my $px = ($x + 1) * 32 - $w;
769     my $py = ($y + 1) * 32 - $h;
770    
771 elmex 1.2 glBegin GL_QUADS;
772 root 1.19 glTexCoord 0, 0; glVertex $px , $py;
773     glTexCoord 0, 1; glVertex $px , $py + $h;
774     glTexCoord 1, 1; glVertex $px + $w, $py + $h;
775     glTexCoord 1, 0; glVertex $px + $w, $py;
776 elmex 1.2 glEnd;
777     }
778     }
779     }
780    
781 root 1.35 # if (1) { # higher quality darkness
782     # $lighting =~ s/(.)/$1$1$1/gs;
783     # my $pb = new_from_data Gtk2::Gdk::Pixbuf $lighting, "rgb", 0, 8, $sw4, $sh, $sw4 * 3;
784     #
785     # $pb = $pb->scale_simple ($sw4 * 0.5, $sh * 0.5, "bilinear");
786     #
787     # $lighting = $pb->get_pixels;
788     # $lighting =~ s/(.)../$1/gs;
789     # }
790    
791     $lighting = new Crossfire::Client::Texture
792     width => $sw4,
793     height => $sh,
794     data => $lighting,
795     internalformat => GL_ALPHA4,
796     format => GL_ALPHA;
797    
798     glBlendFunc GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA;
799     glColor 0, 0, 0, 0.75;
800     glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE;
801     glBindTexture GL_TEXTURE_2D, $lighting->{name};
802     glTexParameter GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR;
803     glBegin GL_QUADS;
804     glTexCoord 0, 0; glVertex 0 , 0;
805     glTexCoord 0, 1; glVertex 0 , $sh * 32;
806     glTexCoord 1, 1; glVertex $sw4 * 32, $sh * 32;
807     glTexCoord 1, 0; glVertex $sw4 * 32, 0;
808     glEnd;
809    
810 elmex 1.2 glDisable GL_TEXTURE_2D;
811     glDisable GL_BLEND;
812     }
813    
814 root 1.16 my %DIR = (
815     SDLK_KP8, [1, "north"],
816 root 1.18 SDLK_KP9, [2, "northeast"],
817 root 1.16 SDLK_KP6, [3, "east"],
818     SDLK_KP3, [4, "southeast"],
819     SDLK_KP2, [5, "south"],
820     SDLK_KP1, [6, "southwest"],
821     SDLK_KP4, [7, "west"],
822     SDLK_KP7, [8, "northwest"],
823 root 1.18
824     SDLK_UP, [1, "north"],
825     SDLK_RIGHT, [3, "east"],
826     SDLK_DOWN, [5, "south"],
827     SDLK_LEFT, [7, "west"],
828 root 1.16 );
829    
830     sub key_down {
831     my ($self, $ev) = @_;
832    
833     my $mod = $ev->key_mod;
834     my $sym = $ev->key_sym;
835    
836     if ($sym == SDLK_KP5) {
837     $::CONN->send ("command stay fire");
838     } elsif (exists $DIR{$sym}) {
839     if ($mod & KMOD_SHIFT) {
840 root 1.18 $self->{shft}++;
841 root 1.16 $::CONN->send ("command fire $DIR{$sym}[0]");
842     } elsif ($mod & KMOD_CTRL) {
843 root 1.18 $self->{ctrl}++;
844 root 1.16 $::CONN->send ("command run $DIR{$sym}[0]");
845     } else {
846 root 1.18 $::CONN->send ("command $DIR{$sym}[1]");
847 root 1.16 }
848     }
849     }
850    
851     sub key_up {
852     my ($self, $ev) = @_;
853    
854     my $mod = $ev->key_mod;
855     my $sym = $ev->key_sym;
856    
857 root 1.18 if (!($mod & KMOD_SHIFT) && delete $self->{shft}) {
858     $::CONN->send ("command fire_stop");
859     }
860     if (!($mod & KMOD_CTRL ) && delete $self->{ctrl}) {
861     $::CONN->send ("command run_stop");
862 root 1.16 }
863     }
864    
865 root 1.35 package Crossfire::Client::Widget::Animator;
866    
867     use SDL::OpenGL;
868    
869     our @ISA = Crossfire::Client::Widget::Bin::;
870    
871     sub moveto {
872     my ($self, $x, $y) = @_;
873    
874     $self->{moveto} = [$self->{x}, $self->{y}, $x, $y];
875 root 1.37 $self->{speed} = 0.2;
876 root 1.35 $self->{time} = 1;
877    
878     ::animation_start $self;
879     }
880    
881     sub animate {
882     my ($self, $interval) = @_;
883    
884     $self->{time} -= $interval * $self->{speed};
885     if ($self->{time} <= 0) {
886     $self->{time} = 0;
887     ::animation_stop $self;
888     }
889    
890     my ($x0, $y0, $x1, $y1) = @{$self->{moveto}};
891    
892     $self->{x} = $x0 * $self->{time} + $x1 * (1 - $self->{time});
893     $self->{y} = $y0 * $self->{time} + $y1 * (1 - $self->{time});
894     }
895    
896     sub _draw {
897     my ($self) = @_;
898    
899     glPushMatrix;
900     glRotate $self->{time} * 10000, 0, 1, 0;
901     $self->{child}->draw;
902     glPopMatrix;
903     }
904    
905 elmex 1.1 1;
906 root 1.5