https://www.segasaturno.com/portal/viewtopic.php?f=33&t=7676&p=79417#p79417 ----------------------------------- Ryo Suzuki 21 Junio 2014, 03:18 AM Re: Trasteando con el Lua Player de Saturn (Tutorial) ----------------------------------- Muy buenas amijos, amantes de la Saturn. Por aquí sigo con mi pequeño curso de programación con el SLP (Saturn Lua Player) del gran Rockin'-B. Le voy echando un vistazo de vez en cuando en los momentos en que las obligaciones me lo permiten. Ir escribiendo en este post con estas particulares "lecciones" me obliga de alguna forma a seguir y a plasmar lo que voy aprendiendo. En ocasiones me cuesta bastante avanzar ya que no hay practicamente nada de documentación de este port del player para Saturn, el original como ya habré comentado era para [url=http://www.luaplayer.org/]PSP. Los ejemplos que vienen apenas estan comentados y son de un nivel ya bastante alto, rollo lo que le puede parecer fácil a Rockin'-B :mrgreen: , además me da la nariz que está pensado para gente que ya se maneja desarrollando para la Saturn con el Orbit y quiera saltar a este SLP... está claro que yo no tenía ni idea :| [b]Virtual LUA[/b] Bueno, hoy vamos a poner polígonos en pantalla. Me ha costado lo suyo conseguir averiguar cómo se hace con este Lua Player. He conseguido entender y separar qué es lo que hace cada cosa de los ejemplos hasta poder aislar la parte de poner una figura poligonal en pantalla. También he conseguido usar figuras poligonales que no estaban en los samples, e incluso exportar modelos tridimensionales que pueda hacer yo mismo con un software 3D gratuíto, como es el [b]Blender[/b]... Pero el tema es bastante complicado, así que hoy explicaré sólo cómo se hace de forma relativamente simple, desde uno de los ejemplos y ya en futuros posts veréis cómo lo hago compilando mis propios datos de modelos poligonales que también nos servirá para otras cosas como sprites y demás. Vamos a coger el ejemplo de la carpeta samples llamado [b]S_3_2[/b]. Con el objetivo, como ya dije, de aprovechar el modelo poligonal de este ejemplo y no tener que hacer todo el proceso de crear e importar el modelo 3D por nosotros mismos. Copiamos la carpeta S_3_2 haciendo un duplicado y le cambiamos el nombre por otro que nos guste más y que la diferencie (yo he puesto [b]POLIGONEO[/b]). Ya que hemos clonado ese sample para editarlo vamos como es habitual a editar el código de Lua que está almacenado como siempre en [b]0_orig.lua[/b]. Abrimos ese archivo con el notepad y nos preparamos para crear nuestro propio código, os iré guiando. [b]Intermedio[/b] Hablando del notepad. Es algo que os quería recomendar, es preferible usar un editor de texto más orientado a temas de programación que son mucho más visuales y tal ya que reconocen las cosas y las organizan mejor para que de un vistazo identifiquemos con más comodidad el código. Ahora estoy utilizando uno que se llama [b]CODEMAX[/b] y que os recomiendo. Es gratuito: http://codemax.luaforge.net/ Fijaos como se ve el código ahora con este editor: [img]http://www.segasaturno.com/portal/files/images/2/codemax_lua.jpg[/img] Mucho más visual y ordenado con los colores para diferenciar cada cosa, ahora siempre usaré este CodeMAX para código del Lua Player. [b]Poniendo Polígonos en pantalla[/b] Vamos al grano y a dejarnos de intermedios. Hoy, para innovar un poco, lo voy a hacer del revés. Primero pongo el código linea a linea comentado y luego adjunto todo el código final para que lo copiéis/peguéis a 0_orig.lua y lo probéis o trastéis con él modificando, o lo que queráis. Vamos allá. Empezamos: [code linenumbers=false]--/*----------------------------------------------------------------------*/ --/* Primeros poligonos en pantalla */ --/*----------------------------------------------------------------------*/[/code] Primero pongo un comentario con el título y tal... (como ya aprendimos con los --) Seguimos con: [code linenumbers=false]local ang, pos = {}, {}[/code] Esto es nuevo, declaramos de esta manera un tanto especial estas variables con valores vacios. ang y pos parecen ser varibales globales ya predefinidas y si no hacemos esto nos saltará un error diciéndonos que intentamos indexar un valor nil. Un valor nil en Lua es: [quote]Nil es el tipo del valor nil, cuya principal propiedad es ser diferente de cualquier otro valor; normalmente representa la ausencia de un valor útil.[/quote] O para que nos quede más claro: [quote]Nil is a type with a single value, nil, whose main property is to be different from any other value. As we have seen, a global variable has a nil value by default, before a first assignment, and you can assign nil to a global variable to delete it. Lua uses nil as a kind of non-value, to represent the absence of a useful value.[/quote] Creo que lo que estamos haciendo con [b]local ang, pos = {}, {}[/b] es decir que esas variables globales(me parece que aunque las pongamos no son locales) las vamos a asignar un valor y no van a ser nil. El caso es que si no hacemos esto tendremos este error (podeis intentar omitir esta linea y vereis lo que sucede...):roll: P.D: Como habréis supuesto, [b]ang [/b]se refiere a [b]angulo[/b] mientras [b]pos[/b] hace referencia a la [b]posición[/b]. Dos valores importantes de nuestro primer modelo poligonal que vamos a mostrar en pantalla. Seguimos con esto: [code linenumbers=false]slInitSystem(TV_320x224,NULL,1)[/code] Vale, nada nuevo bajo el sol. Inciamos el sistema con la resolución y demás como ya tenemos masterizado de otras lecciones. Continuamos con más cosas nuevas: [code linenumbers=false]ang.X = DEGtoANG(20.0) ang.Y = DEGtoANG(22.0) ang.Z = DEGtoANG( 5.0) pos.X = 5.0 pos.Y = 8.0 pos.Z = 190.0 [/code] Quedaos con la copla que la variable [b]ang[/b] tiene tres subvalores por así decirlo. En las coordenadas Y, Z y X. No solo eso, sino que se definen con algo que parece propio de las libreías de SEGA, ese [b]DEGtoANG()[/b] y el valor entre los parentesis del ángulo. Le hemos dado 20 grados en X, 22 en Y y 5 en el eje Z. Nuestro modelo poligonal estará girado en esos angulos esos grados cuando se vea en screen por primera vez. Luego tenemos la variable [b]pos[/b], que volvemos a ver que el tema de que al definirla con el . detrás podemos asignarle varias subvariables, si no entiendo mal. En este caso, como comprenderéis se trata de la posición de la pantalla en la que aparecerá nuestro objeto poligonal Saturnero. Podéis cambiar esos valores luego para hacer pruebas de colocación como he hecho yo. El tema parece ir, en el eje de la X si le das un valor positivo es hacia la derecha, 0 es el centro, etc... En el eje de la Y un valor negativo es arriba, positivo abajo, evidentemente. El el eje de la Z un valor positivo implica enviar el objeto más atrás, negativo traerlo hacia adelante. Pero no quiero alejarme con explicaciones, continuo con mi código: [code linenumbers=false]local datoscd = GFS_Load_name("DATA.BIN", 0, CPU_WRAM_LO, CPU_WRAM_LO_LEN)[/code] Otra cosa nueva a la par que interesante e importante. Creamos la variable llamada [b]datoscd[/b] y le decimos que es igual a un archivo del CDROM que le obligamos a cargar justo en ese momento que la declaramos y que como veis se llama [b]DATA.BIN[/b]. Efectivamente, si vais al ejemplo os dareis cuenta que entre los archivos, además de nuestro querido [b]0_orig.lua[/b], [b]0.bin[/b] (que creo que no lo he comentado pero es el binario que lee la Saturn primero y hace de interprete y ejecuta nuestro código .lua) y demás files está precisamente [b]data.bin[/b]. Como imaginaréis, en ese archivo está la información matemática de nuestro modelo polígonal que vamos a mostrar en este ejemplo. Ya os daré más explicaciones de cómo es su estructura y demás pero ahora sigo adelante... Bien, es la primera vez que cargamos algo desde CD. Hasta ahora nuestro código solo se ejecutaba a sí mismo y no hacía uso de otros recursos. Pero en un futuro tendremos que cargar imagenes, modelos polígonales, música y demás cosas... así que no os habrá extrañado. Vamos a mirar con un poco de detalle qué he hecho y trato de explicarlo en la medida de lo posible. [b]GFS_Load_name("DATA.BIN", 0, CPU_WRAM_LO, CPU_WRAM_LO_LEN)[/b] Ok, [b]GFS_Load_name[/b] es parte del manejo de files del Cd de las librerías de la Saturn. Nada que ver con Lua, ya os lo digo. [b]GFS_[/b] ese prefijo hace referencia a manipulación del CDROM de la 32 bits de SEGA. Va seguido en este caso de[b] Load_name[/b], que no hace falta ser muy listo para adivinar que lo carga en memoria sin ejecutarlo, como los loads de toda la vida (os acordáis de las cintas del Spectrum :mrgreen: ) O sea, le estamos diciendo que cargue DATA.BIN y que lo meta en [b]0, CPU_WRAM_LO, CPU_WRAM_LO_LEN[/b]. Esto puede sonar más a marcianada, pero yo entiendo que lo emplaza en la posición 0, WRAM debe ser algo así como working ram si mi intuición no me falla y veo que hay LO y LO_LEN, que deber ser con len referido quizás a longitud (length). Y LO pues igual algo así como LOW, vete tú a saber que a demasiado llego... jeje Bien hecho, hemos cargado el archivo DATA.BIN que contiene nuestros poligonos en la ram de la Saturn, está listo para ser llamado y ser puesto en pantalla, cuando sea necesario. [code linenumbers=false]if datoscd == nil or datoscd <= 0 then slPrint("Error cargando DATA.BIN desde el CD!", 2, 15) end[/code] Esto puede parecer un poco paranoico, pero es lo suyo. Los condicionales nos iban a valer para muchas cosas como anticipé. Aquí lo que hago es comprobar si el archivo del CD lo ha cargado bien la Saturn. Imaginaos yo que sé.. que por cualquier cosa falle la carga (CD no lee bien, etc...) es un mensaje de error que estaría bien mostrar. Como apreciaréis le estamos diciendo que si la variable [b]datoscd[/b] tiene un valor nil(que ya hemos aprendido lo que es) o es igual o menor que 0 -lo que significaría que no ha cargado el archivo porque por poco que pese en la RAM no será nil ni igual o menor que 0- entonces nos imprima en pantalla avisándonos que ha habido un problema con la carga del archivo desde el CDROM. Esto en principio nunca lo veremos pero saldría esto si llega a suceder: [img]http://www.segasaturno.com/portal/files/images/2/error_loading.jpg[/img] Si sois muy puntillosos podeis montar la iso quitando DATA.BIN o cambiar el nombre o lo que sea y comprobaréis que funciona como es debido. Así nos cercionamos con este condicional que la Saturn cargue bien el archivo en su ram desde el CD. Sigo, que me estoy enrrollando como una persiana pero es que es inevitable ya que hay muchos conceptos nuevos: [code linenumbers=false]local CUBOMODELO = CPU_WRAM_LO[/code] Aquí lo que estoy haciendo es creando la variable [b]CUBOMODELO[/b] que va a ser nuestro modelo poligonal -y si no lo he dicho ya por su nombre intuiréis que se trata de un cubo en 3D- y la asigno a la [b]CPU_WRAM_LO[/b]. Como decía antes debe ser la working ram en la que acabamos de cargar el archivo data.bin. En esta ocasión es porque en [b]data.bin [/b]solo está nuestro modelo poligonal del cubo, en un futuro os enseñaré que puede contener más cosas y entonces será algo más complicado llamarlo y saber en qué posición de la RAM se encuentra. En ese caso, lo que hago es decirle a la Saturn que lo que tienes en la ram que acabas de cargar desde el CDROM es mi CUBOMODELO. Prosigo: [code linenumbers=false]slPrint("Primeros poligonos" , 9, 2) slPrint("Saturn Lua Player tutorial", 9, 3) slPrint("by Ryo Suzuki", 9, 4) slPrint("www.segasaturno.com", 9, 5)[/code] No es necesario explicar el autobombo que ya conocemos, ¿verdad? [code linenumbers=false]while true do slPushMatrix()[/code] De acuerdo, lo meto en el bucle principal del programa que va mostrar el cubo con el "while sea verdad", que va a ser siempre, haz todo esto que te detallo a continuación... Empezamos con [b]slPushMatrix()[/b] [quote]slPushMatrix Temporary storage of matrix (up to 20 matrices can be nested)[/quote] Vale, sé que los temas 3D tienen que ir sobre una matriz. [quote]This function advances the matrix buffer pointer, copies the previous current matrix to the stack, and makes that the new current matrix. If pointer allocation failed, the function returns the FALSE value. Up to 20 matrices can be nested in the buffer. If an attempt is made to nest more than 20 matrices in the matrix buffer, the function returns the FALSE value.[/quote] Buff, da un poco de miedo. Yo no quiero 20, de momento con una me vale. Es inevitable y necesitamos tener la matriz. NOTA: Os sonará igual de temas de programación el stack o pila de ejecución. [url=http://es.wikipedia.org/wiki/Pila_(inform%C3%A1tica))]Aquí teneis más info, pero parece claro que con este [b]slPushMatrix[/b] estamos apilando esta matriz. Seguimos ya casi para bingo: [code linenumbers=false]slTranslate(pos.X,pos.Y,pos.Z)[/code] Otro nuevo comando de las librerías de SEGA. Como podréis intuir lo traslada a una posición. Más que trasladar en este caso es el punto inicial en cuanto a posición en el cual estará nuestro objeto 3D. Fijaos que son las variables que pusimos antes (5 en el eje de la x, 8 en el de la Y y 190 en el eje Z), pero no pueden ser expresadas con números directamente sino que hay que asignarlo así. Es necesario definir esto, de lo contrario la Saturn no sabría donde poner nuestro cubo poligonal en pantalla. Más: [code linenumbers=false] slRotX(ang.X) slRotY(ang.Y) slRotZ(ang.Z)[/code] Esto es opcional, que quede claro. Pero como ya veríais venir de antemano ibamos a rotarlo x grados en los tres ejes, que para algo hicimos antes las variables!! Sega nos dice (o mejor dicho les decía a los pobres programadores profesionales que en su día lidiaban con el infernal sistema) sobre este comando: [quote]slRotX Description: Adding rotation around X axis to current matrix Format: void slRotX(angx) ANGLEangx; Parameters: angx Angle of rotation around X axis FunctionThis function multiplies an X axis rotation matrix with the current matrix. The rotation matrix is expressed below[/quote] Como comprenderéis [b]slRotY [/b]y [b]slRotZ[/b] hacen lo propio en sus respectivos ejes. El caso es que giro un poco el cubo en esos ángulos no solo por capricho, sino también para que se vea mejor. De lo contrario, saldría completamente recto y solo veriamos una cara, que sería muy triste para nuestro primer modelo 3D en pantalla :twisted: Y ya por fin: [code linenumbers=false]slPutPolygon(CUBOMODELO)[/code] Argghh! Que valle de lágrimas. Finalmente ponemos nuestro modelo poligonal de un cubo en pantalla. En esas posiciones que hemos definido en los ejes x,y,z y con los angulos en x,y,z también. El comando[b] slPutPolygon[/b] como su propio nombre indica pone el polígono, entre parentesis está nuestra variable CUBOMODELO que como recordaréis es el archivo DATA.BIN, con los datos de geometría del cubo de marras que tenemos cargado en la ram de la consola. Ya finalizo, hay que cerrar el bucle y darle a la matriz caña: [code linenumbers=false] slPopMatrix() slSynch() end[/code] Con [b]slPopMatrix()[/b] he hecho la operación inversa de lo que hice antes con slPushMatrix, es decir, retirar (o desapilar, con pop) del stack. [b]slSynch() [/b]es el pan nuestro de cada código con la sincronización con el evento. Y por último el [b]end[/b] del bucle while en el que le habiamos metido, que no se nos puede olvidar. Y ya lo tenemos. Generamos la iso y vamos a ver esto: [img]http://www.segasaturno.com/portal/files/images/2/poligonos_lua.jpg[/img] Disfrutad como si no hubiese un mañana de ese cubito 3D que está mostrando la Saturn, jaja. Nuestro -o mejor dicho, mi- primer objeto poligonal puesto en la screen con bastante sudor con este Lua Player. Os pongo el código completo, ahora ya está debidamente explicado todo: [code linenumbers=false]--/*----------------------------------------------------------------------*/ --/* Primeros poligonos en pantalla */ --/*----------------------------------------------------------------------*/ local ang, pos = {}, {} slInitSystem(TV_320x224,NULL,1) ang.X = DEGtoANG(20.0) ang.Y = DEGtoANG(22.0) ang.Z = DEGtoANG( 5.0) pos.X = 5.0 pos.Y = 8.0 pos.Z = 190.0 local datoscd = GFS_Load_name("DATA.BIN", 0, CPU_WRAM_LO, CPU_WRAM_LO_LEN) if datoscd == nil or datoscd <= 0 then slPrint("Error cargando DATA.BIN desde el CD!", 2, 15) end local CUBOMODELO = CPU_WRAM_LO slPrint("Primeros poligonos" , 9, 2) slPrint("Saturn Lua Player tutorial", 9, 3) slPrint("by Ryo Suzuki", 9, 4) slPrint("www.segasaturno.com", 9, 5) while true do slPushMatrix() slTranslate(pos.X,pos.Y,pos.Z) slRotX(ang.X) slRotY(ang.Y) slRotZ(ang.Z) slPutPolygon(CUBOMODELO) slPopMatrix() slSynch() end[/code] Como os decía al principio, sigo investigando y ya sé como poner otros modelos de distinas procedencias e incluso creados por mi mismo, pero eso ya os lo cuento otro día porque para ilustrar esta pequeña tontería me ha dado mucho trabajo para que quede entendible y claro así que temo lo que puede ser lo otro... Espero que haya sido fácil para vosotros, para mi con la documentación que había... no lo fue :lol: [b]Fase Bonus[/b] No, no me refiero al programa de nuestros amigos. Me parece que queda un poco desangelado el cubo ahí tan triste en pantalla. Vamos a moverlo un poco con lo que hemos aprendido en otros ejemplso de sumar valores a variables dentro de un bucle. En su momento podía parecer una parida, pero ahora nos viene bien porque lo trasladará y rotará en el bucle del while. Añadid esto despues del [b]slPutPolygon(CUBOMODELO)[/b] [code linenumbers=false] pos.X = pos.X+0.1 ang.Z = ang.Z+10 ang.X = ang.X+40[/code] Luego ya el slPopMatrix() y demás como estaba en el código de antes... Con eso la liamos parda porque lo desplazamos lentamente hacia la derecha (el eje de las X, valores positivos cada vez más) y lo rotamos algo más rápido en el eje de la z y de la x, para que podamos ver todas sus caras con diferentes colores y tal... Además, apreciaremos que la Saturn falla más que una escopeta de feria a la hora de mostrar polígonos, por lo visto. ¿Es cosa mía o hay bastantes errores de perspectiva y cosas raras? Os pongo la iso directamente por si la quereis bajar y probar en el emulador para ver cómo se mueve y me contais. [img]http://www.segasaturno.com/portal/files/images/2/cubista_lua.jpg[/img] Eso es todo por hoy. ¿Da mucho miedo y nadie se atreve a trastear con el Lua de Saturn? 8)