Introducción a la programación gráfica en C




descargar 139.48 Kb.
títuloIntroducción a la programación gráfica en C
página1/4
fecha de publicación27.08.2016
tamaño139.48 Kb.
tipoPrograma
med.se-todo.com > Documentos > Programa
  1   2   3   4

Cursos / Stratos-ad.com
Introducción a la programación gráfica en C

Introducción a la programación gráfica en C
Autor: Unknown 2000

· Capítulo 1. Introducción.

· Capítulo 2. Configuración del compilador.

· Capítulo 3. Inicialización del modo gráfico.

· Capítulo 4. La paleta no es una moza de pueblo.

· Capítulo 5. Pantallas virtuales.

· Capítulo 6. Tablas pregeneradas.

· Capítulo 7. Carga de imagen en crudo.

· Capítulo 8. Introducción a las 3D.

· Capítulo 9. Sprite y animación.

· Capítulo 10. El scroll.

Capítulo 1.

Introducción.

¡Hola! Aquí comienza un nuevo curso de introducción a la programación gráfica, desde el principio sin descafeinar y cómo no, cortesía de Unknown, este curso/tutorial esta orientado a todos los que no tenéis ni "pa-pa" del asunto y deseáis introduciros en el mundillo del pixel-por-pixel. El contenido del mismo se dará entero en C y en el modo 320x200, (nada de Visual Java++ 6.0 para programar chips 3DFX)  ;-) aunque incluiremos una rutinilla en ensamblador, que será incorporada como función "nomepreguntesporellaquetodavíanotengonipajoleraideadeensamblador".

Cómo no, no nos hacemos responsables de los daños producidos por el uso del código incorporado en esta página web, vamos, que si tu perro observa unos bonitos pixels de color amarillo en la pantalla y se cree que su cajón de arena para hacer sus cosas es tu monitor y te lo enjuaga, no nos culpes por ello, la responsabilidad del uso de nuestras rutinas corre por tu cuenta.  Y sin mas preámbulos empezamos...
Capítulo 2.

Configuración del compilador.
Muuuy importante si estáis usando TurboC o BorlandC y queréis usar tres librerías a las que haremos referencia al final, en la opción Options del menú->Compiler->Code Generation->hay otra ventana que se abre con el botón More...->Advanced Code Generation colocar Floating Point : 80287 (o superior) y Instrucción Set : 80286 (o superior). Para el uso de código en ensamblador (a partir de la parte 2), deberéis tener en el path el TASM y en la opción Transfer del compilador.
Capítulo 3.

Inicialización del modo gráfico.

Llegó el momento tan esperado, el principio y ¿cómo comenzamos ? Antes de nada tiraremos a la basura las BGI, librerías de C de modo gráfico o como lo queramos llamar, ya que estas librerías son peliiiiiin lentas e intentaremos ir creando nuestras propias funciones y procedimientos.

Lo primero que vamos a hacer es "enchufar" el modo gráfico, esto lo haremos gracias a la interrupción 10h de la BIOS del ordenador (una interrupción es un conjunto de macros en ensamblador, cada interrupción suele servir para una cosa, servicios del dos 21h,operaciones con disco,modo de vídeo, uso del ratón, etc. A cada interrupción a la vez se le asocian una serie de servicios que son las distintas rutinas que podemos usar). Usaremos la activación del modo 320x200 con 256 colores que es el servicio 13h :

void SetMCGA()
{
_AX=0x0013 ;
geninterrupt(0x10) ;
}

Para volver al modo texto usamos la misma interrupción 10h, sólo que el servicio 03h :

void SetText()
{
_AX=0x0003 ;
geninterrupt(0x10) ;
}

Vale, ya he entrado en modo gráfico ¿y ahora qué? Ahora toca pintar pixels en la pantalla, esto lo podremos hacer de dos modos :
1º) bien llamando a la interrupción 10h , o bien
2º)escribiendo directamente en memoria
Marear a la BIOS consume bastante tiempo con lo que optaremos por lo segundo, el acceso directo a memoria, hay que decir que la tarjeta lo que hace para dibujar la pantalla es volcar el contenido de los 64000 pixels ==(320x200) de la memoria, cuyo inicio esta situada en la dirección 0xA000 ,cada pixel es un byte (=char) que puede tener los valores 0-255 (0-FF).

unsigned char *vga=( unsigned char *) MK_FP(0xA000,0) ;
void PutPixel(int x,int y, unsigned char col)
{
memset(vga+x+(y*320),col,1) ;
}

El procedimiento PutPixel es crítico ya que si tenemos que realizar una animación a pantalla completa en la cual los colores de los pixels procedan de un cálculo matemático esto significa pintar 64000 pixels por pantalla o sea 64000 llamadas a la función por cada vez que tengamos que ir redibujando la pantalla por lo que el tener esta función optimizada al máximo es vital.
Lo ideal sería tener su contenido en ensamblador optimizado (calculando ticks de reloj y usando las instrucciones que menos ciclos de reloj consumen), esto se sale del propósito de nuestro cursillo de introducción ,sin embargo para los que siempre queréis mas, más adelante os daremos la dirección de una pagina web donde podréis encontrarla optimizada a tope .

Otro procedimiento imprescindible es el de limpiado de pantalla, que no es más que llenar la pantalla de pixels de un color.

void Cls(unsigned char col)
{
memset(vga,col,0xffff) ;
}

y con estas tres prácticas funciones podemos crear nuestro primer programa :

#include
#include
#include
#include
#include
#include

unsigned char *vga=( unsigned char *) MK_FP(0xA000,0) ; //dirección de la memoria de vídeo

void SetMCGA(void) ;
void SetText(void) ;
void PutPixel(int x,int y, unsigned char col) ;
void Cls(unsigned char col) ;

void main(void)
{
int i,j ;
randomize() ;
SetMCGA() ;
Cls(0) ; //limpiamos la pantalla con el color 0=negro.

for(i=100 ;i<200 ;i++) //pintamos un rectángulo (100,50)->(200,100) con pixels de colores aleatorios
{
for(j=50 ;j<100 ;j++)
{

PutPixel(i,j,random(255)) ;

}

}

getch() ;
SetText() ;
}

void SetMCGA()
{
_AX=0x0013 ;
geninterrupt(0x10) ;
}

void SetText()
{
_AX=0x0003 ;
geninterrupt(0x10) ;
}

void PutPixel(int x,int y, unsigned char col)
{
memset(vga+x+(y*320),col,1) ;
}

void Cls(unsigned char col)
{
memset(vga,col,0xffff) ;
}

Capítulo 4.

La paleta no es una moza de pueblo.

Bueno, aquí andamos con la siguiente entrega del curso de programación gráfica, ahora llega la pregunta vital , los colores aleatorios del programa de la parte 1 no eran demasiados, sólo eran 256, qué co##nes hago si necesito pintar por ejemplo en una demo una bonita pantalla de degradados de rojo o azules turquesa o qué co##nes, ¿ qué pasa si los colores que tengo no los aguanto y quiero otros ? Muy sencillo, para ello modificamos la paleta, aquí viene como diría Jesulin el intrínguli de la cuestión , la vga era capaz de generar 256K (262.100 y pico) colores pero debido a la limitación de memoria la vga sólo podía mostrar 256 colores simultáneamente, la vga cuando manda un color de un punto al monitor en realidad lo que le está mandando no es color en sí (o sea, la señal del valor del byte) sino lo que le manda son las componentes R,G,B (rojo verde y azul) de ese byte en cuestión ,vamos, en cristiano, cada uno de los 256 colores tiene 3 componentes: una R o roja, otra G o verde y otra B o azul; el valor de cada componente puede variar entre 0-63, con lo que existen 256K posibles combinaciones de R G B (64*64*64), por ejemplo una paleta cuyos 256 colores vengan con valores G=0 B=0 y R aumentando un valor cada cuatro colores sería una paleta de degradados de rojos, las paletas "continuas" son fundamentales a la hora de hacer demos y muchos efectos de estos se basan en una correcta organización de la misma.

Os estaréis preguntando ¿ y dónde se "modifica" la paleta ?, pues tenemos tres hermosos puertos :

para leer el color el 0x03c7, en el cual se selecciona el color a leer y a continuación se leen los tres valores del puerto 0x03c9.

para escribir el color el 0x03c8 y a continuación escribimos los tres valores de RGB en 0x03c9.

Ahí van unos cuantos procedimientos :

Leemos las componentes R,G ,B de un color.

void GetCol(unsigned char colorno,unsigned char *R,unsigned char *G,unsigned char *B)
{
outp(0x03c7,colorno) ;
*R=inp(0x03c9) ;
*G=inp(0x03c9) ;
*B=inp(0x03c9) ;
}

Establecemos las componentes R,G,B de un color.

void SetCol(unsigned char colorno,unsigned char R,unsigned char G,unsigned char B)
{
outp(0x03c8,colorno) ;
outp(0x03c9,R) ;
outp(0x03c9,G) ;
outp(0x03c9,B) ;
}

ahora por ejemplo con estos procedimientos podríamos construir efectos interesantes como un fundido a blanco o FadeUp :

void FadeUp()
{
int loop1,loop2 ;
unsigned char R,G,B ;

for(loop1=0 ;loop1<64 ;loop1++) //63 es el máximo de iteraciones como mínimo el color puede ser negro
{ //R=G=B=0
WRetrace() ;

for(loop2=0 ;loop2<256 ;loop2++) //para cada uno de los 256 colores
{
GetCol(loop2,&R,&G,&B) ;
if(R<63) R++ ; //vamos aumentando R,G y B R=63,G=63 y B=63 corresponde al blanco
if(G<63) G++ ;
if(B<63) B++ ;
SetCol(loop2,R,G,B) ;

}

}

}

hemos incluido una llamada a WRetrace que es el siguiente procedimiento :

void WRetrace()
{
_DX=0x03DA ;
l1 : asm {
in al,dx ;
and al,0x08 ;
jnz l1 ;
}

l2 : asm {
in al,dx ;
and al,0x08 ;
jz l2 ;
}
}

JAAAAAL QUE ES ESTORRRR EN ENSAMBLADORRRR.... muy faaasssil , es un procedimiento que espera al retrazado vertical del monitor ,"que vale tío pero ¿qué es eso del retrazado vertical del monitor ?". Esta rutina se queda "enganchada" hasta que el haz de electrones del tubo de rayos catódicos termina de pasar por toda la pantalla.

¿por qué co#ones, para qué hay que esperar a que pase el haz del tubo de la pantalla ?, pues muy fácil: para que la pantalla no parpadee, esto es a costa de algo de pérdida de tiempo de ejecución, sin embargo esta "espera" tiene una ventaja y es que en ordenadores con monitores parecidos, el programa ira igual de rápido ya que se queda "enganchado", por ejemplo ejecutando el FadeUp en un Pentium III a 450 Mhz ultima generación si le quitamos la espera al retrazado el cambio de la paleta sería tan rápido que no nos daría tiempo a apreciarlo, mientras si mantenemos el retrazado el cambio de la paleta iría mas o menos igual de rápido en un 486 a 100 con un monitor de 60Hz que en nuestro nuevo y flamante PIII con el mismo monitor a 60 Hz.

Ahora en vez del fundido a blanco lo mismo pero en fundido a negro :

void FadeDown()
{
int loop1,loop2 ;
unsigned char R,G,B ;

for(loop1=0 ;loop1<64 ;loop1++) //63 es el máximo de iteraciones como máximo el color puede ser blanco
{ //R=G=B=63
WRetrace() ;
for(loop2=0 ;loop2<256 ;loop2++) //para cada uno de los 256 colores
{

GetCol(loop2,&R,&G,&B) ;

if(R>0) R-- ; //vamos disminuyendo R,G y B R=0,G=0 y B=0 corresponde al negro

if(G>0) G-- ;

if(B>0) B-- ;

SetCol(loop2,R,G,B) ;

}

}

No os habréis muerto precisamente del estrés producido por el cambio de FadeUp a FadeDown, todo es igual solo que en vez de aumentar RGB en uno disminuimos en uno.

Otra cachondada que se puede hacer con la paleta es rotarla: imaginaos el juego que ofrece, si tenemos una paleta como la del ejemplo del principio, degradada en tonos rojos y "rotamos" la paleta a la izquierda (cada color toma el valor de las componentes RGB del color inmediatamente superior) el degradado parecerá que se va "moviendo"; imaginaos las posibilidades, cascadas de las que "cae" agua, etc. por supuesto se pueden rotar partes de la paleta en vez de la paleta entera. Por ejemplo podíamos tener 1 paleta con 3 degradados, uno rojo, otro verde y otro azul con 64 colores cada degradado y otros 64 colores para nuestras cosas, así podríamos crear una función para rotar indivoidualmente cada uno de los 3 degradados (os animo a que intentéis modificar el programa final de esta parte 2 y rotéis el color del bloque, por ejemplo variando sólo la escala de rojos).

Aquí va RPalLeft() que rota toda la paleta una posición a la izquierda.

void RPalRight(void)
{
int loop1;
unsigned char R,G,B,auxR,auxG,auxB ;

WRetrace() ;

GetCol(0,&auxR,&auxG,&auxB);

for(loop1=0;loop1<255 ;loop1++) //para cada uno de los 256 colores
{
GetCol(loop1+1,&R,&G,&B) ;
SetCol(loop1,R,G,B);
}

SetCol(255,auxR,auxG,auxB) ;

}

No hace falta llegar a quedarse calvo pensando, de que forma seria rotar la paleta a la derecha.

void RPalRight(void)
{
int loop1;
unsigned char R,G,B,auxR,auxG,auxB ;

WRetrace() ;

GetCol(255,&auxR,&auxG,&auxB);

for(loop1=254;loop1>-1 ;loop1--) //para cada uno de los 256 colores
{
GetCol(loop1,&R,&G,&B) ;
SetCol(loop1+1,R,G,B);
}

SetCol(0,auxR,auxG,auxB) ;

}

Bueno, ahora juntamos todo y tenemos :

#include
#include
#include
#include
#include
#include

unsigned char *vga=( unsigned char *) MK_FP(0xA000,0) ; //dirección de la memoria de vídeo

void SetMCGA(void) ;
void SetText(void) ;
void PutPixel(int x,int y, unsigned char col) ;
void Cls(unsigned char col) ;
void WRetrace() ;
void FadeUp() ;
void FadeDown() ;
void RPalRight(void) ;
void GetCol(unsigned char colorno,unsigned char *R,unsigned char *G,unsigned char *B)

{
outp(0x03C7,colorno) ;
*R=inp(0x03C9) ;
*G=inp(0x03C9) ;
*B=inp(0x03C9) ;
}

void SetCol(unsigned char colorno,unsigned char R,unsigned char G,unsigned char B)

{
outp(0x03C8,colorno) ;
outp(0x03C9,R) ;
outp(0x03C9,G) ;
outp(0x03C9,B) ;
}

void main(void)
{
int i,j,k ;
randomize() ;
SetMCGA() ;

for(i=0 ;i<64 ;i++) //generamos paleta de degradados
{
SetCol(i,i,0,0) ;
SetCol(64+i,0,i,0) ;
SetCol(128+i,0,0,i) ;
SetCol(192+i,i,i,i) ;
}

Cls(0) ; //limpiamos la pantalla con el color 0=negro.

for(k=0;k<200;k++)
{
for(i=20+k;i<83+k ;i++) //pintamos un rectángulo (100,50)->(200,100) con pixels de colores degradados
{

for(j=50 ;j<100 ;j++)
{
PutPixel(i,j,i-20) ;
}

}

delay(10);
Cls(0);

}

for(i=20;i<83 ;i++) //pintamos un rectángulo (100,50)->(200,100) con pixels de colores degradados
{
for(j=50 ;j<100 ;j++)
{

PutPixel(i,j,i-20) ;

}

}

delay(1000);

FadeUp() ;

delay(1000);

for(i=0 ;i<64 ;i++) //recuperamos paleta de degradados
{
SetCol(i,i,0,0) ;
SetCol(64+i,0,i,0) ;
SetCol(128+i,0,0,i) ;
SetCol(192+i,i,i,i) ;
}

delay(1000);

FadeDown();

delay(1000);

for(i=0 ;i<64 ;i++) //recuperamos paleta de degradados
{
SetCol(i,i,0,0) ;
SetCol(64+i,0,i,0) ;
SetCol(128+i,0,0,i) ;
SetCol(192+i,i,i,i) ;
}

delay(1000);

while( !kbhit())
{
RPalRight() ;
}

getch() ;

SetText() ;

}

void SetMCGA()
{
_AX=0x0013 ;
geninterrupt(0x10) ;
}

void SetText()
{
_AX=0x0003 ;
geninterrupt(0x10) ;
}

void PutPixel(int x,int y, unsigned char col)
{
memset(vga+x+(y*320),col,1) ;
}

void Cls(unsigned char col)
{
memset(vga,col,0xffff) ;
}

void WRetrace()
{
_DX=0x03DA ;

l1 : asm {
in al,dx ;
and al,0x08 ;
jnz l1 ;
}

l2 : asm {
in al,dx ;
and al,0x08 ;
jz l2 ;
}

}

void RPalRight(void)
{
int loop1;
unsigned char R,G,B,auxR,auxG,auxB ;
WRetrace() ;
GetCol(255,&auxR,&auxG,&auxB);
for(loop1=254;loop1>-1 ;loop1--) //para cada uno de los 256 colores
{
GetCol(loop1,&R,&G,&B) ;
SetCol(loop1+1,R,G,B);
}

SetCol(0,auxR,auxG,auxB) ;
}

void FadeDown()

{

int loop1,loop2 ;
unsigned char R,G,B ;

for(loop1=0 ;loop1<64 ;loop1++) //63 es el máximo de iteraciones como máximo el color puede ser blanco
{ //R=G=B=63
WRetrace() ;

for(loop2=0 ;loop2<256 ;loop2++) //para cada uno de los 256 colores

{

GetCol(loop2,&R,&G,&B) ;

if(R>0) R-- ; //vamos disminuyendo R,G y B R=0,G=0 y B=0 corresponde al negro

if(G>0) G-- ;

if(B>0) B-- ;

SetCol(loop2,R,G,B) ;

}

}

}

void FadeUp()

{

int loop1,loop2 ;

unsigned char R,G,B ;

for(loop1=0 ;loop1<64 ;loop1++) //63 es el máximo de iteraciones como mínimo el color puede ser negro

{ //R=G=B=0

WRetrace() ;

for(loop2=0 ;loop2<256 ;loop2++) //para cada uno de los 256 colores

{

GetCol(loop2,&R,&G,&B) ;

if(R<63) R++; //vamos aumentando R,G y B R=63,G=63 y B=63 corresponde al blanco

if(G<63) G++;

if(B<63) B++;

SetCol(loop2,R,G,B) ;

}

}

}

nota :La paleta siempre se ha de crear después de haber entrado en modo gráfico, si creamos la paleta en modo texto (que también se puede modificar, por cierto, la paleta en modo texto) y entramos en modo gráfico, esta se "reseteara", ojo.

Otro "efectillo" que he observado que se usa mucho en las demos es el de poner el "negativo" de las imágenes y que no consiste en otra cosa que en jugar con la paleta, ya os podéis imaginar como se hace, el "negativo" del blanco es el negro y el del negro el blanco .... lo único que hay que hacer es obtener la componente RGB de cada color de la paleta y obtener su complementario a 63 (por ejemplo 0,0,0->negro pasa a ser 63,63,63 blanco 23,33,13 pasaría a ser 40,30,50, R,G,B-> 63-R,63-G,63-B) así podríamos obtener el "negativo" de la imagen, como ejercicio os propongo que hagáis una función que cambie la paleta a su "negativo", otra cosa que no he hecho en el programa anterior es guardar la paleta en un array (si la paleta es fácil de generar como antes esto no es imprescindible.) que usaremos para restaurarla si hacemos alguna modificación en la misma, más adelante veremos esto en el capítulo 7, en el cual cargaremos las paletas de las imágenes de ficheros de imágenes.
  1   2   3   4

similar:

Introducción a la programación gráfica en C iconTaller com/manual-java/introduccion-java php >Introducción a Java...

Introducción a la programación gráfica en C iconProgramación general. Introducción (fundamentos legales y datos informativos)

Introducción a la programación gráfica en C iconDiseñador de la Comunicación Gráfica

Introducción a la programación gráfica en C iconLa gráfica popular de la época victoriana

Introducción a la programación gráfica en C iconLa representación gráfica del acento

Introducción a la programación gráfica en C iconLa grafica popular en la época victoriana

Introducción a la programación gráfica en C icon2. Reglas generales de la acentuación gráfica

Introducción a la programación gráfica en C iconGráfica da Casa Editora o Clarim

Introducción a la programación gráfica en C iconLa gráfica popular de la época victoriana

Introducción a la programación gráfica en C iconGráfica de Control o de Levey-Jennings


Medicina



Todos los derechos reservados. Copyright © 2015
contactos
med.se-todo.com