jueves, 24 de diciembre de 2020

Mis proyectos abandonados ven la luz: JMusic y Flappy Adventure X

¡Feliz navidad followers! No me he olvidado de vosotros (bueno, un poquito sí) os dejo un post para acabar este increíble e inolvidable 2020 que estoy seguro de que vosotros también pensáis que ha sido el mejor año que hemos tenido nunca

Imagino que leísteis mi anterior articulo sobre mis proyectos abandonados JMusic y Flappy Adventure 3

Pues bien, ¿que ha pasao'?

JMusic:

Finalmente y gracias al tiempo libre de la cuarentena fue terminado antes de cumplir 1 año en desarrollo. No quedó muy distinta a la aplicación que visteis en el screenshot del primer articulo, y tal y como tenía planeado, se quedó para mi uso privado (de hecho la uso muy frecuentemente).

Flappy Adventure X:

Link al GitHub Descargar ISO PSX



No, no me he equivocado con el título. El proyecto de Flappy Adventure 3 tomó un cambio de rumbo para la que es la última aventura de Flappy (que ya era hora de terminar con la saga).

Todo empezó cuando me di cuenta, tras jugar de nuevo al primer Flappy Adventure web de 2015, de que la mecánica de plataformas 2D de Flappy tenía mucho potencial si se desarrollaba correctamente.

Flappy Adventure 2 es un gran juego, y lo seguirá siendo; pero un sucesor mas avanzado también en 3D conllevaría moverme a Unity, o hacer un mayor esfuerzo en Three.js.

Dicho esto, quise cumplir mi objetivo con FA3 de usar más objetos dinámicos pero en una versión 2D que me llevase menos tiempo desarrollar, y que me permitiese con una mayor calidad final. En esta ocasión ademas, quise volver a los orígenes de Flappy Adventure: las videoconsolas retro.

Pensé en la GameBoy Advance, con la cual ya había trabajado, en la Sega Genesis (descartada porque segúramente me tocase programar en ensamblador del 68000). Pero... ¿y por que no ir un paso más adelante y trabajar en un scroller 3D en una videoconsola de 5ª generación? (Sega Saturn, PSX, Nintendo 64). Descubrí (Y probé) un motor muy sencillo y facil de usar en C para la Saturn, que tenía fama de ser difícil de programar, pero me daba pereza en cualquier caso, y no hice na'... Hasta que me regalaron una PS1 chipeada... (El anterior post sobre ensamblador en PSX no fue casualidad)

La cosa había cambiado, iba a poder probar mi código en hardware real, y en una videoconsola que fue muy popular. Tras analizar los SDKs me quedé con el oficial: PSYQ. Pero la cosa solo acababa de empezar. Me iba a tocar aprender el hardware de la PS1: como trabajar con su GPU, su SPU, el lector de CD, las memory card, el GTE para los graficos 3D,...

Capitulo 1: Mis experimentos en PSX

Empecé con ejemplos chorras, como portar mi motor Voxel de GameBoy Advance a PlayStation, pero en esta ocasión con infinitos angulos de rotación. ¿¿Como?? (La PSX no va sobrada de potencia, y un motor software acaba con la poca que tiene)



Resulta que usando la GPU para dibujar la textura del mapa con rotación y escalado dentro de la VRAM, luego se puede enviar de nuevo a la CPU ¿Pero y que pasa con el mapa de profundidad? Un momento... No veis algo raro en la VRAM? Los pixeles de la textura que hemos mandado a la GPU, que supuestamente son colores de RGB555 de 15 bit, en realidad llevan 7 bits de una paleta de 128 colores, y los valores de 8 bit del mapa de profundidad.


¡La GPU aplica escala y rotación al mapa de profundidad! ¡Pero no es una textura, sino una matriz de alturas que luego enviamos de vuelta a la CPU!

Sí, he implementado un ejempo real de GPU computing en una videoconsola de hace 25 años. Aunque poco tiene que ver esto con CUDA.

Y bueno, tambien hice otros experimentos como detectar colisión en un poligono (muchas matemáticas). He aquí la m*** demo que hice, no me digais que no es hermosa:


Pero bueno, si quería hacer un entorno 3D de verdad necesitaría un motor grafico... Y ahi es donde realmente volví a crear un Flappy Engine desde 0, uno que me permitiera crear mis modelos en mi querido Google SketchUp. ¿Os he dicho ya que la PlayStation no tiene hardware para ordenar poligonos por profundidad y hay que apañarselas manualmente con el orden de los poligonos?


También creé mi propio editor de niveles, en el cual ademas del terreno y las monedas, se pueden añadir montones de objetos dinámicos con distintas propiedades. Definí mi propio formato de archivo para estos niveles de mi juego: *.LVL


Y bueno, el juego fue terminado bastante tarde, en marzo de 2021, porque lo cierto es que no me interesaba mucho ponerme a avanzarlo... Pero lo terminé, que es lo importante. A continuación para los curiosos os muestro 2 screenshots del juego en su versión beta de diciembre 2020 mostrando información de depuración.



lunes, 23 de noviembre de 2020

Tutorial hacking PSX: como usar el joypad analogico en los primeros juegos de la playstation

 Si alguna vez habéis decidido usar de nuevo vuestra PS-ONE y habeis puesto uno de los primeros juegos que salieron, os habréis dado cuenta de que si usáis el mando analógico, este no funciona. Al principio los juegos no tenían soporte porque este mando ni siquiera existía.

Entonces, ¿que pasa si queréis jugar estos juegos en hardware original y el pad digital os parece duro, o incomodo? En este tutorial de m...iercoles os enseñaré como hackear estos juegos, para que si teneis la PS con chip/swapdisk podais usar el stick analogico emulando al pad digital para mayor comodidad:

Pongamos como ejemplo uno de los juegos más vendidos, el de Tomb Rider. Al activar el modo analógico en el mando, la pantalla se oscurece, y el juego se pausa.

Tras analizar un poco que causa esto, vemos que hay una función en 0x80055514 encargada de leer la memoria mapeada al joypad, y setear un flag indicando si el dispositivo conectado es un joypad digital (0x80089580) y las teclas que hay pulsadas en este joypad digital (0x80089ca4). Vamos a modificar unicamente esta función:

Empezamos con el checkeo de joypad digital que hace que se oscurezca la pantalla cuando activas el modo analógico
Aquí vemos que se compara el id de dispositivo del joypad digital (0x04) con el id de dispositivo conectado, en este caso un joypad analogico (0x07). Por este motivo, la instruccion je no salta, setea el flag de joypad digital conectado a 0, y se salta todo el código encargado de leer las teclas.

Si cambiamos el salto condicional por uno incondicional, ahora al activar el modo analógico en el pad, el juego ya no se para y los botones funcionan (los sticks siguen sin hacer nada).
El código que sigue a continuación hace algunas cosas como comprobar que SELECT y START estan presionados simultaneamente, incrementando un contador que cuando llega a 0x31, setea un flag en memoria que termina el juego y vuelve a la pantalla de menu. Pero lo más importante, y a lo que vamos... setea distintos bits de r4 que indican las teclas que hay pulsadas, para luego escribir r4 en memoria.
Lo que voy a hacer es, antes de escribir r4 en memoria y retornar, añadir código en el que comprobamos otra vez si el mando conectado es analogico, y en ese caso leer los valores de los sticks, y si se han movido hasta cierto punto, setear los flags del pad digital con operaciones OR como se esta haciendo ya con los botones en el código de arriba.

Pero claro, para inyectar mi código necesito hueco.
"Dame hueco, que habiendo hueco ya sabre..." - Jose Mota
Pues nada, abrimos el PSX.EXE con un editor hexadecimal y buscamos hueco.

Aquí hay un hueco bien hermoso, no mu grande, pero suficiente. El EXE en este juego esta cargado a partir de 0x8000F800 así que le sumamos ese valor en el código.
Y ahora a picar código...
Ahora inyectamos el PSX.EXE modificado en la ISO original con vuestro programa favorito (yo uso psx-mode2, programa de origen español, como debe ser) y lo grabamos. ¡Y ya esta! ¿dudas? ¿comentarios? ok.




lunes, 11 de mayo de 2020

PhotoMean:

Prueba PhotoMean aquí.
Hace varios años ya hice un experimento en el cual me propuse mejorar la calidad de las fotografías realizando varias veces la misma foto, a lo que le puse el nombre de "superresolution". Este experimento no tuvo los resultados esperados, que eran incrementar la resolución aparente, pero si reducía bastante el ruido y mejoraba la calidad de las fotos.
Es por esto que he creado una nueva aplicación web que os permite hacer esto de forma automatizada: combinar varias fotos para obtener una de mayor calidad

Aquí teneis las fotos de ejemplo:

Foto original:

Foto con PhotoMean:

lunes, 30 de marzo de 2020

SQL-Experiments: experimentando queries alternativas en SQL

Como ya sabréis, el lenguaje SQL permite procesar los datos contenidos en una BDD ya sea a la hora de consultarlos, insertarlos, borrarlos, o actualizarlos.
Si queremos hacer con ellos operaciones más complejas, lo habitual es, una vez obtenidos en SQL procesarlos en Java, PHP,...
Pero... ¿hasta que punto podemos ejecutar algoritmos dentro de la propia query SQL?
Recientemente he creado un nuevo respositorio en mi Github donde subir algunos experimentos.

Para inaugurar el repositorio, he subido una query recursiva que permite ejecutar el algoritmo dinámico de Longest common subsequence problem que tambien podeis encontrar en HackerRank bajo el nombre de Commond Child. La query final para SQLite me quedó así de bonica:

WITH
INPUTS(I1,I2) AS (
 SELECT 'HARRY','SALLY'
 UNION ALL SELECT 'AA','BB'
 UNION ALL SELECT 'SHINCHAN','NOHARAAA'
 UNION ALL SELECT 'ABCDEF','FBDAMN'
),
RESULTS(I1,I2,X,Y,A) AS (
 SELECT I1,I2,0,1,'0000'
 FROM INPUTS UNION ALL
 SELECT I1,I2,
  CASE WHEN X=LENGTH(I1) THEN 0 ELSE X+1 END,
  CASE WHEN X=LENGTH(I1) THEN Y+1 ELSE Y END,
  CASE WHEN X=LENGTH(I1) THEN '0000' ELSE
  SUBSTR('0000'||(
   CASE WHEN SUBSTR(I1,X+1,1) = SUBSTR(I2,Y,1)
   THEN 1 + CAST(SUBSTR(A,1+4*(LENGTH(I1)+1),4) AS INTEGER)
   ELSE MAX(CAST(SUBSTR(A,1+4*LENGTH(I1),4) AS INTEGER),CAST(SUBSTR(A,1,4) AS INTEGER)) END
  ),-4,4) END || A
 FROM RESULTS
 WHERE NOT (X=LENGTH(I1) AND Y=LENGTH(I2))
),
FRESULTS(I1,I2,R) AS (
 SELECT I1,I2,CAST(SUBSTR(A,1,4) AS INTEGER) FROM RESULTS WHERE X=LENGTH(I1) AND Y=LENGTH(I2)
)
SELECT * FROM FRESULTS;
Sí os perdeis, tambien teneis otra query más simple que os permite generar un triangulo de pascal como en otro problema de HackerRank. La query es así de bonica:

WITH P(N,ROW,IT,REM) AS (
SELECT '1',1,1,''
UNION ALL
SELECT CASE WHEN REM='' THEN '1' ELSE N||' '|| --FIRST VALUE ALWAYS 1
 CASE WHEN instr(REM, ' ')=0 THEN REM  --IF REM ONLY HAS A NUMBER(1) CONCAT N THIS VALUE
 ELSE substr(REM, 1, instr(REM, ' ')-1) + --ELSE CONCAT SUM OF FIRST 2 NUMBERS OF REM
  CASE WHEN instr(substr(REM, instr(REM, ' ')+1),' ')=0 THEN substr(REM, instr(REM, ' ')+1) ELSE
  substr( substr(REM, instr(REM, ' ')+1),1,instr( substr(REM, instr(REM, ' ')+1),' ')-1) END
 END
END,
CASE WHEN REM='' THEN ROW+1 ELSE ROW END,
CASE WHEN REM='' THEN 1 ELSE IT+1 END,
CASE WHEN REM='' THEN N WHEN instr(REM, ' ')=0 THEN '' ELSE substr(REM, instr(REM, ' ')+1) END --POP FIRST NUMBER FROM REM / SET IT TO PREVIOUS N
FROM P
WHERE ROW<=15
)
SELECT N FROM P WHERE ROW=IT;

Y el resultado de ejecutarla es así de bonico:

1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1 7 21 35 35 21 7 1
1 8 28 56 70 56 28 8 1
1 9 36 84 126 126 84 36 9 1
1 10 45 120 210 252 210 120 45 10 1
1 11 55 165 330 462 462 330 165 55 11 1
1 12 66 220 495 792 924 792 495 220 66 12 1
1 13 78 286 715 1287 1716 1716 1287 715 286 78 13 1
1 14 91 364 1001 2002 3003 3432 3003 2002 1001 364 91 14 1
Os recomiendo ver los enlaces de los problemas y del repositorio donde se explica como están implementados. Ahora sí, esto es importante followers:
¡Sugeridme más experimentos SQL en los comentarios! ;)

domingo, 29 de marzo de 2020

Remote-Clipboard: Compartiendo portapapeles entre varios ordenadores.

Proyecto Github aquí.
Hay mucha gente que trabaja con más de un ordenador a la vez, con maquinas virtuales, etc... Y uno de los problemas a los que se enfrentan es a copiar y pegar entre distintos equipos. Cada uno tiene un portapapeles distinto, y si haces CTRL+C en un ordenador, y CTRL+Z en el otro no obtendrás ese contenido... Hasta ahora.
Con mi nuevo proyecto Java, podéis compartir a través de un servidor el contenido de vuestro portapapeles cada vez que copiais o haceis CTRL+C y actualizar en tiempo real el portapapeles de todos los equipos conectados al servidor (Se envía cifrado con AES del bueno).
¿Dudas? ¿comentarios? Veo que no XD

martes, 17 de marzo de 2020

Obteniendo la colisión de videojuegos en PSX

Proyecto de Github aquí.

Recientemente me enfrenté al proyecto de reversing más complejo que he hecho hasta la fecha, pero antes de nada os pongo un poco en contexto:

Hace ya tiempo apareció en Youtube un canal llamado "GameHut", el cual trata sobre como se desarrollaban los videojuegos antiguamente, en especial en la epoca de la SEGA Saturn/Megadrive. El dueño del canal podría ser cualquier ex-programador de esa epoca... Pero no,  sorprendentemente se trata de Jon Burton, fundador y antiguo jefe de la compañía de videojuegos Travellers Tales.
Os animo a visitar su canal de Youtube ya que es muy interesante.
Curiosamente incluso llegó a ver mi video sobre la tech-demo de TT oculta que encontré, la cual según contestó en Twitter fue desarrollada por él mismo.
Bueno, la cuestion es que yo ya conocía algunos juegos de Travellers Tales, incluyendo los de PSX que estan basados sobre todo en peliculas de Pixar, y estando familiarizado con ellos, me dió la impresión de que compartian el mismo motor de alguna manera, y había algo que siempre había tenido curiosidad, y es... ¿Se puede obtener la colisión de estos juegos de alguna forma para hacerla visible?
Pues me llevó varios días de buscar estructuras de datos en la RAM del emulador relacionadas con la colisión, mucho ensamblador MIPS (Incluso llegué a mirar por encima el funcionamiento del coprocesador de la PSX) y bueno, aunque muchas veces mirar los datos de la RAM y cambiarlos arbitrariamente te da muchas pistas, el hecho de mirar lo que hacían las rutinas de ensamblador que accedían a esas direcciones me ayudó mucho.
Pues al final lo conseguí hacer, y efectivamente el motor de colisión es prácticamente el mismo en todos los juegos de TT, con algunos pequeños cambios entre alguno de ellos, por ejemplo: en TS2 y BLSC el motor es exactamente idéntico, y al contrario que en los juegos previos, los poligonos de colisión pueden ser o bien triangulos o bien cuadrilaterios (en los anteriores solo podían ser triangulos).

Travellers Tales Collision Viewer es una aplicacion Web (Javascript) que lee SaveStates del emulador PSXE y muestra los polígonos y objetos de colisión del nivel cargado en el momento de realizar el SaveState. Tiene soporte para todos los juegos de PSX desarrollados por Travellers Tales. Se muestra no solo la colisión del nivel final, sino también la de los polígonos de prueba que se usarían durante el desarrollo y testing del videojuego ¿A que me ha quedado bonico?



Polígonos de colisión de prueba de distintos tipos, situados fuera de los limites de uno de los niveles de TS2



lunes, 16 de marzo de 2020

El rincon oscuro de Technology-Hellín: Proyectos abandonados

No todos los proyectos que hago acaban haciéndose realidad, la primera vez que pasó fue hace ya 6 años cuando estaba aprendiendo a programar (que tiempos aquellos...) la causa principal fue falta de formación. ¡Casi parece un chiste hoy en día! Que joven que era entonces y que viejo que estoy ahora :P
A día de hoy los motivos por los que puedo cancelar un proyecto son o bien falta de tiempo (tengo mucho menos tiempo libre que antes) o simplemente que tras analizarlo, no encaja. Os dejo los 2 proyectos cancelados más relevantes actualmente:

JMusic
¿Recordais la APP para Android que hice para escuchar y descargar música que se encontraba en Youtube? Finalmente fue abandonada. ¿O eso creiais?

El logotipo del nuevo JMusic

JMusic necesitaba una actualización importante para darle impulso, y eso me hizo replantearla como... Una app de música en la nube privada. ¿Que quiero decir con eso? Sería una aplicación web accesible tanto en PC, IOS, Android,... habría una biblioteca de canciones, y radios online, organizadas por categorías, sincronizada siempre en todo momento en todos los dispositivos. Ademas tendría otras cosas molonas como un portapapeles, y una lista de enlaces compartida, todo sincronizado y almacenado en la nube. La falta de tiempo y los filtros de Instagram le hicieron mucho daño a la pobre:

  • El desarrollo comenzó en Julio de 2019 una mañana de la semana que estuve de vacaciones en Benicassim (la playica). Ya tenía la idea pensada y estaba inspirado, asi que decidí empezar con el layout. Ya la continuaría durante mi tercera semana de vacaciones en Hellín
  • El desarrollo continuó a la vuelta de mis segunda semana de vacaciones, en Asturias, concretamente desde el asiento trasero del coche (el viaje era largo y estaba aburrido) empecé a meterle JavaScript y mas cosicas. Al final de ese mismo día descubrí que me habían aceptado dentro de la beta de SparkAR para crear filtros de Instagram. Era una oportunidad muy importante para mi, para destacar y dar a conocer mis creaciones. JMusic podía esperar, y se quedó en el olvido.
  • Navidades 2019-2020: habían pasado 6 meses, JMusic, mi proyecto en el cual seguía pensando muchas veces, seguía en un estado de desarrollo... Ya os podeis imaginar. Durante todas las vacaciones solo le dediqué 2 mañanas a continuarlo un poco.

¡Y ya esta! Es una APP privada (En principio la estoy haciendo para mi mismo, dudo que nadie quiera probarla) y por lo tanto siempre acabo dándole prioridad a cualquier otra cosa. Eso la esta condenando. Mi intención es que acabe saliendo a la luz algún día, aunque es mi proyecto que lleva más tiempo a mitad de desarrollo.


Flappy Adventure 3 (FA3)

No es un secreto que desde niño siempre quise crear mi propio videojuego 3D. Lo conseguí con FA2 en menos de una semana sin ninguna experiencia previa en diseño de videojuegos 3D. Un año después, tras ser portado a Realidad Virtual (VR), lo tenía claro: con más tiempo, y con la experiencia obtenida, podría hacer un videojuego muy decente, con montones de objetos dinamicos y su propio editor. Empecé con la tormenta de ideas para la 3ª entrega de la saga FA:
  • Seguiría usando la librería Three.js pero esta vez crearía un Flappy Engine desde 0, en el que por una parte crease el modelo de SketchUp (Esta vez los objetos del modelo tendrían propiedades como distancia de dibujado,colisión, apariencia metalizada,..) y por otra parte los objetos dinámicos del nivel se cargarían aparte en un JSON que tambien contendría propiedades como el spawnpoint. Estos objetos tendrían su propio modelo SketchUp y su .js con su código propio, el cual aceptaría parámetros. Habrían muchos mas objetos dinámicos que en FA2, y algunos se crearía para un único nivel en concreto.
  • Para añadir los objetos dinamicos en los niveles junto a sus propiedades (parámetros, como por ejemplo color, velocidad,...), así como para comprobar el rendimiento, número de poligonos, y la correcta visualización (Los objetos tendrían una distancia de dibujado para mejorar el rendimiento y FPS respecto a FA2, donde siempre estaban cargados todos los elementos del nivel) se dispondría de un editor, donde uno se pudiera mover libremente, insertar objetos, colocarlos, y modificar sus propiedades. Estos cambios se podrían comprobar inmediatamente llamando al HTML del juego con el JSON generado como parametro de la URL.
  • En esta entrega se transportaría al jugador a una historia, igual que se hizo en la primera entrega de FA en la que flappy fue en busca de su pareja que finalmente resultó haber sido secuestrada por los Angry Birds. En este caso la historia sería mucho más profunda, con muchos niveles, dialogos,... Terminar cada nivel sería parecido a cuando terminas de ver el capitulo de una serie, que quieres ver como sigue. Se contempló la idea de poder manejar tanto a Flappy como a su pareja (rosa) con distintos poderes cada uno.
  • La jugabilidad sería parecida a la de FA2, es decir, se dispondría de un numero limitado de saltos en el aire y habría que intentar no chocar contra las paredes. 
  • Para FA3 habría pensado utilizar cel shading, que traducido al cristiano significa que la apariencia del videojuego sería como de dibujos animados. Este tipo de renderizado es poco frecuente, y habría llamado la atención. Se ha usado en juegos como Jet Set Radio.
  • El juego habría sido en 3ª persona, puesto que haría mas fácil visualizar la posición de Flappy, y recibí muchos comentarios en FA2 de que "si estaba jugando al Minecraft" solo por el hecho de ser un juego en primera persona.
Lamentablemente, aun anotando todas estas ideas (y otras relacionadas con el código), cancelé el proyecto sin ni siquiera haberlo empezado a desarrollar. Los motivos fueron:
  • Ya existen gran cantidad de juegos Indie con un gran nivel.  La recepción del juego muy probablemente sería nula. Sería hacer el juego para mi solo.
  • El hecho de hacer un motor de 0, me llevaría mucho tiempo existiendo ya herramientas como Unity.
  • Apenas tengo tiempo libre ahora con el trabajo, y por lo menos la mitad de ese tiempo prefiero pasarlo AFK.

domingo, 12 de enero de 2020

Filtro de video mediana: CPU vs GPU

¡Feliz año nuevo chic@s!
Todo empezó cuando decidí crear un filtro de mediana para vídeo, el cual por ejemplo FFMPEG no incluye...
Pero empecemos por el principio... ¿En que consiste el filtro de mediana? Pues es un filtro de reducción de ruido para imagenes en el que para cada pixel, se busca junto a sus pixeles cercanos el que tenga el valor de la mediana.
En el caso de las imagenes en escala de grises es muy sencillo determinar este valor, pues solo tienen un canal con un brillo que pasa de 0 (negro absoluto) a 255 (blanco absoluto), pero en el caso de las imagenes a color, lo que hice fue sumar los valores r+g+b para obtener una luminancia aproximada sin hacer demasiados calculos, y es que uno de los problemas del filtro de mediana para imagenes es que es bastante lento.

Filtro de la mediana en acción: (Abrir imágenes para ver mejor)
Pues teniendo esto en cuenta, me puse a implementar mi código para calcular la mediana en imágenes RAW (RGB) en lenguaje C. Una vez que para cada pixel he obtenido el array con su valor y el de sus cercanos, para obtener la mediana hay que ordenarlos. Tras probar varios algoritmos de ordenación (no todos) el que mejor funcionó fue el insertion sort, y es que aunque suele ser malo ordenando arrays grandes, funciona bien cuando estos son pequeños (ej: en la mediana de 5x5 solo hay 25 elementos) y aunque tal vez no sea el mejor, era suficiente.

Pues tras compilar mi código con optimizaciones de compilador al máximo, y al ejecutarlo usando los 8 cores de mi Intel i5 de 8ª generación (8 hilos), los resultados con un video en HD (1280x720) de 300 frames fueron bastante lentos... La mediana de 3x3 no llegaba a 22 fps, y la de 5x5 que era la que más me interesaba no llegaba a 11fps. Esto en uno de los procesadores más actuales.

Pues iba a dejarlo así como estaba, cuando revisando las caracteristicas de mi portatil, recordé que contaba con una GPU NVIDIA MX130, que aunque es normalilla, nunca había llegado a programar sobre GPU y tenía curiosidad de si era capaz de ejecutar el mismo algoritmo y en cuanto tiempo.
Pues resulta que es posible ejecutar código en la GPU, para ello existen dos opciones: OpenCV (funciona para cualquier GPU de cualquier fabricante) y CUDA (solo para NVIDIA). Yo me decanté por CUDA en esta ocasión.


Pues me puse a aprender un poco sobre como se programaba en CUDA... y tras ejecutar el código equivalente en la GPU los resultados fueron los siguientes:


En esta ocasión la GPU no solo era capaz de ejecutar el mismo código, sino que además lo hacía más rápido. ¡Ya alcanzaba los 25 fps! y ademas usando la mediana de 5x5. Si comparamos la salida de ambos proyectos, vemos que es idéntica.


Si entramos en detalles tecnicos, la GPU es capaz de ejecutar hasta 2048 hilos simultaneos repartidos en distintos bloques. En mi implementación usé bloques de 8x8 hilos en los que cada hilo procesaba un único pixel. La imagen original la copio a la memoria global de la GPU (rápida) puesto que cada pixel iba a ser leido por más de 1 hilo, mientras que la imagen resultante era escrita directamente en memoria de la CPU (esto es denominado Zero Copy) puesto que aunque estos accesos son más lentos, esta memoria solo se accedía una vez por pixel para escribir el resultado y evitamos tener que copiar luego la memoria de la GPU a la CPU.


miércoles, 28 de agosto de 2019

API de geolocalización de Google y sus peligros

Pongámonos en una de las siguientes situaciones:

  • Eres un gran hacker: el p*** amo hackeando redes WI-FI y decides compartir capturas de pantalla/tutoriales de como usas Aircrack-ng o similares
  • Estas usando una aplicación para analizar redes wifi cercanas ya sea en PC o smartphone (Ej: Acrylic WI-FI) y compartes capturas de pantalla de la aplicación
  • Compartes las direcciones MAC de routers WI-FI cercanos de cualquier otra forma (Ej: te engañan mediante ingeniería social)
Suponemos que de alguna de estas formas compartimos las direcciones MAC de routers WI-FI cercanos y las hacemos publicas, no las tachamos ni ocultamos. ¿Que puede pasar?

Comprobamos lo fácil que es encontrar gente compartiendo esta información a través de la red social Instagram, donde comparten por ejemplo capturas de Airodump-ng.
Bueno, pues sin saberlo están compartiendo el lugar donde están/viven/hacen cosas malas. ¿como es posible?

Esto es gracias a la API de geolocalización de Google, la cual mediante las señales de los WI-FI y triangulación permite ubicarnos geográficamente a pesar de no tener GPS. ¿habeis probado alguna vez a pedirle a Google Maps vuestra ubicación desde PC? notaréis que os localiza con gran precisión.

Y es que solo hace falta saber unas pocas direcciones MAC de routers cercanos y Google ya es capaz de localizar la posición con un error de 10-50 metros. ¿Notáis el peligro?
Vamos a probarlo. Ejecutamos la siguiente petición con los datos de 3 direcciones MAC que hemos obtenido en un post de Instagram:
Y obtenemos la siguiente respuesta:
Si añadimos mas direcciones MAC aumentaremos la precisión, aunque con solo 3 ya tenemos un radio de error de tan solo 37 metros.
Ahora buscamos las coordenadas en Google Maps (o Bing Maps o donde querais) y voilà! localizado.
Os animo a jugar un poco con esto y a localizar a distintos jaquers ;)
(SIN IR CON MALAS INTENCIONES)

sábado, 10 de agosto de 2019

Mis filtros AR de Instagram

¡Es una realidad! Formo parte de la beta AR de Facebook, lo que me permite no solo desarrollar sino también publicar filtros AR para las historias de Facebook e Instagram.
Seguramente si sois usuarios de Instagram hayáis seguido alguna cuenta por el hecho de que al seguirla os aparecen nuevos filtros para las historias. Bueno, pues ahora yo también soy una de esas pocas personas, de hecho en España probablemente no seamos ni 50 (En realidad no tengo ni idea, aunque en los grupos solo participa gente extranjera).
Pero hay un problema: no tengo manera de promocionarme, y esta última semana apenas he ganado entre 10 y 20 nuevos seguidores y todos son guiris, así que aquí estamos de nuevo... Otro intento fallido de convertirme en influencer tras el fracaso de mi canal de Lloutuve, y el #UnfollowProjectFest (En realidad este último si que tuvo bastante exito).
En fin, en el primer vídeo podéis ver como son mis primeros filtros, y en el siguiente podéis ver un experimento AR cutre que hice en un par de horas en el que puedo controlar un coche RC virtual superdetallado diseñado en mi querido Google Sketchup (Sí, sigo usando la versión 8, la última que hizo Google).

Resumen:
Spiral: Genera una espiral en movimiento alrededor del cuerpo (varios colores para elegir, se puede cambiar el tamaño pellizcando la pantalla)
Puzzle: Convierte la imagen de la cámara en un puzzle de tamaño a elegir (3x3 - 4x5) que se mezclará y resolverá con movimientos aleatorios que serán cada vez distintos.
Frame: La imagen de la camara aparece en un pequeño rectangulo, circulo, o rombo con 3 colores a elegir (tocando la pantalla se cambian, pellizcando la pantalla se cambia el tamaño)
Malefica: Te convierte en la villana de moda de Disney
Lovely: Aparecen corazones detrás de ti y aplica un filtro rosado.
Mirrors: La imagen de la cámara aparece 4 veces haciendo zoom en zonas aleatorias de la pantalla
OldTV: Simula el efecto pixelado y curvo de los antiguos televisores CRT
Construction: Como el Minecraft pero en AR
Noise: Aplica ruido aleatorio a la imagen. (Se puede variar la intensidad)
Nebulosa: Combina la imagen de la cámara con la de distintas nebulosas que se pueden cambiar tocando la pantalla
Dithering: Aplica pixelado Dither a la imagen de la camara. Se puede cambiar el color y el tamaño de los pixeles pellizcando la pantalla LEDStarIG: La versión descafeinada de mi efecto LEDStar en Facebook en la que no se puede escribir texto personalizado. Versión de FB: https://www.facebook.com/fbcameraeffe...
Heather: Aplica distintos colores con la intensidad deseada sobre la imagen
CelShading: Aplica efecto posterizado a la imagen
Mosaic: La imagen de la camara aparece formada por pequeñas versiones coloreadas de la imagen de la cámara que cambian de tamaño al abrir la boca
Area51: Te convierte en un alien. Si en la cámara hay una segunda persona, la convierte en un alien aun más feo.
LeTRIX: letras verdes que caen que nada tienen que ver con una película conocida y por lo tanto no hay problemas de derechos de autor.
JustMe: Aplica distintos efectos al fondo detrás de ti: Blanco y negro, desenfoque, lineas horizontales, etc...
SpaceLander: 3 niveles de aterrizaje lunar. Girar la cabeza para girar la nave, y abrir la boca para propulsar
NotHuman: Aquí tampoco estoy mencionando ninguna peli de Holliwood. Como curiosidad que nadie ha notado, si cierras el ojo izquierdo se apaga la luz roja.
Fantasy: Efectos de color fantasiosos. Si tocas la pantalla se intensifican
LaserEyes: Cerrando los ojos se activa y desactiva el laser. Tocando la pantalla se cambia el color
TearDrops: Te hace llorar de lo cutre que es el filtro. Abriendo la boca se intensifican las lagrimas (una versión mejorada iba a ser subida pero los moderadores de Facebook no ven bien un filtro en el que sales llorando)
LoveShooter: Otro juego para pasar el rato. Comentad abajo hasta que puntuación habeis llegado. No me hago responsable si os partis el cuello por el nivel 74 (La velocidad sube cada vez más y no he puesto límite por lo que a partir de 50 ya es practicamente imposible). Ahh si, teneis que girar la cabeza para mover la mira y mantenerla 1 segundo en los corazones para hacerlos desaparecer
Thug-Life: Cierra los ojos y veras unas gafas pixeladas caer.

jueves, 28 de marzo de 2019

CTurtle: una buena forma de aprender C con la tortuga de LOGO

Ver CTurtle en mi GitHub
Es posible que algunos conozcáis el lenguaje de programación LOGO, puesto que se enseña/enseñó en algunas escuelas para empezar a aprender programación. Consiste en un lenguaje de programación donde básicamente mueves una tortuga con un lápiz en un entorno gráfico, con comandos como hacer avanzar la tortuga (fd) o hacer girar la tortuga (rt, lt). Esto esta muy bien, pero tiene un inconveniente: una vez dominas el lenguaje, no te va a servir para nada más aparte de mover la tortuga.
Aparte de esto, la mayoría de los interpretes de LOGO son antiguos, no tienen antialising en el dibujado, e incluso algunos ni siquiera son compatibles con los procesadores de 64 bit actuales.
Pues aprovechando estas vacaciones de navidad, he creado una librería para C muy fácil de utilizar que os permitirá hacer dibujicos de la misma manera que se hace en LOGO en el lenguaje de programación C.
Esta librería consta únicamente de 2 archivos turtle.cturtle.h aparte de la librería SDL, y tiene una implementación propia de antialising (En la cual dediqué gran parte del tiempo) y es compatible con Windows, Linux (Incluyendo Raspberry Pi), e imagino que en Mac también.

Ej:
El programa de la imagen sería el siguiente:

#include <stdio.h>
#include "turtle.h"
void fern(int size, int sign);
void fern(int size, int sign)
{
if (size<1) return;
t_penSize(size/4);
t_forward(size);
t_turnRight(70*sign);
fern(size/2,sign*-1);
t_penSize(size/4);
t_turnLeft(70*sign);
t_forward(size);
t_turnLeft(70*sign);
fern(size/2,sign);
t_penSize(size/4);
t_turnRight(77*sign);
fern(size-1,sign);
t_turnRight(173*sign);
t_penUp();
t_forward(size*2);
t_penDown();
t_turnLeft(180);
}
int main(int argc, char ** argv)
{
if (t_init(640,480,window)!=0) puts("Init error");
else {
t_autoframeOff();
t_moveSpeed(200);
t_turnSpeed(0);
t_penUp();
t_goTo(192,450);
t_setAngle(0);
t_penDown();
t_turColor(0,60,0);
fern(25,1);
t_frame();
t_saveBMP("fern.bmp");
t_idle();
}
}

Aparte de las instrucciones básicas como t_forward y t_turnRight también tenemos otras instrucciones opcionales como t_autoframeOff, t_moveSpeed y t_turnSpeed relacionadas con la animación, y otras instrucciones de utilidad interesantes como t_saveBMP que guarda en un archivo BMP el contenido de la pantalla.
La librería esta totalmente documentada en cualquier caso. Si aun así tenéis dudas o sugerencias, me las podéis comentar por aquí.