<commit_before>package Games::Blockminer3D::Client::Frontend;
use common::sense;
use Carp;
use SDL;
use SDLx::App;
use SDL::Mouse;
use SDL::Video;
use SDL::Events;
use SDL::Image;
use SDL::Event;
use OpenGL qw(:all);
use OpenGL::List;
use AnyEvent;
use Math::Trig qw/deg2rad rad2deg pi/;
use Time::HiRes qw/time/;
use POSIX qw/floor/;
use Games::Blockminer3D::Vector;

use Games::Blockminer3D::Client::World;
use Games::Blockminer3D::Client::UI;

use base qw/Object::Event/;

=head1 NAME

Games::Blockminer3D::Client::Frontend - desc

=head1 SYNOPSIS

=head1 DESCRIPTION

=head1 METHODS

=over 4

=item my $obj = Games::Blockminer3D::Client::Frontend->new (%args)

=cut

my ($WIDTH, $HEIGHT) = (720, 400);#600, 400);

sub new {
   my $this  = shift;
   my $class = ref ($this) || $this;
   my $self  = { @_ };
   bless $self, $class;

   $self->init_object_events;
   $self->init_app;
   Games::Blockminer3D::Client::UI::init_ui;
   world_init;

   world ()->reg_cb (chunk_changed => sub {
      my ($w, $x, $y, $z) = @_;
      warn "killed chunk at $x $y $z\n";
      $self->compile_chunk ($x, $y, $z);
   });

   $self->init_physics;
   $self->setup_event_poller;
   $self->init_test;

   return $self
}
sub init_test {
   my ($self) = @_;
   $self->{debug_hud} = Games::Blockminer3D::Client::UI->new (W => $WIDTH, H => $HEIGHT);
   $self->{query_ui} = Games::Blockminer3D::Client::UI->new (W => $WIDTH, H => $HEIGHT);
   $self->{query_ui}->update ({
         window => {
            pos => 'center',
            size => [$WIDTH - ($WIDTH / 5), 50],
            color => "#333333",
            alpha => 1,
         },
         elements => [
            {
               type => 'text', pos => [10, 10],
               size => [150, 38],
               text => "tes teste te eiwe iejfiwfjwei",
               color => "#0000ff",
               font => 'normal'
            },
         ]
   });
   delete $self->{query_ui};
}

sub init_physics {
   my ($self) = @_;

   $self->{phys_obj}->{player} = {
      pos => [5.5, 3.5, 5.5],#-25, -50, -25),
      vel => [0, 0, 0],
   };

   $self->{box_highlights} = [];
}

sub init_app {
   my ($self) = @_;
   $self->{app} = SDLx::App->new (
      title => "Blockminer3D 0.01alpha", width => $WIDTH, height => $HEIGHT, gl => 1);
   SDL::Events::enable_unicode (1);
   $self->{sdl_event} = SDL::Event->new;
   SDL::Video::GL_set_attribute (SDL::Constants::SDL_GL_SWAP_CONTROL, 1);
   SDL::Video::GL_set_attribute (SDL::Constants::SDL_GL_DOUBLEBUFFER, 1);

   glDepthFunc(GL_LESS);
   glEnable (GL_DEPTH_TEST);

   glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   glEnable (GL_BLEND);
   glEnable (GL_CULL_FACE);
   glCullFace (GL_BACK);

   glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
   glEnable (GL_TEXTURE_2D);
   glEnable (GL_FOG);
   glClearColor (0.5,0.5,0.5,1);
   glClearDepth (1.0);
   glShadeModel (GL_FLAT);

   glFogi (GL_FOG_MODE, GL_LINEAR);
   glFogfv_p (GL_FOG_COLOR, 0.5, 0.5, 0.5, 1);
   glFogf (GL_FOG_DENSITY, 0.35);
   glHint (GL_FOG_HINT, GL_DONT_CARE);
   glFogf (GL_FOG_START, 10);
   glFogf (GL_FOG_END,   20);

   glGenTextures_p(1);

 #  $self->load_texture ("res/blocks19.small.png", 1);
   $self->load_texture ("res/construction.jpg", 1);
}

sub _get_texfmt {
   my ($surface) = @_;
   my $ncol = $surface->format->BytesPerPixel;
   my $rmsk = $surface->format->Rmask;
   warn "NCOL $ncol\n";
   ($ncol == 4 ? ($rmsk == 0x000000ff ? GL_RGBA : GL_BGRA)
               : ($rmsk == 0x000000ff ? GL_RGB  : GL_BGR))
}

sub load_texture {
   my ($self, $file, $nr) = @_;

   my ($name) = $file =~ /([^\/]+?)\.png/;

   my $img = SDL::Image::load ($file);
   die "Couldn't load texture: " . SDL::get_error () unless $img;
   SDL::Video::lock_surface ($img);

   my $texture_format = _get_texfmt ($img);

   glBindTexture (GL_TEXTURE_2D, $nr);
   glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

   gluBuild2DMipmaps_s (GL_TEXTURE_2D,
      $img->format->BytesPerPixel, $img->w, $img->h, $texture_format, GL_UNSIGNED_BYTE,
      ${$img->get_pixels_ptr});

   $self->{textures}->{$name} = $nr;
}

sub _render_quad {
   my ($pos, $faces, $light) = @_;
   #d#warn "QUAD $x $y $z $light\n";

   #               0 front  1 top    2 back   3 left   4 right  5 bottom
   my @indices  = qw/0 1 2 3  1 5 6 2  7 6 5 4  4 5 1 0  3 2 6 7  3 7 4 0/;
   my @normals = (
      [ 0, 0,-1],
      [ 0, 1, 0],
      [ 0, 0, 1],
      [-1, 0, 0],
      [ 1, 0, 0],
      [ 0,-1, 0],
   ),
   my @vertices = (
      [ 0,  0,  0 ],
      [ 0,  1,  0 ],
      [ 1,  1,  0 ],
      [ 1,  0,  0 ],

      [ 0,  0,  1 ],
      [ 0,  1,  1 ],
      [ 1,  1,  1 ],
      [ 1,  0,  1 ],
   );

   my @uv = (
    #  w  h
      [1, 1],
      [1, 0],
      [0, 0],
      [0, 1],
   );

   foreach my $face (@$faces) {
      # glNormal3d (@{$normals[$face]}); # we dont use OpenGL lighting!

      foreach my $vertex (0..3) {
         my $index  = $indices[4 * $face + $vertex];
         my $coords = $vertices[$index];

         glColor3d ($light, $light, $light) if defined $light;
         glTexCoord2d(@{$uv[$vertex]});
         glVertex3d(@{vadd ($coords, $pos)});
      }
   }
}

sub _render_highlight {
   my ($pos, $color, $rad) = @_;

   $rad ||= 0.05;
   $pos = vsubd ($pos, $rad, $rad, $rad);
   glPushMatrix;
   glBindTexture (GL_TEXTURE_2D, 0);
   glColor4d (@$color);
   glTranslatef (@$pos);
   glScalef (1 + 2*$rad, 1 + 2*$rad, 1+2*$rad);
   glBegin (GL_QUADS);
   _render_quad ([0, 0, 0], [0..5]);
   glEnd;
   glPopMatrix;
}

sub compile_chunk {
   my ($self, $cx, $cy, $cz) = @_;

   my $chnk = world_get_chunk ($cx, $cy, $cz)
      or return;
   warn "compiling... $cx, $cy, $cz: $chnk\n";
   my $face_cnt;
   $self->{compiled_chunks}->{$cx}->{$cy}->{$cz} = OpenGL::List::glpList {
      glPushMatrix;
      glBegin (GL_QUADS);

      my @quads = map {
         [
            [
               $_->[0]->[0] + ($cx * $Games::Blockminer3D::Client::MapChunk::SIZE),
               $_->[0]->[1] + ($cy * $Games::Blockminer3D::Client::MapChunk::SIZE),
               $_->[0]->[2] + ($cz * $Games::Blockminer3D::Client::MapChunk::SIZE),
            ],
            $_->[1],
            $_->[2],
            $_->[3],
         ]
      } $chnk->visible_quads;
      #d# warn "[" . (scalar @quads) . "] quads\n";

      my $current_texture;

      # sort by texture name:
      for (sort { $a->[3] cmp $b->[3] } @quads) {
         my ($pos, $faces, $light, $tex) = @$_;
         my $tex_nr = 1; # FIXME: $self->{textures}->{$tex};
         if ($current_texture != $tex_nr) {
            glEnd;
            glBindTexture (GL_TEXTURE_2D, $tex_nr);
            glBegin (GL_QUADS);
            $current_texture = $tex_nr;
         }

         $face_cnt += scalar @$faces;

         _render_quad ($pos, $faces, $light);
      }

      glEnd;
      glPopMatrix;

   };
   #d# warn "faces: $face_cnt\n";
}

sub step_animations {
   my ($self, $dt) = @_;

   my @next_hl;
   for my $bl (@{$self->{box_highlights}}) {
      my ($pos, $color, $attr) = @$bl;

      if ($attr->{fading}) {
         next if $color->[3] >= 1; # remove fade
         $color->[3] += $attr->{fading} * $dt;<commit_msg>minor optimiziations which don't impove anything.<commit_after>package Games::Blockminer3D::Client::Frontend;
use common::sense;
use Carp;
use SDL;
use SDLx::App;
use SDL::Mouse;
use SDL::Video;
use SDL::Events;
use SDL::Image;
use SDL::Event;
use OpenGL qw(:all);
use OpenGL::List;
use AnyEvent;
use Math::Trig qw/deg2rad rad2deg pi/;
use Time::HiRes qw/time/;
use POSIX qw/floor/;
use Games::Blockminer3D::Vector;

use Games::Blockminer3D::Client::World;
use Games::Blockminer3D::Client::UI;

use base qw/Object::Event/;

=head1 NAME

Games::Blockminer3D::Client::Frontend - desc

=head1 SYNOPSIS

=head1 DESCRIPTION

=head1 METHODS

=over 4

=item my $obj = Games::Blockminer3D::Client::Frontend->new (%args)

=cut

my ($WIDTH, $HEIGHT) = (720, 400);#600, 400);

sub new {
   my $this  = shift;
   my $class = ref ($this) || $this;
   my $self  = { @_ };
   bless $self, $class;

   $self->init_object_events;
   $self->init_app;
   Games::Blockminer3D::Client::UI::init_ui;
   world_init;

   world ()->reg_cb (chunk_changed => sub {
      my ($w, $x, $y, $z) = @_;
      warn "killed chunk at $x $y $z\n";
      $self->compile_chunk ($x, $y, $z);
   });

   $self->init_physics;
   $self->setup_event_poller;
   $self->init_test;

   return $self
}
sub init_test {
   my ($self) = @_;
   $self->{debug_hud} = Games::Blockminer3D::Client::UI->new (W => $WIDTH, H => $HEIGHT);
   $self->{query_ui} = Games::Blockminer3D::Client::UI->new (W => $WIDTH, H => $HEIGHT);
   $self->{query_ui}->update ({
         window => {
            pos => 'center',
            size => [$WIDTH - ($WIDTH / 5), 50],
            color => "#333333",
            alpha => 1,
         },
         elements => [
            {
               type => 'text', pos => [10, 10],
               size => [150, 38],
               text => "tes teste te eiwe iejfiwfjwei",
               color => "#0000ff",
               font => 'normal'
            },
         ]
   });
   delete $self->{query_ui};
}

sub init_physics {
   my ($self) = @_;

   $self->{phys_obj}->{player} = {
      pos => [5.5, 3.5, 5.5],#-25, -50, -25),
      vel => [0, 0, 0],
   };

   $self->{box_highlights} = [];
}

sub init_app {
   my ($self) = @_;
   $self->{app} = SDLx::App->new (
      title => "Blockminer3D 0.01alpha", width => $WIDTH, height => $HEIGHT, gl => 1);
   SDL::Events::enable_unicode (1);
   $self->{sdl_event} = SDL::Event->new;
   SDL::Video::GL_set_attribute (SDL::Constants::SDL_GL_SWAP_CONTROL, 1);
   SDL::Video::GL_set_attribute (SDL::Constants::SDL_GL_DOUBLEBUFFER, 1);

   glDepthFunc(GL_LESS);
   glEnable (GL_DEPTH_TEST);

   glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   glEnable (GL_BLEND);
   glEnable (GL_CULL_FACE);
   glCullFace (GL_BACK);

   glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
   glEnable (GL_TEXTURE_2D);
   glEnable (GL_FOG);
   glClearColor (0.5,0.5,0.5,1);
   glClearDepth (1.0);
   glShadeModel (GL_FLAT);

   glFogi (GL_FOG_MODE, GL_LINEAR);
   glFogfv_p (GL_FOG_COLOR, 0.5, 0.5, 0.5, 1);
   glFogf (GL_FOG_DENSITY, 0.35);
   glHint (GL_FOG_HINT, GL_DONT_CARE);
   glFogf (GL_FOG_START, 10);
   glFogf (GL_FOG_END,   20);

   glGenTextures_p(1);

 #  $self->load_texture ("res/blocks19.small.png", 1);
   $self->load_texture ("res/construction.jpg", 1);
}

sub _get_texfmt {
   my ($surface) = @_;
   my $ncol = $surface->format->BytesPerPixel;
   my $rmsk = $surface->format->Rmask;
   warn "NCOL $ncol\n";
   ($ncol == 4 ? ($rmsk == 0x000000ff ? GL_RGBA : GL_BGRA)
               : ($rmsk == 0x000000ff ? GL_RGB  : GL_BGR))
}

sub load_texture {
   my ($self, $file, $nr) = @_;

   my ($name) = $file =~ /([^\/]+?)\.png/;

   my $img = SDL::Image::load ($file);
   die "Couldn't load texture: " . SDL::get_error () unless $img;
   SDL::Video::lock_surface ($img);

   my $texture_format = _get_texfmt ($img);

   glBindTexture (GL_TEXTURE_2D, $nr);
   glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
   glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

   gluBuild2DMipmaps_s (GL_TEXTURE_2D,
      $img->format->BytesPerPixel, $img->w, $img->h, $texture_format, GL_UNSIGNED_BYTE,
      ${$img->get_pixels_ptr});

   $self->{textures}->{$name} = $nr;
}

sub _render_quad {
   my ($pos, $faces) = @_;
   #d#warn "QUAD $x $y $z $light\n";

   #               0 front  1 top    2 back   3 left   4 right  5 bottom
   my @indices  = qw/0 1 2 3  1 5 6 2  7 6 5 4  4 5 1 0  3 2 6 7  3 7 4 0/;
   my @normals = (
      [ 0, 0,-1],
      [ 0, 1, 0],
      [ 0, 0, 1],
      [-1, 0, 0],
      [ 1, 0, 0],
      [ 0,-1, 0],
   ),
   my @vertices = (
      [ 0,  0,  0 ],
      [ 0,  1,  0 ],
      [ 1,  1,  0 ],
      [ 1,  0,  0 ],

      [ 0,  0,  1 ],
      [ 0,  1,  1 ],
      [ 1,  1,  1 ],
      [ 1,  0,  1 ],
   );

   my @uv = (
    #  w  h
      [1, 1],
      [1, 0],
      [0, 0],
      [0, 1],
   );

   foreach my $face (@$faces) {
      # glNormal3d (@{$normals[$face]}); # we dont use OpenGL lighting!

      foreach my $vertex (0..3) {
         my $index  = $indices[4 * $face + $vertex];
         my $coords = $vertices[$index];

         glTexCoord2d(@{$uv[$vertex]});
         glVertex3d(@{vadd ($coords, $pos)});
      }
   }
}

sub _render_highlight {
   my ($pos, $color, $rad) = @_;

   $rad ||= 0.05;
   $pos = vsubd ($pos, $rad, $rad, $rad);
   glPushMatrix;
   glBindTexture (GL_TEXTURE_2D, 0);
   glColor4d (@$color);
   glTranslatef (@$pos);
   glScalef (1 + 2*$rad, 1 + 2*$rad, 1+2*$rad);
   glBegin (GL_QUADS);
   _render_quad ([0, 0, 0], [0..5]);
   glEnd;
   glPopMatrix;
}

sub compile_chunk {
   my ($self, $cx, $cy, $cz) = @_;

   my $chnk = world_get_chunk ($cx, $cy, $cz)
      or return;
   warn "compiling... $cx, $cy, $cz: $chnk\n";
   my $face_cnt;
   $self->{compiled_chunks}->{$cx}->{$cy}->{$cz} = OpenGL::List::glpList {
      glPushMatrix;
      glBegin (GL_QUADS);

      my @quads = map {
         [
            [
               $_->[0]->[0] + ($cx * $Games::Blockminer3D::Client::MapChunk::SIZE),
               $_->[0]->[1] + ($cy * $Games::Blockminer3D::Client::MapChunk::SIZE),
               $_->[0]->[2] + ($cz * $Games::Blockminer3D::Client::MapChunk::SIZE),
            ],
            $_->[1],
            $_->[2],
            $_->[3],
         ]
      } $chnk->visible_quads;
      #d# warn "[" . (scalar @quads) . "] quads\n";

      my $current_texture;

      # sort by texture name:
      for (sort { $a->[3] cmp $b->[3] } @quads) {
         my ($pos, $faces, $light, $tex) = @$_;
         my $tex_nr = 1; # FIXME: $self->{textures}->{$tex};
         if ($current_texture != $tex_nr) {
            glEnd;
            glBindTexture (GL_TEXTURE_2D, $tex_nr);
            glBegin (GL_QUADS);
            $current_texture = $tex_nr;
         }

         $face_cnt += scalar @$faces;

         glColor3d ($light, $light, $light) if defined $light;
         _render_quad ($pos, $faces);
      }

      glEnd;
      glPopMatrix;

   };
   #d# warn "faces: $face_cnt\n";
}

sub step_animations {
   my ($self, $dt) = @_;

   my @next_hl;
   for my $bl (@{$self->{box_highlights}}) {
      my ($pos, $color, $attr) = @$bl;

      if ($attr->{fading}) {
         next if $color->[3] >= 1; # remove fade
         $color->[3] += $attr->{fading} * $dt;
{'fraction_non_alphanumeric': 0.19367315927614312, 'fraction_numerical': 0.03398259428097804, 'mean_word_length': 2.4334835190894, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 167, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3941626', 'n_tokens_mistral': 6238, 'n_tokens_neox': 5816, 'n_words': 1260}