ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/DC.pm
Revision: 1.57
Committed: Sun May 21 00:02:00 2006 UTC (17 years, 11 months ago) by root
Branch: MAIN
Changes since 1.56: +1 -0 lines
Log Message:
very alpha code for model drawing hacked in

File Contents

# User Rev Content
1 root 1.1 =head1 NAME
2    
3 root 1.22 CFClient - undocumented utility garbage for our crossfire client
4 root 1.1
5     =head1 SYNOPSIS
6    
7 root 1.22 use CFClient;
8 root 1.1
9     =head1 DESCRIPTION
10    
11     =over 4
12    
13     =cut
14    
15 root 1.22 package CFClient;
16 root 1.1
17     BEGIN {
18     $VERSION = '0.1';
19    
20 root 1.2 use XSLoader;
21 root 1.22 XSLoader::load "CFClient", $VERSION;
22 root 1.1 }
23    
24 root 1.43 use Carp ();
25 root 1.52 use AnyEvent ();
26 root 1.34 use BerkeleyDB;
27 root 1.52
28 root 1.41 use CFClient::OpenGL;
29 root 1.26
30 root 1.19 our %GL_EXT;
31     our $GL_VERSION;
32    
33     our $GL_NPOT;
34 root 1.49 our $GL_DEBUG = 1;
35 root 1.19
36     sub gl_init {
37     $GL_VERSION = gl_version * 1;
38     %GL_EXT = map +($_ => 1), split /\s+/, gl_extensions;
39    
40     $GL_NPOT = $GL_EXT{GL_ARB_texture_non_power_of_two} || $GL_VERSION >= 2;
41    
42 root 1.49 glDisable GL_COLOR_MATERIAL;
43 root 1.26 glShadeModel GL_FLAT;
44 root 1.49 glDisable GL_DITHER;
45 root 1.26 glDisable GL_DEPTH_TEST;
46 root 1.57 glDepthMask 0;
47 root 1.26 glHint GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST;
48    
49 root 1.22 CFClient::Texture::restore_state ();
50 root 1.19 }
51    
52 root 1.49 sub gl_check {
53     return unless $GL_DEBUG;
54    
55     if (my $error = glGetError) {
56 root 1.56 Carp::cluck sprintf "opengl error %x while %s", $error, &sprintf(@_);
57 root 1.49 }
58     }
59    
60 root 1.5 sub find_rcfile($) {
61     my $path;
62    
63 root 1.46 for (grep !ref, @INC) {
64 root 1.22 $path = "$_/CFClient/resources/$_[0]";
65 root 1.5 return $path if -r $path;
66     }
67    
68     die "FATAL: can't find required file $_[0]\n";
69     }
70    
71     sub read_cfg {
72     my ($file) = @_;
73    
74     open CFG, $file
75     or return;
76    
77     my $CFG;
78    
79     local $/;
80     $CFG = eval <CFG>;
81    
82     $::CFG = $CFG;
83    
84     close CFG;
85     }
86    
87     sub write_cfg {
88     my ($file) = @_;
89    
90     open CFG, ">$file"
91     or return;
92    
93     {
94 elmex 1.9 require Data::Dumper;
95 root 1.5 local $Data::Dumper::Purity = 1;
96     $::CFG->{VERSION} = $::VERSION;
97     print CFG Data::Dumper->Dump ([$::CFG], [qw/CFG/]);
98     }
99    
100     close CFG;
101     }
102    
103 root 1.34 mkdir "$Crossfire::VARDIR/pclient", 0777;
104    
105     our $DB_ENV = new BerkeleyDB::Env
106     -Home => "$Crossfire::VARDIR/pclient",
107     -Cachesize => 1_000_000,
108 root 1.39 -ErrFile => "$Crossfire::VARDIR/pclient/errorlog.txt",
109     # -ErrPrefix => "DATABASE",
110 root 1.34 -Verbose => 1,
111 root 1.39 -Flags => DB_CREATE | DB_RECOVER_FATAL | DB_INIT_MPOOL | DB_INIT_LOCK | DB_INIT_TXN,
112 root 1.34 or die "unable to create/open database home $Crossfire::VARDIR/pclient: $BerkeleyDB::Error";
113    
114     sub db_table($) {
115 root 1.38 my ($table) = @_;
116    
117     $table =~ s/([^a-zA-Z0-9_\-])/sprintf "=%x=", ord $1/ge;
118    
119 root 1.34 new CFClient::Database
120     -Env => $DB_ENV,
121 root 1.38 -Filename => $table,
122     # -Filename => "database",
123     # -Subname => $table,
124 root 1.51 -Property => DB_CHKSUM,
125 root 1.34 -Flags => DB_CREATE | DB_UPGRADE,
126     or die "unable to create/open database table $_[0]: $BerkeleyDB::Error";
127     }
128    
129 root 1.52 sub pod_to_pango($) {
130     my ($pom) = @_;
131    
132     $pom->present ("CFClient::PodToPango")
133     }
134    
135     package CFClient::PodToPango;
136    
137     use base Pod::POM::View::Text;
138    
139     our $indent = 0;
140    
141     *view_seq_code =
142     *view_seq_bold = sub { "<b>$_[1]</b>" };
143     *view_seq_italic = sub { "<i>$_[1]</i>" };
144     *view_seq_space =
145     *view_seq_link =
146     *view_seq_index = sub { CFClient::UI::Label::escape ($_[1]) };
147    
148     sub view_seq_text {
149     my $text = $_[1];
150     $text =~ s/\s+/ /g;
151     CFClient::UI::Label::escape ($text)
152     }
153    
154     sub view_item {
155     ("\t" x ($indent / 4))
156     . $_[1]->title->present ($_[0])
157     . "\n"
158     . $_[1]->content->present ($_[0])
159     }
160    
161 root 1.53 sub view_verbatim {
162     (join "",
163     map +("\t" x ($indent / 2)) . "$_\n",
164     split /\n/, CFClient::UI::Label::escape ($_[1]))
165     . "\n"
166     }
167    
168 root 1.52 sub view_textblock {
169     ("\t" x ($indent / 2)) . "$_[1]\n\n"
170     }
171    
172     sub view_head2 {
173     "<big>" . $_[1]->title->present ($_[0]) . "</big>\n\n"
174     . $_[1]->content->present ($_[0])
175     };
176    
177     sub view_over {
178     local $indent = $indent + $_[1]->indent;
179     $_[1]->content->present ($_[0])
180     }
181    
182 root 1.34 package CFClient::Database;
183    
184     our @ISA = BerkeleyDB::Btree::;
185    
186     sub get($$) {
187     my $data;
188    
189     $_[0]->db_get ($_[1], $data) == 0
190     ? $data
191 root 1.37 : ()
192 root 1.34 }
193    
194     my %DB_SYNC;
195    
196     sub put($$$) {
197     my ($db, $key, $data) = @_;
198    
199 root 1.37 $DB_SYNC{$db} = AnyEvent->timer (after => 5, cb => sub { $db->db_sync });
200 root 1.34
201 root 1.37 $db->db_put ($key => $data)
202 root 1.34 }
203    
204 root 1.22 package CFClient::Texture;
205 root 1.3
206 root 1.25 use strict;
207    
208 root 1.3 use Scalar::Util;
209    
210 root 1.41 use CFClient::OpenGL;
211 root 1.3
212 root 1.35 my %TEXTURES;
213 root 1.3
214 root 1.14 sub new {
215 root 1.4 my ($class, %data) = @_;
216    
217 root 1.14 my $self = bless {
218 root 1.15 internalformat => GL_RGBA,
219     format => GL_RGBA,
220 root 1.29 type => GL_UNSIGNED_BYTE,
221 root 1.14 %data,
222     }, $class;
223 root 1.4
224 root 1.35 Scalar::Util::weaken ($TEXTURES{$self+0} = $self);
225 root 1.4
226     $self->upload;
227    
228     $self
229     }
230    
231     sub new_from_image {
232 root 1.33 my ($class, $image, %arg) = @_;
233 root 1.4
234 root 1.33 $class->new (image => $image, %arg)
235 root 1.4 }
236    
237 root 1.3 sub new_from_file {
238 root 1.42 my ($class, $path, %arg) = @_;
239 root 1.3
240     open my $fh, "<:raw", $path
241     or die "$path: $!";
242    
243     local $/;
244 root 1.42 $class->new_from_image (<$fh>, %arg)
245 root 1.3 }
246    
247 root 1.14 #sub new_from_surface {
248     # my ($class, $surface) = @_;
249     #
250     # $surface->rgba;
251     #
252     # $class->new (
253     # data => $surface->pixels,
254 root 1.24 # w => $surface->width,
255     # h => $surface->height,
256 root 1.14 # )
257     #}
258    
259 root 1.21 sub new_from_layout {
260 root 1.42 my ($class, $layout, %arg) = @_;
261 root 1.14
262 root 1.50 my ($w, $h, $data, $format, $internalformat) = $layout->render;
263 root 1.14
264     $class->new (
265 root 1.24 w => $w,
266     h => $h,
267 root 1.14 data => $data,
268 root 1.50 format => $format,
269     internalformat => $format,
270 root 1.29 type => GL_UNSIGNED_BYTE,
271 root 1.42 %arg,
272 root 1.4 )
273 root 1.3 }
274    
275 root 1.8 sub new_from_opengl {
276     my ($class, $w, $h, $cb) = @_;
277    
278 root 1.48 $class->new (w => $w || 1, h => $h || 1, render_cb => $cb)
279 root 1.8 }
280    
281 root 1.19 sub topot {
282     (grep $_ >= $_[0], 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768)[0]
283     }
284    
285 root 1.3 sub upload {
286     my ($self) = @_;
287    
288 root 1.27 return unless $GL_VERSION;
289 root 1.3
290 root 1.6 my $data;
291 root 1.3
292     if (exists $self->{data}) {
293 root 1.6 $data = $self->{data};
294 root 1.25
295 root 1.24 } elsif (exists $self->{render_cb}) {
296     glViewport 0, 0, $self->{w}, $self->{h};
297 root 1.12 glMatrixMode GL_PROJECTION;
298     glLoadIdentity;
299 root 1.31 glOrtho 0, $self->{w}, 0, $self->{h}, -10000, 10000;
300 root 1.12 glMatrixMode GL_MODELVIEW;
301     glLoadIdentity;
302 root 1.25 $self->{render_cb}->($self, $self->{w}, $self->{h});
303 root 1.8
304 root 1.3 } else {
305 root 1.29 ($self->{w}, $self->{h}, $data, $self->{internalformat}, $self->{format}, $self->{type})
306     = CFClient::load_image_inline $self->{image};
307 root 1.3 }
308    
309 root 1.24 my ($tw, $th) = @$self{qw(w h)};
310 root 1.19
311 root 1.47 unless ($tw > 0 && $th > 0) {
312 root 1.24 $tw = $th = 1;
313     $data = "\x00" x 64;
314     }
315    
316 root 1.32 $self->{minified} = [CFClient::average $tw, $th, $data]
317 root 1.33 if $self->{minify};
318 root 1.32
319 root 1.24 unless ($GL_NPOT) {
320     # TODO: does not work for zero-sized textures
321 root 1.19 $tw = topot $tw;
322     $th = topot $th;
323    
324 root 1.43 if (($tw != $self->{w} || $th != $self->{h}) && defined $data) {
325 root 1.24 my $bpp = (length $data) / ($self->{w} * $self->{h});
326 root 1.20 $data = pack "(a" . ($tw * $bpp) . ")*",
327 root 1.24 unpack "(a" . ($self->{w} * $bpp) . ")*", $data;
328     $data .= ("\x00" x ($tw * $bpp)) x ($th - $self->{h});
329 root 1.19 }
330     }
331    
332 root 1.24 $self->{s} = $self->{w} / $tw;
333     $self->{t} = $self->{h} / $th;
334 root 1.19
335 root 1.41 $self->{name} ||= glGenTexture;
336 root 1.3
337     glBindTexture GL_TEXTURE_2D, $self->{name};
338    
339     glTexParameter GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP;
340     glTexParameter GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP;
341 root 1.42
342     if ($::FAST) {
343     glTexParameter GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST;
344     glTexParameter GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST;
345 root 1.45 } elsif ($self->{mipmap} && $GL_VERSION >= 1.4) {
346     # alternatively check for 0x8191
347     glTexParameter GL_TEXTURE_2D, GL_GENERATE_MIPMAP, 1;
348     glTexParameter GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR;
349     glTexParameter GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR;
350 root 1.42 } else {
351     glTexParameter GL_TEXTURE_2D, GL_GENERATE_MIPMAP, $self->{mipmap};
352     glTexParameter GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR;
353 root 1.45 glTexParameter GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR;
354 root 1.42 }
355 root 1.3
356 root 1.45 glGetError;
357    
358 root 1.8 if (defined $data) {
359     glTexImage2D GL_TEXTURE_2D, 0,
360 root 1.15 $self->{internalformat},
361 root 1.54 $tw, $th,
362 root 1.8 0,
363 root 1.14 $self->{format},
364 root 1.29 $self->{type},
365 root 1.8 $data;
366 root 1.49 CFClient::gl_check "uploading texture %dx%d if=%x f=%x t=%x",
367     $tw, $th, $self->{internalformat}, $self->{format}, $self->{type};
368 root 1.8 } else {
369     glCopyTexImage2D GL_TEXTURE_2D, 0,
370 root 1.15 $self->{internalformat},
371 root 1.8 0, 0,
372 root 1.19 $tw, $th,
373 root 1.8 0;
374 root 1.49 CFClient::gl_check "copying to texture %dx%d if=%x",
375     $tw, $th, $self->{internalformat};
376 root 1.8 }
377 root 1.55
378     glBindTexture GL_TEXTURE_2D, 0; # just to be on the safe side
379 root 1.3 }
380    
381     sub DESTROY {
382     my ($self) = @_;
383    
384 root 1.35 delete $TEXTURES{$self+0};
385    
386 root 1.41 glDeleteTexture delete $self->{name}
387 root 1.36 if $self->{name};
388 root 1.3 }
389    
390 root 1.54 sub restore_state {
391 root 1.3 $_->upload
392 root 1.36 for values %TEXTURES;
393 root 1.54 }
394 root 1.3
395 root 1.1 1;
396    
397     =back
398    
399     =head1 AUTHOR
400    
401     Marc Lehmann <schmorp@schmorp.de>
402     http://home.schmorp.de/
403    
404     =cut
405