Lecciones de Programación en TIGCC


La siguiente es parte de una serie de lecciones diseñadas para ayudarle a aprender cómo programar en C para las calculadoras TI-89, TI-89 Titanium, TI-92+ y Voyage 200 en el ambiente de desarrollo TIGCC.

Ésta no es la primera lección, así que se harán algunas suposiciones con el fin de hacer esta lección tan sencilla como sea posible.
  1. Usted ha leído, o al menos entendido los conceptos presentados en las lecciones previas.
  2. Usted sabe cómo construir o generar (compilar y enlazar) proyectos utilizando TIGCC y probarlos utilizando VTI o TiEmu.
  3. Usted sabe cómo buscar información en la documentación de TIGCC para tener otros puntos de referencia.
Si lo desea, puede descargar el código fuente del programa, el archivo del proyecto, y los archivos binarios aquí.

Lección 3: Una Introducción a los Gráficos


Paso 1 - Información Acerca de la Pantalla de las Calculadoras TI-68k


La TI-89 (Original o Titanium), Ti-92+ y Voyage 200 operan todas en formas muy similares. Todas tienen una sección de memoria utilizada para controlar la visualización en pantalla. La memoria tiene 240 bits * 128 bits de tamaño, representando 240 pixeles de ancho por 128 pixeles de alto, las cuales son las dimensiones de pantalla de la TI-92+ y la Voyage 200. Las TI-89 tienen el mismo bloque de memoria, pero utilizan solamente los primeros 160 pixeles de cada fila, con 100 pixeles de altura. Entonces, aunque los programas pueden utilizar la memoria extra sin causar ningún daño, no será mostrada en pantalla.

Cubriremos dos tipos de información visualizada en la pantalla: líneas y "sprites". Las líneas fueron alguna vez muy importantes para programas sencillos, porque los sprites eran mucho más complicados en ensamblador, pero ahora no son tan importantes como antes. No obstante, son un buen punto de partida para entender los fundamentes de la visualización. En el otro ejemplo, trataremos con sprites, y cómo manipularlos en su forma sencilla (no enmascarada). Sprites avanzados (enmascarados) serán cubiertos en una lección futura.

Cuando usted escriba sus programas, trate de recordar las diferencias de pantalla entre las TI-89 y las Ti-92+/Voyage 200, si quiere que sus programas sean compatibles con todas estas calculadoras. Como las TI-89 son un poco más comunes, puede escoger desarrollar programas para la pantalla de la TI-89, pero utilizar variables de teclado para que sean compatibles con todas las calculadoras. Esta no es una solución ideal, pero permitirá que sus programas se ejecuten en ambas calculadoras sin requerir modificaciones. Usted siempre podrá convertir después el programa para que corra mejor en la pantalla de las TI-92+/Voyage 200.

Paso 2 - Dimensiones de Pantalla y Dibujo de Líneas


En este ejemplo, borraremos la pantalla y luego dibujaremos líneas en posiciones seleccionadas aleatoriamente en la pantalla con longitudes y ángulos variables.

Inicie TIGCC y cree un nuevo proyecto. Cree un nuevo Archivo Fuente de C (C Source File) y llámelo lineas.c. Guarde el proyecto en un subdirectorio llamado leccion3. Modifique el archivo lineas.c para que se vea como el código que sigue:



// C Source File
// Created 12/18/00; 3:44:14 PM
// Updated 8/22/2002; 10:47 PM

#include <tigcclib.h>

// Main Function
void _main(void)
{
	int x1, y1, x2, y2;
	int ciclo;

	// planta el generador de números aleatorios
	randomize();
	
	// borra la pantalla
	ClrScr();
	
	// despliega el texto de introducción
	DrawStr(0, 0, "Prueba de Líneas 1.0", A_NORMAL);
	DrawStr(0, 10, "Presione Cualquier Tecla", A_NORMAL);
	DrawStr(0, 20, "Presione ESC para salir", A_NORMAL);
	
	while (ngetchx() != KEY_ESC) {
		// borra la pantalla
		ClrScr();
	
		// ejecuta este bucle 10 veces (0-9 = 10)
		for (ciclo = 0; ciclo < 10; ciclo++) {
			// escoge coordenadas aleatorias para la línea
			x1 = random(LCD_WIDTH);
			y1 = random(LCD_HEIGHT);
			x2 = random(LCD_WIDTH);
			y2 = random(LCD_HEIGHT);
		
			// dibuja la línea en las coordenadas aleatorias
			DrawLine(x1, y1, x2, y2, A_NORMAL);
		}
	}
}


Paso 3a - Compilar y Ejecutar el Programa


Los cambios están de nuevo en el método _main(). Genere el proyecto y envíe el programa al emulador. Se verá algo similar a lo siguiente, pero como estamos dibujando líneas seleccionadas aleatoriamente, no será exactamente igual, por supuesto:

TI-89 lineas.89z TI-92+, Voyage200 lineas.9xz, lineas.v2z

Paso 3b - Analizar el Programa


El programa introduce varias funciones nuevas y un nuevo tipo de bucle: el bucle for. Es el programa más grande que hemos creado hasta el momento, así que asegúrese de que entiende las lecciones 1 y 2, porque las necesitará para entender esta.
int x1, y1, x2, y2;
int ciclo;
No hemos hablado realmente de esto de manera específica, pero las declaraciones de variable son muy flexibles. Podemos declarar variables del mismo tipo en la misma línea, o en líneas diferentes. Algunas veces resulta conveniente agrupar variables por su función. En vista que tenemos dos categorías de variables, que llamaré las variables de línea (las variables 'x sub i' y 'y sub i'), y la variable ciclo (utilizada para el nuevo bucle for). La mayoría de gente que escribe programas en C utiliza variables críptica y pobremente nombradas. No hay nada de malo en esto excepto porque es difícil de entender para otras personas, y eventualmente, usted mismo puede confundirse con su significado. Para evitar esto, siempre intentaré utilizar nombres de variables descriptivos. Aparte de esta breve cuestión, usted sabe cómo declarar variables enteras, y eso es todo lo que estamos haciendo aquí. Además, de nuevo no declaramos valores para las variables. Serán inicializadas por las funciones y comandos que las utilizarán después en el programa.
// planta el generador de números aleatorios
randomize();
Esta es una de las funciones utilizadas para generar números aleatorios. Debemos tener lo que llamamos una 'semilla' para ayudarnos a calcular los números 'aleatorios'. (En realidad son pseudo-aleatorios, pero usted no notará la diferencia). Esta función captura un número de uno de los temporizadores de la calculadora para plantar el generador de números aleatorios con él. Todo lo que usted necesita saber es que debe llamar siempre la función randomize() para asegurarse de no utilizar la misma semilla. Teniendo en cuenta que las calculadoras no tienen relojes integrados, estas semillas pueden ser las mismas en ocasiones, pero la probabilidad de que eso ocurra es extremadamente baja, así que no se preocupe mucho por esto. Si necesita asegurarse de que los números aleatorios no sean nunca los mismos, debe utilizar un método diferente o plantar el generador con la función srand(), pero en este caso tenemos muy poca necesidad de ese tipo de precisión, así que no voy a estudiarla aquí.
// borra la pantalla
ClrScr();
Notará que esta función no es la 'clrscr()' que hemos empleado en ejemplos anteriores. Esto se debe a que no estamos utilizando la biblioteca stdio (entrada/salida estándar) en este programa, pues clrscr() es parte de la biblioteca stdio, y realiza manejos especiales para esa biblioteca. ClrScr() simplemente borra la pantalla, y es una función integrada al TIOS, directamente por la gente de TI. Esto quiere decir que es más pequeña que la función clrscr(), la cual debe reiniciar la posición de despliegue para los comandos printf() además de borrar la pantalla. Sólo recuerde que ClrScr() y clrscr() no son lo mismo, y que si usted no está utilizando funciones printf() de la biblioteca stdio, debería utilizar ClrScr() en lugar de clrscr() ya que así ahorra espacio. Si utiliza funciones printf(), entonces debe usar clrscr() para reiniciar la posición de despliegue, lo cual es necesario en ese caso.
// despliega el texto de introducción
DrawStr(0, 0, "Prueba de Líneas 1.0", A_NORMAL);
DrawStr(0, 10, "Presione Cualquier Tecla", A_NORMAL);
DrawStr(0, 20, "Presione ESC para salir", A_NORMAL);
Hemos vuelto a utilizar DrawStr para este programa.
while (ngetchx() != KEY_ESC) {
	// borra la pantalla
	ClrScr();
Aquí está la primera parte del bucle while. Usted ha visto cosas similares a ésta antes, pero para refrezcar su memoria, la condición es, mientras el valor retornado por la función ngetchx() no sea igual a la tecla ESC, ejecute el cuerpo del bucle.

Vemos también que el primer comando en el cuerpo del bucle while es el comando ClrScr(), que como hemos visto arriba, borra la pantalla.
// ejecuta este bucle 10 veces (0-9 = 10)
for (ciclo = 0; ciclo < 10; ciclo++) {
	// escoge coordenadas aleatorias para la línea
	x1 = random(LCD_WIDTH);
	y1 = random(LCD_HEIGHT);
	x2 = random(LCD_WIDTH);
	y2 = random(LCD_HEIGHT);
		
	// dibuja la línea en las coordenadas aleatorias
	DrawLine(x1, y1, x2, y2, A_NORMAL);
}
Este es un nuevo tipo de bucle. Ya hemos visto que los bucles 'while' evalúan la condición, y ejecutan el cuerpo del bucle (recuerde que el cuerpo está contenido dentro de las llaves { }) mientras la condición sea verdadera. Cuando ya no sea más verdadera, el bucle while detiene la ejecución del cuerpo, y el programa continúa.

Los bucles 'for' son un poco diferentes. En lugar de evaluar una condición, la función de un bucle for es ejecutar un grupo de sentencias cierto número de veces. Los bucles for en realidad sí tienen condiciones, pero son secundarias a la naturaleza principal del bucle for.

La sintaxis del bucle for es como sigue. for (variable = valor inicial; variable es algo con respecto a un valor; cambio de la variable) { // haga algo aquí }. Lo que esto significa es sencillo. Tenemos una variable, la cual nos dirá cuando ejecutar el ciclo. El bucle for controla la inicialización de la variable, la condición de prubea y el cambio de la variable de forma que el bucle sólo sea ejecutado algunas veces.

for (ciclo = 0; ciclo < 10; ciclo++) { } significa: dele a la variable 'ciclo' el valor inicial de 0. Entonces, mientras el valor de la variable 'ciclo' sea menor que el valor '10', ejecute el cuerpo del bucle. Al final de cada ejecución del cuerpo del bucle, incremente el valor de la variable 'ciclo' en uno. Sencillo, ¿no?

Los bucles for son una de las construcciones de programación más poderosas en C, y una vez que usted le coja el tiro a la sintaxis, son fáciles de utilizar y entender. Sólo recuerde las tres partes básicas de la construcción for:
  1. Inicializar la variable
  2. Verificar la condición.
  3. Cambiar la variable al final de cada ciclo.
La construcción del bucle for que hemos empleado es probablemente la más común. Iniciamos la variable en 0. Comparamos su valor con uno más alto. Entonces incrementamos su valor. Veremos otros tipos de bucles for en lecciones futuras.

Ahora continuemos con el cuerpo del bucle.
// escoge coordenadas aleatorias para la línea
x1 = random(LCD_WIDTH);
y1 = random(LCD_HEIGHT);
x2 = random(LCD_WIDTH);
y2 = random(LCD_HEIGHT);
Estas cuatro sentencias son sentencias de asignación. Aquí capturamos valores aleatorios (para esto fue que utilizamos la función randomize() al comienzo) y los asignamos a las coordenadas.

La función random() selecciona un número aleatorio entre 0 y x - 1, donde x es el argumento que usted le pasa a la función random(x). Esta función retorna este número seleccionado aleatoriamente. Entonces la sentencia x1 = random(LCD_WIDTH); selecciona un número aleatorio entre 0 y LCD_WIDTH (que está definido para ser 160 en las TI-89 y 240 en las TI-92+/Voyage 200) - 1 y asigna este número a la variable x1. Esto nos da las coordenadas de la primera posición en x. La sentencia y1 = random(LCD_HEIGHT); selecciona un número aleatorio entre 0 y LCD_HEIGHT (que es igual a 100 en la TI-89 y 128 en la TI-92+/Voyage 200) - 1 y asigna ese número a la variable y1[1]. Repetimos este proceso para obtener (x2, y2). Ahora tenemos los valores de dos puntos, que serán los extremos de una línea.
// dibuja la línea en las coordenadas aleatorias
DrawLine(x1, y1, x2, y2, A_NORMAL);
Esta función, que está integrada en el TIOS, dibuja una línea entre dos puntos definidos por los extremos (x1,y1) y (x2,y2). El último argumento es una configuración de atributo. Una línea estándar es A_NORMAL, pero hay muchas otras configuraciones. Puede leer más acerca de éstas en la documentación de TIGCC[2]. DrawLine() está definida en archivo de cabecera graph.h.

Paso 2c - Conclusiones Programáticas


Este programa nos dio una introducción a muchos conceptos nuevos (algunos de ellos gráficos) acerca de los gráficos y la compatibilidad entre pantallas de las calculadoras TI-89/92+/V200. Aunque las ilustraciones gráficas fueron simples dibujos de líneas, usted puede apreciar el sistema basado en pixeles de la pantalla, y teniendo en cuenta que es tan pequeña, puede también aprecir cómo cada pixel cuenta, así que debe aprovechar cada uno.

Un trabajo mucho más relevante del sistema gráfico está contenido en el siguiente ejemplo de sprites simples.

Continúe con la Parte II



Notas:


[1]: Las expresiones LCD_HEIGHT y LCD_WIDTH son pseudo-constantes, es decir, macros definidas para que parezcan y actúen como constantes. Sus valores están definidos en el archivo de cabecera 'compat.h' y corresponden a la altura de la pantalla en pixeles y al ancho de la pantalla en pixeles respectivamente. Por lo tanto, tendrán valores distintos para las TI-89 (Original o Titanium) y las TI-92+/Voyage 200, tal como se ilustra en el texto.

[2]: Los atributos que pueden ser utilizados con la función DrawLine y su significado son los siguientes:



Copyright © 1998-2004 Techno-Plaza
Copyright por la Traducción y las Notas © 2006 Camilo Rodríguez