Karoshi MSX Community

Desarrollo MSX => Desarrollo (Español/Spanish) => Mensaje iniciado por: samsaga2 en 17 de Agosto de 2011, 10:18:45 am



Título: Conversor de sprites con bit CC
Publicado por: samsaga2 en 17 de Agosto de 2011, 10:18:45 am
He estado intentando hacer un conversor de sprites que tenga en cuenta el modo mixto de los msx 2 (al puro estilo sprite converter http://www.msx.org/modules.php?op=modload&name=Downloads&file=index&req=visit&lid=305). Pero por ahora lo único que consigo es un churro la mar de mono.

Teniendo una paleta preparada, ¿que algoritmo puedo usar para extraer los sprites usando el modo mixto?


Título: Re: Conversor de sprites con bit CC
Publicado por: SapphiRe_MSX en 17 de Agosto de 2011, 10:59:07 pm
Supongamos que son sprites de dos planos, si fueran más las ecuaciones se complicarían un poquito, pero teniendo la paleta ya preparada y fijada no es muy problemático. Por cada línea del sprite, tenemos que los colores han de satisfacer una ecuación del estilo:

(Color Sprite 0) OR (Color Sprite 1) = (Color Mezcla)

Tienes que analizar en cada línea qué colores hay y si satisfacen esa ecuación, pero como la paleta es fija, puedes probar todas las posibles combinaciones de colores (realmente sólo hay 3). Supongamos que encuentras tres colores (aparte del transparente) digamos A, B y C. Entonces:

-Si A OR B = C, para el sprite 0 ponemos el A y para el 1 el B (o viceversa)
-Si A OR C = B, para el sprite 0 ponemos el A y para el 1 el C (o viceversa)
-Si B OR C = A, para el sprite 0 ponemos el B y para el 1 el C (o viceversa)

Si los colores de esa línea no satisfacen ninguna de las ecuaciones, entonces no se puede convertir en un sprite multicolor de 2 planos. Ojo, esto es porque tienes la paleta fija. Si tuvieras que moverla, entonces la cosa se complicaría un poco, porque habría que crear un sistema con las 16 ecuaciones que obtendríamos por todas las líneas del sprite y resolver el sistema (si es que es posible, claro).

Supongamos que los colores satisfacen la ecuación. Entonces nos fijamos en la posición de los colores en la línea y si nos encontramos:

-Un pixel transparente: se traduce en un bit 0 para ambos sprites
-Un pixel del color para el sprite 0: se traduce en un bit 1 para el sprite 0 y en un bit 0 para el sprite 1.
-Un pixel del color para el sprite 1: se traduce en un bit 0 para el sprite 1 y en un bit 1 para el sprite 0.
-Un pixel del color mezclado: se traduce en un bit 1 para ambos sprites

De esta forma tienes ya la línea de los dos sprites y su color. Repitiendo el procedimiento para todas las líneas, tendrás el sprite completo.

Espero que esto te sirva.


Título: Re: Conversor de sprites con bit CC
Publicado por: samsaga2 en 18 de Agosto de 2011, 08:08:22 am
Genial, lo probaré como dices. Os mantendré informados. Colgaré el script en perl cuando lo tenga funcionando.


Título: Re: Conversor de sprites con bit CC
Publicado por: samsaga2 en 20 de Agosto de 2011, 03:29:11 pm
Ha funcionado a la perfección. Aujnque sólo soporta un máximo de dos sprites no creo que nadie use más con el modo mixto.

Es un script en perl. Os lo adjunto por si le puede ser de utilidad a alguien:

Código:
use strict;
use warnings;
use Image::Magick;
use List::MoreUtils qw/ uniq /;

sub bin2dec {
return unpack("N", pack("B32", substr("0" x 32 . shift, -32)));
}

sub extract_pattern {
my ($row) = @_;
 
my @colors = sort {$a<=>$b} grep {$_} uniq @{$row};
my $color_a = shift @colors;
my $color_b = shift @colors;
my $color_c = shift @colors;

die "Too many colors." if $#colors >= 0;

if(defined $color_c) {
if(($color_b | $color_c) == $color_a) {
($color_a, $color_c) = ($color_c, $color_a);
} elsif(($color_a | $color_c) == $color_b) {
($color_b, $color_c) = ($color_c, $color_b);
} elsif(($color_a | $color_b) != $color_c) {
die "Wrong row colors.";
}
}

my @layers = ();
my $cc = defined $color_c ? 64 : 0;

my @bits0 = map {defined $color_a && $_ == $color_a || defined $color_c && $_ == $color_c ? 1 : 0} @{$row};
push @layers, [\@bits0, $color_a];

if (defined $color_b) {
my @bits1 = map {$_ == $color_b || defined $color_c && $_ == $color_c ? 1 : 0} @{$row};
push @layers, [\@bits1, ($color_b | $cc)];
}

return \@layers;
}

sub export_sprite {
my ($image, $tx, $ty) = @_;

my @sprite0 = ();
my @sprite1 = ();

foreach my $y (0..15) {
my $oy = $ty + $y;

my @row = ();
foreach my $x (0..15) {
my $ox = $tx + $x;
$row[$x] = $image->[0]->Get("Index[$ox,$oy]");
}

my $layers = extract_pattern \@row;
$sprite0[$y] = $layers->[0];
$sprite1[$y] = $layers->[1] if $layers->[1];
}

my @sprites = (\@sprite0, \@sprite1);
return \@sprites;
}

sub print_sprite_patterns {
my ($sprite, $file) = @_;

foreach my $column (0..1) {
foreach my $y (0..15) {
my $row = $sprite->[$y]->[0];
my $bits = '';
$bits .= $row->[$column * 8 + $_]||0 for(0..7);
my $byte = bin2dec($bits);
print $file "db $byte\t; B:$bits R:$y\n";
}
}
}

sub print_sprite_colors {
my ($sprite, $file) = @_;

foreach my $y (0..15) {
my $byte = $sprite->[$y]->[1] || 0;
my $color = $byte & 15;
my $cc = $byte & 64 ? 1 : 0;
print $file "db $byte\t; C:$color CC:$cc R:$y\n";
}
}

sub export_sprites {
my ($filename, $out_pattern, $out_color) = @_;

# read image
my $image = Image::Magick->new;
$image->Read($filename);

# image size
my $width = $image->Get("width");
my $height = $image->Get("height");

if($width % 16 || $height % 16) {
die "Wrong image size: $width x $height. Must be multiple of 16x16.\n";
}

open OUTPAT, ">$out_pattern" or die "Cannot create $out_pattern file.";
open OUTCOL, ">$out_color" or die "Cannot create $out_color file.";

# export sprites
my $sprites_qty = ($width / 16) * $height / 16;
my $x = 0;
my $y = 0;
for(my $i = 1; $i <= $sprites_qty; $i++) {
# extract sprite layers
my $sprites = export_sprite $image, $x, $y;

# write sprite
print OUTPAT "\t; sprite $i at ($x, $y) ------------\n";
print OUTCOL "\t; sprite $i at ($x, $y) ------------\n";
for my $layer_no (0..scalar @$sprites - 1) {
print OUTPAT "\t; layer $layer_no\n";
print_sprite_patterns $sprites->[$layer_no], *OUTPAT;

print OUTCOL "\t; layer $layer_no\n";
print_sprite_colors $sprites->[$layer_no], *OUTCOL;
}

# next sprite
$x += 16;
if($x == $width) {
$x = 0;
$y += 16;
}
}

close OUTPAT;
close OUTCOL;
}

if($#ARGV < 0) {
die "Missing filename.";
}

my $file_pat = $ARGV[1] || (split /\./, $ARGV[0])[0].".pat";
my $file_col = $ARGV[2] || (split /\./, $ARGV[0])[0].".col";
export_sprites $ARGV[0], $file_pat, $file_col;


Título: Re: Conversor de sprites con bit CC
Publicado por: SapphiRe_MSX en 20 de Agosto de 2011, 06:45:57 pm
Ha funcionado a la perfección. Aujnque sólo soporta un máximo de dos sprites no creo que nadie use más con el modo mixto.

¡Genial! Yo lo que quiero es hacer algo parecido, pero que permita reordenar la paleta si es necesario. Será mi primer proyecto en Java, ya que tengo que aprender ese lenguaje.

¡¡Gracias por compartir código!!


Título: Re: Conversor de sprites con bit CC
Publicado por: samsaga2 en 21 de Agosto de 2011, 07:54:31 am
¿Como lo vas ha hacer para reordenar la paleta? Ahora mismo sólo se me ocurre probar todas las combinaciones posibles (que con 16 colores no son demasiadas).


Título: Re: Conversor de sprites con bit CC
Publicado por: MsxKun en 21 de Agosto de 2011, 10:28:55 am
Ha funcionado a la perfección. Aujnque sólo soporta un máximo de dos sprites no creo que nadie use más con el modo mixto.

Jiejie  ;D Crees mal... En el personaje de mi nuevo juego junto 3 sprites con el fin de tener 5 colores (que podrian ser 6 si quisiera).  >:D


Título: Re: Conversor de sprites con bit CC
Publicado por: SapphiRe_MSX en 21 de Agosto de 2011, 11:40:48 pm
Jiejie  ;D Crees mal... En el personaje de mi nuevo juego junto 3 sprites con el fin de tener 5 colores (que podrian ser 6 si quisiera).  >:D

De hecho podrían ser 7 colores por línea :D


Título: Re: Conversor de sprites con bit CC
Publicado por: samsaga2 en 23 de Agosto de 2011, 06:51:19 am
Ha funcionado a la perfección. Aujnque sólo soporta un máximo de dos sprites no creo que nadie use más con el modo mixto.

Jiejie  ;D Crees mal... En el personaje de mi nuevo juego junto 3 sprites con el fin de tener 5 colores (que podrian ser 6 si quisiera).  >:D

Esa paleta de colores debe dar dolores de cabeza  :griel:

Si alguien usa el conversor y cree que le será útil que soporte más de dos sprites para el color mixto que me lo diga, ya que creo que se me ha ocurrido una forma de hacerlo.


Título: Re: Conversor de sprites con bit CC
Publicado por: SapphiRe_MSX en 23 de Agosto de 2011, 08:19:04 am
¿Como lo vas ha hacer para reordenar la paleta? Ahora mismo sólo se me ocurre probar todas las combinaciones posibles (que con 16 colores no son demasiadas).

Pues son demasiadas, concretamente 20.922.789.888.000, ¡casi na! La idea sería hacer lo mismo que te indiqué, pero como no sabemos la paleta de colores, antes de analizar los colores de cada línea habría que encontrar un sistema de ecuaciones que fuese compatible.

Posiblemente con una estrategia de análisis de grafos tipo backtracking podría encontrarse una respuesta en un tiempo bastante razonable. Tendré que echarle una pensada al tema y a ver si saco un prototipo de algoritmo en haskell.


Título: Re: Conversor de sprites con bit CC
Publicado por: MsxKun en 23 de Agosto de 2011, 10:49:06 am
Ha funcionado a la perfección. Aujnque sólo soporta un máximo de dos sprites no creo que nadie use más con el modo mixto.

Jiejie  ;D Crees mal... En el personaje de mi nuevo juego junto 3 sprites con el fin de tener 5 colores (que podrian ser 6 si quisiera).  >:D

Esa paleta de colores debe dar dolores de cabeza  :griel:

Que va, solo es controlar 5 colores antes de hacer nada y tenerlo claro. A veces la forma menos complicada de hacer las cosas es, efectivamente, la menos complicada :P