Thursday, April 19, 2007
Tuesday, April 17, 2007
It is very common, to want to have a program which can open other little windows.
How can we create little windows that are called by another window?
Maybe, these little windows could be called by a special event, perhaps a mouse event>
void mouse(int button, int state, int x, int y){//controla mouse de la window principal
switch( button ){
case GLUT_RIGHT_BUTTON:
if( state == GLUT_DOWN ){
subWindows=glutCreateWindow( "coordenadas" );
glutDisplayFunc( renderScene);
//glutIdleFunc(renderScene);
glutMouseFunc(raton);
// if(GLUT_VISIBLE) glutIdleFunc(NULL);
}
break;
}
In this function, we are going to be creating another little window, that shall show the spienski fractal. This window will be created when we right click our first window. subWindows=glutCreateWindow( "coordenadas" ); subWindows is a int identifier that can help us, for example when we wish to destroy the window.
We are also especifiy what functions to call when it is isrt displayed, when it is wating to recieve a comand from the mouse (idle situation) and we are also telling the window to what function relate the mouse to. Doing this, we can decide what happens when the user right clicks being in this window. In this case, we shall open an animation of another triangle.( Not of a robot, cuz our little robot friend was made with windows api, and ahhh we're using glut right now..and it gets really complicated..)
Notice that the idle function is not speciphid right now for this function, it isn't necesary to have this function actived since this window can pretty much stay with the same state as it had with it's display function. tHhis idle function is very important, when we have an animation, for example for the triangle one, and for the first window that prints the mouse coordinates.
We must define for each window animation what idle function should be called, notice that the main window has one, and that the triangle animation has another. We also tell the window to stop is idle functiton when it isn't visible, since it would just be a waste of energy to be moving around without really having anyone that pays attention to you.. it also better o tell which function has it's idle related to it, so you don't et taht while one window is running suddenly the others take uo this idle also.
This is done with the following fucntion>
glutSetWindow(subWindow3);
Anyway...here is the code>
#include
#include "./glut.h"
#include
#include
#include
#include "myDefs.h"
#include
void raton2(int button, int state, int x, int y);
void subTriangle(int n, float x1, float y1, float x2, float y2, float x3, float y3);
float angleT=0;//for moing the riangle animation
float angle=0.0,deltaAngle = 0.0,ratio;
int mainWindows=0,subWindow=0,subWindow3=0,subWindow1=0,subWindows=0;
int depth = 7;
float x=0.0f,y=1.75f,z=30.0f;
float Xm,Ym;
float lx=0.0f,ly=0.0f,lz=-1.0f;
int deltaMove = 0;
sPoint mida;
sPoint midc,midb,a,b,c;
float scaling=1;
int font=(int)GLUT_STROKE_ROMAN;
int counter=0;
int delta=1;
bool IsDragging = false;
int red=0,blue=1,green=1;
void myTimer(int value);
void drawSierpinski(float x1, float y1, float x2, float y2, float x3, float y3);
void raton(int button, int state, int x, int y);
void renderScene3(void) {
glutSetWindow(subWindow3);
// notice that we're now clearing the depth buffer
// as well this is required, otherwise the depth buffer
// gets filled and nothing gets rendered.
// Try it out, remove the depth buffer part.
glClear(GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT);
// save the previous settings, in this case save
// we're refering to the camera settings.
glPushMatrix();
angleT++;// finally increase the angle for the next frame
// Perform a rotation around the y axis (0,1,0)
// by the amount of degrees defined in the variable angle
glRotatef(angleT, 0.0,1.0,0.0);
glBegin(GL_TRIANGLES);
glVertex3f(-0.5,-0.5,0.0);
glVertex3f(0.5,0.0,0.0);
glVertex3f(0.0,0.5,0.0);
glEnd();
// discard the modelling transformations
// after this the matrix will have only the camera settings.
// swapping the buffers causes the rendering above to be
// shown
glPopMatrix();
glutSwapBuffers();
}
void drawLines(float x,float y, float z)
{
int ranx=rand()%1;
int rany=rand()%1;
int ranz=rand()%1;
if(red=0)red=1;
glTranslatef(x,y,z);
glBegin(GL_LINES);
glColor3f(1,rany,ranz);
glVertex3f(109.0, 104.0, 2.0);
glVertex3f(-6.0, -24.0, 3.3);
glEnd();
counter=0;
}
void changeSize(int w, int h)
{
// Prevent a divide by zero, when window is too short
// (you cant make a window of zero width).
if(h == 0)
h = 1;
ratio = 1.0f * w / h;
// Reset the coordinate system before modifying
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Set the viewport to be the entire window
glViewport(0, 0, w, h);
// Set the clipping volume
gluPerspective(45,ratio,1,10000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(x, y, z,
x + lx,y + ly,z + lz,
0.0f,1.0f,0.0f);
}
void initScene() {
glEnable(GL_DEPTH_TEST);
glLineWidth(4.0);
glutTimerFunc(1000,myTimer,1);
a.x=0;
a.y=0;
b.x=2.5;
b.y=4.3;
c.x=5;
c.y=0;
mida.x=(b.x-a.x)/2;
mida.y=(b.y-a.y)/2;//bottom left
midb.x=(c.x-a.x)/2;
midb.y=(c.y-a.y)/2;
midc.x=c.x-((c.x-b.x)/2);
midc.y=(b.y-a.y)/2; //bottom right
}
void myTimer(int value){
counter=counter+delta;
glutPostRedisplay();
glutTimerFunc( 1000,myTimer, 1);
}
void orientMe(float ang) {
lx = sin(ang);
lz = -cos(ang);
glLoadIdentity();
gluLookAt(x, y, z,
x + lx,y + ly,z + lz,
0.0f,1.0f,0.0f);
}
void moveMeFlat(int i) {
x = x + i*(lx)*0.1;
z = z + i*(lz)*0.1;
glLoadIdentity();
gluLookAt(x, y, z,
x + lx,y + ly,z + lz,
0.0f,1.0f,0.0f);
}
void renderStrokeCharacter(float x, float y, float z, void *font,char *string)
{
char *c;
glPushMatrix();
glTranslatef(x, y, z);
glScalef(scaling,scaling,0);
for (c=string; *c != '\0'; c++) {
glutStrokeCharacter(font, *c);
}
glPopMatrix();
}
void renderScene(void) {
/*if (deltaMove)
moveMeFlat(deltaMove);
if (deltaAngle) {
angle += deltaAngle;
orientMe(angle);
}*/
glClear(GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT);
char result[100];
sprintf( result, "%f", Xm );
/*if(counter==5)
{
// randomize();
int x1=rand()%99;
int y1=rand()%99;
drawLines(x1,y1,0);
counter=0;
}*/
drawSierpinski(b.x,b.y,a.x,a.y,c.x,c.y);
glPopMatrix();
//glFlush();
glutSwapBuffers();
}
void renderSceneCoor(void) {
/*if (deltaMove)
moveMeFlat(deltaMove);
if (deltaAngle) {
angle += deltaAngle;
orientMe(angle);
}*/
glutSetWindow(mainWindows);
glClear(GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT);
glPushMatrix();
char result[100];
char result2[100];
sprintf( result, "%f", Xm );
sprintf( result, "%f", Ym );
renderStrokeCharacter(-600,150,-800,(void *)font,"x");
renderStrokeCharacter(-400,150,-800,(void *)font,result);
renderStrokeCharacter(-600,-60,-800,(void *)font,"y");
renderStrokeCharacter(-400,-60,-800,(void *)font,result2);
drawSierpinski(b.x ,b.y,a.x,a.y,c.x,c.y);
glPopMatrix();
//glFlush();
glutSwapBuffers();
}
void pressKey(int key, int x, int y) {
switch (key) {
case GLUT_KEY_LEFT : scaling=2; deltaAngle = - 0.01f;break;
case GLUT_KEY_RIGHT : scaling=2; deltaAngle = 0.01f;break;
case GLUT_KEY_UP : deltaMove = 1;break;
case GLUT_KEY_DOWN : deltaMove = -1;break;
}
}
void releaseKey(int key, int x, int y) {
switch (key) {
case GLUT_KEY_LEFT :
case GLUT_KEY_RIGHT : deltaAngle = 0.0f;break;
case GLUT_KEY_UP :
case GLUT_KEY_DOWN : deltaMove = 0;break;
}
}
void processMenuEvents(int option) {
font = option;
}
/*void createMenus() {
int menu = glutCreateMenu(processMenuEvents);
glutAddMenuEntry("Roman",(int)GLUT_STROKE_ROMAN);
glutAddMenuEntry("Mono Roman",(int)GLUT_STROKE_MONO_ROMAN);
glutAttachMenu(GLUT_RIGHT_BUTTON);
}*/
void mouse(int button, int state, int x, int y){//controla mouse de la window principal
switch( button ){
case GLUT_RIGHT_BUTTON:
if( state == GLUT_DOWN ){
subWindows=glutCreateWindow( "coordenadas" );
glutDisplayFunc( renderScene);
//glutIdleFunc(renderScene);
glutMouseFunc(raton);
// if(GLUT_VISIBLE) glutIdleFunc(NULL);
}
break;
}
}// end mouse
void raton(int button, int state, int x, int y){//mueve mouse fur 2 fenster
switch( button ){
case GLUT_RIGHT_BUTTON:
if( state == GLUT_DOWN ){
subWindow3=glutCreateWindow( "robot" );
glutDisplayFunc( renderScene3 );
//glutIdleFunc(renderScene3);
glutMouseFunc(raton2);
if (GLUT_VISIBLE)
glutIdleFunc(renderScene3);
else
glutIdleFunc(NULL);
//glutMotionFunc( mouseDragg );
}
break;
case GLUT_LEFT_BUTTON:
if(state==GLUT_DOWN){
//glutDestroyWindow(subWindows);
}
break;
}
}
void raton2(int button, int state, int x, int y){//mueve mouse fur 2 fenster
switch( button ){
case GLUT_RIGHT_BUTTON:
if( state == GLUT_DOWN ){
glutDestroyWindow(subWindow3);
}
break;
}
}// end raton2, ventana2
void drawSierpinski(float x1, float y1, float x2, float y2, float x3, float y3)
{
//Draw the 3 sides of the triangle as black lines
glBegin(GL_TRIANGLES);
glColor3f( 1.0, 1.0, 0.0 );
glVertex2d( x1,y1);//top
glVertex2d( x2,y2);//bottom left
glVertex2d(x3,y3); //bott
glEnd();
//Call the recursive function that'll draw all the rest. The 3 corners of it are always the centers of sides, so they're averages
subTriangle
(
1, //This represents the first recursion
(x1 + x2) / 2, //x coordinate of first corner
(y1 + y2) / 2, //y coordinate of first corner
(x1 + x3) / 2, //x coordinate of second corner
(y1 + y3) / 2, //y coordinate of second corner
(x2 + x3) / 2, //x coordinate of third corner
(y2 + y3) / 2 //y coordinate of third corner
);
}
//The recursive function that'll draw all the upside down triangles
void subTriangle(int n, float x1, float y1, float x2, float y2, float x3, float y3)
{
//Draw the 3 sides as black lines
glBegin(GL_TRIANGLES);
glColor3f( 1.0, 0.0, 0.0 );
glVertex2d(x1,y1);//top
glVertex2d( x2,y2);//bottom left
glVertex2d(x3,y3); //bott
glEnd();
//Calls itself 3 times with new corners, but only if the current number of recursions is smaller than the maximum depth
if(n < xm="x;" ym="y;" isdragging =" true;" realy =" viewport[3]" x =" wx;" y =" wy;" key ="=" mainwindows="glutCreateWindow(">
Sunday, April 08, 2007
El jueves, mientras esperaba a Mugen, me tiré abajo de los árboles que están junto a la central con Jordi y con Itzel-O. Itzel-O tenía que acabar su tarea para Lunares asi que tenía que estar sentada. Jordi y yo nos estábamos haciendo gueyes. Bueno, total, no sé porque empezamos a platicar de pendejadas de cuando íbamos en la primaria y en la secundaria. Como temas comunes salieron el estar en la escolta, los festivales, los bailes colectivos, los talleres en la secu, los regalos del dia de las madres, los uniformes...infinidad de temas. A todos en algún punto de nuestras vidas nos han pasado cosas relativas a esos temas. Como lo que me contó Itzel-O de una individua a quien se le cayeron los calzones en plena escolta. Como lo de querer bailar Smack My Bitch Up en la escuela de Jordi. Como cuando en la primaria nos bannearon del Museo del Niño. Infinidad de historias padrísimas that make you remember so much....en fin, Itzel-O: ENJAAAAAMBRE!!!
Ese mismo jueves, Mugen me llevó a practicar Pump It Up. Para los que no saben, el Pump It Up es el equivalente koreano al Dance Dance Revolution. Aqui en México es mas practicado el Pump porque las máquinas son mas accesibles y puedes modificarlas más facilmente. Al modificarlas, me refiero meterles canciones que tu hagas. Por ejemplo, hay una máquina que tiene "Get This Party Started" de Pink. Como dice Mugen, esa canción sirve para practicar los pasos dobles. En fin, Mugen me ha estado enseñando a jugar en la máquina desde que empezamos a andar, o sea, hace un mes. Jugar un juego de baile es algo que siempre quize hacer. El inútil de Raúl nunca pudo enseñarme bien porque 1, ni él sabía bien y 2, íbamos a Dave and Busters y ese es un mal lugar para jugar porque tienes que andar pateando loncheras. Mugen me lleva a un arcade en el centro donde ya va gente grande que respeta los créditos que le echas a la máquina y es donde está la máquina mas moderna. Mugen es un vago piolota para ese juego y se la rifa super cabrón. Baila casi todas las canciones en crazy y las pasa casi todas. Cuando jugamos en modo arcade, él es quien pasa las canciones para que podamos bailar largo tiempo. Pero ayer pasó lo que nunca: pasé 3 canciones. Sabrán que ya estaba empezando a "marcar los pasos" (que la máquina te los detecte y te los cuente como good, perfect etc.), pero ayer pasé una canción con A y otras dos con C. Eso es muy bueno. Mugen me dijo que yo estaba aprendiendo al paso en que él aprendió, pero hasta cierto punto voy más rápido, que cuando él aprendió iba todos los dias. Yo voy 2 veces por semana a lo mucho y he avanzado bastante. Eso me dijo Mugen. Me sentí realmente contenta, porque estaba pudiendo hacer algo que deseaba deep down y para lo que creeia no tener coordinación. Mucho mejor, me estaba enseñando alguien a quien quiero tanto. Es algo que podemos compartir los dos y mi gran deseo es que algún dia llegue a ser igual de buena que él. Luv ya, little boy....
El viernes era otros de esos dias de hueva. Me da hueva ir los viernes a clase, pero pues ya que, llevo mi fofo trasero y a veces entro y a veces no. Éste Viernes no entré, pero hice algo más divertido que clase de Gervacia. Me fui a sentar a la oficina de Jo-Jo-Jorge a ver su trabajo aburrido y monótono. Su trabajo se describe como limitarse a dar informes y no hacer nada. Pero su oficina tiene a hell of a view. Ves casi todo el sur desde su oficina (está en un sexto piso). Y está muy callado y solo allá arriba, its really relaxing. Me encanta, porque Jorge es el encargado de dar los resultados de los exámenes de acreditación de idioma. La gente como idiota va y los pide y Jorge les mete los sustotes de "Presentaste el exámen en Enero...déjame ver...nop, tu nombre no aparece en la lista. Ah, no, lo presentaste en Febrero...ok, si pasaste. Ve a servicios escolares por tu constancia". La gente pasa de estar lívida a estar realmente alegre. En su oficina llegamos a estar Eriuzu, Mel, Ernesto y yo. Pero luego ya nos quedamos Eriuzu, Jorge y Yo. Traiamos buen desmadre: que si a Eriuzu le tocó ser funcionario de casilla (Yo si quize, asi de simple!!), que si Eurotrash es un inútil que todo rompe y desmadra, que si la oficina de Jorge sería mas alegre si tuviera un canario, que si los subtitulos de las peliculas, que si se podrian lanzar cosas desde la ventana...lo mejor del asunto, es que mas tarde llegó Gervacia a ver si Jorge no había incendiado la oficina y ni a mi ni a Eliud nos dijo nada de que no habiamos entrado a su clase. Es mas, me pregunto si siquiera se acuerda de que teniamos clase con ella. Fue muy divertido estar en la oficina de Jorge porque es muy silenciosa y nadie te fastidia. Aparte, es un buen lugar para que no te de calor ni frio y cuentas buena compañia. Jorge, yo como tu consciencia moral que te orilla a que te robes los cubiertos de metal de Arqui, te digo una cosa: si instalas una máquina de capuccino en la oficina de Gervacia, dejo la carrera y me voy ahi a hacer nada!
Me gusta hacer posts personales como éste. Me doy cuenta que mi vida no es un asco y que no soy de dar pena because I enjoy small moments in life. No estoy muy segura, pero a la otra persona a quien le había confesado ésta afición era a la mamá de mi abogado y me dijo que no tenía que apenarme por eso, que sencillamente la vida vale la pena por todas esas cosas pequeñas. Asi que, si algún dia ven que mi mirada está perdida y estoy sonriendo sin una razón aparente, I'm just enjoying that little moment in life....
There are days, that have very special events, that are rearly forgotten. There are other days..when it's mostly because one is very tried, full of troubles, that evetything just seems to pass by. This was happening to me, a week ago. It was actually really helpful for me to take this week off. I think I'm thinking clearer, really paying attention to what I'm doing.
Anyway, I was sitting in my living room, and sudenly something crossed my mind...What as I doing two tuesdays ago???? What was I doing in my favorite lab class???
what???
I remember it was March 27, 10 days after my mom's birthday but bla bla bla bla bla my other l
when I was 7 or 6 , I rememebr I had to do a picture of how I'd be when I was grown up. I rmemeber I drew myself with long straight hair, (i used to have straight hair) with a pen in my hand. I wanted to be a writer , when I grew up. I loved writing, I rememebr I would mont little plays for my school friends, I'd do differnet voices and interpreat diffenet characters...
Now, those days of writing are long gone. ... I think I stopped writitng writing, because ...
I don't quiet know why. Maybe it had something to do with my parent's approval. I guess that could explain, why I'm currenlty studying computer engineering!
Don't get me wrong, I enjoy programming, and I do love math, learing new things, finding solutions...but I miss playing, I miss making up characters, interpreating them...
ANyway, returning to the matter, that day in my Graphics lab class, my dear teacher, showed us a munch of neat examples using glut. We saw an example of a fractal.
I was really intreged by it.
I made my own little fractal here, which can be view by a special little window, this window can view only the desired part of the fractal. (we also saw some things about glutSpecialFunc (SpecialKey), as well as swapBuffers, which can help the screen not seem as if it is twiching...
I'm including as always the code->
#include
#include
#include
#include
#include
#include
//#include
#include "MyDefs.h"
// Some global vars
float CD = 0.0f;
sPoint CP, pa;
sPoint UpperLeftCorner, LowerRightCorner;
bool StartClipping = false;
bool IsDragging = false;
boolean right=false;
boolean left=false;
boolean top=false;
boolean bottom=false;
int main( int argc, char **argv)
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB );
glutInitWindowSize( 500, 500 );
glutInitWindowPosition( 0, 0 );
glutCreateWindow( "Snowflake" );
myInit();
glutDisplayFunc( display );
glutMouseFunc( mouse );
glutMotionFunc( mouseDragg );
glutMainLoop();
return 0;
}
void myInit( void ){
// Black as bk
glClearColor( 0.0, 0.0, 0.0, 1.0 );
//Draw color
glColor3f( 1.0, 0.0, 0.0 );
// Projection Matrix
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluOrtho2D( -12.0, 5.0, -6.0, 10.0 );
glMatrixMode( GL_MODELVIEW );
UpperLeftCorner.x = 0.0f;
UpperLeftCorner.y = 0.0f;
LowerRightCorner.x = 0.0f;
LowerRightCorner.y = 0.0f;
}
// Builds the Koch curve, recursive
void Koch( float dir, float len, int n ){
if( n > 0 ){
Koch( dir, len/3, n-1 );
dir = dir + 60.0f;
Koch( dir, len/3, n-1);
dir = dir - 120.0f;
Koch( dir, len/3, n-1);
dir = dir + 60.0f;
Koch( dir, len/3, n-1);
}else{
bool isDrawn = true;
sPoint paAux;
pa.x = CP.x + (double)len*cos((double)(rads*dir));
pa.y = CP.y + (double)len*sin((double)(rads*dir));
paAux = pa;
if( StartClipping ){
/// Aqui deben colocar su rutina de recorte, en el caso del codigo que desarrolle iba asi
/// isDrawn = clippingWindow->clipLine( &CP, &amp;pa );
/// isDrawn es un booleano que dice si la linea es visible y se usa en el if fuera de esta condicion
/// CP y pa son dos estructuras que les paso. La estructura es muy simple, solo contiene un punto
/// Por ahora dejo encendido el valor de isDrawn, para que se dibuje la region de recorte y toda la curva
/// Cuando coloquen ustedes su rutina, entonces solo sera visible la linea indicada por CP y pa
//isDrawn = true;
isDrawn = cyrusBeck(CP, pa, UpperLeftCorner, LowerRightCorner);
//std::cout << "I am alive" << cp =" paAux;" cp =" paAux;" dist =" 0.0f;" x =" CP.y" state ="=" realy =" viewport[3]" z =" 0.0" x =" wx;" y =" wy;" isdragging =" false;" window =" [(%f,">(%f, %f)]\n", UpperLeftCorner.x, UpperLeftCorner.y, LowerRightCorner.x, LowerRightCorner.y);
if( UpperLeftCorner.x > LowerRightCorner.x ){
pAux.x = UpperLeftCorner.x;
UpperLeftCorner.x = LowerRightCorner.x;
LowerRightCorner.x = pAux.x;
}
if( UpperLeftCorner.y < y =" UpperLeftCorner.y;" y =" LowerRightCorner.y;" y =" pAux.y;">SetClippingWindow( UpperLeftCorner, LowerRightCorner );
StartClipping = true;
display();
}
break;
case GLUT_RIGHT_BUTTON:
if( state == GLUT_DOWN )
exit(EXIT_SUCCESS);
break;
default:
break;
}
}//End mouse
void mouseDragg( int x, int y){
GLint viewport[4];
GLdouble mvMatrix[16], projMatrix[16];
GLint realY;
GLdouble wx, wy, wz;
glGetIntegerv( GL_VIEWPORT, viewport );
glGetDoublev( GL_MODELVIEW_MATRIX, mvMatrix );
glGetDoublev( GL_PROJECTION_MATRIX, projMatrix );
IsDragging = true;
realY = viewport[3] - (GLint)y - 1;
gluUnProject( (GLdouble)x, (GLdouble)realY, 0.0f, mvMatrix, projMatrix, viewport, &wx, &amp;wy, &wz );
LowerRightCorner.x = wx; LowerRightCorner.y = wy;
display();
}//mouseDragg
bool cyrusBeck( sPoint& p0,
sPoint& p1,
sPoint UpperLeftCorner,
sPoint LowerRightCorner ){
if( p0.x == p1.x && p0.y == p1.y ){
const double ulcXdiff = p0.x - UpperLeftCorner.x;
const double ulcYdiff = p0.y - UpperLeftCorner.y;
const double lrcXdiff = LowerRightCorner.x - p0.x;
const double lrcYdiff = LowerRightCorner.y - p0.y;
/*
* Si ulcXdiff < 0 =""> esta fuera del lado Izquierdo
* Si ulcYdiff < 0 =""> esta por arriba del clip area
* Si lrcXdiff < 0 =""> esta fuera del lado derecho
* Si lrcYdiff < 0 =""> esta por abajo del clip area
*/
//Evaluando
if( ( ulcXdiff < t_left =" NOINTERSEC;" t_right =" NOINTERSEC;" t_up =" NOINTERSEC;" t_bottom=" NOINTERSEC;" x =" p1.x" y =" p1.y" te =" 0," tl =" 1" temp =" 0;" den =" dotProduct(right_normal," x="UpperLeftCorner.x;" y="(LowerRightCorner.y-UpperLeftCorner.y)/2;" num =" dotProduct(left_normal," temp =" num/den;" t_left="temp;" t_left =" ("> 1)? NOINTERSEC: temp;
//if( t_left != NOINTERSEC ){
den *= -1;
left=true;
if( den > 0)
tE = getmax(tE,t_left);
else tL = getmin(tL, t_left);
std::cout << "Izquierda" << x =" p0.x" y =" p0.y" x =" p0.x" y =" p0.y" den =" dotProduct(left_normal," x="LowerRightCorner.x;" y="(LowerRightCorner.y-UpperLeftCorner.y)/2;" num =" dotProduct(right_normal," temp =" num/den;" t_right ="temp;"> 1)? NOINTERSEC: temp;
//if( t_right != NOINTERSEC ){
den *= -1;
right=true;
if( den > 0) tE = getmax(tE,t_right);
else tL = getmin(tL, t_right);
std::cout << "Derecha" << den =" dotProduct(bottom_normal," y="UpperLeftCorner.y;" x="(LowerRightCorner.x-UpperLeftCorner.x)/2;" num =" dotProduct(up_normal," temp =" num/den;" t_up="temp;"> 1)? NOINTERSEC: temp;
//if( t_up != NOINTERSEC ){
den *= -1;
top=true;
if( den > 0) tE = getmax(tE,t_up);
else tL = getmin(tL, t_up);
std::cout << "Arriba" << den =" dotProduct(up_normal," y="LowerRightCorner.y;" x="(LowerRightCorner.x-UpperLeftCorner.x)/2;" num =" dotProduct(bottom_normal," temp =" num/den;" t_bottom ="temp;" bottom="true;"> 0)tE = getmax(tE,t_bottom);
else tL = getmin(tL, t_bottom);
std::cout << "Abajo" << x =" p0.x" y =" p0.y" x =" p0.x" y =" p0.y">
pues bien..Hooondemos en que diablos es Glut->
Glut es una libreria muy util para los programas hechos en OpenGl, la cual basicamente opera a nivel de sistema las entradas y salidas del sistema operativo en el cual se haya trabajando.
La sfunciones que lleva acabo incluyen definicion de la ventana, control de la ventana, monitoreo del teclado y del mouse. rutinas para dibujar una serie de diferentes primitivas geometricas, como son cubos, espferas la tasita de te...Incluso se pueden hacerunos menucitos graciososo, de tipo popup...como los q ue usaron en el programa de bmp font... veamos algunas de sus funciones->
glutInit inicia la libreria GLUT. Recibe dos parametros, que son los parametros que son recibidos por el main desde la linea de comando. glutInit extraera de la linea de comando los parametros que sean entendidos
por GLUT. Por el momento poco nos interesa saber cuales son, y ademas dependen del sistema operativo en el que corra.
gluInit inicializara la libreria GLUT y negociara una sesion con el sistema (de ventanas) en el que este corriendo. Puede pasar que el programa se cierre si GLUT no puede gestionar una sesion, o si el sistema no soporta OpenGL. Del mismo modo reaccionara si recibe una linea de comando incorrecta.
glutInitDisplayMode(GLUT);
glutInitDisplayMode configura el modo de video inicial, el mismo recibe un parametro, con el que se le indica la configuracion deseada, el prototipo de la funcion es
void glutInitDisplayMode(unsigned int modo);
Debido a que cada opcion son mascaras de bits, se puede seleccionar mas de una mediante la operacion logica OR. Los modos permitidos son (estos no son la totalidad de los modos, pero los mas usados, para ver una lista completa, vease “The OpenGL Utility Toolkit (GLUT) Programming Interfase")
GLUT_GRBA | selecciona una ventana con modo RGBA por omision se selecciona esta si no se especifio ni RGBA o INDEX. |
GLUT_RGB | sinonimo para RGBA |
GLUT_SINGLE | selecciona una ventana con un solo buffer de color, si no se selecciona ni SINGLE ni DOUBLE, por omision se utiliza este |
GLUT_DOUBLE | selecciona una ventana con doble buffer. |
GLUT_ACCUM | selecciona una ventana con un buffer de acumulacion (o accumulation buffer) |
GLUT_ALPHA | selecciona una ventana cuyos color buffers tienen un componente alpha |
GLUT_DEPTH | selecciona una ventana con Depth Buffer (o Z-Buffer, o buffer de profundidad) |
GLUT_STENCIL | selecciona una ventana con un stencil buffer |
Por el momento solo iniciamos una ventana con RGB, en los proximos tutoriales iremos iniciando mas cosas, como Depth Buffer, Double Buffer, y demas.
glutInitWindowSize(300,300);
Aqui le indicamos a GLUT que la ventana que creara debe tener una dimension de 300x300 (ancho x alto).
glutCreateWindow("glTut #1");
Aqui le indicamos a GLUT que efectivamente cree la ventana en el sistema que se esta corriendo. glutCreateWindow toma como parametro un string, en el que se le indica el titulo de la ventana.
Bien, a partir de aqui viene la parte de asignacion de rutinas, nosotros debemos asignarle a GLUT que rutinas utilizara como Display, Reshape, Idle, entrada de datos, y demas. Cada una de estas tendra caracteristicas diferentes que veremos mas adelante. La ventaja que nos provee el hecho de que nosotros debamos asignarles las funciones, radica en que tenemos un poco mas de libertad con respecto al nombre de las mismas (si alguien ha utilizado alguna vez el workframe de D3D habra visto que incomodo resulta).
Asignemos ahora las rutinas.
glutDisplayFunc(Display);
Aqui le indicamos a GLUT que la rutina utilizada como Display sera la llamada Display. Este tipo de rutinas se ejecuta una vez por ciclo de programa, y sera la que realice todas las operaciones graficas (o sea de render).
glutReshapeFunc(Reshape);
Aqui hacemos lo mismo que antes, solo que esta vez le asignamos la rutina de Reshape. Reshape se ejecuta cuando la ventana es cambiada de tamaño, y la primera vez que la aplicacion es ejecutada.
glutKeyboardFunc(KeyDown);
Esta vez asignamos la funcion de I/O. Esta rutina se ejecuta cada vez que se detecta una entrada de datos por teclado, y sera la responsable de manejar e interpretar esa entrada.
glutIdleFunc(Idle);
Por ultimo asignamos la rutina de Idle. Idle se ejecuta una vez por ciclo de programa, y es usada usualmente para albergar el codigo de manejo de variables de la aplicacion.
Una vez asignadas todas las rutinas necesarias, el programa entra en un ciclo constante que termina cuando la aplicacion es cerrada. Dentro de este ciclo se ejecutaran las rutinas Display, Idle, y cuando sea necesario KeyDown y Reshape La entrada al ciclo se realiza mediante el llamado a
glutMainLoop();
Aqui terminamos el analisis de nuestro primer programa, si bien aun no hicimos nada con OpenGL, ya tenemos una pequeña aplicacion base, que nos servira (con unas pequeñas modificaciones) para nuestros futuros ejemplos y programas
GLUT soporta dos tipos de ventanas: top-level windows y subwindows. Ambos tipos soportan OpenGL rendering y las llamadas GLUT . Existe un identificador para ambos tipos de ventanas:
- glutCreateWindow : glutCreateWindow crea a top-level window. The name will be provided to the window system as the window's name. The intent is that the window system will label the window with the name.
- glutCreateSubWindow: creates a subwindow of the window identified by win of size width and height at location x and y within the current window. Implicitly, the current window is set to the newly created subwindow.
glutSetWindow, glutGetWindow: glutSetWindow sets the current window; glutGetWindow returns the identifier of the current window. If no windows exist or the previously current window was destroyed, glutGetWindow returns zero. glutSetWindow does not change the layer in use for the window; this is done using glutUseLayer.
glutDestroyWindow: glutDestroyWindow destroys the window specified by win and the window's associated OpenGL context, logical colormap (if the window is color index), and overlay and related state (if an overlay has been established). Any subwindows of destroyed windows are also destroyed by glutDestroyWindow. If win was the current window, the current window becomes invalid ( glutGetWindow will return zero).
glutPostRedisplay: Mark the normal plane of current window as needing to be redisplayed. The next iteration through glutMainLoop, the window's display callback will be called to redisplay the window's normal plane. Multiple calls to glutPostRedisplay before the next display callback opportunity generates only a single redisplay callback. glutPostRedisplay may be called within a window's display or overlay display callback to re-mark that window for redisplay.
glutSwapBuffers: Performs a buffer swap on the layer in use for the current window. Specifically, glutSwapBuffers promotes the contents of the back buffer of the layer in use of the current window to become the contents of the front buffer. The contents of the back buffer then become undefined. The update typically takes place during the vertical retrace of the monitor, rather than immediately after glutSwapBuffers is called.
glutPositionWindow
:
glutPositionWindow
requests a change in the position of the
current window
. For top-lev
el windows, the
x
and
y
parameters are pixel offsets from the screen origin. For subwindows, the
x
and
y
parameters are pixel offsets from the window's parent window origin.
glutReshapeWindow: glutReshapeWindow requests a change in the size of the
current window. The width and height parameters are size extents in pixels. The width and height must be positive values.
glutFullScreen: glutFullScreen requests that the current window be made full screen. The exact semantics of what full screen means may vary by window system. The intent is to make the window as large as possible and disable any window decorations or borders added the window system. The window width and height are not guaranteed to be the same as the screen width and height, but that is the intent of making a window full screen.
glutPopWindow, glutPushWindow: glutPopWindow and glutPushWindow work on both top-level windows and subwindows. The effect of pushing and popping windows does not take place immediately. Instead the push or pop is saved for execution upon return to the GLUT event loop. Subsequent push or pop requests on a window replace the previously saved request for that window. The effect of pushing and popping top-level windows is subject to the window system's policy for restacking windows.
glutShowWindow, glutHideWindow, glutIconifyWindow : glutShowWindow will show the current window (though it may still not be visible if obscured by other shown windows). glutHideWindow will hide the current window. glutIconifyWindow will iconify a top-level window, but GLUT prohibits iconification of a subwindow. The effect of showing, hiding, and iconifying windows does not take place immediately. Instead the requests are saved for execution upon return to the GLUT event loop. Subsequent show, hide, or iconification requests on a window replace the previously saved request for that window. The effect of hiding, showing, or iconifying top-level windows is subject to the window system's policy for displaying windows.
glutSetWindowTitle, glutSetIconTitle: These routines should be called only when the current window is a top-level window. Upon creation of a top-level window, the window and icon names are determined by the name parameter to glutCreateWindow. Once created, glutSetWindowTitle and glutSetIconTitle can change the window and icon names respectively of top-level windows. Each call requests the window system change the title appropriately. Requests are not buffered or coalesced. The policy by which the window and icon name are displayed is window system dependent.
glutSetCursor: glutSetCursor changes the cursor image of the current window. Each call requests the window system change the cursor appropriately. The cursor image when a window is created is GLUT_CURSOR_INHERIT. The exact cursor images used are implementation dependent. The intent is for the image to convey the meaning of the cursor name. For a top-level window, GLUT_CURSOR_INHERIT uses the default window system cursor.
GLUT_CURSOR_RIGHT_ARROW
Arrow pointing up and to the right.
GLUT_CURSOR_LEFT_ARROW
Arrow pointing up and to the left.
GLUT_CURSOR_INFO
Pointing hand.
GLUT_CURSOR_DESTROY
Skull & cross bones.
GLUT_CURSOR_HELP
Question mark.
GLUT_CURSOR_CYCLE
Arrows rotating in a circle.
GLUT_CURSOR_SPRAY
Spray can.
GLUT_CURSOR_WAIT
Wrist watch.
GLUT_CURSOR_TEXT
Insertion point cursor for text.
GLUT_CURSOR_CROSSHAIR
Simple cross-hair.
GLUT_CURSOR_UP_DOWN
Bi-directional pointing up & down.
GLUT_CURSOR_LEFT_RIGHT
Bi-directional pointing left & right.
GLUT_CURSOR_TOP_SIDE
Arrow pointing to top side.
GLUT_CURSOR_BOTTOM_SIDE
Arrow pointing to bottom side.
GLUT_CURSOR_LEFT_SIDE
Arrow pointing to left side.
GLUT_CURSOR_RIGHT_SIDE
Arrow pointing to right side.
GLUT_CURSOR_TOP_LEFT_CORNER
Arrow pointing to top-left corner.
GLUT_CURSOR_TOP_RIGHT_CORNER
Arrow pointing to top-right corner.
GLUT_CURSOR_BOTTOM_RIGHT_CORNER
Arrow pointing to bottom-left corner.
GLUT_CURSOR_BOTTOM_LEFT_CORNER
Arrow pointing to bottom-right corner.
GLUT_CURSOR_FULL_CROSSHAIR
Full-screen cross-hair cursor (if possible, otherwise GLUT_CURSOR_CROSSHAIR).
GLUT_CURSOR_NONE
Invisible cursor.
GLUT_CURSOR_INHERIT
Use parent's cursor.
Ahora que la ventana ha sido creada, es necesario mostrarla. Para ello la función
main llama a la función glutDisplayFunc(). Esta función es la más importante de las
funciones callback. Gracias a la definición de las funciones callback, GLUT hace posible
una dinámica de programación de aplicaciones OpenGL. Una función callback será
llamada por GLUT para hacer alguna operación especifica cada vez que se produzca un
evento. En este caso, glutDisplayFunc(display), define que la función display que es
pasada como argumento sea ejecutada cada vez que GLUT determine que la ventana debe
ser dibujada (la primera vez que se muestra la ventana) o redibujada (cuando se maximiza,
cuando se superponen varias ventanas, etc).
La ultima función que es llamada en el main es glutMainLoop(). Esta función se
encarga de pasar el control del flujo del programa a la GLUT, de manera que cada vez que
ocurra un “evento” sean llamadas las funciones definidas como callbacks hasta que el la
ventana se cierre.
La función GLUT glutWireTorus(0.25, 0.75, 28, 28) dibuja un toroide de frame de
hilos cuyo radio interno es el double 0,25; radio externo el double 0,75; el primer entero 28
representa el numero de lados que se puede observar en cada sección radial y el segundo
entero 28 el numero de divisiones radiales del toroide.
La función GLUT glutWireCube(0.60) dibuja un cubo cuyo tamaño queda
determinado por su único parámetro de valor float.
DEFINIENDO EL ÁREA DE PROYECCIÓN INICIAL
Una vez que se ha dibujado un objeto en la ventana es necesario definir el área de
proyección inicial que se desea de la figura en la ventana. Para ello se debe manipular el
área de proyección por medio de la función callback glutReshapeFunc(). Esta función
callback especifica cuál función será llamada cada vez que la ventana sea redimensionada
o movida, pero también es utilizada para definir inicialmente el área de proyección de la
figura en la ventana.
Overlay Management
When overlay hardware is available, GLUT provides a set of routine for establishing, using, and removing an overlay for GLUT windows. When an overlay is established, a separate OpenGL context is also established. A window's overlay OpenGL state is kept distinct from the normal planes OpenGL state.
glutEstablishOverlay: glutEstablishOverlay establishes an overlay (if possible) for the current window. The requested display mode for the overlay is determined by the initial display mode. glutLayerGet(GLUT_OVERLAY
glutUseLayer : changes the layer in use for the current window.
glutRemoveOverlay: glutRemoveOverlay removes the overlay (if one exists). It is safe to call glutRemoveOverlay even if no overlay is currently established--it does nothing in this case. Implicitly, the window's layer in use changes to the normal plane immediately once the overlay is removed.
glutPostOverlayRedisplay : marks the overlay of the current window as needing to be redisplayed.
glutShowOverlay, glutHideOverlay : glutShowOverlay shows the overlay of the current window; glutHideOverlay hides the overlay. The effect of showing or hiding an overlay takes place immediately. Note that glutShowOverlay will not actually display the overlay unless the window is also shown (and even a shown window may be obscured by other windows, thereby obscuring the overlay). It is typically faster and less resource intensive to use these routines to control the display status of an overlay as opposed to removing and re-establishing the overlay.
Primitivas de objetos predefinidos
Hay algunos objetos que vamos a renderizar muy a menudo, y que por tanto, ya vienen definidos. Así,
disponemos de las siguientes funciones:
- glutWireSphere(radius, slices, stacks), glutSolidSphere(radius, slices, stacks)
- glutWireCube(size), glutSolidCube(size)
- glutWireCone(base, height, slices, stacks), glutSolidCone(base, height, slices, stacks)
- glutWireDodecahedron(void), glutSolidDodecahedron(void)
- glutWireOctahedron(void), glutSolidOctahedron(void)
- glutWireTetrahedron(void), glutSolidTetrahedron(void)
- glutWireIcosahedron(void), glutSolidIcosahedron(void)
- glutWireTeapot(void), glutSolidTeapot(void)
Control del mouse
De entre los callbacks que nos da la GLUT, son especialmente interesantes para el control del mouse los
siguientes:
Definición de menús
La GLUT provee una manera sencilla de definir menús para nuestra aplicación. Veamos algunas de las
herramientas de que disponemos para trabajar con menús:
Funciones de CallBack
Hay cuatro funciones de callback de debemos conocer.
- Display: Esta función es invocada cuando el sistema determina que el contenido de la ventana tiene que ser redibujado, por ejemplo cuando la ventana se abre, o arrastramos otra ventana por delante de esta. La función de glut encargada de registrar este evento es glutDisplayFunc(). La función que registramos no tiene ningún argumento de entrada.
- Reshape: La ventada de la aplicación puede cambiar de tamaño, normalmente porque el usuario arrastre alguno de los bordes de la ventana con el ratón. La función que registra este evento es glutReshapeFunc(). Y la función que nosotros registremos para manejar el evento debe tener dos parámetros enteros. Cuando se ejecute esta función de redimensión estos dos parámetros contendrán los nuevos valores del tamaño de la ventana.
- Mouse: Esta función va a manejar los eventos que sean producidos por el ratón. Por ejemplo, que uno de los botones se presione o se suelte. La función que registra este evento es glutMouseFunc(). Al igual que en el caso anterior, esta función, al ser invocada pasa argumentos a la función de callback. En este caso estos argumentos describen la posición del ratón y el evento que se acaba de producir.
- Keyboard: Esta función es muy parecida a la anterior. En este caso en lugar del ratón se trata de un evento de teclado. La función de glut que registra el callback es glutKeyboardFunc(). Y como viene siendo normal, a la función de callback también se le pasa información sobre la tecla en la que se ha producido el evento. Como caso excepcional, al callback también se le suministra información sobre la posición del ratón en el momento que se pulsó la tecla.
- glutEntryFunc: sets the mouse enter/leave callback for the current window.
- glutSpecialFunc: sets the special keyboard callback for the current window.
- glutSpaceballMotionFunc: sets the Spaceball motion callback for the current window.
- glutSpaceballRotateFunc: sets the Spaceball rotation callback for the current window.
- glutSpaceballButtonFunc: The Spaceball button callback for a window is called when the window has Spaceball input focus (normally, when the mouse is in the window) and the user generates Spaceball button presses.
- glutButtonBoxFunc: sets the dial & button box button callback for the current window.
- glutDialsFunc: sets the dial & button box dials callback for the current window.
- glutTabletMotionFunc: sets the special keyboard callback for the current window.
- glutTabletButtonFunc: sets the special keyboard callback for the current window.
- glutMenuStatusFunc: sets the global menu status callback.
- glutIdleFunc: sets the global idle callback.
- glutTimerFunc: registers a timer callback to be triggered in a specified number of milliseconds.
Manejo de Color y Color Bitmap
- glutSetColor: sets the color of a colormap entry in the layer of use for the current window.
- glutGetColor: retrieves a red, green, or blue component for a given color index colormap entry for the layer in use's logical colormap for the current window.
- glutCopyColormap: copies the logical colormap for the layer in use from a specified window to the current window.
Recuperación del estado
- glutGet : retrieves simple GLUT state represented by integers.
- glutLayerGet : retrieves GLUT state pertaining to the layers of the current window.
- glutDeviceGet : recupera la información del dispositivo GLUT representado por números enteros.
- glutGetModifiers vuelve el estado de la llave del modificante cuando ciertos servicios repetidos fueron generados.
- glutExtensionSupported : ayuda a determinar fácilmente si una extensión dada de es soportada por OpenGL.
Representación de la fuente
- glutBitmapCharacter: representa un carácter a memoria de imagen que usa OpenGL.
- glutBitmapWidth: vuelve la anchura de un carácter a memoria de imagen.
- glutStrokeCharacter: representa un carácter en movimiento usando OpenGL.
- glutStrokeWidth: regresa el tamaño de un carácter en movimiento
Representación geométrica del objeto
- glutSolidSphere, glutWireSphere: representan una esfera en sólido o en wireframe respectivamente.
- glutSolidCube, glutWireCube: representa un cubo en un sólido o en wireframe respectivamente
- glutSolidCone, glutWireCone: representa un cono en un sólido o en wireframe respectivamente
- glutSolidTorus, glutWireTorus: representa un toroide en un sólido o en wireframe respectivamente
- glutSolidDodecahedron, glutWireDodecahedron: representa un dodecaedro en un sólido o en wireframe respectivamente
- glutSolidOctahedron, glutWireOctahedron: representa un octaedro en un sólido o en wireframe respectivamente
- glutSolidTetrahedron, glutWireTetrahedron: representa un tetraedro en un sólido o en wireframe respectivamente
- glutSolidIcosahedron, glutWireIcosahedron: representa un icosaedro(20 lados) en un sólido o en wireframe respectivamente
- 11.9 glutSolidTeapot, glutWireTeapot : representa una tetera en un sólido o en wireframe respectivamente
As long as I can remember, I've had english teachers that have left some mark on me, good or bad. When its a good thing, I remember them fondly and try to live up to their teachings. When its a bad thing, I just remember as the example of what teaching is not supposed to be. People have heard me say "fuck, I feel like I have just been at Ms.Sandra's class" when I come out of Pikarya's class. And that's because they both have some fixation with English Literature. They have it with a reason, thats the subject that they both teach ¬¬. I also say sometimes "Man, I miss Kelly" and that is because all I ever learned from grammar is because of him. He was EXTREMELY pacient regarding grammar. He knew I was lazy and still tried to keep me interested. I'm still lazy and still have a hard time with grammar, but the few things I got right on Pikarya's English 4 test were because of him.
I've got this teacher, whom we are not gonna fully name. Let's just call him Jara. This young man reminds me of Kelly so much. See, Kelly used to give us these assignments about public speaking and stuff. We had to organize a debate and investigate on both sides. The typical issues that came up were abortion, gun control, drug legalization and junk of the kind. These were controversial issues and you could easily find stuff online. It was 1999 back then...internet was not what it is today. Sure, you could find things easily, but you had to rewrite them and make them look like you did them. Back then, any numbscull could download things and pass it as theirs. Today, you can still do it but is not that easy to get away with it. Teacher are more aware of what's online and all the information you can get. I'm digressing now, the point is that Kelly was from the first teachers that became aware of how internet works. I specially remember once when he caught this gal with a complete copy/paste from a website. For him, it was evident because of the syntax and the vocabulary. Still, this gal thought Kelly was stupid enough not to realize she had downloaded it.
Kelly was my junior high english teacher. I'm in college now and have other subjects. Still, I have maaany papers to do and little time to do them. Jara is just a kid when it come to teaching and also, this Kid is a junior high teacher. What annoys me, is that this guy is like Kelly but in a college class. And still, Kelly wouldn't be so annoying when it comes down to grading papers. Sure, Kelly got suspicious of well written things. But not ALL things. See, this kid googles anything that seems well written and doesnt trust anyone. In his mind, students aren't able of writing good stuff. They always download things. I won't deny the fact that there are still cases in which people steal things from the internet, though its not everyone. To make things shorter, this kid thinks that we all are his junior high students and that our papers are not worth it. He think he's dealing with a bunch of 14 year olds who are not trustworthy.
Comparing this kid Jara with Kelly, I've come to realize that I feel as if I never left junior high at all. I still have to do stupid expositions in class. I still have to do a paper and be worried about things seeming as if I had stolen them from internet. I still feel bored in class. I still don't pay attention. All these defects didn't exist on Kelly's class. He was a better teacher, even if he was teaching junior high english. He trusted us most of the times. His project weren't dull and boring. His class was interesting, even if grammar sucks. In a nutshell, Kelly respected us.
All this to say that there are some people who are meant to stay teaching silly junior high kids and there are others who are meant for better things.
I hope you are writting screenplays.
I hope you still listen Nikita's Soundtrack.
I hope you still read Calvin and Hobbes.
I hope you still like hockey.
I hope you still take the school bus.
I'm baack....I got some looovin, I returned to do a little more programming.
We are gonn be a little more serios this this time, but we're gonna talk about an interesting subject, a timer function.
How can a timer function help us in any way?
It turns out to be a handy place to run our game's logic rules - a few programming tricks can help us to run the logic as often as we want (if, for example, you want to drop the block by a line every second, you can play some tricks with either the value parameter or global variables to have this function run the logic module after a second has passed). Furthermore, we can also use it for specified programatically. Something like a combination of "As fast as we can" and "as often as we want," this method can be used to specify a programatically-varied framerate. Basically, this allows those with better video cards to get a more visually stimulating experience, while still preserving as much of the flow as possible.
Now I have to admit, I'm not as familiar with this method , but the leap of logic to get there isn't all that large to begin with. Basically, you use C++'s time library to obtain a reference to the system clock (the number of milliseconds), which you then post against a target frame rate. This way, if you're doing some intense 3D stuff, and your computer can't really handle it, you can still roughly regulate the motion that takes place on the screen by multiplying the desired motion per frame by the ratio of target frames/actual frames.
I made a simple code, where I display a timer. This timer is running like crazy, incrementing itself every 1000 miliseconds. But, when the user right clicks the counter resets itself, aaand when the user left clicks the mouse, the timer takes a little pause.
Here's the code->
#include
#include "./glut.h"
#include
#include
#include
float angle=0.0,deltaAngle = 0.0,ratio;
float x=0.0f,y=1.75f,z=30.0f;
float lx=0.0f,ly=0.0f,lz=-1.0f;
int deltaMove = 0;
float scaling=1;
int font=(int)GLUT_STROKE_ROMAN;
int counter=0;
int delta=1;
void myTimer(int value);
void changeSize(int w, int h)
{
// Prevent a divide by zero, when window is too short
// (you cant make a window of zero width).
if(h == 0)
h = 1;
ratio = 1.0f * w / h;
// Reset the coordinate system before modifying
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Set the viewport to be the entire window
glViewport(0, 0, w, h);
// Set the clipping volume
gluPerspective(45,ratio,1,10000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(x, y, z,
x + lx,y + ly,z + lz,
0.0f,1.0f,0.0f);
}
void initScene() {
glEnable(GL_DEPTH_TEST);
glLineWidth(4.0);
glutTimerFunc(1000,myTimer,1);
}
void myTimer(int value){
counter=counter+delta;
glutPostRedisplay();
glutTimerFunc( 1000,myTimer, 1);
}
void orientMe(float ang) {
lx = sin(ang);
lz = -cos(ang);
glLoadIdentity();
gluLookAt(x, y, z,
x + lx,y + ly,z + lz,
0.0f,1.0f,0.0f);
}
void moveMeFlat(int i) {
x = x + i*(lx)*0.1;
z = z + i*(lz)*0.1;
glLoadIdentity();
gluLookAt(x, y, z,
x + lx,y + ly,z + lz,
0.0f,1.0f,0.0f);
}
void renderStrokeCharacter(float x, float y, float z, void *font,char *string)
{
char *c;
glPushMatrix();
glTranslatef(x, y, z);
glScalef(scaling,scaling,0);
for (c=string; *c != '\0'; c++) {
glutStrokeCharacter(font, *c);
}
glPopMatrix();
}
void renderScene(void) {
if (deltaMove)
moveMeFlat(deltaMove);
if (deltaAngle) {
angle += deltaAngle;
orientMe(angle);
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
char result[100];
sprintf( result, "%d", counter );
renderStrokeCharacter(-400,150,-800,(void *)font,result);
renderStrokeCharacter(-400,0, -800,(void *)font,"Ich liebe Viktor!");
glPopMatrix();
glutSwapBuffers();
}
void pressKey(int key, int x, int y) {
switch (key) {
case GLUT_KEY_LEFT : scaling=2; deltaAngle = -0.01f;break;
case GLUT_KEY_RIGHT : scaling=2; deltaAngle = 0.01f;break;
case GLUT_KEY_UP : deltaMove = 1;break;
case GLUT_KEY_DOWN : deltaMove = -1;break;
}
}
void releaseKey(int key, int x, int y) {
switch (key) {
case GLUT_KEY_LEFT :
case GLUT_KEY_RIGHT : deltaAngle = 0.0f;break;
case GLUT_KEY_UP :
case GLUT_KEY_DOWN : deltaMove = 0;break;
}
}
void processMenuEvents(int option) {
font = option;
}
/*void createMenus() {
int menu = glutCreateMenu(processMenuEvents);
glutAddMenuEntry("Roman",(int)GLUT_STROKE_ROMAN);
glutAddMenuEntry("Mono Roman",(int)GLUT_STROKE_MONO_ROMAN);
glutAttachMenu(GLUT_RIGHT_BUTTON);
}*/
void mouse(int button, int state, int x, int y){
switch( button ){
case GLUT_LEFT_BUTTON:
if( state == GLUT_DOWN ){
scaling=1.3;
counter=0;//para riniciar el contador...
delta=1;//reiniciando el contador, de nuevo se debe poder ir icremntando
}
break;
case GLUT_RIGHT_BUTTON:
if( state == GLUT_DOWN ){
scaling=.5;
delta=0;//pausa al contador.
}
break;
}
}// end mouse
void processNormalKeys(unsigned char key, int x, int y) {
if (key == 27)
exit(0);
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(100,100);
glutInitWindowSize(640,360);
glutCreateWindow("Saiph's love Declaration");
initScene();
glutKeyboardFunc(processNormalKeys);
glutIgnoreKeyRepeat(1);
glutSpecialFunc(pressKey);
glutSpecialUpFunc(releaseKey);
// createMenus();
glutMouseFunc(mouse);
glutDisplayFunc(renderScene);
glutIdleFunc(renderScene);
glutReshapeFunc(changeSize);
glutMainLoop();
return(0);
}