Generador de gráficos ondulados

Started by carles, February 10, 2016, 09:46:13 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

carles

Debido a las quejas constantes de PiXeL de que mis algoritmos gráficos consumen mucha cpu, que son incompatibles con su librería de multijugador en red local y que no se que problema pasa con PixTudio... al final en la última Global Game Jam hice una modificación para que en vez de ondular el gráfico cada frame se generase los png para su posterior uso. Como eso fue algo puntual me he decidido a hacerlo definitivo.

¡He aquí la forma final del algoritmo de ondulación de gráficos!¡El Ondulatron!

Instrucciones:
En las constantes están las variables para seleccionar el gráfico(Archivo) y la carpeta de destino(Destino).
Teclas V y H para cambiar eje de giro a Vertical u Horizontal.
Teclas Q y W para incrementar/reducir el radio, en pixeles.
Teclas A y S para incrementar/reducir la velocidad angular, en milésimas de grado.
Teclas Z y X para incrementar/reducir el desfase, en milésimas de grado.
Teclas E y R para incrementar/reducir el porcentaje de corrección, es para mantener un lado quieto.
Tecla Intro para generar los gráficos.
Tecla Esc para salir.


program Ondulatron;


import "mod_map";
import "mod_proc";
import "mod_say";
import "mod_text";
import "mod_video";
import "mod_math";
import "mod_key";


const
archivo="fuego.png";
destino="ondular/";
vertical=0;
horizontal=1;
end


process main();


private
angulo; //angulo del giro
distancia; //longitud del eje de giro
desfase; //defase
grafico; //id del gráfico
radio; //radio de giro
float r_cor;//radio de giro de correción
float r_inc;//incremento del radio de correccion
omega; //velocidad angular
delta; //incremento del desfase
eje; //eje de giro: vertical u horizontal
correccion; //indica si los extremos deban estar quietos
exportar; //indica si esta exportando
n; //variable auxiliar para la exportación
end

begin
set_mode(800,600,32);
write(0,0,0,0,"fps");
write_var(0,50,0,0,fps);


say("Instrucciones");
say("V y H para cambiar eje de giro");
say("Q y W para incrementar/reducir el radio");
say("A y S para incrementar/reducir la velocidad angular");
say("Z y X para incrementar/reducir el desfase");
say("E y R para incrementar/reducir la correccion");
say("Intro para generar el grafico");
say("Esc para salir");

x=400;
y=300;
grafico=load_png(archivo);
eje=vertical;
radio=10;
write(0,0,10,0,"radio");
write_var(0,50,10,0,radio);
omega=5000;
write(0,0,20,0,"omega");
write_var(0,50,20,0,omega);
delta=20000;
write(0,0,30,0,"delta");
write_var(0,50,30,0,delta);
write(0,0,40,0,"correccion");
write_var(0,70,40,0,correccion);
exportar=false;
loop
if(eje==vertical) //eje vertical
graph=new_map(radio*2+graphic_info(0,grafico,g_wide),graphic_info(0,grafico,g_height),32);
angulo=desfase;
if(correccion==0)
r_cor=radio;
else
r_cor=0;
r_inc=radio/(graphic_info(0,grafico,g_height)*abs(correccion)*0.01);
end
if(correccion > 0)
from distancia=0 to graphic_info(0,grafico,g_height);
map_block_copy(0,graph,radio+get_distx(angulo,r_cor),distancia,grafico,0,distancia,graphic_info(0,grafico,g_wide),1,0);
angulo-=omega;
if(r_cor < radio)
r_cor+=r_inc;
end
end
else
from distancia=graphic_info(0,grafico,g_height) to 0 step -1;
map_block_copy(0,graph,radio+get_distx(angulo,r_cor),distancia,grafico,0,distancia,graphic_info(0,grafico,g_wide),1,0);
angulo-=omega;
if(r_cor < radio)
r_cor+=r_inc;
end
end
end
else //eje horizontal
graph=new_map(graphic_info(0,grafico,g_wide),radio*2+graphic_info(0,grafico,g_height),32);
angulo=desfase;
if(correccion==0)
r_cor=radio;
else
r_cor=0;
r_inc=radio/(graphic_info(0,grafico,g_wide)*abs(correccion)*0.01);
end
if(correccion > 0)
from distancia=0 to graphic_info(0,grafico,g_wide);
map_block_copy(0,graph,distancia,radio+get_disty(angulo,r_cor),grafico,distancia,0,1,graphic_info(0,grafico,g_height),0);
angulo-=omega;
if(r_cor < radio)
r_cor+=r_inc;
end
end
else
from distancia=graphic_info(0,grafico,g_wide) to 0 step -1;
map_block_copy(0,graph,distancia,radio+get_disty(angulo,r_cor),grafico,distancia,0,1,graphic_info(0,grafico,g_height),0);
angulo-=omega;
if(r_cor < radio)
r_cor+=r_inc;
end
end
end
end
desfase+=delta;
if(desfase>360000)
desfase-=360000;
if(exportar==true) exit(); end
end
if(exportar==false)
if(key(_v)) eje=vertical; end
if(key(_h)) eje=horizontal; end

if(key(_q)) radio++; end
if(key(_w)) radio--; end
if(radio < 0) radio=0; end

if(key(_a)) omega+=500; end
if(key(_s)) omega-=500; end

if(key(_z)) delta+=500; end
if(key(_x)) delta-=500; end

if(key(_e)) correccion++; end
if(key(_r)) correccion--; end
if(correccion > 100) correccion=100; end
if(correccion < -100) correccion=-100; end

if(key(_enter))
exportar=true;
write(0,0,60,0,"Exportando");
say("Exportando");
angulo=0;
desfase=0;
end

if(key(_esc)) exit(); end
end
if(exportar==true)
png_save(0,graph,destino+n+".png");
n++;
end
frame;
unload_map(0,graph);
end
end




panreyes

¿Ves? Te lo dije. Mis quejas sirven para algo xD

Y el problema con PixTudio era el coste de crear, actualizar y destruir el mapa constantemente, sobre todo al principio cuando era de 1920x1080 xD

Drumpi

Le tendré que echar un vistazo, pero ¿crear, actualizar y destruir? ¿por qué no crear, crear, crear... y volver a usar, volver a usar, volver a usar?
O mejor aún, como se tiene acceso al buffer del map, se crea un mapa más grande, con la imágen y bandas negras a los lados (en caso de que la ondulación sea lateralmente), y se realizan desplazamientos de bytes, que es mucho más rápido que map_block_copy y similares... si es que en PiXTudio aun se tiene acceso al buffer del map :P
Hala, como con 1001 procesos sólo va a 9 FPS, vamos a meterle 32 veces más, a ver si revienta.
(Drumpi epic moment)

carles

Quote from: Drumpi on February 11, 2016, 12:36:56 AMLe tendré que echar un vistazo, pero ¿crear, actualizar y destruir? ¿por qué no crear, crear, crear... y volver a usar, volver a usar, volver a usar?

El objetivo de esta nueva versión es esa, crear los gráficos para su posterior uso. He descartado el hacerlo esto en el propio código por que es incompatible con el multijugador en red local desarrollado por PiXeL. Y porque guardar en memoria veinte copias de un gráfico de 1940x1080 me parece una burrada.


Quote from: Drumpi on February 11, 2016, 12:36:56 AMO mejor aún, como se tiene acceso al buffer del map, se crea un mapa más grande, con la imágen y bandas negras a los lados (en caso de que la ondulación sea lateralmente), y se realizan desplazamientos de bytes, que es mucho más rápido que map_block_copy y similares... si es que en PiXTudio aun se tiene acceso al buffer del map :P


Esta parte me ha sonado así: 或者更好的,因為你有機會來緩衝圖,大圖被創建,對雙方的形象和黑條(如果紋波橫向),以及他們執行字節偏移,這是多少比 map_block_copy 和類似更快...如果在 PiXTudio 甚至可以訪問緩衝器地圖 :P .
Perdona Drumpi pero esos conceptos son demasiado avanzados para mi.


Drumpi

A ver, intentaré ser más claro:
Un mapa se guarda en memoria como un array de datos. No sé seguro si los primeros valores son los datos de cabecera (ancho y alto de la imágen, profundidad de color, etc...), pero después vienen una serie de valores que son los bytes/words/ints de cada pixel (según si trabajamos con un mapa de 8b, 16b o 32b). Al ser valores de un array en memoria, acceder a ellos es mucho más rápido que las funciones GET y PUT de BennuGD/PiXTudio (que acceden al render de video, bla bla bla).

Teniendo esto claro, necesitamos poder desplazar los pixels hacia la izquierda o a la derecha, que consiste en desplazar los valores de los bytes tantas posiciones como sea necesario (si movemos el valor de la 5ª posición a la 4ª, lo desplazaremos a la izquierda, pero si lo movemos a la 6ª será a la derecha; para desplazarlo hacia arriba habría que desplazarlo tantas posiciones hacia la izquierda como columnas tenga la imágen). No sé si alguna vez has visto cómo se almacenan en la memoria RAM realmente los valores de un array bidimensional.

Como no queremos que al desplazar los valores un pixel hacia la izquierda se pierda el valor de la primera posición (se le sobreescribiría la de la segunda), lo ideal es que el mapa tuviera una columna extra vacía de pixels a la izquierda (de, paso, evitamos que los valores de la primera columna acaben en la última columna, es decir: en una imágen de 3x3, la primera posición es la 0, y el pixel de la coordenada (0,1) se encuentra en la posición 3, pero si lo pasamos a la posición 2, entonces se dibujará en la coordenada (2,0)).
Lo mismo pasaría al mover los pixels a la derecha, necesitamos otra columna a la derecha. Entonces, si el efecto ondulante mueve los pixels un total de 8 pixels a izquierda y derecha, necesitamos 8 columnas vacías a izquierda y derecha (las franjas negras a los lados que mencionaba en el mensaje anterior).

Si te sigue sonando a chino, coge papel cuadriculado. Pinta un cuadrado de 4x4 y numera las casillas de izquierda a derecha, y de arriba a abajo, igual que lees un texto, y luego escribe esos números en el mismo orden en una línea. Haz otro cuadrado de 4x4, pero al escribir los números, empieza por el segundo que tengas en esa línea y verás que te sobra un hueco al final, pero las tres primeras columnas serán iguales que las tres columnas de la derecha del primer cuadrado. Has hecho un desplazamiento de todo el mapa a la izquierda.
No sé si queda más claro ^^U
Hala, como con 1001 procesos sólo va a 9 FPS, vamos a meterle 32 veces más, a ver si revienta.
(Drumpi epic moment)

carles

Gracias Drumpi me ha quedado todo más claro, pero sigo teniendo el mismo problema: son conceptos demasiado avanzados para mi y no sabría aplicarlos a la práctica.

Drumpi

Bueno, pues por si te animas a investigar:
http://wiki.bennugd.org/index.php?title=Map_buffer
;)

Y ya sabeis que si me pillais libre, os puedo echar una mano con el código (si teneis un mapa del mismo :P).
Hala, como con 1001 procesos sólo va a 9 FPS, vamos a meterle 32 veces más, a ver si revienta.
(Drumpi epic moment)